Wemos D1 Mini Door Contact (plus temperature)

, posted: 16-Nov-2017 07:58

Creating a garage door contact switch for detecting if the door is open.

I had my garage door added to my house alarm. In doing so, it was added to a button on the remote we use for arming and disarming. Well after one morning where my son accidentally opened the garage door (which we can’t see from the house) I looked at adding a reed switch to the door to detect it’s open state.

I hadn’t used a Wemos D1 Mini before but I liked the size of them, and there seemed to be a fair bit of code around to base off.

After buying 3, and finally taking delivery of some DHT shields (DHT12 for temperature), some reed switches and a few other bits and pieces for future projects I started playing in the Arduino IDE.

 

What most blogs will give you is a schematic breadboard with the Wemos pins, but then it tends to get a little fuzzy in showing how the various components are wired up.

eg:

So in actual case with my 2 wire reed switch, I wired 1 wire to the ground header of the wemos, the other wire to the D2 header.

wemos-reed

Excuse the soldering, it’s been a long time.  Also I’ve moved these connections to the rear, as I intend to mount in an enclosure and want the DHT Shield on top exposed the the air (not that the temperature on this is important).

But what you should see is the D2 and GND pins being used.  The DHT Shield communicates on D4.

Next the code.

I’ve decided on a framework called Homie.  This is an MQTT enabled framework that allows for over the air (OTA) firmware updates and a consistent messaging protocol for sensors.

There are a number of blog posts aroudn getting a Wemos D1 to work in the Arduino IDE, so I wont cover this.

https://wiki.wemos.cc/tutorials:get_started:get_started_in_arduino

https://www.cnx-software.com/2016/03/22/getting-started-with-wemos-d1-mini-esp8266-board-dht-relay-shields/

https://diyprojects.io/shield-wemos-d1-mini-dht11-dht22-arduino-code-esp-easy/#.WgunAdNL-1s

The simple blink samples are well worth doing if you’ve not played before.

As for Homie.  Here is the quick Start http://marvinroger.github.io/homie-esp8266/2.0.0-beta.1/quickstart/getting-started/

I started with the Version1 stable, but quickly moved to the Version 2 (beta at time of writing) for access to the OTA updates.

Once the D1 Mini was working in the Arduino IDE, and the Homie Framework installed and running on your mini.  You’re now in the position to look at this specific project.

There are two parts we need to think about.  The reed switch and the temperature sensor.  I will mostly concentrate on the reed switch as that’s the least documented.

#include <Homie.h>
#include <WEMOS_DHT12.h>

#define FW_NAME "dhtshield-reed-dht12"
#define FW_VERSION  "1.0.3"

/* Magic sequence for Autodetectable Binary Upload */
const char *__FLAGGED_FW_NAME = "\xbf\x84\xe4\x13\x54" FW_NAME "\x93\x44\x6b\xa7\x75";
const char *__FLAGGED_FW_VERSION = "\x6a\x3f\x3e\x0e\xe1" FW_VERSION "\xb0\x30\x48\xd4\x1a";
/* End of magic sequence for Autodetectable Binary Upload */

/* Reed pin */
#define REED_PIN D2
int doorState = 0;


const int TEMPERATURE_INTERVAL = 300;
unsigned long lastTemperatureSent = 0;
DHT12 dht12;

HomieNode reedNode("reed", "state");
HomieNode temperatureNode("temperature", "temperature");
HomieNode humidityNode("humidity", "humidity");


void setupHandler() {
   // Do what you want to prepare your sensor
   reedNode.setProperty("state").send("on");
   pinMode(REED_PIN, INPUT_PULLUP);
   temperatureNode.setProperty("unit").send("c");
   humidityNode.setProperty("unit").send("%");
}

void loopHandler() {
   int lastDoorState = doorState;
   doorState = digitalRead(REED_PIN);
   String doorStateString = "unk";

  if (lastDoorState != doorState) {
     if (doorState == 1) {
       doorStateString = "open";
       //reedNode.setProperty("state").send("open"); 
       Homie.getLogger() << "Door State: OPEN" << endl;
     } else if (doorState == 0){
       doorStateString = "closed";
       //reedNode.setProperty("state").send("closed");
       Homie.getLogger() << "Door State: CLOSED" << endl;
     } else {
       //reedNode.setProperty("state").send("unk");
       doorStateString = "unk";
       Homie.getLogger() << "Door State: UNKNOWN" << endl;
     }
     reedNode.setProperty("state").send(doorStateString); 
   }

  if (millis() - lastTemperatureSent >= TEMPERATURE_INTERVAL * 1000UL || lastTemperatureSent == 0) {
     if(dht12.get()==0){
         float temperature = dht12.cTemp;
         float humidity = dht12.humidity;
         Homie.getLogger() << "Temperature: " << temperature << " °C" << endl;
         Homie.getLogger() << "Humidity: " << humidity << " %" << endl;
         temperatureNode.setProperty("degrees").send(String(temperature));
         humidityNode.setProperty("percent").send(String(humidity));
         reedNode.setProperty("state").send(doorStateString); 
     }
     lastTemperatureSent = millis();
   }
   delay(1000);
}

void setup() {
   // put your setup code here, to run once:
   Serial.begin(115200);
   Serial << endl << endl;
   Homie_setFirmware(FW_NAME, FW_VERSION);
   Homie.setSetupFunction(setupHandler).setLoopFunction(loopHandler);

  reedNode.advertise("state");
   temperatureNode.advertise("unit");
   temperatureNode.advertise("degrees");
   humidityNode.advertise("unit");
   humidityNode.advertise("percent");


   Homie.setup();
}

void loop() {
   // put your main code here, to run repeatedly:
   Homie.loop();

}

 

Lets break some of it down, include statements for the Homie framework, and the DHT shield. 

#include <Homie.h>
#include <WEMOS_DHT12.h>

 

The name and definition of the firmware (used when there is an OTA server).

#define FW_NAME "dhtshield-reed-dht12"
#define FW_VERSION  "1.0.3"

/* Magic sequence for Autodetectable Binary Upload */
const char *__FLAGGED_FW_NAME = "\xbf\x84\xe4\x13\x54" FW_NAME "\x93\x44\x6b\xa7\x75";
const char *__FLAGGED_FW_VERSION = "\x6a\x3f\x3e\x0e\xe1" FW_VERSION "\xb0\x30\x48\xd4\x1a";
/* End of magic sequence for Autodetectable Binary Upload */

 

 

The pin number for the reed switch and a variable to hold the door state.

/* Reed pin */
#define REED_PIN D2
int doorState = 0;

 

Variables to the DHT shield, the important one is the DHT12 which is the object that will perform the reading.

const int TEMPERATURE_INTERVAL = 300;
unsigned long lastTemperatureSent = 0;
DHT12 dht12;

 

This is the Homie Property that will hold the reed switch state.

HomieNode reedNode("reed", "state");

 

And two more for the temperature and humidity readings from the DHT Shield.

HomieNode temperatureNode("temperature", "temperature");
HomieNode humidityNode("humidity", "humidity");

 

Here is all your specific code for your sensors.  So in this case I’m setting the reed property type (eg on off), and defining the pin that is read.  For the DHT I’m setting the unit type for the temperature and humidity.

void setupHandler() {
   // Do what you want to prepare your sensor
   reedNode.setProperty("state").send("on");
   pinMode(REED_PIN, INPUT_PULLUP);
   temperatureNode.setProperty("unit").send("c");
   humidityNode.setProperty("unit").send("%");
}

 

I’ve skipped over the main loop handler and will cover that last, as it’s the bit that does the work.

The setup function sending the firmware name and version, sets up the looping function (loophandler) and tells all the nodes to advertise their properties.

void setup() {
   // put your setup code here, to run once:
   Serial.begin(115200);
   Serial << endl << endl;
   Homie_setFirmware(FW_NAME, FW_VERSION);
   Homie.setSetupFunction(setupHandler).setLoopFunction(loopHandler);

   reedNode.advertise("state");
   temperatureNode.advertise("unit");
   temperatureNode.advertise("degrees");
   humidityNode.advertise("unit");
   humidityNode.advertise("percent");


   Homie.setup();
}

 

Here is part of the main loop handler.  This is concerned with the reading of the reed switch.  The current doorState is kept, then the reed switch GPIO port is read.

Then only if the previous door state and current differ does it translate the pin state into an MQTT friendly (OpenHAB Contact) state – of ‘OPEN’ or ‘CLOSED’

void loopHandler() {
   int lastDoorState = doorState;
   doorState = digitalRead(REED_PIN);
   String doorStateString = "unk";

  if (lastDoorState != doorState) {
     if (doorState == 1) {
       doorStateString = "open";
       //reedNode.setProperty("state").send("open"); 
       Homie.getLogger() << "Door State: OPEN" << endl;
     } else if (doorState == 0){
       doorStateString = "closed";
       //reedNode.setProperty("state").send("closed");
       Homie.getLogger() << "Door State: CLOSED" << endl;
     } else {
       //reedNode.setProperty("state").send("unk");
       doorStateString = "unk";
       Homie.getLogger() << "Door State: UNKNOWN" << endl;
     }
     reedNode.setProperty("state").send(doorStateString); 
   }

 

The line

reedNode.setProperty("state").send(doorStateString); 

is what sends the current state to the MQTT broker.

 

The rest is all concered with reading the state of the DHT shield if the last time the temperature was read is > that the interval set in the settings, eg 300 seconds or 300000 milliseconds.

if (millis() - lastTemperatureSent >= TEMPERATURE_INTERVAL * 1000UL || lastTemperatureSent == 0) {
     if(dht12.get()==0){
         float temperature = dht12.cTemp;
         float humidity = dht12.humidity;
         Homie.getLogger() << "Temperature: " << temperature << " °C" << endl;
         Homie.getLogger() << "Humidity: " << humidity << " %" << endl;
         temperatureNode.setProperty("degrees").send(String(temperature));
         humidityNode.setProperty("percent").send(String(humidity));
         reedNode.setProperty("state").send(doorStateString); 
     }
     lastTemperatureSent = millis();
   }
   delay(1000);
}

Here are all the properties being sent to MQTT

temperatureNode.setProperty("degrees").send(String(temperature));
humidityNode.setProperty("percent").send(String(humidity));
reedNode.setProperty("state").send(doorStateString);

The state of the reed switch is sent regardless on the same interval, if not already set.  Probably not needed as homie defaults each message to retained on the MQTT broker.

Lastly the function is looped each second.

 

Once this code is uploaded to the D1 via the Arduino IDE.  Open the Serial Monitor to see messages with the connected D1 Mini.  This should show the device attempting to connect to a WIFI network – of which it doesn’t know any.  So you need to post it a config file which tells the device how to connect.  http://marvinroger.github.io/homie-esp8266/2.0.0-beta.1/configuration/json-configuration-file/.  Once the device has figured it there is no known network, it will actually create an AP.  Connect to this and from here navigate to http://setup.homie-esp8266.marvinroger.fr which should take you to the Wemos D1 mini running homie.  Here there are pages to configure the device name (this is the MQTT topic it will use), it’s nice name, the WIFI network and password, the location of your MQTT broker and base topic.  Enter all these and save.

I use a base of sensors/d1mini for my MQTT topic.  And for a device name garage-sensor, I should expect to see mqtt messages appearing in the topic sensors/d1mini/garage-sensor. I use this naming scheme for other devices as well, such as a raspberry pi with a DHT sensor is on sensors/dht/<device>.

At this point the device should reboot.  I found mine do not, so I have to hard reboot (pull power).  Again keep it connected via serial monitor and you should see it come up and connect to your WIFI network.

If you seen the connect to the network, then you can now go to your mqtt broker and check for messages.  Given mine is on a linux, I’ll be using the linux mosquitto commands.  But any MQTT client will work.

To list all entries for this example device I’d enter (assuming that I was running the command on the same server as the mqtt broker.:

mosquitto_sub –v –t sensors/d1mini/garage-sensor/#

sensors/d1mini/garage-sensor/$homie 2.0.0
sensors/d1mini/garage-sensor/$implementation esp8266
sensors/d1mini/garage-sensor/$implementation/config {"name":"Garage","device_id":"garage-sensor","wifi":{"ssid":"IOT"},"mqtt":{"host":"192.168.10.41","mDNS":"mqtt","port":1883,"base_topic":"sensors/d1mini/"},"ota":{"enabled":true,"host":"192.168.10.41","port":9081,"path":"/custom_ota"}}
sensors/d1mini/garage-sensor/$implementation/version 2.0.0
sensors/d1mini/garage-sensor/$implementation/ota/enabled true
sensors/d1mini/garage-sensor/$mac xx:xx:xx:xx:xx:xx
sensors/d1mini/garage-sensor/reed/$type state
sensors/d1mini/garage-sensor/reed/$properties state
sensors/d1mini/garage-sensor/reed/state closed
sensors/d1mini/garage-sensor/temperature/$type temperature
sensors/d1mini/garage-sensor/temperature/$properties unit,degrees
sensors/d1mini/garage-sensor/temperature/unit c
sensors/d1mini/garage-sensor/temperature/degrees 16.70
sensors/d1mini/garage-sensor/humidity/$type humidity
sensors/d1mini/garage-sensor/humidity/$properties unit,percent
sensors/d1mini/garage-sensor/humidity/percent 68.20
sensors/d1mini/garage-sensor/humidity/unit %
sensors/d1mini/garage-sensor/$name Garage
sensors/d1mini/garage-sensor/$localip 192.168.100.21
sensors/d1mini/garage-sensor/$stats/interval 60
sensors/d1mini/garage-sensor/$stats/signal 86
sensors/d1mini/garage-sensor/$stats/uptime 343921
sensors/d1mini/garage-sensor/$fw/name dhtshield-reed-dht12
sensors/d1mini/garage-sensor/$fw/version 1.0.3
sensors/d1mini/garage-sensor/$online true

So if I see this then I know the device is a, working, two, reading my reed switch and DT shield.  It may take a little while for the DHT values to be populated.  The $online tag is really useful for know the device in online and running.

Next we’ll get the values into OpenHAB – but the concept should be similar for Home Assistant.  Here is an items file I have for my D1Mini sensors.  Once thin I like with the new version of OpenHAB2 is that you can (if you wish) segregate items types by technology.

Group g_d1mini "D1 Mini"
Group g_d1mini_garage "Garage"  (g_d1mini)
/* Garage*/
Number   d1mini_garage_temperature  "Temperature [%.1f °C]" <temperature> (g_d1mini_garage) {mqtt="<[mqtt:sensors/d1mini/garage-sensor/temperature/degrees:state:default]"}
Number   d1mini_garage_humidity  "Humidity [%.1f%%]" <humidity>   (g_d1mini_garage) {mqtt="<[mqtt:sensors/d1mini/garage-sensor/humidity/percent:state:default]"}
Number   d1mini_garage_signal  "Signal [%.1f%%]" <signal>   (g_d1mini_garage) {mqtt="<[mqtt:sensors/d1mini/garage-sensor/$stats/signal:state:default]"}
Number   d1mini_garage_uptime  "Uptime [%d]" <humidity>   (g_d1mini_garage) {mqtt="<[mqtt:sensors/d1mini/garage-sensor/$stats/uptime:state:default]"}
String   d1mini_garage_ip  "IP [%s]"   (g_d1mini_garage) {mqtt="<[mqtt:sensors/d1mini/garage-sensor/$localip:state:default]"}
String   d1mini_garage_name  "Name [%s]"    (g_d1mini_garage) {mqtt="<[mqtt:sensors/d1mini/garage-sensor/$name:state:default]"}
Contact  d1mini_garage_door "Door [%s]"  (g_d1mini_garage) {mqtt="<[mqtt:sensors/d1mini/garage-sensor/reed/state:state:MAP(onoff.map)]"}
Contact  d1mini_garage_online "Online [%s]"  (g_d1mini_garage) {mqtt="<[mqtt:sensors/d1mini/garage-sensor/$online:state:MAP(onoff.map)]"}

So this assumes your mqtt broker for OpenHAB is set up and running, and accepting messages.  Here is the config page: http://docs.openhab.org/addons/bindings/mqtt1/readme.html

So a quick run down, here is the garage door reed switch.  It is a contact item (which is a read only switch in openhab) which has a state of OPEN or CLOSED.  Equally a switch will work.

Contact  d1mini_garage_door "Door [%s]"  (g_d1mini_garage) {mqtt="<[mqtt:sensors/d1mini/garage-sensor/reed/state:state:MAP(onoff.map)]"}

The important bits here is that it’s using the MQTT binding, with a defined mqtt server (done as part of the OpenHAB config, and looking at sensors/d1mini/garage-sensor/reed/state for it’s state information.  If we look back at the code, when the reed switch is open (too far from each other) the word “open” will be posted to this topic.  When closed, ”closed” is posted.  As that wasn’t what OpenHAB was actually expecting, it expected OPEN and CLOSED in capitals, the MAP(onoff.map) is a translation table which translates open to OPEN.

So in OpenHAB (basic UI) I see the sensor show up as follows:

image

Other related posts:
RM3's also - but this time with more geek.
Controlling a 12v fan from a raspberry Pi.
OpenHAB and Bluetooth beacons for temperature (Blue Maestro Tempo Disc)




comments powered by Disqus

davidcole's profile

davidcole Cole
Lower Hutt
New Zealand


Been thinking it would be nice to have a blog but not sure if I have enough to say.

I'm an I.T worker from Wellington New Zealand.

I like my toys so this will probably have posts about my dealings with those.

My Cellphone is an iPhone 5s

I run a NextPVR based PVR at home to replace my video recorder, DVD player and to host all my music. I'm also really big on Plex, for centralising all my music, videos and I've written a plugin or two for it for accessing live TV and for storing recordings with metadata.





TVNZ Ondemand App behind Unblo...
(27-Feb-2013 19:39, 11626 views)
Controlling a 12v fan from a r...
(17-Jan-2017 07:49, 9449 views)
eReceipts - Why don't we have ...
(12-Jan-2012 10:01, 8996 views)
OpenHAB and Bluetooth beacons ...
(19-Dec-2016 21:39, 8922 views)
PDF Forms - why you no boxes?...
(26-Jun-2012 09:04, 8123 views)
Free $80 - come and get ur mon...
(20-Sep-2011 13:11, 7774 views)
Contactless Payments - part 2...
(21-Sep-2011 15:12, 5423 views)
RM3's also - but this time wit...
(16-Jul-2017 20:16, 5393 views)
Little Boys and their Sewing M...
(27-Dec-2009 11:09, 5363 views)
Wemos D1 Mini Door Contact (pl...
(16-Nov-2017 07:58, 5259 views)