This simple tutorial will explain how to configure OpenHab 2 in order to remotely control a Relay (electrically operated Switch).
It is based on my mini project with the NICE SpA Robo 500 Sliding Gate Opener but you can adopt it to your needs and control many other devices from OpenHab 2 using an ESP8266 based board.
Requirements
- OpenHAB 2 Snapshot (I used Build # 636 but any version greater than beta4 will do)
- Mosquitto MQTT Broker (v1.4.10)
- MQTT Binding (v1.9.0.201612100210) with MQTT-Eventbus
- Wemos D1 mini (or any ESP-8266EX based board)
- Wemos D1 Relay Shield (or any compatible Relay Shield)
For this tutorial, I assume that you can install OpenHAB 2 & Mosquitto and get them both up and running with default configurations. I will spend most of my time explaining how to configure OH2 and its components (MQTT Binding) as well as the ESP board. If you need help with OH2 & Mosquitto setup, you can check out this great tutorial also: Install and setup OpenHAB 2.0 with Mosquitto and ESPEasy+HC-SR04
System, Subsystem & Components
A high level overview of the solution is displayed in the image below:
The System (aka Solution) is composed of 3 main Subsystems and each Subsystem has its own components (aka configs).
Subsystem 1 = OpenHAB 2
The core of the solution where all the magic happens
Following the basic installation of OH2, you need to install the MQTT Binding.
This can be done from the Paper UI -> Extensions -> Bindings -> MQTT Binding (binding-mqtt1 - 1.9.0.SNAPSHOT)
We will configure the MQTT service and the MQTT Event Bus in Subsystem 2 section below.
For now, we must enable our simple āpush-buttonā in OH2 and to display it in our sitemap.
Add the following text to your items file:
Switch Robo500 "Robo 500 Relay" <siren> {autoupdate="false"}
and the following text to your sitemap file:
Frame {
Switch item=Robo500 mappings=[ON="GO!"]
}
This will display a simple button on your sitemap with the text āGO!ā. Pressing this button will send an āONā command to the Switch item called āRobo500ā. We will use this command later on to pass it over to the ESP8266 via the MQTT Eventbus.
Subsystem 2 = MQTT & Eventbus
Next step is to install and configure our MQTT Binding to connect to our Mosquitto Message Broker and setup the MQTT-Eventbus.
Edit your mqtt.cfg
and introduce your settings for the connection to the Mosquitto server:
MQTT.url=tcp://localhost:1883
MQTT.clientId=openhab
MQTT.user=openhab
MQTT.pwd=some_password
Now, we will create a massive link between the OpenHAB 2 Eventbus and MQTT. In this case, ALL commands and status updates will be published to the MQTT Broker.
Edit your mqtt-eventbus.cfg
and configure the following settings:
broker=MQTT
statePublishTopic=openhab/out/${item}/state
commandPublishTopic=openhab/out/${item}/command
stateSubscribeTopic=openhab/in/${item}/state
commandSubscribeTopic=openhab/in/${item}/command
In this case, OH2 will publish everything to the openhab/out
followed by the item name and the state or command topic.
It will also subscribe to multiple topics, listening for state updates and/or commands to be posted to the openHAB event bus.
Subsystem 3 = ESP8266 & Relay Shield
To be able to control the Robo 500 Sliding Gate Opener, we need to create a short circuit between 2 pins (#9 & #12) found on its motherboard. This executes a Step command that controls the motor (in sequence: Open -> Stop -> Close -> Stop).
We will create an Adruino Sketch that has WiFi enabled, MQTT support, can accept OTA updates and subscribes to the MQTT topic that is populated by OH2 Eventbus for this specific item.
In case a message is published to the monitored topic, we will close the circuit on the relay for 100 milliseconds and then open it up again to issue the control command to the Robo 500 unit.
The Adruino Sketch is the following:
/*
* Dim - Relay Shield Toggle v1.0
* Closes the relay for 100 ms, then opens based on OH2 event
* Relay Shield transistor closes relay when D1 is HIGH
*/
#include <ESP8266WiFi.h>
#include <ESP8266mDNS.h>
#include <WiFiUdp.h>
#include <ArduinoOTA.h>
#include <Adafruit_MQTT.h>
#include <Adafruit_MQTT_Client.h>
/************************* WiFi Access Point *********************************/
#define WLAN_SSID "<ssid>"
#define WLAN_PASS "<pass>"
/************************* MQTT Broker Setup *********************************/
#define mqtt_server "<mqtt_broker>"
#define mqtt_serverport 1883 // use 8883 for SSL
#define mqtt_username "<mqtt_username>"
#define mqtt_password "<mqtt_password>"
/************************* Constants, Variables, Integers, etc *********************************/
const int relayPin = D1;
const long togDelay = 100; // pause for 100 milliseconds before toggling to Open
const long postDelay = 200; // pause for 200 milliseconds after toggling to Open
int value = 0;
int relayState = LOW;
// Create an ESP8266 WiFiClient class to connect to the MQTT server.
WiFiClient client;
// Setup the MQTT client class by passing in the WiFi client and MQTT server and login details.
Adafruit_MQTT_Client mqtt(&client, mqtt_server, mqtt_serverport, mqtt_username, mqtt_password);
// Setup subscription 'Robo500' for monitoring topic for changes.
Adafruit_MQTT_Subscribe Robo500 = Adafruit_MQTT_Subscribe(&mqtt, "openhab/out/Robo500/command");
/*************************** Sketch Code ************************************/
void MQTT_connect();
void setup() {
Serial.begin(115200);
Serial.println(""); Serial.println(F("Booting... v1.0"));
pinMode(relayPin, OUTPUT);
// Connect to WiFi access point.
Serial.print("Connecting to "); Serial.println(WLAN_SSID);
WiFi.mode(WIFI_STA);
WiFi.begin(WLAN_SSID, WLAN_PASS);
while (WiFi.waitForConnectResult() != WL_CONNECTED) {
Serial.println("Connection Failed! Rebooting in 5 secs...");
delay(5000);
ESP.restart();
}
// Setup MQTT subscription for Robo500 feed.
mqtt.subscribe(&Robo500);
// Begin OTA
ArduinoOTA.setPort(8266); // Port defaults to 8266
ArduinoOTA.setHostname("robo500"); // Hostname defaults to esp8266-[ChipID]
ArduinoOTA.setPassword((const char *)"<pass>"); // No authentication by default
ArduinoOTA.onStart([]() {
Serial.println("Start");
});
ArduinoOTA.onEnd([]() {
Serial.println("\nEnd");
});
ArduinoOTA.onProgress([](unsigned int progress, unsigned int total) {
Serial.printf("Progress: %u%%\r", (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("");
Serial.println("Ready & WiFi connected");
Serial.print("IP address: "); Serial.println(WiFi.localIP());
}
void loop() {
ArduinoOTA.handle();
// Ensure the connection to the MQTT server is alive (this will make the first
// connection and automatically reconnect when disconnected). See the MQTT_connect
// function definition further below.
MQTT_connect();
// this is our 'wait for incoming subscription packets' busy subloop
// try to spend your time here
Adafruit_MQTT_Subscribe *subscription;
while ((subscription = mqtt.readSubscription(5000))) {
if (subscription == &Robo500) {
Serial.print(F("Got: ")); Serial.println((char *)Robo500.lastread);
// close the relay for 100 ms
Serial.println("Close Relay for 100 ms & then Open");
digitalWrite(relayPin, HIGH);
delay(togDelay);
digitalWrite(relayPin, LOW);
delay(postDelay);
}
}
// ping the server to keep the mqtt connection alive
// NOT required if you are publishing once every KEEPALIVE seconds
// if(! mqtt.ping()) {
// mqtt.disconnect();
// }
}
// Function to connect and reconnect as necessary to the MQTT server.
// Should be called in the loop function and it will take care if connecting.
void MQTT_connect() {
int8_t ret;
// Stop if already connected.
if (mqtt.connected()) {
return;
}
Serial.print("Connecting to MQTT... ");
uint8_t retries = 3;
while ((ret = mqtt.connect()) != 0) { // connect will return 0 for connected
Serial.println(mqtt.connectErrorString(ret));
Serial.println("Retrying MQTT connection in 5 seconds...");
mqtt.disconnect();
delay(5000); // wait 5 seconds
retries--;
if (retries == 0) {
// basically die and wait for WDT to reset me
while (1);
}
}
Serial.println("MQTT Connected!");
}
Pictures from the onsite installation: