wifi, mqtt, clock, log [UNTESTED]

This commit is contained in:
Patrick Haßel 2025-01-06 15:05:07 +01:00
commit b6d1d319a8
11 changed files with 346 additions and 0 deletions

2
.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
/.pio/
/.idea/

19
platformio.ini Normal file
View File

@ -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\"

63
src/clock.cpp Normal file
View File

@ -0,0 +1,63 @@
#include "clock.h"
#include <log.h>
#include <WiFi.h>
#include <wifi.h>
#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;
}

18
src/clock.h Normal file
View File

@ -0,0 +1,18 @@
#ifndef CLOCK_H
#define CLOCK_H
#include <Arduino.h>
void clockLoop();
bool isClockSet();
String getClockStr();
bool isCorrectTime(time_t now);
time_t clockCorrect(time_t t);
void clockCorrect(time_t *t);
#endif

70
src/log.cpp Normal file
View File

@ -0,0 +1,70 @@
#include "log.h"
#include <clock.h>
#include <cstdio>
#include <HardwareSerial.h>
#include <cstdarg>
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);
}

21
src/log.h Normal file
View File

@ -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

15
src/main.cpp Normal file
View File

@ -0,0 +1,15 @@
#include <HardwareSerial.h>
#include <mqtt.h>
#include "wifi.h"
#include "clock.h"
void setup() {
Serial.begin(115200);
}
void loop() {
wifiLoop();
clockLoop();
mqttLoop();
}

43
src/mqtt.cpp Normal file
View File

@ -0,0 +1,43 @@
#include "mqtt.h"
#include <log.h>
#include <PubSubClient.h>
#include <WiFi.h>
#include <wifi.h>
#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");
}
}
}

6
src/mqtt.h Normal file
View File

@ -0,0 +1,6 @@
#ifndef MQTT_H
#define MQTT_H
void mqttLoop();
#endif

81
src/wifi.cpp Normal file
View File

@ -0,0 +1,81 @@
#include "wifi.h"
#include <ArduinoOTA.h>
#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;
}

8
src/wifi.h Normal file
View File

@ -0,0 +1,8 @@
#ifndef WIFI_H
#define WIFI_H
void wifiLoop();
bool isWiFiConnected();
#endif