RF24Network Updates & More

I’ve made my Pro Micro/Mini ISP breakout board and Raspberry Pi nRF24L01+ breakout board as per my previous post and decided to get on with trying out RF24Mesh. The problem there was that with the newer commits to RF24 and RF24Network, I was getting no response from the Arduino’s to the RPi.

After some debugging with the author of the libraries on GitHub, we managed to find the culprit – not really the clone issue or the differing module issue, but actually a bit of an oddity in how dynamic payloads and dynamic ACKs work together. So with the Development branch re-opened, we now have the modules talking again. It may need some more work to get mesh working though. So for now I’m sticking to RF24Network, not RF24Mesh.

I’ve migrated all of my various sensor modules to a more streamlined setup – essentially there’s a daemon listening on the Pi which directly populates the database now, rather than the previous separate cronjob. It also handles taking measurements from the DS18B20 sensor on the Pi breakout. The daemon also accepts TCP connections should I want to use an ESP8266 sensor, its also handy for debugging using netcat. Each module sends each sensor reading separately, so each RF24 transmission is under 16 bytes long, rather than pushing the 32 byte limit.

One of my new modules is a 3.3v 8MHz Pro Mini 328, from which I have removed the LED’s and regulator to drop the current use. I’ve also configured its fuses and boards.txt to run at 1MHz from the internal oscillator and set all unused digital pins to INPUT_PULLUP. Now its using under 4uA at sleep. The boards.txt entry looks like:

promini1mhz.name=Pro Mini 328 (1.8v, 1MHz internal osc, BOD off)
promini1mhz.upload.maximum_size=30720
promini1mhz.upload.maximum_data_size=2048
promini1mhz.upload.speed=9600
promini1mhz.upload.protocol=usbasp
promini1mhz.upload.using=usbasp
promini1mhz.bootloader.low_fuses=0x62
promini1mhz.bootloader.high_fuses=0xD4
promini1mhz.bootloader.extended_fuses=0x07
promini1mhz.bootloader.unlock_bits=0x3F
promini1mhz.bootloader.lock_bits=0x0F
promini1mhz.bootloader.path=atmega
promini1mhz.bootloader.file=ATmegaBOOT_168_atmega328_pro_8MHz.hex
promini1mhz.build.mcu=atmega328p
promini1mhz.build.f_cpu=1000000L
promini1mhz.build.core=arduino
promini1mhz.build.variant=standard

I then added the BH1750FVI light sensor to the circuit and found that the sleep current was the same as when it was awake taking readings, about 110-145uA, instead of 5uA the manufacturers claim. So I switched to using the BH1750FVI library as it had better sleep support. Alas that didn’t fix things and I decided the module simply wasn’t sleeping. After some reading of the datasheet and playing with code I finally figured out that after calling power_on and reset to wake the device from a power_down, you have to set the resolution mode again. I also found that disabling the pullup resistors on the I2C pins helps, as the module already has internal pullups. I’ve tested it down to 1.5v, which is quite far below any of the components ratings, but it works….

// include libraries
#include <Wire.h>
#include <BH1750FVI.h>
#include <RF24.h>
#include <RF24Network.h>
#include <SPI.h>
#include <LowPower.h>

// global vars
BH1750FVI lightMeter;

// init network ce,csn
RF24 radio(9,10);
RF24Network network(radio);
const uint16_t this_node = 4;
const uint16_t other_node = 0;

void gotoSleep()
{
    // sleep radio
    radio.powerDown();

    // sleep mcu for 225x8/60=30mins
    for(int i=0; i<225; i++)
    {
        LowPower.powerDown(SLEEP_8S, ADC_OFF, BOD_OFF);
    }

    // wake radio and sensor
    radio.powerUp();
    lightMeter.Reset();
    lightMeter.SetMode(OneTime_H_resolution_Mode);
    delay(200);
}

void setup(void)
{
    // set unused digital pins to input pullups to save power
    const int unusedPins[] = {0,1,2,3,4,5,6,7,8,14,15,16,17};
    for (int i=0; i < 13; i++)
    {
        pinMode(unusedPins[i], INPUT_PULLUP);
    }

    // init sensor
    lightMeter.begin();
    lightMeter.SetAddress(Device_Address_L);
    lightMeter.SetMode(OneTime_H_resolution_Mode);

    // disable pullups as sensor already has them
    pinMode(SDA, INPUT); // a4
    pinMode(SCL, INPUT); // a5

    // init radio
    SPI.begin();
    radio.begin();
    network.begin(90, this_node);
    radio.setRetries(15,15);
    radio.setDataRate(RF24_250KBPS);
    radio.setPALevel(RF24_PA_MAX);
}

void loop()
{
    // pump network
    network.update();

    // take a sensor reading, pad to 2dp
    long lux = lightMeter.GetLightIntensity() * 100;
    if (lux == 0)
    {
        // take another reading, its not ready
        delay(200);
        lux = lightMeter.GetLightIntensity() * 100;
    }

    // create data structure - bh1750=type11
    char txBuffer[16] = "";
    sprintf(txBuffer,"%d;%d;%ld",this_node,11,lux);

    // transmit
    RF24NetworkHeader header(other_node);
    network.write(header,&txBuffer,sizeof(txBuffer));

    // sleep
    gotoSleep();
}

I finally got my hands on a Particle Photon. However I found a bug in the way it reports its error status to dfu-util, it flashes ok but says it hasn’t. The fix is in 0.4.5 but requires a bootloader ID upgrade, so it won’t be 100% fixed until 0.4.6, unless I get a JTAG programmer to set it in the meantime. Otherwise it seems to be more mature than the Spark Core – well they fixed most of the issues there before working on the HAL for the Photon I guess.

I’ve also started playing with an MRFC522 RFID reader/writer and some cards/keyrings – worrying how easy it is to clone those things! I’ve also got some HC-05 Bluetooth modules to play with next.

We’ve also made a few commits to arduino-mk this month.

RF24Mesh Sensor Nodes

I’m going to get back into making Arduino sensors for the house/garden. I’m going to use the RF24Mesh library this time instead of just RF24Network so that the sensors can forward packets along from each other, hopefully meaning that I can use the smallest radio modules instead of the PA+LNA variants which suck a lot more current e.g. 45-115mA instead of 15mA.

I plan on using a bunch of 3.3v Sparkfun Pro Mini boards with the regulator/LED removed, and fed a clean 3.3v to VCC from a Pololu step-up regulator, with a 10uF decoupling capacitor across VCC/GND on the radio.

As I hate programming with a USB UART and dupont cables to the Pro Mini, I decided to make a little ISP breakout board. That means I can connect my USBASP using a regular 6-pin ICSP cable and feed the Mini 3.3v – I must remember to set the jumper! As luck would have it, it actually has the same pinout as the Pro Micro (contrary to various pinout documents) so I could even use it with that to make burning the Leonardo bootloader easier.

On the Raspberry Pi side I’m going to make a breakout board with a LM1117T-3.3 regulator to supply a clean 3.3v with enough current for the radio, from the 5v GPIO pin as the 3.3v GPIO pin can only source 50mA. It’ll also have a header for the radio and decoupling capacitors.

Both of these boards are going to make use of the 24×18 perfboards I got recently, rather than veroboard I usually use.

RF24Network

I’ve been playing with the rewritten RF24 and RF24Network librariy forks and am impressed. The RF24Network library is a much more reliable way of using multiple nodes than just using the same channel/pipe and hoping you won’t get timing conflicts with RF24 e.g. I’d find the data from 2 nodes would merge! Also hardware SPI finally works on the Raspberry Pi.

I’ve updated my weather station scripts, I now have the RPi as the master receiving node0 (with a new 17dBm antenna!); the MOSFET-based Arduino as node1 in the shed, but with the BMP085 pressure/altitude disabled as it was returning absolute rubbish, I think its a hardware issue and not the Adafruit lib; and the older non-MOSFET Arduino as node2 in my office, just reporting its DS18B20 readings in an attempt to prolong battery life – I’ve desoldered the DHT11/BMP085 to see if that helps.

I’ve breadboarded up a node3 that’s powered by a CR2032 coincell and just has the ATmega328P, chip-antenna nRF24L01+, TO92-packaged DS18B20 and two resistors, just to see how the battery life goes. I might even make a 5v board that can be mains powered – or a USB-powered SFE Pro Micro….

My new scripts are here and a graph of the results showing both sensor boards is below:

Gadgets On Order

Been a while since I did some shopping and year end is approaching, why give it all to the taxman?

So I’m purchasing some more nRF24L01+ kit, I’m going to make a bunch of RF24Network devices to dot around – some inside with 5v mains power and new temperature sensors and some outside with larger antenna’s. I was going to buy some SI24R01’s which are supposed to be more powerful Taiwanese ripoffs of the nRF24L01+, but I couldn’t get the pricepoint.

I’ve also bought some PoE kit in case I ever feel like putting a RPi or IPcam in the shed or somewhere there’s no mains power or ethernet coverage.

I’m getting a bit fed up of pulling chips off of veroboard sockets and putting them in some breadboard to reprogram them, so I’ve bought a ZIF socket and another USBASP cable adaptor to make a kind of USBASP breakout board for those circuits where I’ve not added a 6-pin ICSP header. I’ll add a couple of female headers to put a crystal in too.

I’ve also fixed the reset issues in arduino-mk 1.3.3 and even started on a 1.5 branch.

Weather Station Mk2

I’ve redesigned my Arduino weather station to incorporate a P-channel MOSFET to switch power to the peripherals on and off to hopefully save battery life. The ATmega328P always gets 3.3v, but then uses Sleepy() to conserve power anyway, but the DHT11, BMP085, DS18B20 and nRF24L01+ get powered off when not in use. Oddly enough the voltage seems to drop to 0.7v rather than 0v completely, but I guess no current flows.

I had to change my code a little to re-initialise the radio once per loop and control the MOSFET from a digital pin: download.

I tidied up the veroboard a bit – pink wires are 3.3v constant for the ATmega, red wires are controlled by the MOSFET, black is GND, blue is data:

I hard a hard time finding a through-hole MOSFET than worked at TTL voltage (the FQP7P06 I first tried only worked properly at CMOS 5v) but I eventually settled on the NDB6020P which can be switched using as little as 2.5v.

I’m currently calibrating the DHT11 and keeping an eye on how long the battery lasts, so for the moment the weather station is in the house rather than the shed, here’s some results (its also tweeting using Python/C++ on the RaspberryPi, I didn’t need to update them):

Update: it seems that turning the peripherals on and off is making the readings from them more reliable, as the BMP085 and DS18B20 readings are almost identical and the DHT11 is within one degree – given that it uses integers this is as near as it will get.

Update 2: the weather station has been running on 2xAA’s for over 12 days now, without the MOSFET it would last under 8 days.

Update 3: the board eventually stopped after 30 days, although since then I’ve been having problems with it stopping even though the battery is not dead – perhaps a range problem…. Anyway I’ve added the boards.txt definition I used below:

atmega328bb.name=ATmega328 on a breadboard (3.3v, 8 MHz internal clock)
atmega328bb.upload.maximum_size=30720
atmega328bb.upload.protocol=usbasp
atmega328bb.upload.using=usbasp
atmega328bb.bootloader.low_fuses=0xE2
atmega328bb.bootloader.high_fuses=0xD8
atmega328bb.bootloader.extended_fuses=0x07
atmega328bb.bootloader.path=atmega
atmega328bb.bootloader.file=ATmegaBOOT_168_atmega328_pro_8MHz.hex
atmega328bb.bootloader.unlock_bits=0x3F
atmega328bb.bootloader.lock_bits=0x0F
atmega328bb.build.mcu=atmega328p
atmega328bb.build.f_cpu=8000000L
atmega328bb.build.core=arduino
atmega328bb.build.variant=standard