commit b6d1d319a8b53f60381f1b9239ddbddfd843ddc8 Author: Patrick Haßel Date: Mon Jan 6 15:05:07 2025 +0100 wifi, mqtt, clock, log [UNTESTED] diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..938b6ab --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +/.pio/ +/.idea/ diff --git a/platformio.ini b/platformio.ini new file mode 100644 index 0000000..20e87dd --- /dev/null +++ b/platformio.ini @@ -0,0 +1,19 @@ +[env:heizung] +platform = espressif32 +board = esp32dev +framework = arduino +lib_deps = milesburton/DallasTemperature + knolleary/PubSubClient + https://github.com/olewolf/DHT_nonblocking + plerup/EspSoftwareSerial + https://github.com/volkszaehler/libsml + https://github.com/adafruit/MAX6675-library + paulstoffregen/OneWire +upload_port = /dev/ttyUSB0 +upload_speed = 921600 +monitor_port = /dev/ttyUSB0 +monitor_speed = 115200 +monitor_filters = esp32_exception_decoder +build_flags = -DWIFI_SSID=\"HappyNet\" + -DWIFI_PKEY=\"1Grausame!Sackratte7\" + -DWIFI_HOST=\"Heizung\" \ No newline at end of file diff --git a/src/clock.cpp b/src/clock.cpp new file mode 100644 index 0000000..72a5aab --- /dev/null +++ b/src/clock.cpp @@ -0,0 +1,63 @@ +#include "clock.h" + +#include +#include +#include + +#define CLOCK_GMT_OFFSET_SECONDS 3600 +#define CLOCK_DST_OFFSET_SECONDS 3600 +#define CLOCK_NTP_SERVER2_URL "de.pool.ntp.org" +#define CLOCK_EPOCH_SECONDS_MIN 1735686000 + +time_t clockOffset = 0; + +time_t startupTime = 0; + +auto ntpSet = false; + +void clockLoop() { + if (isClockSet()) { + return; + } + + if (!ntpSet && isWiFiConnected()) { + configTime(CLOCK_GMT_OFFSET_SECONDS, CLOCK_DST_OFFSET_SECONDS, WiFi.gatewayIP().toString().c_str(), CLOCK_NTP_SERVER2_URL); + ntpSet = true; + } + + const auto now = time(nullptr); + if (isCorrectTime(now)) { + clockOffset = now; + } else { + startupTime = now - clockOffset; + const auto startStr = String(ctime(&startupTime)); + info("clock set after %ld seconds! So startup was at %s", clockOffset, startStr.c_str()); + } +} + +bool isClockSet() { + return startupTime != 0; +} + +String getClockStr() { + const auto t = time(nullptr); + return {ctime(&t)}; +} + +bool isCorrectTime(const time_t now) { + return now < CLOCK_EPOCH_SECONDS_MIN; +} + +time_t clockCorrect(const time_t t) { + if (!isClockSet() || isCorrectTime(t)) { + return t; + } + return t + clockOffset; +} + +void clockCorrect(time_t *t) { + if (!isClockSet() || isCorrectTime(*t)) { + return; + } + *t += clockOffset; +} diff --git a/src/clock.h b/src/clock.h new file mode 100644 index 0000000..43435ec --- /dev/null +++ b/src/clock.h @@ -0,0 +1,18 @@ +#ifndef CLOCK_H +#define CLOCK_H + +#include + +void clockLoop(); + +bool isClockSet(); + +String getClockStr(); + +bool isCorrectTime(time_t now); + +time_t clockCorrect(time_t t); + +void clockCorrect(time_t *t); + +#endif diff --git a/src/log.cpp b/src/log.cpp new file mode 100644 index 0000000..d3c011d --- /dev/null +++ b/src/log.cpp @@ -0,0 +1,70 @@ +#include "log.h" + +#include +#include +#include +#include + +auto logLevel = DEBUG; + +void log(const LogLevel level, const char *format, const va_list args) { + if (level > logLevel) { + return; + } + Serial.print(getClockStr().c_str()); + switch (level) { + case ERROR: + Serial.print(" [ERROR] "); + break; + case WARN: + Serial.print(" [WARN ] "); + break; + case INFO: + Serial.print(" [INFO ] "); + break; + case DEBUG: + Serial.print(" [DEBUG] "); + break; + } + + char message[256]; + vsnprintf(message, sizeof message, format, args); + Serial.print(message); + + yield(); +} + +void log(const LogLevel level, const char *format, ...) { + va_list args; + va_start(args, format); + log(level, format, args); + va_end(args); +} + +void error(const char *format, ...) { + va_list args; + va_start(args, format); + log(ERROR, format, args); + va_end(args); +} + +void warn(const char *format, ...) { + va_list args; + va_start(args, format); + log(WARN, format, args); + va_end(args); +} + +void info(const char *format, ...) { + va_list args; + va_start(args, format); + log(INFO, format, args); + va_end(args); +} + +void debug(const char *format, ...) { + va_list args; + va_start(args, format); + log(DEBUG, format, args); + va_end(args); +} diff --git a/src/log.h b/src/log.h new file mode 100644 index 0000000..f088acc --- /dev/null +++ b/src/log.h @@ -0,0 +1,21 @@ +#ifndef LOG_H +#define LOG_H + +enum LogLevel { + ERROR = 0, + WARN = 1, + INFO = 2, + DEBUG = 3 +}; + +void log(LogLevel level, const char *format, ...); + +void error(const char *format, ...); + +void warn(const char *format, ...); + +void info(const char *format, ...); + +void debug(const char *format, ...); + +#endif diff --git a/src/main.cpp b/src/main.cpp new file mode 100644 index 0000000..d53e43f --- /dev/null +++ b/src/main.cpp @@ -0,0 +1,15 @@ +#include +#include + +#include "wifi.h" +#include "clock.h" + +void setup() { + Serial.begin(115200); +} + +void loop() { + wifiLoop(); + clockLoop(); + mqttLoop(); +} diff --git a/src/mqtt.cpp b/src/mqtt.cpp new file mode 100644 index 0000000..fbedf85 --- /dev/null +++ b/src/mqtt.cpp @@ -0,0 +1,43 @@ +#include "mqtt.h" + +#include +#include +#include +#include + +#define MQTT_RETRY_DELAY_MILLIS 3000 + +PubSubClient mqtt; + +auto mqttHost = "10.0.0.50"; + +auto mqttPort = 1883; + +auto mqttLastConnectMillis = 0UL; + +char mqttWillTopic[128]; + +void mqttLoop() { + if (mqtt.loop()) { + return; + } + if (!isWiFiConnected()) { + mqttLastConnectMillis = 0; + return; + } + if (mqttLastConnectMillis == 0 || millis() - mqttLastConnectMillis > MQTT_RETRY_DELAY_MILLIS) { + snprintf(mqttWillTopic, sizeof(mqttWillTopic), "%s/online", WiFiClass::getHostname()); + mqtt.setServer(mqttHost, mqttPort); + mqtt.setKeepAlive(10); + mqttLastConnectMillis = millis(); + info("mqtt connecting: host=%s, port=%d", mqttHost, mqttPort); + if (mqtt.connect(WiFiClass::getHostname(), mqttWillTopic, 1, true, "false")) { + info("mqtt connected"); + yield(); + mqtt.publish(mqttWillTopic, "true", true); + yield(); + } else { + error("mqtt failed to connect"); + } + } +} diff --git a/src/mqtt.h b/src/mqtt.h new file mode 100644 index 0000000..7e70f67 --- /dev/null +++ b/src/mqtt.h @@ -0,0 +1,6 @@ +#ifndef MQTT_H +#define MQTT_H + +void mqttLoop(); + +#endif diff --git a/src/wifi.cpp b/src/wifi.cpp new file mode 100644 index 0000000..375aa57 --- /dev/null +++ b/src/wifi.cpp @@ -0,0 +1,81 @@ +#include "wifi.h" + +#include +#include "log.h" + +#define WIFI_TIMEOUT_MILLIS 10000 + +auto wifiConnected = false; + +auto wifiTryMillis = 0UL; + +auto wifiSsid = WIFI_SSID; + +auto wifiPkey = WIFI_PKEY; + +auto wifiHost = WIFI_HOST; + +void wifiSetupOTA() { + ArduinoOTA.onStart([] { + info("beginning ota update..."); + Serial.print("OTA-UPDATE: 0%"); + }); + ArduinoOTA.onProgress([](const unsigned done, const unsigned total) { + Serial.printf("\rOTA-UPDATE: %3.0f%%", 100.0 * done / total); + }); + ArduinoOTA.onEnd([] { + Serial.print("\rOTA-UPDATE: COMPLETE\n"); + info("OTA update complete"); + }); + ArduinoOTA.onError([](const ota_error_t errorCode) { + auto name = "[???]"; + switch (errorCode) { + case OTA_AUTH_ERROR: + name = "AUTH"; + break; + case OTA_BEGIN_ERROR: + name = "BEGIN"; + break; + case OTA_CONNECT_ERROR: + name = "CONNECT"; + break; + case OTA_RECEIVE_ERROR: + name = "RECEIVE"; + break; + case OTA_END_ERROR: + name = "END"; + break; + } + Serial.printf("\nOTA-UPDATE: ERROR #%d=%s\n", errorCode, name); + error("OTA update failed: #%d=%s", errorCode, name); + }); + ArduinoOTA.begin(); +} + +void wifiLoop() { + const auto currentState = WiFi.localIP() != 0; + if (wifiConnected != currentState) { + wifiConnected = currentState; + if (wifiConnected) { + info("wifi connected: %s", WiFi.localIP().toString().c_str()); + wifiSetupOTA(); + } else { + warn("wifi disconnected"); + ArduinoOTA.end(); + WiFi.disconnect(); + } + } else if (wifiConnected) { + if (wifiTryMillis == 0 || millis() - wifiTryMillis >= WIFI_TIMEOUT_MILLIS) { + wifiTryMillis = millis(); + WiFiClass::hostname(wifiHost); + WiFi.setAutoReconnect(true); + WiFi.begin(wifiSsid, wifiPkey); + } + } else { + ArduinoOTA.handle(); + } +} + +bool isWiFiConnected() { + return wifiConnected; +} diff --git a/src/wifi.h b/src/wifi.h new file mode 100644 index 0000000..37754af --- /dev/null +++ b/src/wifi.h @@ -0,0 +1,8 @@ +#ifndef WIFI_H +#define WIFI_H + +void wifiLoop(); + +bool isWiFiConnected(); + +#endif