commit a2cf20a1894dbee93ff78074108c6e12ce2a89c2 Author: Patrick Haßel Date: Thu Feb 13 23:17:22 2025 +0100 wifi, ota, time, mqtt, MySerial, TSL2561 diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..243ea5f --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +/.pio/ \ No newline at end of file diff --git a/platformio.ini b/platformio.ini new file mode 100644 index 0000000..6d31b38 --- /dev/null +++ b/platformio.ini @@ -0,0 +1,12 @@ +[env:Helligkeit] +platform = espressif8266 +board = esp12e +framework = arduino +lib_deps = https://github.com/adafruit/Adafruit_TSL2561 + https://github.com/knolleary/pubsubclient +build_flags = -DHOSTNAME=\"Helligkeit\" +monitor_speed = 115200 +upload_protocol = espota +upload_port = 10.0.0.160 +;upload_port = /dev/ttyUSB0 +;upload_speed = 460800 diff --git a/src/main.cpp b/src/main.cpp new file mode 100644 index 0000000..9964960 --- /dev/null +++ b/src/main.cpp @@ -0,0 +1,16 @@ +#include "wifi.h" +#include "tsl2561.h" +#include "mqtt.h" + +void setup() { + delay(500); + MySerial.printf("\n\n\nStartup\n"); + wifiConnect(); + sensorSetup(); +} + +void loop() { + wifiLoop(); + sensorLoop(); + mqttLoop(); +} \ No newline at end of file diff --git a/src/mqtt.cpp b/src/mqtt.cpp new file mode 100644 index 0000000..834643e --- /dev/null +++ b/src/mqtt.cpp @@ -0,0 +1,42 @@ +#include "mqtt.h" +#include "wifi.h" + +#include +#include + +WiFiClient client; + +PubSubClient mqtt(client); + +MySerialClass MySerial(mqtt); + +unsigned long mqttFailureMillis = 0; + +void mqttLoop() { + if (!mqtt.loop() && isWifiConnected() && (mqttFailureMillis == 0 || millis() - mqttFailureMillis >= 3000)) { + mqtt.setServer("10.0.0.50", 1883); + if (mqtt.connect(HOSTNAME, HOSTNAME, 0, false, "disconnected\n")) { + yield(); + mqttPublish("garten/log", "connected\n"); + MySerial.printf("MQTT connected as \"%s\"\n", HOSTNAME); + mqttFailureMillis = 0; + } else { + MySerial.printf("Failed to connect MQTT.\n"); + mqttFailureMillis = max(1UL, millis()); + } + } +} + +void mqttPublish(const char *topic, const float value, const char *unit) { + if (!isTimeSet()) { + return; + } + char buffer[200]; + snprintf(buffer, sizeof buffer, R"({"timestamp": %lld, "value": %s, "unit": "%s"})", time(nullptr), isnan(value) ? "null" : String(value).c_str(), unit); + mqttPublish(topic, buffer); +} + +void mqttPublish(const char *topic, const char *payload) { + mqtt.publish(topic, payload); + yield(); +} diff --git a/src/mqtt.h b/src/mqtt.h new file mode 100644 index 0000000..dcbf1c9 --- /dev/null +++ b/src/mqtt.h @@ -0,0 +1,73 @@ +#ifndef MQTT_H +#define MQTT_H + +#include +#include "PubSubClient.h" +#include "wifi.h" + +void mqttLoop(); + +void mqttPublish(const char *topic, float value, const char *unit); + +void mqttPublish(const char *topic, const char *payload); + +class MySerialClass : public Stream { + + PubSubClient& mqtt; + + uint8_t buffer[500] = {}; + + uint8_t *bufferWrite = buffer; + + uint8_t *bufferLast = buffer + sizeof(buffer) - 1; + + size_t overflow = 0; + + bool due = false; + +public: + + explicit MySerialClass(PubSubClient& mqttClient) : mqtt(mqttClient) { + Serial.begin(115200); + } + + size_t write(uint8_t data) override { + Serial.write(data); + if (bufferWrite < bufferLast) { + *bufferWrite++ = data; + *bufferWrite = 0; + } else { + overflow++; + } + if (due || data == '\n' || bufferWrite >= bufferLast) { + due = true; + if (mqtt.connected()) { + if (overflow > 0) { + mqtt.publish(HOSTNAME, "\n### LOG BUFFER OVERFLOW BY %d BYTES ###\n"); + overflow = 0; + } + mqtt.publish(HOSTNAME, (const char *) buffer); + bufferWrite = buffer; + *bufferWrite = 0; + due = false; + } + } + return 1; + } + + int available() override { + return 0; + } + + int read() override { + return -1; + } + + int peek() override { + return -1; + } +}; + +extern MySerialClass MySerial; + +#endif diff --git a/src/tsl2561.cpp b/src/tsl2561.cpp new file mode 100644 index 0000000..4112a56 --- /dev/null +++ b/src/tsl2561.cpp @@ -0,0 +1,39 @@ +#include "tsl2561.h" +#include "mqtt.h" + +#include +#include +#include + +Adafruit_TSL2561_Unified tsl = Adafruit_TSL2561_Unified(TSL2561_ADDR_FLOAT, 12345); + +void sensorSetup() { + if (tsl.begin()) { + MySerial.printf("TSL2561: Initialized.\n"); + } else { + MySerial.printf("TSL2561: Failed to initialize.\n"); + } + tsl.enableAutoRange(true); + tsl.setIntegrationTime(TSL2561_INTEGRATIONTIME_402MS); +} + +void sensorRead() { + sensors_event_t event; + if (!tsl.getEvent(&event)) { + MySerial.printf("TSL2561: Failed to read.\n"); + sensorSetup(); + } else if (event.light == 0) { + MySerial.printf("TSL2561: Too bright.\n"); + } else { + mqttPublish("garten/helligkeit", event.light, "lux"); + } +} + +void sensorLoop() { + unsigned long now = millis(); + static unsigned long last = 0; + if (last == 0 || now - last >= 2000) { + last = max(1UL, now); + sensorRead(); + } +} diff --git a/src/tsl2561.h b/src/tsl2561.h new file mode 100644 index 0000000..f900e84 --- /dev/null +++ b/src/tsl2561.h @@ -0,0 +1,8 @@ +#ifndef TSL2561_H +#define TSL2561_H + +void sensorSetup(); + +void sensorLoop(); + +#endif diff --git a/src/wifi.cpp b/src/wifi.cpp new file mode 100644 index 0000000..cbfc233 --- /dev/null +++ b/src/wifi.cpp @@ -0,0 +1,76 @@ +#include +#include +#include "wifi.h" +#include "mqtt.h" + +bool wifiConnected = false; + +bool timeSet = false; + +unsigned long wifiSince = 0; + +void wifiConnect() { + wifiSince = max(1UL, millis()); + WiFi.setHostname(HOSTNAME); + WiFi.begin("HappyNet", "1Grausame!Sackratte7"); + configTime(TZ_Europe_Berlin, "107.189.12.98"); + ArduinoOTA.begin(); + yield(); +} + +void timeLoop() { + const time_t now = time(nullptr); + const time_t nowHour = now / 3600; + static unsigned long lastHour = 0; + if (!timeSet) { + if (now > 1700000000) { + timeSet = true; + lastHour = nowHour; + MySerial.printf("Got time: %s\n", getTimeString().c_str()); + } + } else { + if (lastHour != nowHour) { + lastHour = nowHour; + MySerial.printf("%s\n", getTimeString().c_str()); + } + } +} + +void wifiLoop() { + ArduinoOTA.handle(); + if (WiFi.localIP() == 0UL) { + if (wifiConnected) { + wifiConnected = false; + MySerial.printf("WiFi disconnected.\n"); + wifiConnect(); + } else if (wifiSince == 0 || millis() - wifiSince >= 10000) { + WiFi.disconnect(); + yield(); + wifiConnect(); + } + } else { + if (!wifiConnected) { + wifiConnected = true; + MySerial.printf("WiFi connected as \"%s\" (%s)\n", HOSTNAME, WiFi.localIP().toString().c_str()); + } + timeLoop(); + } +} + +String getTimeString() { + time_t now; + time(&now); + tm info{}; + localtime_r(&now, &info); + char buffer[32]; + strftime(buffer, sizeof buffer, "%F %T %z", &info); + return {buffer}; +} + +bool isWifiConnected() { + return wifiConnected; +} + +bool isTimeSet() { + return timeSet; +} \ No newline at end of file diff --git a/src/wifi.h b/src/wifi.h new file mode 100644 index 0000000..edd18d4 --- /dev/null +++ b/src/wifi.h @@ -0,0 +1,16 @@ +#ifndef WIFI_H +#define WIFI_H + +#include + +void wifiConnect(); + +void wifiLoop(); + +String getTimeString(); + +bool isWifiConnected(); + +bool isTimeSet(); + +#endif