My latest "speedy" design: a small case for an Arduino Nano and a NRF24 module used as a Repeater.
Get it at Thingiverse
My latest "speedy" design: a small case for an Arduino Nano and a NRF24 module used as a Repeater.
Get it at Thingiverse
Today i made another couple of tests with a repeater to see if i can get signal from my first floor to the ground floor (where is the gateway) with promising results. Still waiting for my NRF24/PA/LNA to arrive still.
I was wondering if its ok to set the MY_RF24_PA_LEVEL to HIGH on all powered nodes (sensors, repeater and gateway), or the performance will be degraded?
Talking about the frequency ranges, i have a mesh of wifi Ubiquiti Unifi AP's in my house, which are able to do a RF scan and show me the channels that are more utilized. It seems the more crowded channels here are (20 MHz): 5 (2421-2443), 6 (2431-2453 MHz), and (40 MHz): 3 (2401-2443), 5 (2411-2453) and 9 (2431-2473).
With this in mind, im setting up my nodes on channel 2 (MY_RF24_CHANNEL 1 if im correct) where there is 0% utilization.
PS: i have an original Nokia charger rated at 5v on the label but actually gives out 7v dc... Had another one rated at 5.4v but i measured aroud 7.6. Are these chargers supposed to work with a pre-determined load?
Hi everyone.
I've introduced a small 0.96" OLED display (based on the SSD1306) on the temperature and humidity node, so you can read directly the values as you enter the house compartment (as you can see above).
Since i dont know the reliability of this kind of displays and they are a bit bright (of if they have some kind of burn-in issue), im asking you guys for some ideas to turn it off and back on, maybe taking into account info got from the controller (and even display other info).
Im using the u8g2 display library wich has the instruction "setContrast", but these displays dont support contrast control. It seems the only way is to turn it off with the instruction "setPowerSave".
I was thinking of displaying the current date also and maybe turn it off at night. For this i was thinking of using the "requestTime()" command…
What do you guys think?
Here is my code so you can take a look and use on your own projects:
// Enable debug prints
//#define MY_DEBUG
#define MY_RADIO_RFM69
#define MY_IS_RFM69HW
#define MY_RFM69_NEW_DRIVER
#define MY_RFM69_FREQUENCY RFM69_433MHZ
#define MY_NODE_ID 15
// #define MY_REPEATER_FEATURE
#include <SPI.h>
#include <MySensors.h>
#include <DHT.h>
#include <U8g2lib.h>
#include <Wire.h>
U8G2_SSD1306_128X64_NONAME_1_HW_I2C u8g2(U8G2_R0, A5, A4); // U8G2 Constructor (A5 - Clock SCL ; A4 - Data SDA)
// Set this to the pin you connected the DHT's data pin to
#define DHT_DATA_PIN 3
// Set this offset if the sensor has a permanent small offset to the real temperatures.
// In Celsius degrees (as measured by the device)
#define SENSOR_TEMP_OFFSET 0
// Sleep time between sensor updates (in milliseconds)
// Must be >1000ms for DHT22 and >2000ms for DHT11
static const uint64_t UPDATE_INTERVAL = 60000;
// Force sending an update of the temperature after n sensor reads, so a controller showing the
// timestamp of the last update doesn't show something like 3 hours in the unlikely case, that
// the value didn't change since;
// i.e. the sensor would force sending an update every UPDATE_INTERVAL*FORCE_UPDATE_N_READS [ms]
static const uint8_t FORCE_UPDATE_N_READS = 10;
#define CHILD_ID_HUM 0
#define CHILD_ID_TEMP 1
float lastTemp;
float lastHum;
uint8_t nNoUpdatesTemp;
uint8_t nNoUpdatesHum;
bool metric = true;
MyMessage msgHum(CHILD_ID_HUM, V_HUM);
MyMessage msgTemp(CHILD_ID_TEMP, V_TEMP);
DHT dht;
void before(){
u8g2.begin();
u8g2.firstPage();
do {
u8g2.setFont(u8g2_font_helvR14_tf);
u8g2.drawStr(38,15,"OLED");
u8g2.drawStr(15,35,"Temp+Hum");
u8g2.drawStr(46,60,"v1.2");
} while ( u8g2.nextPage() );
delay(3000);
u8g2.clear();
u8g2.firstPage();
do {
u8g2.drawStr(3, 32, "Connecting...");
} while ( u8g2.nextPage() );
}
void presentation()
{
// Send the sketch version information to the gateway
sendSketchInfo("TEMPHUM_OLED", "1.2");
// Register all sensors to gw (they will be created as child devices)
present(CHILD_ID_HUM, S_HUM);
present(CHILD_ID_TEMP, S_TEMP);
metric = getControllerConfig().isMetric;
}
void setup()
{
u8g2.clear();
dht.setup(DHT_DATA_PIN); // set data pin of DHT sensor
if (UPDATE_INTERVAL <= dht.getMinimumSamplingPeriod()) {
u8g2.firstPage();
do {
u8g2.setFont(u8g2_font_haxrcorp4089_tr); // 7 PIXEL HIGHT
u8g2.drawStr(1,12,"WARNING: UPDATE_INTERVAL");
u8g2.drawStr(1,24,"is smaller than supported by");
u8g2.drawStr(1,36,"the sensor!");
} while ( u8g2.nextPage() );
delay(4000);
}
// Sleep for the time of the minimum sampling period to give the sensor time to power up
// (otherwise, timeout errors might occure for the first reading)
sleep(dht.getMinimumSamplingPeriod());
}
void loop()
{
while (transportCheckUplink() == false){
u8g2.firstPage();
do {
u8g2.setFont(u8g2_font_helvR14_tf); // 14 px height
u8g2.drawStr(3, 32, "Disconnected!");
} while ( u8g2.nextPage() );
}
// Force reading sensor, so it works also after sleep()
dht.readSensor(true);
// Get temperature from DHT library
float temperature = dht.getTemperature();
if (isnan(temperature)) {
Serial.println("Failed reading temperature from DHT!");
} else if (temperature != lastTemp || nNoUpdatesTemp == FORCE_UPDATE_N_READS) {
// Only send temperature if it changed since the last measurement or if we didn't send an update for n times
lastTemp = temperature;
// apply the offset before converting to something different than Celsius degrees
temperature += SENSOR_TEMP_OFFSET;
if (!metric) {
temperature = dht.toFahrenheit(temperature);
}
// Reset no updates counter
nNoUpdatesTemp = 0;
send(msgTemp.set(temperature, 1));
#ifdef MY_DEBUG
Serial.print("T: ");
Serial.println(temperature);
#endif
} else {
// Increase no update counter if the temperature stayed the same
nNoUpdatesTemp++;
}
// Get humidity from DHT library
float humidity = dht.getHumidity();
if (isnan(humidity)) {
Serial.println("Failed reading humidity from DHT");
} else if (humidity != lastHum || nNoUpdatesHum == FORCE_UPDATE_N_READS) {
// Only send humidity if it changed since the last measurement or if we didn't send an update for n times
lastHum = humidity;
// Reset no updates counter
nNoUpdatesHum = 0;
send(msgHum.set(humidity, 1));
#ifdef MY_DEBUG
Serial.print("H: ");
Serial.println(humidity);
#endif
} else {
// Increase no update counter if the humidity stayed the same
nNoUpdatesHum++;
}
u8g2.firstPage();
do {
u8g2.setFont(u8g2_font_fub30_tn);
u8g2.setCursor(2, 35);
u8g2.print(temperature, 1);
u8g2.setFont(u8g2_font_inb16_mf);
u8g2.drawGlyph(88, 35, 0x00b0); // degree
u8g2.drawStr(100, 35, "C");
u8g2.setCursor(70, 60);
u8g2.print(humidity, 0);
u8g2.drawStr(100, 60, "%");
u8g2.setFont(u8g2_font_open_iconic_thing_2x_t); // 16 pix height
u8g2.drawGlyph(45, 60, 0x0048); // drop
} while ( u8g2.nextPage() );
// Sleep for a while to save energy
wait(UPDATE_INTERVAL); // POWERED NODE
}
Be advised that this code is almost near the memory capacity of the Nano 328P...
Hi everyone,
Already posted this over at the troubleshooting section, so im posting here also for whoever is interested. My "compact" temperature + humidity node enclosure with a little window for a 0.96" OLED display.
Every part is in place using the printed spacers and the back is attached with 2 self drilling screwers.
https://www.thingiverse.com/thing:3019468
Thanks for all the input guys and the vote of confidence regarding the NRF24!
So, since there are a lot of people telling to go for the RFM69, I've ordered a couple of them to do some testing. Im still going to test the NRF24/PA/LNA but after all you guys said, im not feeling very confident…
If everything doesnt go according to pIan, i guess im going to have to try to fit the RFM69 inside my already printed boxes and have an antena protruding out of the box… not very pretty… Ah well. Nothing is perfect.
Anyway, I think there should be somekind of note on the radio page of the main website, stating this kind of problem regarding range and construction type.
Will keep in touch.
@mfalkvidd hmm, that’s a nice suggestion... I don’t have motion sensors where they are but maybe I can integrate it on the actual node...
Will give it some thought.
Thanks!
@pihome Sure! Its no trade secret.
Ive used the U8g2lib for the display which is connected at A4 and A5, as defined in the code.
You should power the display directly to a good power source (3.3 ~ 5.5V) since you are also powering a radio module.
Its basically the temp+hum sketch where Ive included some lines of code for the display. At boot it displays the message "Connecting…". If the gateway or repeater is offline or out of range, it wont do anything else unless MY_TRANSPORT_WAIT_READY_MS is of a different value than the default (not pretty sure but ive read that the default is to wait forever).
It will then display temp + hum with a small chain icon at the bottom (connected). If the gateway goes offline it displays "Disconnected!"
Im not sure if this is bug free, so feel free to debug and add new functionalities.
// Enable debug prints
//#define MY_DEBUG
// Enable and select radio type attached
#define MY_RADIO_NRF24
//#define MY_RADIO_RFM69
//#define MY_RS485
#define MY_RF24_CHANNEL 1 //////////////
#define MY_RF24_PA_LEVEL RF24_PA_HIGH //////////////
#include <SPI.h>
#include <MySensors.h>
#include <DHT.h>
#include <U8g2lib.h> //////////////////////
#include <Wire.h> /////////////////////////
U8G2_SSD1306_128X64_NONAME_1_HW_I2C u8g2(U8G2_R0, A5, A4); // U8G2 Constructor (PINS: A5 - Clock SCL ; A4 - Data SDA)
// Set this to the pin you connected the DHT's data pin to
#define DHT_DATA_PIN 3
// Set this offset if the sensor has a permanent small offset to the real temperatures.
// In Celsius degrees (as measured by the device)
#define SENSOR_TEMP_OFFSET 0
// Sleep time between sensor updates (in milliseconds)
// Must be >1000ms for DHT22 and >2000ms for DHT11
static const uint64_t UPDATE_INTERVAL = 60000;
// Force sending an update of the temperature after n sensor reads, so a controller showing the
// timestamp of the last update doesn't show something like 3 hours in the unlikely case, that
// the value didn't change since;
// i.e. the sensor would force sending an update every UPDATE_INTERVAL*FORCE_UPDATE_N_READS [ms]
static const uint8_t FORCE_UPDATE_N_READS = 10;
#define CHILD_ID_HUM 0
#define CHILD_ID_TEMP 1
float lastTemp;
float lastHum;
uint8_t nNoUpdatesTemp;
uint8_t nNoUpdatesHum;
bool metric = true;
MyMessage msgHum(CHILD_ID_HUM, V_HUM);
MyMessage msgTemp(CHILD_ID_TEMP, V_TEMP);
DHT dht;
void before(){
u8g2.begin();
u8g2.firstPage();
do {
u8g2.setFont(u8g2_font_helvR14_tf);
u8g2.drawStr(38,15,"OLED");
u8g2.drawStr(15,35,"Temp+Hum");
u8g2.drawStr(46,60,"v1.2");
} while ( u8g2.nextPage() );
delay(3000);
u8g2.clear();
u8g2.firstPage();
do {
u8g2.drawStr(3, 32, "Connecting...");
} while ( u8g2.nextPage() );
}
void presentation()
{
// Send the sketch version information to the gateway
sendSketchInfo("TEMPHUM_OLED", "1.2");
// Register all sensors to gw (they will be created as child devices)
present(CHILD_ID_HUM, S_HUM);
present(CHILD_ID_TEMP, S_TEMP);
metric = getControllerConfig().isMetric;
}
void setup()
{
u8g2.clear();
dht.setup(DHT_DATA_PIN); // set data pin of DHT sensor
if (UPDATE_INTERVAL <= dht.getMinimumSamplingPeriod()) {
u8g2.firstPage();
do {
u8g2.setFont(u8g2_font_haxrcorp4089_tr); // 7 PIXEL HIGHT
u8g2.drawStr(1,12,"WARNING: UPDATE_INTERVAL");
u8g2.drawStr(1,24,"is smaller than supported by");
u8g2.drawStr(1,36,"the sensor!");
} while ( u8g2.nextPage() );
delay(4000);
}
// Sleep for the time of the minimum sampling period to give the sensor time to power up
// (otherwise, timeout errors might occure for the first reading)
sleep(dht.getMinimumSamplingPeriod());
}
void loop()
{
while (transportCheckUplink() == false){
u8g2.firstPage();
do {
u8g2.setFont(u8g2_font_helvR14_tf); // 14 px height
u8g2.drawStr(3, 32, "Disconnected!");
} while ( u8g2.nextPage() );
}
// Force reading sensor, so it works also after sleep()
dht.readSensor(true);
// Get temperature from DHT library
float temperature = dht.getTemperature();
if (isnan(temperature)) {
Serial.println("Failed reading temperature from DHT!");
} else if (temperature != lastTemp || nNoUpdatesTemp == FORCE_UPDATE_N_READS) {
// Only send temperature if it changed since the last measurement or if we didn't send an update for n times
lastTemp = temperature;
// apply the offset before converting to something different than Celsius degrees
temperature += SENSOR_TEMP_OFFSET;
if (!metric) {
temperature = dht.toFahrenheit(temperature);
}
// Reset no updates counter
nNoUpdatesTemp = 0;
send(msgTemp.set(temperature, 1));
#ifdef MY_DEBUG
Serial.print("T: ");
Serial.println(temperature);
#endif
} else {
// Increase no update counter if the temperature stayed the same
nNoUpdatesTemp++;
}
// Get humidity from DHT library
float humidity = dht.getHumidity();
if (isnan(humidity)) {
Serial.println("Failed reading humidity from DHT");
} else if (humidity != lastHum || nNoUpdatesHum == FORCE_UPDATE_N_READS) {
// Only send humidity if it changed since the last measurement or if we didn't send an update for n times
lastHum = humidity;
// Reset no updates counter
nNoUpdatesHum = 0;
send(msgHum.set(humidity, 1));
#ifdef MY_DEBUG
Serial.print("H: ");
Serial.println(humidity);
#endif
} else {
// Increase no update counter if the humidity stayed the same
nNoUpdatesHum++;
}
u8g2.firstPage();
do {
u8g2.setFont(u8g2_font_fub30_tn);
u8g2.setCursor(2, 35);
u8g2.print(temperature, 1);
u8g2.setFont(u8g2_font_inb16_mf);
u8g2.drawGlyph(88, 35, 0x00b0); // degree
u8g2.drawStr(100, 35, "C");
u8g2.setCursor(70, 60);
u8g2.print(humidity, 0);
u8g2.drawStr(100, 60, "%");
u8g2.setFont(u8g2_font_open_iconic_thing_2x_t); // 16 pix height
u8g2.drawGlyph(45, 60, 0x0048); // drop
u8g2.setFont(u8g2_font_open_iconic_www_2x_t); // 16 pix height
u8g2.drawGlyph(2, 60, 0x004f); // CONNECTION ICON
} while ( u8g2.nextPage() );
// Sleep for a while to save energy
//sleep(UPDATE_INTERVAL);
delay(UPDATE_INTERVAL); // POWERED NODE
}
Hi everyone,
As promised, the box over at Thingiverse (smaller version):
https://www.thingiverse.com/thing:3019468
So, to try to solve the range issues of the NRF24 node networks deployed inside masonry-mortar buildings, i've setup a repeater on my first floor. I have a serial gateway with an amplified NRF24 at the groundfloor and a node that works normally.
At the first floor i have 2 nodes (temp+hum) where only one is able to connect to the gateway in this normal setup. Ive then installed a repeater with a fixed ID which gets connection to the gateway without problems.
Ive then forced the nodes at the first floor to connect to the repeater with:
#define MY_PARENT_NODE_ID 51
#define MY_PARENT_NODE_IS_STATIC
Everything works ok for an hour or so, and then i begin to notice in Domoticz that the time the nodes were "seen" starts to be 20, 30, 50 minutes without reporting the readings and i get the info on my nodes that transportCheckUplink() is false. If i restart the repeater, everything starts to work but the same issue happens again… Has anyone come across something similar? Ive checked the log of the repeater but since this issue takes a bit of time to show up, ill need to plug it to a laptop and collect the full log.
Im now trying to setup one of the temp+hum nodes also as a repeater, but since my nodes have a small OLED im trying to implement a delayed display update since ive removed the "sleep" function. I hope this doesnt spam the gateway…
As always, any insights are more than welcome.
Thank you.
Well, that didn’t solve it... got both nodes disconnected as before. It seems the repeater hangs for some reason...
I’ve also noticed that the “last seen” time for the repeater that appears in Domoticz is the time it was powered up and presented to the gateway. It doesn’t get updated.
I guess the only way to debug this is to collect all the log from the repeater until the nodes get disconnected...
@m3nt4lll Try to assign a fixed node ID to your sensors nodes with the line:
#define MY_NODE_ID 12
Change the number to what you like.
I also had the same problem with a serial gateway with RFM69 and a simple temp+hum node. They did startup ok but no communication between them.
I then assigned a node ID to the sensor node and oddly it worked…
Other thing i noticed is that im not getting internal messages delivered to the gateway, only sensor values defined by MyMessage and presented.
The sketch info sent with sendSketchInfo doesnt show on Domoticz side, neither does battery levels sent with sendBatteryLevel. If i just change the radio to a NRF24 with the same sketch code, everything works…
@m3nt4lll If you get communication, see if you have this problem too.
I wonder if this has anything to do with Ack collision discussed here ? It seems the fix suggested by @Koresh didt get implemented yet…
Any ideias guys?
Did some testing today and i can now confirm that this issue with internal messages not getting delivered to the controller is now FIXED with commit 5d159a6 .
Thanks @tekka