Running a Wireless Temp. and Humidity Sensor for over 1 year on a CR2032

This article will discuss and demonstrate how to build a Wireless Temperature and Humidity sensor based on the Talk² Whisper Node and a DHT11. The sensor node is capable of running well over a year on a single CR2032 coin-cell and transmit data for distances over 1 Kilometer.

A similar article was previous posted by us on the Hackster.io community and can be accessed via the following link:  https://www.hackster.io/Talk2/temp-and-humidity-sensor-with-a-cr2032-for-over-1-year-580114

blog-whispernode-0-3v-board-mini.jpg

Whisper Node board.

The remote node will be configured to transmit data every 60 seconds to another Whisper Node, acting as a gateway/base station and located 100 meters away. The data will be finally uploaded to a Google Could server running InfluxDB and Grafana to display the data.

Be aware this won't be our shortest story! The information here will focus on low-power development techniques and measurement, as well a detailed analysis of how much energy we really have available from a coin-cell.

Finally, this post will present many practical tests and some maths, sparing some common knowledge like: how to put a micro-controller to sleep, as there are plenty of information about it on the Internet.

Motivation

If you're an electronic engineer or a electronic hobbyist, you probably know, or at least have an idea, how to put a few sensors and a micro-controller together. It's great and lots of fun to see the real-life data being collected and printed over a Serial terminal or even stored in some kind of memory. Unfortunately things start to get more complicated when we need to move this bench sketch to the real world scenario. Normally far away from a computers, power-outlets or USB cables.

Knowing there are difficulties and pit-falls when moving away from our bench or lab, this article aims to educate the reader how a real-life, remote and low-power solution that can be built to work according to the expectations. The Temperature and Humidity sensor is just an example, and similar principles can be tailored for many other projects.

Additionally, the reason for choosing the DHT11 and a CR2032 was to create a sense of bigger challenge. If you already had the opportunity to work with both parts you know that the DHT11 is a very slow and clunky sensor, theoretically incompatible with low-power. At the same time the CR2032 has very little capacity, no more than 650 milliwatts/hour* of energy.

*For comparison, a single AA Alkaline has over 3000 milliwatts/hour!

Final Results

For the readers looking for a quick outcome, we've published part of the final results before getting into the full technical details. Below you can see two Grafana screen-shots using the data published into the cloud, followed by the prototype and final hardware:

blog-grafana-dht11.pngblog-grafana-dht11-zoom.png

Grafana dashboard showing Temperature, Humidity and Battery Voltage.

blog-whisper-node-dht11-proto.jpg

Although the picture shows a pair of AA batteries, all calculations are based on a CR2032 coin-cell.

blog-whisper-node-dht11.jpg

The "final" assembly, now directly into the Whisper Node and using the CR2032 battery.

In terms of energy, we conclude that our solutions had only 171mA/h @ 3.3v available. In other words, 564mW/h, which we'll prove it's enough to run the sensor node for almost two years - or even more if some requirements are optimized.

All calculations, together with practical scope captures, will be demonstrated below. Although it might sound not interesting and difficult for some, there will be only simple maths based on addition, division and multiplication.

A word before starting the real post: low-power is not the simplest subject, some thinking, persistence and trial+error are necessary to get the most of a battery.

Understanding the problem

To understand better the problem, let's have a look on what we're trying to achieve:

blog-dht11-cr2032-overview.png
Solution overview.

The basic idea is to publish the DHT11 sensor's data to a server running in the Cloud. Again that it's just a model, this can be easily adapted to similar projects.

Together with the diagram above, let's define the following requirements:

  • The sensor node is located 100m away from any power source, in a enclosed area of difficult access - inside a factory's attic for example;
  • The data collected needs to be available on the Internet in the form of graphs, showing current and historical values;
  • Data needs to be collected every 60 seconds and available 24/7;
  • Temperatures on the attic varies from 0°C to over 40°C;
  • The equipment needs to be small as possible, no thicker than 15mm.

Picking the components

Now that we have a list of requirements presented above, it's obvious that our solution needs to be powered by battery and rely on wireless communication.

The last requirement is pushing us to use a CR2032 battery as power source, because of size constraints. On real-life different requirements will determine the options for your project.

blog-cr2032.jpgblog-dht11.jpg

CR2032 battery and a DHT11 sensor

There's nothing forcing the usage of a DHT11 sensor, which is indeed a very poor option for this kind of application. The decision to use the DHT11 was just to make it a better exercise, showing how hardware and software can be adapted to work together in a low-power configuration. For a real-life application a more robust sensor could be used, like the  TE HTU21D.

For the wireless communication, it needs to be based on radio as there's no visual/line-of-sight for IR or Laser beans. Because the solution needs to be powered by battery, WiFi (802.11) or any other high-level protocol is out-of-question* - ESP8266 is a no no!

For this reason a sub-GHz digital radio, based on FSK modulation, is a appropriated choise in terms of reliability and power-consumption. Although OOK modulation consumes even less energy, the transmission speed and reliability are normally lower, making the FSK a more efficient transmission method.

*The power requirement to communicate using sophisticated protocols like WiFi is incredibly high, making the use of those not a practical solution!

blog-esp8266.jpg

ESP8266 or other WiFi modules are not adequate choices for low-power.

blog-rfm69.jpg

RFM69W is a sub-GHz digital RF module, better option for low-power applications.

The Whisper Node has been chosen because it has a built-in RFM69 sub-GHz radio module and it's designed with low-power in mind. The board can be powered by standard batteries and provide a stable 3.3V from any voltage source, down to 0.9V.

The stable voltage is essential, specially when dealing with devices that only work at certain voltage levels or can suffer with voltage variations: like most of the sensors.

Choosing ready-to-use boards and modules saves development time and improves the reliability. It also significantly cuts down research, prototyping and implementation for low to medium volume production.

How much energy do we have?

Now that we have an idea about which components to use, the next step is to understand if the solution is feasible or not. The most critical component in our application is the power source, the coin-cell battery, so it's essential to get familiar with its characteristics.

The CR2032 battery has no more than 250mAh of energy, and this number is only true if the energy is drained constantly at very very low rate, or alternatively, by quick medium-rate pulses. Another aspect is the cell's voltage, when brand new, it's around 3V. This value will drop down to 2V by the end of the battery's life. As the voltage drops significantly, it's also important to know the Battery Energy in milliwatts/hour as well. According to the  Energizer CR2032 datasheet, each coin-cell holds around 653 milliwatts/hour.

blog-gauge.jpg

A CR2032 has no more than 653 milliwatts/hour.

If we expect to run our solution for a whole year without need to change batteries, here the average consumption we need to get on the battery side:

1 year = 365 days * 24 hours = 8760 hours
250mAh / 8760h = 0.0285mA or around 28uA of average consumption.

The figure above is without taking other variables in consideration, like the battery self-discharge or the voltage drop, and that's already a very little to consume!

Note we've mentioned "at the battery side" before. That's because we still need to calculate the step-up regulator and its efficiency. Remember, the battery provides no more than 3V, but the Whisper Node runs at 3.3V.

To calculate the energy available to the board itself, after the step-up regulator, we simply divide the cell energy by the voltage:

653mW/h / 3.3V = 197mA/h

The formula above give us the real capacity at 3.3V. But wait, 197mA/h of capacity would only be possible if we had an 100% efficient step-up. Now, looking at the Whisper Node step-up documentation, we can see it's close to 95% efficient @ 2.5V with a 100R load (33mA).

blog-cr2032-dischargecurve.png
From the datasheet, a similar CR2032 usage results in an average voltage of 2.6V during its life.

Also checking the  MCP16251 regulator datasheet, we can see the efficiency drops to around 83% at low currents @ 2.4v (at 0.1mA).

blog-mcp16251-efficiency.png
The MCP16251 step-up regulator efficiency at different VINs and currents output.

As our application should spend time on both modes, sleeping and running, we can chose something in between. Let's defined we have 87% of average efficiency from our step-up. Applying it to our already small amount of energy we get:

197mA/h * 0.87 = 171mA/h

At this point we know that we have only 171mA/h @ 3.3V (564mW/h) available to spend along a full year. In other words 171mA/h / 8760h = 0.0195mA of average current, less than 20uA!

How much energy do we need

Now that we know how much (or how little) energy we have available, the next step is to list every way we're going to spend it, starting with the kind of usages we can't control, like the sleeping current, followed by the important ones.

This exercise can be done by using information provided by datasheets together with some way of "pausing" or timing each event. Serial "printing" how long each operation takes can be used. For example, just print the "micros" before and after sending a radio message and you'll have a good idea how long it takes:

(...)
Serial.println(micros());
myRadio.send(myMessage);
Serial.pring(micros());
(...)

Repeat the step above for each little task and you can get the approximated time you spend on each one.

Alternatively, a more practical method, is using an oscilloscope and a shunt resistor. This arrangement might not be ideal for low current measurements because it'll will require a very high resistor to measure properly the little spikes, otherwise you'll only see noise.

blog-ucurrent.jpg

uCurrent can be easily used with a scope to capture real-time current consumption with precision.

blog-bourns-shunt.jpg

Bourns open air shunt resistor.

blog-shunt-ucurrent.jpg

0.1Ω Resistor joining the uCurrent input terminals.

I personally like to use the  uCurrent, but I use it with a custom resistor configuration. By joining the current input terminals with a high precision 0R1 (0.1 Ohms) and moving the selector switch to 1mV/nA I can get 10mV per mA scale. This is required because the oscilloscope will always have a few millivolts of noise no matter how expensive it is.

Finally, the low currents and tasks where you can "hold" it, like sleeping modes or blinking an LED might be better measured using the good and old ammeter. Just make sure you "blink" or sleep for a bit longer (few seconds) so you can get a stable current reading.

DHT11 powering strategy

As the DHT11 does not offer any kind of sleeping mode, I'll be using a MCU GPIO to power it. This technique allows to turn the sensor On and Off only when it's required. Remember that MCU GPIOs are normally limited to source and drain a very small amount of current, if you need to control anything bigger, make sure you use a Mosfet or Transistor.

Also some DHT11 libraries available on the Internet (like the Adafruit one) enables the internal pull-up for the MCU pin connected to the DHT11 data pin. This is not necessary as we already have an external pull-up. Disabling it help us saving some extra current.

Moreover, the DHT11 is a terribly slow sensor, which requires long waiting periods before you can start reading data from it. For that reason many of the "delays" used on the DHT11 library have been replaced with "MCU sleep" calls. For example*:

(...)
// Go into high impedence state to let pull-up raise data line level and
// start the reading process.
digitalWrite(_pin, HIGH);
//delay(250);   // <- Commented and replaced with the line below!
LowPower.powerDown(SLEEP_250MS, ADC_OFF, BOD_OFF);
// First set data line low for 20 milliseconds.
pinMode(_pin, OUTPUT);
digitalWrite(_pin, LOW);
delay(20);     // <- Commented and replaced with the line below!
LowPower.powerDown(SLEEP_30MS, ADC_OFF, BOD_OFF);
uint32_t cycles[80];
{
  // Turn off interrupts temporarily because the next sections are timing critical
  // and we don't want any interruptions.
  InterruptLock lock;
(...)

*Code above from https://github.com/adafruit/DHT-sensor-library/bl...

Practical experimentation

To get some real-life current consumption figures the following code has been written. The idea is to turn On and Off a few components and measure their consumption individually - this not the real code, just for illustration:

#include <LowPower.h>
#define DHT_PWD_PIN A2
setup() {
    myRadio.sleep();
    myFlash.sleep();
    digitalWrite(DHT_PWD_PIN, LOW);
    pinMode(DHT_PWD_PIN, OUTPUT);
}
loop() {
    // Here we can measure how much current we need at sleep
    LowPower.powerDown(SLEEP_8S, ADC_OFF, BOD_OFF);
    // Here we can measure how much the MCU running consumes
    delay(10000);
    // Turn on the Blue LED and we can measure again
    digitalWrite(T2_WPN_LED_1, HIGH);
    delay(10000);
    digitalWrite(T2_WPN_LED_1, LOW);
    // Turn the DHT11 Sensor ON and we can measure again
    digitalWrite(DHT_PWD_PIN, HIGH);
    LowPower.powerDown(SLEEP_8S, ADC_OFF, BOD_OFF);
    digitalWrite(DHT_PWD_PIN, LOW);
}

All the current measuring has been done after the voltage regulator - in other words, this is the actual components' consumption at 3.3V.

  • All board components sleeping + MCU Watchdog: 0.0045mA (4.5uA)
  • MCU running and all board components sleeping: 6.94mA
  • MCU running, Blue Led ON and all board components sleeping: 9.44mA
  • Everything sleeping + MCU Watchdog + DHT11 Powered On: 0.5mA

As we can see the values are pretty close to the component datasheet:

blog-atmega328p-16mhz-powerdown.png
MCU at sleep + watchdog @ 3.3V = ±4.2uA

blog-atmega328p-16mhz-runningcurrent.png
MCU Running at 16MHz @ 3.3V = ±6mA

blog-dht11-current.png
DHT11 Current = ±0.5mA

Now we still need to measure some other processes, like the Radio power usage, together with the timing of each operation. For this exercise an oscilloscope will be used to capture the first version of our real-code running. As discussed previously, this could be done by isolating the tasks and "printing" the time it takes to run if you don't have an oscilloscope.

Using the trick of adding a 0.1R resistor to the uCurrent, each milliamp will appear as 10 millivolts + noise in the scope. Below is how our code behaves:

blog-scope-dht11-cr2032.png
Full running cycle overview.

blog-scope-dht11-cr2032-a.png
Zoom at the first part: reading the battery and PSU voltage and transmitting.

blog-scope-dht11-cr2032-b.png
Zoom at the second part: reading the DHT11 temp. and humidity and transmitting.

From the scope capture above we now know the following:

  • Each Radio TX message takes around 1.6ms and consumes 55mA. We have 4 messages to send;
  • Each analog reading + filling the radio buffer takes about 0.3ms and consumes about 9mA - total of 0.6ms;
  • Reading the DHT11 consumes about 10mA and it takes 4ms;
  • We keep the LED On for 10ms;
  • The DHT11 is On (while MCU is sleeping) for 250ms + 30ms*;

*Note I've changed this values from the scope capture as the sensor was misbehaving with less than 250ms running time before start to reading it.

Again, the observed values are very close to the datasheet:

blog-rfm69w-tx-current-pdf.png
RFM69W TX at 13dBm (±45mA) + MCU running (±10mA) = 55mA

The reason why we don't do all measurements using an oscilloscope is because small currents are translated into very low voltage changes by the uCurrent and the oscilloscope always captures some noise.

Calculating consumption

With the information above we can now calculate the average consumption of our solution. To do that we need to basically multiply the milliamps by the time it's running and later divide by the total time.

The power consumption will be break into parts, so it's easy to understand the weight of each one. Remember, our full cycle is 60 seconds sleeping + execution time.

LED

10ms * 9.44mA = 94.4mA*ms

Battery and power supply voltage reading and transmitting

0.6ms * 9mA + (1.6ms * 2) * 55mA =
5.4mA*ms + 176mA*ms = 181.4mA*ms

DHT11 reading and transmitting

(250ms + 30ms) * 0.5mA + 4ms * 10mA + (1.6ms * 2) * 55mA =
140mA*ms + 40mA*ms + 176mA*ms = 356mA*ms

Total Time and Running period Average

Sum of all operations LED + Voltage Reading and TX + DHT11 and TX:
10ms + (0.6ms + 3.2ms) + (250ms + 30ms + 4ms + 3.2ms) = 301ms
Sum of all operations divided by the total time calculated above:
(94.4mA*ms + 181.4mA*ms + 356mA*ms) / 301ms = 2.099mA average

Now that we know our average consumption for the running period, we need to calculate the average for our whole cycle, 60 seconds sleeping + 301 milliseconds running:

60000ms * 0.0045mA + 301ms * 2.099mA =
270mA*ms + 631.799mA*ms = 901.799mA*ms

Finally

901.799mA*ms / (60000ms + 301ms) =
901.799mA*ms / 60301ms = 0.01495mA

Sensor node final results

Considering we have an average consumption of 0.01495mA, or just about 15uA, we can now calculate how many days the solution can run with only 171mAh:

171mAh / 0.015mA = 11400hours or 475 days or 1.3 years!

Sensor node code optimization

As part of the code improvements for this project, the most important is to put the MCU into sleep while giving some time to the DHT11 to work.

A few additional improvements for power-saving could also be done at the coding level:

  • Use "sleep" instead of "delay" for the LED blinking;
  • Remove the LED blinking at all;
  • Reduce the clock frequency to 8MHz (would require testing);
  • Spread the radio TX calls along the 60 seconds to balance the current draw pulses;
  • Reduce the message size to spend less time transmitting.

Additional improvement could be done by reducing the frequency the battery and/or power supply voltages are read/sent. Instead of every minute, it could be done every 10-30 minutes.

Base node hardware

Having a sensor running at very low-power is almost useless if you don't have a way to receive the data and publish/store it somewhere. The fact that our remote node is running a very simple RF protocol require us to have a gateway.

The main gateway function is to "translate" the messages from a simple format to a more complex format, to be used in other systems. We can't expect the sensor node to send data directly into a SQL database or InfluxDB.

For this solution I've chosen to use another  Whisper Node connected via Serial port to a Raspberry PI. Although this is not the only way of implementing it, I believe the RPI is a very flexible, powerful and reliable platform.

Before you think/ask: no you wouldn't never build the sensor node using a RPI powered by battery... it's quite the same thing as trying to commute driving an 8 axles truck!

Base node software

For the software part I've coded it in Python. It's a widely used open-source language, with plenty of modules and libraries available. Note that the messages will first arrive into the base Whisper Node's RFM69, which will simply "print" it to the serial port using a binary or hex representation.

The messages are kept in binary as much as possible. This reduces the overall size and increase communication speed. We leave for the RPI to decode those messages and convert into any other desired format.

For this project the messages received by the RPI, via Serial, are decoded and routed to the InfluxDB running on a Cloud server. Again the RPI is powerful enough to decode and re-encode messages in any other format you chose.

blog-node-gateway-amqp-diagram.png
A full gateway-to-cloud approach using RabbitMQ as transport.

For additional resilience and flexibility a queuing service, like RabbitMQ could be used between the RPI, the InfluxDB and the Cloud Server. In this case even Internet connectivity could be lost that the RPI's RabbitMQ instance would hold the messages and forward them all once the Cloud Server is reachable again (see Shovel Plug-in).

Cloud server

Many times we tend to keep all services locally, in our own servers. For many scenarios this is a reasonable approach, but having the option to rent a server in the cloud can be a great alternative.

Do you know that you can "rent" a server for less than USD6.00 at the  Google Cloud? By-the-way, I don't have any commercial relationship with Google but it's amazing to have a very reliable service at this price.

blog-googlecould-price.png
Copy of one of my Google Cloud statements.

The price is for the most basic service, but even that, there's no need to worry about power, connectivity, hardware upgrades, nothing!

Now you still need to pay attention for a few things:

  • Security
  • Confidentiality
  • Capacity to relocate

Although the whole Cloud services can be very secure, it's up to the owner to configure firewall, SSH keys and mechanism to prevent unauthorized access. For example, you probably want to look for ways to prevent everybody on the Internet seeing your SSH service.

For the Confidentiality, in this project, we don't have much to worry about as there's not top-secret data being stored. But for other kinds of project you might need to verify contracts and ways of encrypting the data so it's not easily accessible by the Cloud vendor.

It's very important as well to think ways of moving your services off the Cloud or to another cloud provider. This could be for many reasons, from price change to service quality.

Conclusion

Designing and implementing a remote ultra-low power remote node can be a challenging task. For that reason it's very important to clearly define the requirements instead of guessing how the end-result will look like.

Knowing the available hardware and being familiar with low-power coding sometimes is not enough. It's also necessary to understand measurement techniques and use use the proper tools.

Every uA and ms running count!

The impact of a single design decision might determine if you can run your project for one month or one year using a single battery. In the same way, adding to much complexity to your hardware and software can lead to obscure behavior with disastrous results.

Extras

Here some interesting graph showing the battery voltage variation along 3 days, where it's easy to see the affect of the ambient temperature over the battery voltage reading.

blog-battery-vs-temperature-graph.png
Battery voltage reading varies as much as 0.1V, following the ambient temperature changes.

-