我正在尝试创建一个车库门传感器/电机控制器并将其连接到我的 Home Assistant 实例。我的经纪人是树莓派上的本地蚊子。
该设备是 Wemos D1 mini,继电器连接到 D1 引脚和模拟输入以确定门的当前状态。
问题在于,一旦与代理建立 MQTT 连接,设备就会一直出现不可用状态。我在日志中看不到任何提示问题的内容。最重要的是,当它是offline
.
这是我用于 LWT/可用性主题的特定代码。
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();
}
这是完整的代码:
#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