From c49c537dbcbfb6d19eef19d379d62562e7480c7a Mon Sep 17 00:00:00 2001 From: Flo Date: Tue, 10 Mar 2026 07:09:41 +0100 Subject: [PATCH] switch to MQTT --- platformio.ini | 5 +- src/MyMqttClient.cpp | 132 +++++++++++++++++++++++++++++ src/MyMqttClient.h | 47 ++++++++++ src/Version.h | 8 +- src/fensterPiepser_NodeMCU_32S.cpp | 4 + 5 files changed, 191 insertions(+), 5 deletions(-) create mode 100644 src/MyMqttClient.cpp create mode 100644 src/MyMqttClient.h diff --git a/platformio.ini b/platformio.ini index 3900500..59a0d24 100644 --- a/platformio.ini +++ b/platformio.ini @@ -12,13 +12,14 @@ platform = espressif32 board = nodemcu-32s framework = arduino -upload_port = COM9 +upload_port = COM3 upload_speed = 921600 monitor_speed = 115200 build_flags = -I ./src/xcp -I ./src/Receivers433 -I ./src/Receivers433/Receivers3ByteKeys -lib_deps = +lib_deps = adafruit/Adafruit GFX Library@^1.12.4 thingpulse/ESP8266 and ESP32 OLED driver for SSD1306 displays@^4.6.1 + knolleary/PubSubClient @ ^2.8 diff --git a/src/MyMqttClient.cpp b/src/MyMqttClient.cpp new file mode 100644 index 0000000..9d8fdfe --- /dev/null +++ b/src/MyMqttClient.cpp @@ -0,0 +1,132 @@ +/* + * MyMqttClient.cpp + * + * Publishes window open/close events to an MQTT broker. + */ + +#include +#include "MyMqttClient.h" +#include "Version.h" + +#define MQTT_RECONNECT_INTERVAL_MS 5000u +#define WIFI_RECONNECT_INTERVAL_MS 10000u + +MyMqttClient myMqttClient; + +MyMqttClient::MyMqttClient() + : mqttClient(wifiClient) + , lastConnectAttemptMs(0) + , lastWifiReconnectMs(0) +{ + mqttClient.setServer(MQTT_BROKER_IP, MQTT_BROKER_PORT); + mqttClient.setKeepAlive(300); +} + +bool MyMqttClient::ensureConnected() +{ + if (mqttClient.connected()) + { + return true; + } + + if (!WiFi.isConnected()) + { + return false; + } + + if (millis() - lastConnectAttemptMs < MQTT_RECONNECT_INTERVAL_MS) + { + return false; + } + + lastConnectAttemptMs = millis(); + + Serial.printf("[MQTT] Connecting to %s:%d ...\n", MQTT_BROKER_IP, MQTT_BROKER_PORT); + + bool ok; + if (strlen(MQTT_USER) > 0) + { + ok = mqttClient.connect(MQTT_CLIENT_ID, MQTT_USER, MQTT_PASSWORD); + } + else + { + ok = mqttClient.connect(MQTT_CLIENT_ID); + } + + if (ok) + { + Serial.println("[MQTT] Connected"); + mqttClient.publish(MQTT_TOPIC_STATUS, + "{\"event\":\"hello\",\"client\":\"" MQTT_CLIENT_ID VERSION_STR "\"}"); + } + else + { + Serial.printf("[MQTT] Connect failed, rc=%d\n", mqttClient.state()); + } + + return ok; +} + +void MyMqttClient::publishFensterEvent(const char* name, bool bOpen) +{ + if (!ensureConnected()) + { + Serial.println("[MQTT] Cannot publish – not connected"); + return; + } + + char payload[64]; + snprintf(payload, sizeof(payload), + "{\"fenster\":\"%s\",\"event\":\"%s\"}", name, bOpen ? "open" : "close"); + + if (mqttClient.publish(MQTT_TOPIC_FENSTER, payload)) + { + Serial.printf("[MQTT] Published: %s\n", payload); + } + else + { + Serial.println("[MQTT] Publish failed"); + } +} + +void MyMqttClient::publishStatus(const char* payload) +{ + if (!ensureConnected()) + { + return; + } + mqttClient.publish(MQTT_TOPIC_STATUS, payload); +} + +void MyMqttClient::onLoop() +{ + if (!WiFi.isConnected()) + { + if (millis() - lastWifiReconnectMs >= WIFI_RECONNECT_INTERVAL_MS) + { + lastWifiReconnectMs = millis(); + Serial.println("[WiFi] Disconnected – reconnecting ..."); + WiFi.reconnect(); + } + return; + } + + if (WiFi.isConnected()) + { + ensureConnected(); + mqttClient.loop(); + + static uint32_t tNextRssiMs = 0; + if (millis() >= tNextRssiMs) + { + tNextRssiMs = millis() + 600000u; + if (mqttClient.connected()) + { + char payload[48]; + snprintf(payload, sizeof(payload), + "{\"event\":\"rssi\",\"rssi\":%d}", (int)WiFi.RSSI()); + mqttClient.publish(MQTT_TOPIC_STATUS, payload); + } + } + } +} diff --git a/src/MyMqttClient.h b/src/MyMqttClient.h new file mode 100644 index 0000000..3a6f334 --- /dev/null +++ b/src/MyMqttClient.h @@ -0,0 +1,47 @@ +/* + * MyMqttClient.h + * + * Publishes window open/close events to an MQTT broker. + */ + +#ifndef MYMQTTCLIENT_H_ +#define MYMQTTCLIENT_H_ + +#include +#include + +// ============================================================ +// MQTT Configuration +// ============================================================ +#define MQTT_BROKER_IP "flokke.de" +#define MQTT_BROKER_PORT 1883 +#define MQTT_CLIENT_ID "Fensterpiepser" PROJECT_VARIANT +#define MQTT_TOPIC_FENSTER "fenster/events" +#define MQTT_TOPIC_STATUS "fenster/status" +// Optional: set to "" if no authentication required +#define MQTT_USER "lightcontrol" +#define MQTT_PASSWORD "mR9o3OYpAzUZvS" +// ============================================================ + +class MyMqttClient +{ +private: + WiFiClient wifiClient; + PubSubClient mqttClient; + + uint32_t lastConnectAttemptMs; + uint32_t lastWifiReconnectMs; + + bool ensureConnected(); + +public: + MyMqttClient(); + + void publishFensterEvent(const char* name, bool bOpen); + void onLoop(); + void publishStatus(const char* payload); +}; + +extern MyMqttClient myMqttClient; + +#endif /* MYMQTTCLIENT_H_ */ diff --git a/src/Version.h b/src/Version.h index 119cc08..27a492f 100644 --- a/src/Version.h +++ b/src/Version.h @@ -11,11 +11,13 @@ #include "main.h" #if VERSION_DG_ONLY -#define PROJECT_NAME "FENSTER_PIEPSER_NODEMCU_32_S_DG" +#define PROJECT_VARIANT "_DG" #else -#define PROJECT_NAME "FENSTER_PIEPSER_NODEMCU_32_S_EG" +#define PROJECT_VARIANT "_EG" #endif -#define VERSION_STR "v1.3.2" + +#define PROJECT_NAME "FENSTER_PIEPSER_NODEMCU_32_S" PROJECT_VARIANT +#define VERSION_STR "v2.0.0" #endif /* VERSION_H_ */ diff --git a/src/fensterPiepser_NodeMCU_32S.cpp b/src/fensterPiepser_NodeMCU_32S.cpp index 865d74b..c0b6abb 100644 --- a/src/fensterPiepser_NodeMCU_32S.cpp +++ b/src/fensterPiepser_NodeMCU_32S.cpp @@ -15,6 +15,7 @@ #include "InterruptHandler.h" #include "xcp/XcpPort.h" #include "UpdateHandler.h" +#include "MyMqttClient.h" #include "main.h" #include "Version.h" #include "WiFi.h" @@ -257,6 +258,7 @@ void loop() dataSender.onLoop(); #endif + myMqttClient.onLoop(); UpdateHandler(); #endif @@ -458,6 +460,8 @@ static void handleKeyReceived(void) bUpdateDisp = true; dataSender.requestSend(); bRequestShortBeep = true; + myMqttClient.publishFensterEvent(alleFenster[i]->name, + lastKeyDirection == DIRECTION_OPEN); if (lastKeyDirection == DIRECTION_CLOSE) { tBeepingStartWithoutWindowClose = 0u;