IoT Doorbell Part 3 (OpenHAB and MQTT)

Last time I took apart my doorbell, added an ESP8266 and connected it so it could detect when the doorbell was ringing. But how should I communicate with the ESP8266, and what should I do with this data?

I decided to explore the OpenHAB home automation software and came across a solution that I’m pretty happy with.

I’d heard of OpenHAB before, but never really explored it in any detail. OpenHAB is a home automation software solution, and its main strength is that it gets different devices talking together. You can then build interfaces and rules to control things based on the data that’s available.

My goal with the IOT doorbell is a simple one – I just want to get an email whenever the doorbell is pressed. After a bit of searching, I found that OpenHAB’s rule engine has the capability to send email messages – so that side of my project is definitely doable.

The other challenge will be getting the ESP8266 to communicate with the OpenHAB system. There are a few options here – initially, I planned some sort of HTTP GET/POST based system, but that seemed a bit clunky and limited if I wanted to expand on it in future. Eventually, I stumbled upon MQTT based communication – a publisher/subscriber model, which sounded ideal. There is an MQTT binding for OpenHAB, and there’s an MQTT library for Arduino.

First things first, I needed to get OpenHAB installed and configured. This was a lengthy process, and I ended up following the fantastic guide here. I set OpenHAB up on a Raspberry Pi 2 B, and it seems to run pretty quickly – I’d happily recommend this setup for anyone else that wants to try the same thing.

After getting OpenHAB installed, I started working on my Arduino sketch. I started with two example sketches I wanted to combine – the MQTT example in the library, and the over-the-air programming example I’d already flashed previously.

After combining these two sketches, all I needed to actually do was simple – monitor the pin the doorbell was connected to, and publish an update to the MQTT topic when that pin changes.

#include <ESP8266WiFi.h>
#include <ESP8266mDNS.h>
#include <WiFiUdp.h>
#include <ArduinoOTA.h>
#include <PubSubClient.h>

#define LED_PIN 0
#define UPDATE_RATE 60 //regardless of change, broadcast message every X seconds
#define DOORBELL_PIN 12

const char* ssid = "NetworkSSID";
const char* password = "NetworkPassword";
const char* mqtt_server = "192.168.1.50";
const char* topic = "home/doorbell1";

WiFiClient espClient;
PubSubClient client(espClient);
long lastMsg = 0;
char msg[50];
int value = 0;

int doorbell = 0;
int doorbell_prev = 999;


void callback(char* topic, byte* payload, unsigned int length) {
 Serial.print("Message arrived [");
 Serial.print(topic);
 Serial.print("] ");
 for (int i = 0; i < length; i++) {
 Serial.print((char)payload[i]);
 }
 Serial.println();
}

void reconnect() {
 // Loop until we're reconnected
 Serial.print("Attempting MQTT connection...");
 // Attempt to connect
 if (client.connect("ESP8266Client")) {
 Serial.println("connected");
 // Once connected, publish an announcement...
 client.publish("outTopic", "hello world");
 // ... and resubscribe
 client.subscribe("inTopic");
 } else {
 Serial.print("failed, rc=");
 Serial.print(client.state());
 Serial.println(" try again in 5 seconds");
 // Wait 5 seconds before retrying
 delay(5000);
 }
}

void setup() {
 Serial.begin(115200);

 Serial.println("Booting");
 WiFi.mode(WIFI_STA);
 WiFi.begin(ssid, password);
 while (WiFi.waitForConnectResult() != WL_CONNECTED) {
 Serial.println("Connection Failed! Rebooting...");
 delay(5000);
 ESP.restart();
 }

 // Hostname defaults to esp8266-[ChipID]
 ArduinoOTA.setHostname("esp8266-sonata");

 ArduinoOTA.onStart([]() {
 Serial.println("Start");
 });
 ArduinoOTA.onEnd([]() {
 Serial.println("End");
 });
 ArduinoOTA.onProgress([](unsigned int progress, unsigned int total) {
 Serial.printf("Progress: %u%%\n", (progress / (total / 100)));
 });
 ArduinoOTA.onError([](ota_error_t error) {
 Serial.printf("Error[%u]: ", error);
 if (error == OTA_AUTH_ERROR) Serial.println("Auth Failed");
 else if (error == OTA_BEGIN_ERROR) Serial.println("Begin Failed");
 else if (error == OTA_CONNECT_ERROR) Serial.println("Connect Failed");
 else if (error == OTA_RECEIVE_ERROR) Serial.println("Receive Failed");
 else if (error == OTA_END_ERROR) Serial.println("End Failed");
 });
 ArduinoOTA.begin();
 Serial.println("Ready");
 Serial.print("IP address: ");
 Serial.println(WiFi.localIP());

 client.setServer(mqtt_server, 1883);
 client.setCallback(callback);
}

void publishUpdate() {
 snprintf (msg, 75, "%ld", doorbell);
 Serial.print("Publish message: ");
 Serial.println(msg);
 client.publish(topic, msg);
}

void loop() {
 ArduinoOTA.handle();

 while (!client.connected()) {
 reconnect();
 ArduinoOTA.handle();
 }
 client.loop();

 doorbell = digitalRead(DOORBELL_PIN);

 long now = millis();
 if (now - lastMsg > UPDATE_RATE * 1000) {
 lastMsg = now;
 publishUpdate();
 }

 if(doorbell != doorbell_prev) {
 publishUpdate();
 }

 doorbell_prev = doorbell;

}

Leave a Reply

Your email address will not be published. Required fields are marked *