RPIWeather: My wireless monitoring system

Some of the first posts on this blog were about how to interact with the famous nRF24L01 2.4GHz radio chipset from both an Arduino and a Raspberry Pi. Well.. Much have happened in the mean time, but at least I have managed to put together something using what I learned back then. I decided to make a wireless monitoring system for environmental data in and around our house with at least one sensor node in each room as well as a couple of sensors outside. It is called RPIWeather and you can get all the code and documentation by clicking the name. This post is just meant as a short summary.

RPIWeather consists of a bunch of wireless sensor nodes, a base station that collects the data packets, a database server, and one or more frontends. My goal has been to collect data at 5 minute intervals and keep it indefinitely for analysis, comparison, and visualization. This creates some demands for power efficiency and reliability, which I find interesting.

The sensor nodes

My first prototype was based around an Arduino and some proto-board and is described here, here, and here. It looked like this:

Arduino with nRF24L01 and DHT22

Arduino with nRF24L01 and DHT22

To keep things simple, clean, and small, I decided to ditch the Arduino platform and code in straight avr-libc for the ATtiny84 chip from Atmel. So I made another prototype, but this time with an ATtiny84 instead.

Partial prototype without the DHT22 sensor

Partial prototype without the DHT22 sensor

Little by little a schematic emerged. Besides the radio, the sensor and the MCU, I also needed some sort of power supply. As the sensor nodes are to be distributed throughout the house, this implied battery power, but it couldn’t just be any old battery. The thing is that the radio chip can only tolerate up to 3.6v and the DHT22 sensor can only operate down to ~3v, which leaves a narrow band of usable voltages. A traditional voltage regulator would have burned though the batteries quite quickly, so I had to put in a switching boost converter. This way 2 AA NiMH batteries can deliver a reasonably stable 3.3v supply voltage for the circuit. Pro tip: when buying NiMH batteries, do yourself a favor and use the low self-discharge kind like Eneloop. In this use-case they will go for several months between charges.

Schematic for the sensor nodes

Schematic for the sensor nodes

With the schematic in place, I made a PCB layout and sent it to ITEAD for manufacturing. Here are a couple of pictures showing various stages of assembly. The funny shape of the boards was needed to make them fit snugly into some cool boxes from New Age Enclosures.

Sensor node PCBs

Sensor node PCBs

The first 10 finished boards

The first 10 finished boards

Inside a single sensor node

Inside a single sensor node

A single sensor node

A single sensor node

The back of a sensor node

The back of a sensor node

The 10 first sensor nodes

The 10 first sensor nodes

In addition to the DHT22 sensors, I have also made firmware for collecting data from a wind vane and a rain gauge. But I haven’t deployed any of that yet. Maybe next spring…

All in all the main results for the sensors are:

  • They work! I have tested concurrent operation of 10 units without major problems.
  • Firmware optimized for ATtiny84 @ 1 MHz (8MHz crystal with the CKDV8 fuse set)
  • Temperature and humidity measurement using a DHT22 sensor
  • Wind speed and wind direction measurement using a La Crosse TX23 anemometer
  • Rainfall measurement using a WS-2300-16 rain gauge
  • Wireless operation using the very popular nRF24L01+ 2.4 GHz radio chip
  • Very compact CRC32 implementation
  • Battery powered operation using a very efficient 3.3v DC/DC converter
  • Power management by sleeping the CPU and turning off unneeded hardware
  • Battery voltage measurement included in data packet
  • Typical battery draw while sleeping has been measured to around 17uA
  • Total firmware size from 3.0 kiB to 3.5 kiB (depending on sensor type)

The base station

I use a Raspberry Pi as base station. To make it more appliance-like than a typical Raspbian installation, I have instead installed a variant of Tiny Core Linux called piCore. This is basically a very small Linux distribution that loads all programs into memory on boot and leaves the SD card alone after this. This eliminates the usual risk of corrupting the file system when doing a power-cycle.

On the base station I have installed a small python script that continually polls the nRF24L01 radio using the Raspberry Pi’s built-in SPI interface pins. When a data packet arrives, it is buffered (in case of network problems) and forwarded to the database.

The database

With my limited data requirements, I could probably use any old database out there without issues. However, given the nature of the data, it was natural to select a so-called timeseries database. For this project I chose InfluxDB, which was very, very easy to set up on my Ubuntu-based file server. It automatically exposes a simple HTTP interface for storing and querying data, which is just what I need for this project.

The frontend(s)

Well, I’m not quite there yet… So far the only frontend is the admin interface that is built in to InfluxDB. Not very user friendly (not to mention the Wife Acceptance Factor)! The next step now is to make some sort of nice frontend for this. I have several ideas floating around my head:

  • An intranet website. The easiest way.
  • An Android widget. Both the wife and I have Android smartphones.
  • Dedicated hardware devices. This would be a great use-case for my new ESP8266 wifi modules and some 84×48 Nokia LCDs I have lying around.

Stay tuned…

14 thoughts on “RPIWeather: My wireless monitoring system

  1. Thomas COUTANCEAU

    Hello,
    I want to make a weather station (anenometer) with raspberry pi and the TX23.
    Could you put some info about this? How to connect the TX23 to the PI, how to collect the data?

    Thanks.

    Reply
  2. atbrask Post author

    Hi,

    I have implemented some code that can sample the TX23 anemometer from one of the wireless sensor nodes in my system. You can find the code in my GitHub repository for this project. There is a link in this blog entry near the top. It is just regular C++, but in its current state it’s only running on Atmel AVR microcontrollers. I should be possible to port to the Raspberry Pi using a single GPIO pin. Another option would be to flash it onto e.g. an ATtiny85 and connect to that from the Pi. That would off-load some timing critical code from the Pi.

    Regarding the data protocol of the TX23 I used these links:
    https://www.john.geek.nz/2012/08/la-crosse-tx23u-anemometer-communication-protocol/
    http://www.rd-1000.com/chpm78/lacrosse/Lacrosse_TX23_protocol.html
    http://www.rd-1000.com/chpm78/lacrosse/Receive_Lacrosse_TX23_data_2.html

    Reply
  3. Bogdan

    Congrats for the project!
    I am thinking of something similar but with OpenHab integration.
    1. Do you get good range with the NRF modules?
    2. What is the expected battery life for each sensor?
    3. Have you considered storing a DB locally on the RPi gateway?
    4. Do you get low battery alert/notification (somehow) for each sensor?

    Reply
    1. atbrask Post author

      Thanks 🙂
      OpenHAB integration would a cool addition! As for your questions:

      1. Inside the house I have almost perfect reception from the sensors. It’s sometimes a bit spotty for the outside sensors. Every data packet contains an increasing sequence number which makes data quality issues easy to detect. I think the range is comparable to our regular wifi network.

      2. I have absolutely no idea… 🙂 I hope they’ll last a year on each charge. They have been running a couple of months now, and so far my data only shows a tiny dip in voltage. The voltage itself probably isn’t a great indicator of battery health, but it’s very easy to measure. Each sensor contains 2 eneloop AA batteries, and the mean voltage right now is around 2.6 volts. 2000mAh goes a long way when the current in sleep mode is measured in the lower two-digit uA.

      3. Yes, but I decided to keep the RPi as “idiot proof” as possible so a power failure or a SD card failure wouldn’t corrupt anything. Essentially it’s only a data gateway, but it does buffer the data if the database server becomes unavailable for a while.

      4. Well, yes and no. One of the ATtiny’s analog inputs is used as a simple voltmeter for the battery. I collect and store everything, but I haven’t (yet) set up any alert system.

      Reply
  4. Alan Medina

    Hi! congrats for your project!! its amazing… i have a question… how can i measurement the battery voltage using a 3.3v DC/DC converter?, in my case i use de NCP1402. I see that in your schematic you use a 1M resistor and 100nf capacitor, Can you give me a explanation?

    regards 😀 … sorry for my bad english

    Reply
    1. atbrask Post author

      Thank you! 🙂

      The Attiny MCU runs on a more or less steady 3.3v from the DC/DC boost converter regardless of the actual battery voltage. The batteries are then also connected directly to an analog input through a 1M resistor and 100nf capacitor (which you noticed) that act as a low-pass filter. I don’t really know if it’s necessary, though..

      However, the point is that this analog input can be used as a voltmeter in the range 0v…3.3v. It works because the battery voltage in this case by definition is less than 3.3v. The A/D converters in AVR MCUs have 10 bits of resolution, which gives us a reading in the range 0..1023. Here 0 means 0v and 1023 means 3.3v. I assume that it’s fairly linear across the entire range, but I don’t know if that’s true. So if it reads e.g. 806 then the batteries are at 2.6v.

      I have no reason to believe that it won’t work with the NCP1402. As long as it outputs a reasonably clean 3.3v there should be no problem.

      And by the way.. Your English is fine. 🙂

      Reply
  5. Kris

    Hey Asbjørn… Great project! I’m trying to compile under Windows (win-avr) but getting loads of errors… Do you happen to know what version of avr-libc is required ?

    src/SensorNodeTypes.h:25: error: use of enum ‘SensorTypeEnum’ without previous declaration
    src/SensorNodeTypes.h:25: error: expected unqualified-id before ‘:’ token
    src/SensorNodeTypes.h:36: error: use of enum ‘QualityEnum’ without previous declaration
    src/SensorNodeTypes.h:36: error: expected unqualified-id before ‘:’ token
    src/SensorNodeTypes.h:62: error: ‘SensorTypeEnum’ does not name a type
    src/SensorNodeTypes.h:63: error: ‘QualityEnum’ does not name a type

    Reply
    1. atbrask Post author

      Hi,

      Thanks! It’s still a work-in-progress project, but at least the sensors have now been running for close to a year on their first charge without hiccups.

      As for your problem I don’t think the specific version of avr-libc is the problem. I’m almost completely sure it’s caused by missing compiler flags. You’ll need to compile using the bundled Makefile or alternatively copy all the compiler flags from it into your build setup.

      The errors you pasted in here relate to the declaration of some of the enumerations. They are declared with an underlying type to specify explicitly how they are to be serialized when the data is transmitted. I don’t use win-avr, but as far as I know it uses gcc as its compiler, and in gcc it’s a fairly new feature, so you need the compiler flag -std=c++0x

      I have only tested that the project can compile from the command line on Linux and OS X. If you still experience problems, I can try installing win-avr on my Windows box.

      Reply
      1. Kris

        Hey Asbjørn

        Thanks for the quick response … I was also under the impression this may be due to the win-avr on Windows, but last night I tried building it under linux(ubuntu), and the results are the same… I’m using the make file you’ve supplied, and the flag is there. I’ve installed avr-libc via the package manager, so not sure if it’s up to date … any chance you can check the version of avr-libc you’re using ?
        I’m really keen to get this going, I’m redesigning the PCB to fit a more conventional sensor case, and I will use it to manage central heating in my house … time is of the essence, winter is coming 😉

        :~/Node/RPIWeather/SensorNodes/Firmware$ make rebuild UNITID=0x0102 VCC=3320 SENSORTYPE=DHT22
        rm -f bin/*
        avr-gcc -Os -fdata-sections -ffunction-sections -Wl,–gc-sections -Wall -mcall-prologues -mrelax -mmcu=attiny84 -std=c++0x -DF_CPU=1000000 -DVCC=3320 -DUNITID=0x0102 -DSENSORTYPE=DHT22 -DFIRMWAREVERSION=0x0104 -DMAGICNUMBER=0x20130928 -DTXPIPE=0x2013092801LL -DRXPIPE=0x2013092802LL -DCHANNEL=0x5c src/Battery.cpp src/CRC32.cpp src/DHT22.cpp src/PowerManagedSensor.cpp src/Sensor.cpp src/SensorNodeMain.cpp src/TX23.cpp src/WDTSleep.cpp src/WS_2300_16.cpp -o bin/firmware.obj
        src/CRC32.cpp:22: warning: only initialized variables can be placed into program memory area
        In file included from src/Sensor.h:25,
        from src/PowerManagedSensor.h:22,
        from src/DHT22.h:22,
        from src/DHT22.cpp:23:
        src/SensorNodeTypes.h:25: error: use of enum âSensorTypeEnumâ without previous declaration
        src/SensorNodeTypes.h:25: error: expected unqualified-id before â:â token
        src/SensorNodeTypes.h:36: error: use of enum âQualityEnumâ without previous declaration
        src/SensorNodeTypes.h:36: error: expected unqualified-id before â:â token
        src/SensorNodeTypes.h:62: error: âSensorTypeEnumâ does not name a type
        src/SensorNodeTypes.h:63: error: âQualityEnumâ does not name a type
        src/SensorNodeTypes.h:64: error: ISO C++ forbids initialization of member âValueâ
        src/SensorNodeTypes.h:64: error: making âValueâ static
        src/SensorNodeTypes.h:64: error: ISO C++ forbids in-class initialization of non-const static member âValueâ
        src/SensorNodeTypes.h:70: error: ISO C++ forbids initialization of member âMagicNumberâ
        src/SensorNodeTypes.h:70: error: making âMagicNumberâ static
        src/SensorNodeTypes.h:70: error: ISO C++ forbids in-class initialization of non-const static member âMagicNumberâ
        src/SensorNodeTypes.h:71: error: ISO C++ forbids initialization of member âFirmwareVersionâ
        src/SensorNodeTypes.h:71: error: making âFirmwareVersionâ static
        src/SensorNodeTypes.h:71: error: ISO C++ forbids in-class initialization of non-const static member âFirmwareVersionâ
        src/SensorNodeTypes.h:72: error: ISO C++ forbids initialization of member âUnitIDâ
        src/SensorNodeTypes.h:72: error: making âUnitIDâ static
        src/SensorNodeTypes.h:72: error: ISO C++ forbids in-class initialization of non-const static member âUnitIDâ

        Reply
        1. atbrask Post author

          Hmm.. That’s a bit weird as I did most of the development on my Ubuntu box. I’ll take a look at this tonight. Which version of Ubuntu are you using?

          Cool project you have there! I don’t control anything in my setup. It’s purely for monitoring and self-education. Are you planning to implement your own data collection backend and frontend like I’m doing (slowly) or are you going to use one of the cloud based options like, for example, ThingSpeak?

          Pro tip: If you are ever going to put a sensor outside, then I suggest finding another sensor than the DHT22. It really, really doesn’t like dew. During the past year I have destroyed two of them by simply putting them outside. My current one measures temperature OK, but the relative humidity reads as 1%. Somehow I doubt that…

          Winter is indeed coming! The night is dark and full of terrors. 😉

          Reply
          1. Kris

            Solved, used a new Ubuntu installation (14.04) and it just worked no problem. Looks like win-avr is a no go, but on updated linux platform the compile works fine.

            Thanks for the “pro tip”, all of my nodes are intended to be installed inside the house so should be good with the DHT22 …

            Now I need to figure out how to get RTC working with piCore as I can’t always rely on NTP 🙂

          2. atbrask Post author

            I just had a look at WinAVR. The latest version I could find is from 2010 and includes GCC 4.3.3, which is incompatible with the C++ code in this project. As far as I can deduce, the typed enum stuff I talked about earlier wasn’t added until GCC 4.4.

            As for piCore, you could just as well use Raspbian. I just like piCore because it’s so lightweight and simple. That is, until you realise that you need to create your own packages for everything slightly less common… 🙂

  6. Pingback: RPIWeather: Adding off-the-shelf wireless sensors | The ramblings of atbrask

Leave a Reply

Your email address will not be published. Required fields are marked *