From c2de0695c06963957f5bf0d98d5335f255979f94 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Patrick=20Ha=C3=9Fel?= Date: Fri, 14 Feb 2025 10:04:29 +0100 Subject: [PATCH] mqtt cmd + uptime --- src/main.cpp | 2 +- src/mqtt.cpp | 41 +++++++++++++++++++++++++++++++++++------ src/mqtt.h | 14 ++++++++------ src/tsl2561.cpp | 6 +++--- src/wifi.cpp | 45 ++++++++++++++++++++++++++++++++++++++++----- src/wifi.h | 4 ++++ 6 files changed, 91 insertions(+), 21 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 4230af8..96856e5 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -4,7 +4,7 @@ void setup() { delay(500); - MySerial.printf("\n\n\nStartup\n"); + Log.printf("\n\n\nStartup\n"); wifiConnect(); sensorSetup(); } diff --git a/src/mqtt.cpp b/src/mqtt.cpp index c9eb127..9c53d41 100644 --- a/src/mqtt.cpp +++ b/src/mqtt.cpp @@ -1,4 +1,7 @@ #include "mqtt.h" + +#include + #include "wifi.h" #include @@ -8,23 +11,49 @@ WiFiClient client; PubSubClient mqtt(client); -MySerialClass MySerial(mqtt); +LogClass Log(mqtt); unsigned long mqttFailureMillis = 0; // ReSharper disable once CppUseAuto -const char* LOG_TOPIC = (String("log/") + HOSTNAME).c_str(); +const String logTopic = String("log/") + HOSTNAME; + +// ReSharper disable once CppUseAuto +const String cmdTopic = String("cmd/") + HOSTNAME; + +void mqttCallback(char *topic, const uint8_t *payload, unsigned int length) { + char message[500]; + length = min(sizeof message - 1, length); + memcpy(message, payload, length); + *(message + length) = 0; + Log.printf("MQTT received: topic=\"%s\", message=\"%s\"\n", topic, message); + if (strcmp(message, "reboot") == 0) { + Log.printf("rebooting...\n"); + delay(500); + mqtt.disconnect(); + delay(500); + EspClass::restart(); + } else if (strcmp(message, "info") == 0) { + Log.printf("INFO\n"); + Log.printf(" %-10s %s\n", "SSID:", WiFi.SSID().c_str()); + Log.printf(" %-10s %s\n", "IP:", WiFi.localIP().toString().c_str()); + Log.printf(" %-10s %d\n", "RSSI:", WiFi.RSSI()); + Log.printf(" %-10s %s\n", "uptime:", uptimeString().c_str()); + } +} void mqttLoop() { if (!mqtt.loop() && isWifiConnected() && (mqttFailureMillis == 0 || millis() - mqttFailureMillis >= 3000)) { mqtt.setServer("10.0.0.50", 1883); - if (mqtt.connect(HOSTNAME, LOG_TOPIC, 0, false, "disconnected\n")) { + if (mqtt.connect(HOSTNAME, logTopic.c_str(), 0, false, "disconnected\n")) { yield(); - mqttPublish(LOG_TOPIC, "connected\n"); - MySerial.printf("MQTT connected as \"%s\"\n", HOSTNAME); + mqttPublish(logTopic.c_str(), "connected\n"); + mqtt.setCallback(mqttCallback); + mqtt.subscribe(cmdTopic.c_str()); + Log.printf("MQTT connected as \"%s\"\n", HOSTNAME); mqttFailureMillis = 0; } else { - MySerial.printf("Failed to connect MQTT.\n"); + Log.printf("Failed to connect MQTT.\n"); mqttFailureMillis = max(1UL, millis()); } } diff --git a/src/mqtt.h b/src/mqtt.h index 0e536c2..2601413 100644 --- a/src/mqtt.h +++ b/src/mqtt.h @@ -5,7 +5,9 @@ #include "PubSubClient.h" #include "wifi.h" -extern const char* LOG_TOPIC; +extern const String logTopic; + +extern const String cmdTopic; void mqttLoop(); @@ -17,7 +19,7 @@ void mqttPublish(const char *topic, float value, const char *unit); void mqttPublish(const char *topic, const char *payload); -class MySerialClass final : public Stream { +class LogClass final : public Stream { PubSubClient& mqtt; @@ -33,7 +35,7 @@ class MySerialClass final : public Stream { public: - explicit MySerialClass(PubSubClient& mqttClient) : mqtt(mqttClient) { + explicit LogClass(PubSubClient& mqttClient) : mqtt(mqttClient) { Serial.begin(115200); } @@ -49,10 +51,10 @@ public: due = true; if (mqtt.connected()) { if (overflow > 0) { - mqtt.publish(LOG_TOPIC, "\n### LOG BUFFER OVERFLOW BY %d BYTES ###\n"); + mqtt.publish(logTopic.c_str(), "\n### LOG BUFFER OVERFLOW BY %d BYTES ###\n"); overflow = 0; } - mqtt.publish(LOG_TOPIC, reinterpret_cast(buffer)); + mqtt.publish(logTopic.c_str(), reinterpret_cast(buffer)); bufferWrite = buffer; *bufferWrite = 0; due = false; @@ -74,6 +76,6 @@ public: } }; -extern MySerialClass MySerial; +extern LogClass Log; #endif diff --git a/src/tsl2561.cpp b/src/tsl2561.cpp index 51a96c4..6ae3339 100644 --- a/src/tsl2561.cpp +++ b/src/tsl2561.cpp @@ -11,9 +11,9 @@ auto tsl = Adafruit_TSL2561_Unified(TSL2561_ADDR_FLOAT); void sensorSetup() { if (tsl.begin()) { - MySerial.printf("TSL2561: Initialized.\n"); + Log.printf("TSL2561: Initialized.\n"); } else { - MySerial.printf("TSL2561: Failed to initialize.\n"); + Log.printf("TSL2561: Failed to initialize.\n"); } tsl.enableAutoRange(true); tsl.setIntegrationTime(TSL2561_INTEGRATIONTIME_402MS); @@ -25,7 +25,7 @@ void sensorRead() { tsl.getLuminosity(&broadband, &ir); const auto illuminance = tsl.calculateLux(broadband, ir); if (illuminance == 65536) { - MySerial.printf("TSL2561: Failed to read.\n"); + Log.printf("TSL2561: Failed to read.\n"); sensorSetup(); } else { mqttPublish("garden/illuminance", illuminance, "lux"); diff --git a/src/wifi.cpp b/src/wifi.cpp index 3e09505..f87aea6 100644 --- a/src/wifi.cpp +++ b/src/wifi.cpp @@ -23,6 +23,40 @@ void wifiConnect() { yield(); } +uint64_t uptimeOffset = 0; + +void uptimeLoop() { + const auto now = millis(); + static auto uptimeLast = 0UL; + if (now < uptimeLast) { + uptimeOffset += static_cast(-1); + } + uptimeLast = now; +} + +uint64_t uptimeMillis() { + return uptimeOffset + millis(); +} + +String uptimeString() { + const auto ms = uptimeMillis(); + const auto days = static_cast(ms / (24 * 60 * 60 * 1000)); + const auto hours = static_cast(ms / (60 * 60 * 1000) % 24); + const auto minutes = static_cast(ms / (60 * 1000) % 60); + const auto seconds = static_cast(ms / 1000 % 60); + char buffer[32]; + if (days > 0) { + snprintf(buffer, sizeof buffer, "%d day%s, %d hour%s", days, days == 1 ? "" : "s", hours, hours == 1 ? "" : "s"); + } else if (hours > 0) { + snprintf(buffer, sizeof buffer, "%d hour%s, %d minute%s", hours, hours == 1 ? "" : "s", minutes, minutes == 1 ? "" : "s"); + } else if (minutes > 0) { + snprintf(buffer, sizeof buffer, "%d minute%s, %d second%s", minutes, minutes == 1 ? "" : "s", seconds, seconds == 1 ? "" : "s"); + } else { + snprintf(buffer, sizeof buffer, "%d second%s", seconds, seconds == 1 ? "" : "s"); + } + return {buffer}; +} + void timeLoop() { const auto now = time(nullptr); const auto nowHour = now / 3600; @@ -31,12 +65,12 @@ void timeLoop() { if (now > 1700000000) { timeSet = true; lastHour = nowHour; - MySerial.printf("Got time: %s\n", getTimeString().c_str()); + Log.printf("Got time: %s\n", getTimeString().c_str()); } } else { if (lastHour != nowHour) { lastHour = nowHour; - MySerial.printf("%s\n", getTimeString().c_str()); + Log.printf("%s\n", getTimeString().c_str()); } } } @@ -46,7 +80,7 @@ void wifiLoop() { if (WiFi.localIP() == 0UL) { if (wifiConnected) { wifiConnected = false; - MySerial.printf("WiFi disconnected.\n"); + Log.printf("WiFi disconnected.\n"); wifiConnect(); } else if (wifiConnectBeginMillis == 0 || millis() - wifiConnectBeginMillis >= WIFI_TIMEOUT_MS) { WiFi.disconnect(); @@ -57,10 +91,11 @@ void wifiLoop() { if (!wifiConnected) { wifiConnected = true; wifiConnectBeginMillis = 0; - MySerial.printf("WiFi connected as \"%s\" (%s)\n", HOSTNAME, WiFi.localIP().toString().c_str()); + Log.printf("WiFi connected as \"%s\" (%s)\n", HOSTNAME, WiFi.localIP().toString().c_str()); } - timeLoop(); } + uptimeLoop(); + timeLoop(); } String getTimeString() { diff --git a/src/wifi.h b/src/wifi.h index edd18d4..1937f62 100644 --- a/src/wifi.h +++ b/src/wifi.h @@ -13,4 +13,8 @@ bool isWifiConnected(); bool isTimeSet(); +uint64_t uptimeMillis(); + +String uptimeString(); + #endif