Device: Arduino UNO with MQTT
Objectives : let OpenHAB know that the Arduino UNO decive is alive and kicking
MQTT LWT: Status reachability of this external device
How it started: I was charmed of the Last Will and Testament used in the TasmOTA-sketch for the SonOff devices. But reading these sketches is reading some hocus pocus abracadabra (not always but…)
So when I tried to implement this in an Arduino UNO sketch I had some problem to find a simplified example. The MQTT essentials (part 9) about this subject are helpful but did not bring me closer the required (preferred cut & paste) Arduino statement. Luckily (for me) I found more straightforward examples at this [place].
So in the end the statement is rather simple replace:
if (client.connect(MQTT_CLIENTID, MQTT_SERVER_UID, MQTT_SERVER_PWD))
with
if (client.connect(MQTT_CLIENTID, MQTT_SERVER_UID, MQTT_SERVER_PWD, MQTT_LWT_TOPIC, 0, true, “Offline”, true))
and add an extra line
client.publish(MQTT_LWT_TOPIC, “Online”, true);
The other problem I wanted to tackle was to show the IP-address of an Arduino UNO in OpenHAB. After several attempt I found somewhere (sorry lost the link) how to do this part:
// convert IP-address to a string for in this case MQTT
char* ip2CharArray(IPAddress IP) {
static char a[16];
sprintf(a, "%d.%d.%d.%d", IP[0], IP[1], IP[2], IP[3]);
return a;
}
In combination with a common sensor the DHT22 the full sketch is:
/*
Starting Sketch from: PubSubClient and surfing the internet by WJ4IoT
Attached sensor DHT22 on D5
*/
#include <SPI.h>
#include <Ethernet.h>
/************************* Ethernet Client Setup *****************************/
// Update these with values suitable for your network.
byte mac[] = {0x00, 0x00, 0x00, 0x00, 0xF00, 0x01};
//Uncomment the following, and set to a valid ip if you don't have dhcp available.
//#include <Dhcp.h>
//IPAddress iotIP (192, 168, 0, 235);
//Uncomment the following, and set to your preference if you don't have automatic dns.
//#include <Dns.h>
//IPAddress dnsIP (8, 8, 8, 8);
//If you uncommented either of the above lines, make sure to change "Ethernet.begin(mac)" to "Ethernet.begin(mac, iotIP)"
//or "Ethernet.begin(mac, iotIP, dnsIP)"
/*************************** MQTT Setup **************************************/
#include <PubSubClient.h>
const char* MQTT_SERVER = "192.168.x.y"; //shaky part not sure why i need both ip as name
const char* MQTT_SERVER_UID = "openhabian";
const char* MQTT_SERVER_PWD = "password";
#define MQTT_SERVERPORT 1883
const char* MQTT_LWT_TOPIC = "unoDHT/LWT"; // <- sync with deviceID !!!
const char* MQTT_IN_TOPIC = "unoDHT/in/#";
const char* MQTT_OUT_TOPIC = "unoDHT/out";
const char* MQTT_CLIENTID = "unoDHT";
EthernetClient ethClient;
PubSubClient client(MQTT_SERVER, MQTT_SERVERPORT, ethClient);
/*************************** LIBRARY Setup **************************************/
// DHT Temperature & Humidity Sensor
// Unified Sensor Library Example
// Written by Tony DiCola for Adafruit Industries
// Released under an MIT license.
// Depends on the following Arduino libraries:
// - Adafruit Unified Sensor Library: https://github.com/adafruit/Adafruit_Sensor
// - DHT Sensor Library: https://github.com/adafruit/DHT-sensor-library
// - See guide for details on sensor wiring and usage:
// https://learn.adafruit.com/dht/overview
//#include <Adafruit_Sensor.h>
#include <DHT.h>
//#include <DHT_U.h>
#define DHTPIN 5 // Pin which is connected to the DHT sensor.
// Uncomment the type of sensor in use:
// #define DHTTYPE DHT11 // DHT 11
#define DHTTYPE DHT22 // DHT 22 (AM2302)
// #define DHTTYPE DHT21 // DHT 21 (AM2301)
//DHT_Unified dht(DHTPIN, DHTTYPE);
DHT dht(DHTPIN, DHTTYPE);
uint32_t delayMS;
double t, h;
/*************************** Variables **************************************/
String returnmsg;
int reconnects = 0;
long now, lastMsg = 0;
long timeBetweenMessages = 60000; // sec x 1000
/*************************************************************************/
void setup()
{
Ethernet.begin(mac); // with IP based upon DSN-server
Serial.begin(115200);
while (!Serial) {
Serial.print("."); // wait for serial port to connect. Needed for native USB port only
}
/*
Serial.println("sketch: MQTT_UNO_DHT22");
Serial.print("compiled: ");
Serial.print(__DATE__);
Serial.print(" ");
Serial.println(__TIME__);
Serial.println("Following sensors are/should be connected");
Serial.println("-> Digital D5 = DHT22");
Serial.println("-----------------------------------------");
*/
//pinMode(LED_BUILTIN, OUTPUT);
reconnect();
Serial.println("DHTxx test!");
dht.begin();
Serial.println("Begin with loop.....");
}
/*************************************************************************/
void loop()
{
now = millis();
//client.loop();
// Reading temperature or humidity takes about 250 milliseconds!
// Sensor readings may also be up to 2 seconds 'old' (its a very slow sensor)
float h = dht.readHumidity();
// Read temperature as Celsius (the default)
float t = dht.readTemperature();
// Read temperature as Fahrenheit (isFahrenheit = true)
float f = dht.readTemperature(true);
// Check if any reads failed and exit early (to try again).
if (isnan(h) || isnan(t) || isnan(f)) {
Serial.println("Failed to read from DHT sensor!");
return;
}
if (!client.connected()) {
reconnect();
}
if (now - lastMsg > timeBetweenMessages ) {
lastMsg = now;
returnmsg = "{\"reconnects\":";
returnmsg += reconnects;
returnmsg += ",\"IP\":";
returnmsg += ip2CharArray(Ethernet.localIP());
returnmsg += ",\"temp\":";
returnmsg += t;
returnmsg += ",\"hum\":";
returnmsg += h;
returnmsg += "}";
client.publish( MQTT_OUT_TOPIC , (char*) returnmsg.c_str(), true );
client.subscribe(MQTT_IN_TOPIC);
Serial.println(returnmsg);
}
}
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
void reconnect() {
// Loop until we're reconnected
while (!client.connected()) {
++reconnects;
Serial.println("Attempting MQTT connection...");
//connect (clientID, username, password, willTopic, willQoS, willRetain, willMessage) https://pubsubclient.knolleary.net/api.html#connect4
if (client.connect(MQTT_CLIENTID, MQTT_SERVER_UID, MQTT_SERVER_PWD, MQTT_LWT_TOPIC, 0, true, "Offline", true)) {
//if (client.connect(MQTT_CLIENTID, MQTT_SERVER_UID, MQTT_SERVER_PWD)) {
//Serial.println("....connected");
//publish ready
client.publish(MQTT_LWT_TOPIC, "Online", true);
//subscribe in topic
client.subscribe(MQTT_IN_TOPIC);
} else {
//Serial.print("failed, rc=");
//Serial.print(client.state());
//Serial.println(" try again in 5 seconds");
// Wait 5 seconds before retrying
delay(5000);
}
}
}
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// convert IP-address to a string for in this case MQTT
char* ip2CharArray(IPAddress IP) {
static char a[16];
sprintf(a, "%d.%d.%d.%d", IP[0], IP[1], IP[2], IP[3]);
return a;
}
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
How it looks in OpenHAB: