NodeMCU, broadcast and an event

Goal for this post: program ESP to send event. We will broadcast an event packet into network and read it. But lets start from beginning. What is broadcast?
Broadcast is a method of transferring a message to all recipients simultaneously [Wikipedia].
Contrary to unicast when you send data to one and only one recipient. But how to send something everywhere? Broadcast address are IP one that ends with 255, for a base network broadcast address is
One important aspect is that broadcast use UDP not TCP.  In short words, TCP connect and provide reliability and UDP send packet and forget but is faster.

First we will write simple server and client application. Of course in Python 🙂

Broadcast client and server

I hope you know something about network programming, sockets and client-server architecture.

Our server script is typical Python implementation with one difference:

import socket

s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
s.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
s.bind(('', 5053))

print("waiting for messages")
while 1:
        message, address = s.recvfrom(1024)
        print("Message from %s: %s" % (address, message.decode()))
        s.sendto("OK!".encode(), address)

This line:

s.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)

enable our socket to listen to broadcast packets. Without it all such packets are dropped. We must enable it manually.

And client:

import socket
import random

address = ('<broadcast>', 5053)

s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
s.sendto(("lucky number is: "+str(random.randint(1, 100))).encode(), address)

(buf, ip) = s.recvfrom(1024)
print("from %s: %s" % (ip, buf.decode()))

See that we are using special address. You may specify address manualy, for example or even

This server we will use when playing with NodeMCU.

Broadcast from ESP

Back to NodeMCU and Lua. Get boilerplate.
For start we will transmit one broadcast packet to see if it works. Open main.lua and copy:

print ("core ready")

srv=net.createConnection(net.UDP, 0)
srv:connect(5053, wifi.sta.getbroadcast())

srv:send("From: "..NODE_ID )


We are creating UDP socket and connect it to broadcast address. It is very nice that we may get broadcast IP for our network by wifi.sta.getbroadcast().

And that is it. Simple code to send packet. Our server can receive it.


Lets connects eight buttons to NodeMCU board. We have lots of GPIOs. And first fail, some GPIOs are used internally… D9 and D10 are connected to serial, D4 to led and in my case D0 didn’t work.. so we have only 6 pins! Plan changed, 4 buttons as directions and two as actions.

D1 __/__.
D2 __/__|
D3 __/__|
D5 __/__|
D6 __/__|
D7 __/__|
GND ____|

See that we connect GPIOs via buttons to the ground, and in code we check for 0 value. It was something new for me.
Pins that we used are: D1, D2, D3, D5, D6 and D7. To call function when button is pressed we use triggers.
Our packet will consist of few fields: chip_id, node and event. Chip_id is set to node.chipid() – this is current device internal id. Next is node=NODE_ID, this one is from parameters-device. And finally we have event, this one is our event name like event.up, event.down and so.
There is another small trick we are using, it is lock handler. When button is pressed we check for lock and if we can we send data and start timer that will release lock. Lock time is defined in parameters.lua as BTN_TIMEOUT = 500.
This lock allows us to send event only after half a second, small anti-flood protection.
Last thing defined in parameters is SERVER_PORT = 5053. This one define port we choose for communication.
Lets see the code:

print ("core ready")

lock = false

data = {}
data.event = 0
data.chip_id = node.chipid()
data.node = NODE_ID

srv=net.createConnection(net.UDP, 0)
srv:connect(SERVER_PORT, wifi.sta.getbroadcast())

We set lock to false and prepare data object. This one will be send. Next we initialize UDP socket.

function sendEvent(event)
    if lock then
        lock = true

    data.event = event
    ok, json = pcall(cjson.encode, data)
    if ok then
      print (json)
    tmr.alarm(0, BTN_TIMEOUT, 0, resetLock)

This function is used to broadcast event. We call it from triggers attached to buttons. Event attribute is a string with event name. First we set our lock to true, next event name is assigned to object, object is converted to json and we send it.
Then we start a timer with unlock.

function resetLock()
    lock = false

This code set our lock to false – release lock

function btnDown()

function btnLeft()

function btnUp()

function btnRight()

function btnAction1()

function btnAction2()

gpio.mode(1, gpio.INT, gpio.PULLUP)
gpio.mode(2, gpio.INT, gpio.PULLUP)
gpio.mode(6, gpio.INT, gpio.PULLUP)
gpio.mode(7, gpio.INT, gpio.PULLUP)

gpio.mode(3, gpio.INT, gpio.PULLUP)
gpio.mode(5, gpio.INT, gpio.PULLUP)

gpio.trig(1, 'down', btnDown)
gpio.trig(2, 'down', btnLeft)
gpio.trig(7, 'down', btnUp)
gpio.trig(6, 'down', btnRight)

gpio.trig(5, 'down', btnAction1)
gpio.trig(3, 'down', btnAction2)

We setup pins and attach functions that will be triggered upon clicking.


We made small circuit with 6 buttons, when button is pressed event is broadcasted and our python script can read it and display.



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 )

Twitter picture

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

Facebook photo

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

Google+ photo

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

Connecting to %s