More ESP8266 Lua Projects

I had some more fun with Lua on the ESP8266 wifi modules. These things are so cheap and so versatile that I have already reserved a dedicated subnet for sensor nodes in the house.

The latest ESP8266 projects are a temperature logger for the water temperature of the central heating and a meter reader for water consumption.

The NodeMCU Lua firmware has native support for onewire, making it trivial to add some DS18B20 temperature sensors. A bit of Lua glues these to a TCP socket and outputs the sensor values when a TCP connection is made. This way it is very easy to grab the sensor values from MRTG.

MRTG Then generates pretty graphs like the one below. In this graph the red line shows the hot water from the central heating boiler, the blue area is the return water temperature.

The code behind this is too dirty to publish, some cleaning up needs to be done first. The water usage logger is a better example.

The water usage logger uses a reflective infrared sensor mounted on the water meter. The water meter has a disc with a reflective part that the sensor can detect, giving an impulse per liter of water used.

The impulse output of the sensor is connected to a GPIO on the ESP8266, the ESP8266 increments a global counter on every impulse received. It also listens for TCP connections, when a connection is received it emits the measured values in the format that MRTG expects for external scripts. Thus making it easy to gather the values from MRTG using nothing more than netcat.

main.lua
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
gpio0 = 3
gpio2 = 4

count = {0, 0}

gpio.mode(gpio0, gpio.INT)
gpio.mode(gpio2, gpio.INT)

function increment(index, state)
  count[index] = count[index] + 1
end

gpio.trig(gpio0, "up", function (state) increment(1, state) end)
gpio.trig(gpio2, "up", function (state) increment(2, state) end)

srv=net.createServer(net.TCP)
srv:listen(5555, function(c)
        str = ""
        for i=1,2 do
                str = str .. tostring(count[i]).."\n"
        end
        str = str .. tostring(tmr.now()).." ticks\n"
        str = str .. "node-"..tostring(node.chipid()).."\n"
        c:send(str)
        c:on("sent", function(c) c:close() end)
end)

On a TCP connect the ESP8266 emits something similar to this:

402
0
1915768749 ticks
node-12341234

This is exactly the format that MRTG uses, making MRTG side of things very simple:

1
2
3
4
5
6
7
8
9
10
11
12
Title[water]: Water Flow
Target[water]: `/bin/nc water.metering.iot.intra.isquared.nl 5555`
PageTop[water]: <H1>Water Flow</H1>
Options[water]: nopercent, noo, perminute
MaxBytes[water]: 10000
Factor[water]: 1
YTicsFactor[water]: 1
WithPeak[water]: wmy
YLegend[water]: Liter/min
ShortLegend[water]: l/min
LegendI[water]: flow
Colours[water]: BLUE#2222aa, BLUE#2222aa, LIGHTBLUE#3399ff, LIGHTBLUE#3399ff

The gas and electricity meters still pose a bit of a problem, the infrared sensors have a had time picking up a signal from those. For electricity

I’ll probably add one or two kWh meters with an S0 output behind the meter provided by the utility company. This is easier and probably more reliable than trying to read the meter optically.

Graphing many more values using MRTG will probably also demand too much from the Raspberry Pi that now does all the graphing. A cusom solution using RRDTool will probably be a better solution.

Comments