The Problem
Many devices with sensors spend the majority of time in deep sleep, wake up, take a measurement, communicate it over WiFi and go back to sleep.
WiFi communication is typically the step that takes the longest and consumes the most battery power.
How do we optimize our code to spend less time being connected to and communicating over WiFi?
Solution
Don’t communicate the measurement unless it is a certain percentage larger or smaller than the previously reported measurement.
Results
This algorithm change resulted in my sensor/Wemos D1 Mini combo consuming three hundred (300!) times less power over same time period.
You can find a simple Lua code sample that illustrates this solution below the following details.
Details
I have a battery powered moisture sensor that takes a measurement roughly every 15 minutes. I worked on optimizing its deep sleep and was able to do that, but then I wanted to focus on the meatier part of its power consumption.
Now I take the measurement and before connecting to WiFi to communicate the value to my MQTT broker I read the last communicated value stored in a file.
If the value is within 5% of the latest reading I simply go back to sleep and skip the entire WiFi step. If there is no previously communicated value or it has changed enough, then send over MQTT and update the value stored in the file.
Of course, the magnitude of improvement that this optimization will deliver to your project depends on how volatile your measurements are or how granular your reporting needs are.
If your values change a lot between readings or you need to know about every slightest change, this is not for you.
In the case of my moisture sensor though it was a dramatic improvement. The sensor communicated once every 5 hours on average instead of 4 times/hour.
Using a Wemos D1 Mini + moisture sensor’s average WiFi connected consumption of about 85mA vs non-WiFi 30mA we can do some math:
Default way: (4 times / hour) * (6 seconds of connecting and communicating / time) * 5 hours = 120 seconds
. Which is about 120 / 3600 * 85 = 3mA
.
Optimized way: (4 times / hour) * (0.5 seconds / time) * 5 hours = 10 seconds
. Which works out to 10 / 3600 * 30 = < 0.01mA
.
In my case, that’s 300 times less power consumed in the same amount of time! Incredible, considering the ease of implementation.
Sample Code
I’m using Lua programming language in my ESP8266 projects but this can be easily translated to any other language of your liking.
local last_reading_file_name = 'last_reading.txt'
local reading = nil
local get_last_reported_value = function()
if file.open(last_reading_file_name, 'r') then
local last_val = tonumber(file.read(100))
file.close()
return last_val
end
return nil
end
local save_last_reported_value = function()
if file.open(last_reading_file_name, 'w') then
file.write(reading)
file.close()
end
end
local read_value = function()
reading = adc.read(0)
local last_value = get_last_reported_value()
local percent_change = (math.abs((last_value or 0) - reading) / reading) * 100
if last_value == nil or percent_change > 5 then
connect_to_wifi_and_publish_to_mqtt("your_topic", message, qos, retain, sleep_function)
else
sleep_function("Skipping reporting over WiFi, change: " .. percent_change .. "%")
end
end
read_value()
sleep_function
and connect_to_wifi_and_publish_to_mqtt
are outside of this post’s scope and will be very specific to your project.
Please let me know if this was helpful to you and if wanted me to expand on anything in this post.
Leave a Reply