Cheap and simple window security with ESP8266 and openHAB
October 30, 2015
Next chapter in my openHAB journey, is how to make a cheap and simple switch, which will monitor a switch mounted to a window or door.
To do this, I decided to use the ESP8266. It is widely available for purchase, is cheap, can connect to WiFi easily, and there are made support for multiple programming languages.
In this guide, I will only use NodeMCU and LUA to do the programming part.
The receiver for the commands from the ESP8266 will be mosquitto to receive the MQTT messages, and openHAB to react with rules to those messages.
Notice: For this guide to work, it will need a mosquitto mqtt server to run, openHAB, and LUA code to be send to an ESP8266 module. How to get these installed and configure, won’t be covered in this guide.
These were the items I decided on, and as you can see, the total is only just above £7, which is about $11. And that price can even be even lower, by quite a bit actually. If you look in the list, the biggest expense is the NodeMCU board, but there are cheaper alternatives to it. The reason for me choosing this over just a stand-alone ESP8266, is because it is easy to program through the on-board usb port. Easy to flash with NodeMCU if a mistake is made in the programming and it ends up in a loop, crashing over and over. And because it got a 3.3v regulator on too. For beginners in hardware and coding, this is what I have found the best solution, and least frustrating way to learn how it works.
Since everything we need to run the ESP8266, already is on the development board, all we need to do is to connect the switch to one of the pins.
Here I have connected one of the two black wires coming from the switch to D3, and the other to GND.
This will pull the pin down to GND when the magnet is removed, and the reed switch close.
For a permanent installation, I recommend soldering the wires directly to the pins, or using some pin-header connectors.
Next step is some code which we can send to the ESP8266.
Not much configuration is needed, in fact, only thing you need to change, is the wifi credentials, ip of the mosquitto server, deviceID and roomID.
With this you can give it some kind of identification, so you easily can find it later.
With roomID, you can specify the room the module is located in. In this example I got it in my livng room.
How does it actually work?
After sending your code to the ESP8266, connected the switch, and powered it all up, it will connect to your WiFi. After successfully connecting to the WiFi network, it will try to connect to the MQTT server. If this also succeed, it will start a timer, which will trigger the mqttPublish function. The mqttPublish will continuously send the pin status to the MQTT server, with the delay defined in syncDelay. This is only to make sure the status on the server is updated regularly, so the rule we set up later, always got some good data to react on.
But having it send the status only once every 60 seconds, could in the worst case scenario, give a burglar up to 60 seconds to disable the system after opening the door or window. To make this difficult, the switchPin is defined as a trigger, so as soon as it changes, it will send the status about it having changed, which will happen in less than a second.
Another smart feature, is the LWT, which is “Last Will and Testament”. This we can use to also get a message, if the device for some reason lost connection to the server.
Depending on how sensitive you want it to be, you can adjust the “keepAlive” variable. I set it to 30, so 30 seconds after the device disconnected, the server will send a message on the /lwt channel. More about this topic in the openHAB rules section.
wifi.sta.config("SSID" , "KEY")
syncDelay = 60
deviceID = "esp10"
roomID = "living"
keepAlive = 30
switchPin = 3
switchState = 0;
m = mqtt.Client("ESP8266".. deviceID, keepAlive)
m:lwt("/lwt", roomID .."/" .. deviceID, 2, 0)
ip = wifi.sta.getip()
print ("Mqtt Reconnecting to " .. broker .. " from " .. ip)
tmr.alarm(1, 10000, 0, function()
local sendState = "OFF"
if (switchState == 1) then
sendState = "ON"
m:publish("/home/".. roomID .."/" .. deviceID .. "/state", sendState, 0, 0)
tmr.alarm(0, 1000, 1, function()
if wifi.sta.status() == 5 and wifi.sta.getip() ~= nil then
m:connect(broker, 1883, 0, function(conn)
print("Mqtt Connected to:" .. broker)
tmr.alarm(0, syncDelay*1000, 1, function() mqttPublish(); end)
gpio.mode(switchPin, gpio.INPUT, gpio.PULLUP)
pinDebounce = 0
gpio.trig(switchPin, "both",function (level)
if (pinDebounce == 0) then
pinDebounce = 1
tmr.alarm(6, 50, 0, function() pinDebounce = 0; end)
switchState = gpio.read(switchPin);
To be able to react to the messages from the ESP8266 about our switch, we also need to define it in openHAB.
The first thing we need is an item. This will be defined as a switch, and looks like this.
If you look in the last part of the line, you can see the “living” and “esp10” from the LUA code, go again in here. This is our way to link the messages from the ESP8266, to the switch, and hopefully make enough sense, so we in a few months still can figure out which one it is.
If you want to be able to see the state of the switch on the page, you also need to define it in a sitemap. That could be done like this.
And it would then look like this, first with the window closed
and then with the window open
The reason for it being like this, is because when the switch is closed (magnet is next to it), the reed switch inside is pulled shut by the magnet, and the pin is pulled down to GND. When the magnet is removed, the reed switch opens, and the internal pull-up resistor will pull the pin up to 3.3v, and the status of the switch will then be OFF.
To react on the messages coming from the ESP8266, we also need to set up a rule. A simple rule could look like this.
Item windowSwitchLiving changed from OFF to ON
pushover("Living room window opened!", 2)
in this I also use the Pushover addon for openHAB, to help me send a message to my phone with the notification. The “2” at the end of the call, is to set it to the highest priority.
Sending it will the highest priority will cause the notification to require acknowledgement, otherwise it will regularly notify about the same message, until acknowledgement.
In the code we specified what should happen if the device unexpectedly disappear, and all we need to do now, is to tell openHAB what to do with that message.
We start with an item to hold the messages we get.
and after that, we need a rule to handle what should happen when we get a message.
Item nodeLWT received command
var String state = nodeLWT.state.toString()
pushover(state + " has disconnected.", 1)
When a device suddenly disappears, you should then get a notification looking something like this. As before, you can can change the priority, by changing the number in the end of the pushover function.