NodeMCU event handlers – 18b20 as good start

We have a nice NodeMCU server for LCDs. But there is one catch. We can control one LCD or all connected LCDs. But imagine that we have two LCDs and we want to display different content on each.

In message we can set node name but not device connected to it. So there is case with 1+ screens or broader with many devices connected to one Node.

Another problem: we start LCD server and we want lets say start a server with temperature sensor. We cannot. Lcd would take port and that is all. To do something with this we will introduce event handlers and listers. Big and useful change.
Each module would have an event handler, a function that gets message and do something with it. Returns true when it can handle this event and false when not.

I mention temperature sensor, currently we have none so first lets create one.

Temperature sensor

I’m talking about sensor but what will we use? I have a spare 18b20 – ideal for this. Logic behind this module is very straightforward, respond to events asking for temperature. But that is good, we can focus on handler and listener idea.


I’m using 18B20 connected via 1-wire bus to NodeMCU. Pin that I use is D3

1 ----GND
2 -+-- D ---- D3 @ nodemcu
   [] - resistor 470
3 -+-- +5 

Displaying temperature

Here you can find a nice example of how to get and display temperature. We will use it and adapt to our case.
I have moved parts into functions, do some cleaning and made a module from it.

local sensor = {} = nil
sensor.addr = nil
sensor.device_id = {0x10, 0x28}

sensor.init = function(pin) = pin
    count = 0
      count = count + 1
      addr = ow.reset_search(pin)
      addr =
    until (addr ~= nil) or (count > 100)
    if addr == nil then
        print("Device not found")
        sensor.addr = addr
        crc = ow.crc8(string.sub(sensor.addr,1,7))
        if crc == sensor.addr:byte(8) then
            if (not sensor.is_device(sensor.addr:byte(1))) then
                print("Device is not a DS18B20 family device.")
                sensor.addr = nil
            print("CRC invalid - not a device ?")
            sensor.addr = nil

    return sensor.addr

sensor.is_device = function(data)
    for i, v in ipairs(sensor.device_id) do        
        if v == data then
            return true

    return false

sensor.get_temperature = function(round)
    ow.reset(, sensor.addr)
    ow.write(, 0x44, 1)
    present = ow.reset(, sensor.addr)
    data = string.char(
    for i = 1, 8 do
        data = data .. string.char(
    crc = ow.crc8(string.sub(data,1,8))
    if crc == data:byte(9) then
        t = (data:byte(1) + data:byte(2) * 256) * 625
        t1 = t / 10000
        t2 = t % 10000        
        if round ~= nil and round ~= false then return t1 else return t1.."."..t2 end
        return nil

return sensor;


pin = 3

temp = require "18b20"


Function init takes pin as parameter, setup this pin as ow bus and search for device that is 18b20. When it is found function store addr for future use.
This module has one function for user: get_temperature. If you pass parameter it will round temperature data. Without it raw value is returned.


Our module has only one event that will listen to: temperature.current.
As I mention earlier we gonna use event handlers. But what it is?
I will use temperature module to show this. We have a main module: 18b20, now we gonna create another module to handle events: 18b20_handler. This module will receive main class as parameter, so it would know on what node it would execute events.
Okey, we have the Node, we have the handler to call events on Node but what would call this handler ?
Good question 🙂 We need something to do this, like a server that would listen to incoming connections and pass message with event to all handlers. We need of course register handlers in listener.
To sum it up:

Node -[node]-> Handler <-[event]- server <- message

Lets start from handler. In our case, temperature sensor handler, we handle only one event: temperature.current. So our handler should look like this (nice file 18b20_handler.lua):

local handler = {}

handler.node = nil
handler.round = nil

handler.handle = function (socket, message)
    response = false
    if message ~= nil and message.event ~= nil then
        if message.event == 'temperature.current' then
            r = handler.round
            if type(message['parameters']) == 'table' and type(message.parameters['round'] ~= nil)then
                r = message.parameters['round'] 
            message = network_message.prepareMessage()
            message.response = handler.node.get_temperature(r)
            network_message.sendMessage(socket, message)
            response = true

    return response

return handler

This is a nice handler:) It react to an event and can round variable if proper attribute in message is set. It gets socket and message. Response is transferred back to source via socket.

Another question: how to use it? And answer: my looks like this:

print ("core ready")
network_message = require "network_message"

pin = 3

temp = require "18b20"
temp_handler = require "18b20_handler"
temp_handler.node = temp


svr = net.createServer(net.UDP)
svr:on('receive', function(socket, message) 
    message = network_message.decodeMessage(message) 
    temp_handler.handle(socket, message)


Simple is it? We start a server and pass received message to handler. To test it all I used such python script:

import socket
import json

address = ('', 5053)

packet = {
    'protocol': 'iot:1',
    'node': 'computer',
    'chip_id': 'd45656b45afb58b1f0a46',
    'event': 'temperature.current',
    'parameters': {
        # 'round': False
    'targets': [

s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
msg = json.dumps(packet)
s.sendto(msg.encode(), address)
(buf, ip) = s.recvfrom(1024)
print("from %s: %s" % (ip, buf.decode()))

And it is all working:

{"chip_id": "d45656b45afb58b1f0a46", "targets": ["ALL"], "parameters": {}, "event": "temperature.current", "protocol": "iot:1", "node": "computer"}
from ('', 5053): {"chip_id":194799,"protocol":"iot:1","node":"node-40x4","targets":["ALL"],"event":"","response":"26.3750"}


First part of refactoring is done. We have a nice event handler for temperature module. Next we need to do handler a for lcd_hd44780 module. After that we will do something with server (event listener).

Module 18B20 added to boilerplae


One comment

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )


Connecting to %s