I'm trying to create a Garage door sensor / motor controller and connect it to my instance of Home Assistant. My broker is the local mosquito on the Raspberry pi.
The device is a Wemos D1 mini with a relay connected to D1 pin and an analog input to determine the current state of the door.
The problem is that the device keeps coming up as unavailable as soon as the MQTT connection is made to the broker. I can't see anything in the logs to suggest a problem. On top of that I can still successfully publish to and from the device while it's offline
.
This is the specific code I'm using for the LWT / availability topic.
String clientId = "GarageDoorSensor-" + String(random(0xffff), HEX);
if (client.connect(clientId.c_str(), mqtt_user, mqtt_password, availabilityTopic, 0, true, payloadNotAvailable)) {
Serial.println("connected");
client.publish(availabilityTopic, payloadAvailable, true);
client.subscribe(commandTopic);
Serial.println("Subscribed to: ");
Serial.println(commandTopic);
Serial.println(availabilityTopic);
getAndSendDoorStatus();
}
Here is the full code:
#include <ESP8266WiFi.h>
#include <PubSubClient.h>
#include <ArduinoJson.h>
#include "My_Helper.h"
WiFiClient espClient;
PubSubClient client(espClient);
void setup_wifi() {
delay(10);
// We start by connecting to a WiFi network
Serial.println();
Serial.print("Connecting to ");
Serial.println(ssid);
//Set WiFi mode so we don't create an access point.
WiFi.mode(WIFI_STA);
WiFi.begin(ssid, password);
Serial.println(WiFi.mode(WIFI_STA));
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
randomSeed(micros());
Serial.println("");
Serial.println("WiFi connected");
Serial.println("IP address: ");
Serial.println(WiFi.localIP());
}
void reconnect() {
// Loop until we're reconnected
while (!client.connected()) {
Serial.print("Attempting MQTT connection...");
// Attempt to connect
String clientId = "GarageDoorSensor-" + String(random(0xffff), HEX);
if (client.connect(clientId.c_str(), mqtt_user, mqtt_password, availabilityTopic, 0, true, payloadNotAvailable)) {
Serial.println("connected");
client.publish(availabilityTopic, payloadAvailable, true);
client.subscribe(commandTopic);
Serial.println("Subscribed to: ");
Serial.println(commandTopic);
Serial.println(availabilityTopic);
getAndSendDoorStatus();
} 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() {
pinMode(relaySwitch, OUTPUT);
pinMode(doorInput, INPUT);
Serial.begin(115200);
// put your setup code here, to run once:
setup_wifi();
client.setServer(mqtt_server, 1883);
client.setCallback(callback);
while (!client.connected()) {
reconnect();
}
StaticJsonDocument<1024> mqttConfig;
mqttConfig["name"] = mqttDeviceName;
mqttConfig["device_class"] = mqttDeviceClass;
mqttConfig["state_topic"] = stateTopic;
mqttConfig["command_topic"] = commandTopic;
mqttConfig["state_open"] = opened;
mqttConfig["state_closed"] = closed;
mqttConfig["state_closing"] = closing;
mqttConfig["state_opening"] = opening;
mqttConfig["payload_open"] = payloadOpen;
mqttConfig["payload_close"] = payloadClose;
mqttConfig["payload_stop"] = payloadStop;
mqttConfig["optimistic"] = false;
mqttConfig["retain"] = true;
mqttConfig["availability_topic"] = availabilityTopic;
mqttConfig["payload_available"] = payloadAvailable;
mqttConfig["payload_not_available"] = payloadNotAvailable;
char json[1024];
serializeJsonPretty(mqttConfig, json);
client.publish(configTopic, json, true);
}
void loop() {
if (!client.connected()) {
reconnect();
}
client.loop();
delay(1000);
getAndSendDoorStatus();
}
void callback(char* topic, byte* message, unsigned int length) {
String messageStr;
for (int i = 0; i < length; i++) {
messageStr += (char)message[i];
}
if (String(topic) == commandTopic) {
Serial.print("Home Assistant Command: ");
Serial.println(messageStr);
if((messageStr == payloadOpen && doorStatus != opened) || messageStr == "forceOpen"){
//open door is not already open or we are running a test.
openTheDoor();
}else if((messageStr == payloadClose && doorStatus != closed) || messageStr == "forceClose"){
//close door is not already closed or we are running a test
closeTheDoor();
}else if(messageStr == payloadStop){
//make sure we undo the relevant switches to stop the motion based on the previous status
if(doorStatus == opened){
closeTheDoor();
}else if(doorStatus == closed){
openTheDoor();
}
}
prevDoorStatus = doorStatus;
if(messageStr == "incrementOpenThreshold"){
openThreshold = openThreshold + 1;
String msg = "Set open threshold to: " + openThreshold;
client.publish(stateTopic, msg.c_str(), true);
}
if(messageStr == "decrementOpenThreshold"){
openThreshold = openThreshold - 1;
String msg = "Set open threshold to: " + openThreshold;
client.publish(stateTopic, msg.c_str(), true);
}
}
}
void getAndSendDoorStatus(){
int doorState = analogRead(doorInput);
//Door fully open?
if(doorState < openThreshold){
statusToOpen();
} else {
statusToClosed();
}
if(prevDoorStatus != doorStatus){
Serial.print("Door ");
Serial.println(doorStatus);
client.publish(stateTopic, doorStatus, true);
delay(500);
if(doorStatus == opened){
openTheDoor();
} else {
closeTheDoor();
}
prevDoorStatus = doorStatus;
}
}
void closeTheDoor(){
digitalWrite(relaySwitch, closeDoor);
}
void statusToClosed(){
doorStatus = closed;
}
void openTheDoor(){
digitalWrite(relaySwitch, openDoor);
}
void statusToOpen(){
doorStatus = opened;
}
MY_HELPER.H
#ifndef MY_HELPER_H
#define MY_HELPER_H
const char* ssid = "YOUR_WIFI_SSID";
const char* password = "YOUR_WIFI_PASSWORD";
const char* mqtt_user = "YOUR_MQTT_USER";
const char* mqtt_password = "YOUR_MQTT_PASSWORD";
const char* mqtt_server = "YOUR_MQTT_SERVER";
const char* stateTopic = "homeassistant/cover/garage/door/state";
const char* commandTopic = "homeassistant/cover/garage/door/set";
const char* configTopic = "homeassistant/cover/garage/door/config";
const char* availabilityTopic = "homeassistant/cover/garage/door/availability";
const char* doorStatus = "";
const char* prevDoorStatus = "";
const char* mqttDeviceName = "Garage Door";
const char* mqttDeviceClass = "garage";
int prevDoorState;
int openThreshold = 15;
const int relaySwitch = D1;
const int doorInput = A0;
const int conexT1 = LOW;
const int conexT2 = HIGH;
const int openDoor = conexT1;
const int closeDoor = conexT2;
//Statuses
const char* opened = "open";
const char* closed = "closed";
const char* closing = "closing";
const char* opening = "opening";
const char* stopped = "stopped";
//pay loads
const char* payloadOpen = "OPEN";
const char* payloadClose = "CLOSE";
const char* payloadStop = "STOP";
const char* payloadAvailable = "online";
const char* payloadNotAvailable = "offline";
#endif