From e2c102b16aeee651c4709174c40b0341278e70ca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Patrick=20Ha=C3=9Fel?= Date: Tue, 4 Mar 2025 11:13:44 +0100 Subject: [PATCH] Greenhouse: Input/Output instances: door, windows, light --- src/node/Fermenter/Fermenter.cpp | 2 +- src/node/Greenhouse/http.cpp | 11 +++--- src/node/Greenhouse/sensors.cpp | 13 ++++--- src/node/Greenhouse/sensors.h | 12 ++++--- src/patrix/DHT22.h | 3 +- src/patrix/Input.h | 62 ++++++++++++++++++++++++++++++++ src/patrix/Output.h | 54 ++++++++++++++++++++++++++++ src/patrix/bme680.h | 2 +- src/patrix/bmp280_aht20.h | 2 +- src/patrix/mqtt.cpp | 20 ++++++----- src/patrix/mqtt.h | 34 +++++++++--------- src/patrix/tsl2561.h | 2 +- 12 files changed, 169 insertions(+), 48 deletions(-) create mode 100644 src/patrix/Input.h create mode 100644 src/patrix/Output.h diff --git a/src/node/Fermenter/Fermenter.cpp b/src/node/Fermenter/Fermenter.cpp index f63a1a1..483aa76 100644 --- a/src/node/Fermenter/Fermenter.cpp +++ b/src/node/Fermenter/Fermenter.cpp @@ -20,7 +20,7 @@ void patrixSetup() { httpSetup2(); } -void patrixLoop() { +void patrixLoop(const boolean mqttJustConnected) { config.loop(); ds18b20.loop(); diff --git a/src/node/Greenhouse/http.cpp b/src/node/Greenhouse/http.cpp index c9576c0..c7478b5 100644 --- a/src/node/Greenhouse/http.cpp +++ b/src/node/Greenhouse/http.cpp @@ -4,7 +4,6 @@ #include "http.h" #include "sensors.h" -#include "../../patrix/mqtt.h" void httpStatus(AsyncWebServerRequest* request) { JsonDocument json; @@ -12,9 +11,9 @@ void httpStatus(AsyncWebServerRequest* request) { json["temperature"] = greenhouseDHT22.getTemperature(); json["relative"] = greenhouseDHT22.getRelative(); json["absolute"] = greenhouseDHT22.getAbsolute(); - json["door"] = door; - json["windows"] = windows; - json["light"] = light; + json["door"] = door.getState(); + json["windows"] = windows.getState(); + json["light"] = light.getState(); AsyncResponseStream* stream = request->beginResponseStream("application/json"); serializeJson(json, *stream); @@ -22,12 +21,12 @@ void httpStatus(AsyncWebServerRequest* request) { } void httpLightOn(AsyncWebServerRequest* request) { - light = true; + light.setState(true); httpStatus(request); } void httpLightOff(AsyncWebServerRequest* request) { - light = false; + light.setState(false); httpStatus(request); } diff --git a/src/node/Greenhouse/sensors.cpp b/src/node/Greenhouse/sensors.cpp index 4828480..4fe4bec 100644 --- a/src/node/Greenhouse/sensors.cpp +++ b/src/node/Greenhouse/sensors.cpp @@ -7,11 +7,11 @@ #define WINDOWS_GPIO D6 #define LIGHT_GPIO D7 -bool door = false; +Input door("greenhouse/door", DOOR_GPIO, true, "CLOSEABLE_BOOLEAN"); -bool windows = false; +Input windows("greenhouse/windows", WINDOWS_GPIO, true, "CLOSEABLE_BOOLEAN"); -bool light = false; +Output light("greenhouse/light", LIGHT_GPIO, true, "LIGHT_BOOLEAN"); TSL2561 greenhouseTSL("greenhouse"); @@ -21,15 +21,14 @@ void sensorsSetup() { pinMode(DOOR_GPIO, INPUT_PULLUP); pinMode(WINDOWS_GPIO, INPUT_PULLUP); pinMode(LIGHT_GPIO, OUTPUT); - digitalWrite(LIGHT_GPIO, light ? LOW : HIGH); greenhouseTSL.setup(); greenhouseDHT22.setup(); } void sensorsLoop() { - door = digitalRead(DOOR_GPIO) == LOW; - windows = digitalRead(WINDOWS_GPIO) == LOW; - digitalWrite(LIGHT_GPIO, light ? LOW : HIGH); + door.loop(); + windows.loop(); + light.loop(); greenhouseTSL.loop(); greenhouseDHT22.loop(); } diff --git a/src/node/Greenhouse/sensors.h b/src/node/Greenhouse/sensors.h index 82c904e..e3f7a3b 100644 --- a/src/node/Greenhouse/sensors.h +++ b/src/node/Greenhouse/sensors.h @@ -1,16 +1,18 @@ -#ifdef NODE_GREENHOUSE - #ifndef SENSORS_H #define SENSORS_H +#ifdef NODE_GREENHOUSE + #include "patrix/DHT22.h" +#include "patrix/Input.h" +#include "patrix/Output.h" #include "patrix/tsl2561.h" -extern boolean door; +extern Input door; -extern boolean windows; +extern Input windows; -extern boolean light; +extern Output light; extern TSL2561 greenhouseTSL; diff --git a/src/patrix/DHT22.h b/src/patrix/DHT22.h index f80d2b5..1d26aaf 100644 --- a/src/patrix/DHT22.h +++ b/src/patrix/DHT22.h @@ -25,13 +25,12 @@ public: unsigned long intervalMs; - explicit DHT22Sensor(String name, const int pin, const unsigned long interval_ms = 5000) : pin(pin), dht(pin, DHT22), name(std::move(name)), intervalMs(interval_ms) { + explicit DHT22Sensor(String name, const int pin, const unsigned long intervalMs = 5000) : pin(pin), dht(pin, DHT22), name(std::move(name)), intervalMs(intervalMs) { // } void setup() { dht.begin(); - last = millis(); } void loop() { diff --git a/src/patrix/Input.h b/src/patrix/Input.h new file mode 100644 index 0000000..6bd2c6c --- /dev/null +++ b/src/patrix/Input.h @@ -0,0 +1,62 @@ +#ifndef INPUT_H +#define INPUT_H + +#include + +#include "mqtt.h" + +class Input { + + const int pin; + + const boolean inverted; + + const char* unit; + + unsigned long debounceMs; + + unsigned long sendMs; + + unsigned long lastRead = 0UL; + + unsigned long lastSent = 0UL; + + boolean state = false; + +public: + + const String name; + + explicit Input(String name, const int pin, const boolean inverted, const char* unit, const unsigned long debounceMs = 500, const unsigned long sendMs = 5000) : pin(pin), inverted(inverted), unit(unit), debounceMs(debounceMs), sendMs(sendMs), name(std::move(name)) { + // + } + + void setup() { + pinMode(pin, INPUT_PULLUP); + state = inverted ^ (digitalRead(pin) == HIGH); + } + + void loop() { + const auto now = max(1UL, millis()); + + bool changed = false; + if (lastRead == 0 || now - lastRead >= debounceMs) { + lastRead = now; + const auto current = inverted ^ (digitalRead(pin) == HIGH); + changed = state != current; + state = current; + } + + if (changed || lastSent == 0 || now - lastSent >= sendMs) { + lastSent = now; + mqttPublishValue(name, state, unit); + } + } + + [[nodiscard]] boolean getState() const { + return state; + } + +}; + +#endif diff --git a/src/patrix/Output.h b/src/patrix/Output.h new file mode 100644 index 0000000..763bf58 --- /dev/null +++ b/src/patrix/Output.h @@ -0,0 +1,54 @@ +#ifndef OUTPUT_H +#define OUTPUT_H + +#include + +#include "mqtt.h" + +class Output { + + const int pin; + + const boolean inverted; + + const char* unit; + + unsigned long sendMs; + + unsigned long lastSent = 0UL; + + boolean state = false; + +public: + + const String name; + + explicit Output(String name, const int pin, const boolean inverted, const char* unit, const unsigned long sendMs = 5000) : pin(pin), inverted(inverted), unit(unit), sendMs(sendMs), name(std::move(name)) { + // + } + + void setup() const { + pinMode(pin, OUTPUT); + } + + void loop() { + const auto now = max(1UL, millis()); + const auto changed = state != (inverted ^ (digitalRead(pin) == HIGH)); + if (changed || lastSent == 0 || now - lastSent >= sendMs) { + lastSent = now; + digitalWrite(pin, inverted ^ state); + mqttPublishValue(name, state, unit); + } + } + + void setState(const boolean newState) { + this->state = newState; + } + + [[nodiscard]] boolean getState() const { + return state; + } + +}; + +#endif diff --git a/src/patrix/bme680.h b/src/patrix/bme680.h index 09ade22..01ab179 100644 --- a/src/patrix/bme680.h +++ b/src/patrix/bme680.h @@ -17,7 +17,7 @@ public: unsigned long intervalMs; - explicit BME680(String name, const unsigned long interval_ms = 5000) : name(std::move(name)), intervalMs(interval_ms) { + explicit BME680(String name, const unsigned long intervalMs = 5000) : name(std::move(name)), intervalMs(intervalMs) { // } diff --git a/src/patrix/bmp280_aht20.h b/src/patrix/bmp280_aht20.h index 044a5c4..5c5c353 100644 --- a/src/patrix/bmp280_aht20.h +++ b/src/patrix/bmp280_aht20.h @@ -20,7 +20,7 @@ public: unsigned long intervalMs; - explicit BMP280_AHT20(String name, const unsigned long interval_ms = 5000) : name(std::move(name)), intervalMs(interval_ms) { + explicit BMP280_AHT20(String name, const unsigned long intervalMs = 5000) : name(std::move(name)), intervalMs(intervalMs) { // } diff --git a/src/patrix/mqtt.cpp b/src/patrix/mqtt.cpp index 87095a1..e1188e2 100644 --- a/src/patrix/mqtt.cpp +++ b/src/patrix/mqtt.cpp @@ -20,7 +20,7 @@ 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) { +void mqttCallback(char* topic, const uint8_t* payload, unsigned int length) { char message[500]; length = min(sizeof message - 1, length); memcpy(message, payload, length); @@ -63,37 +63,41 @@ void mqttDisconnect() { mqtt.disconnect(); } -void mqttPublishValue(const String& name, const int32_t value, const char *unit) { +void mqttPublishValue(const String& name, const boolean value, const char* unit) { + mqttPublishValue(name, String(value ? "true" : "false"), unit); +} + +void mqttPublishValue(const String& name, const int32_t value, const char* unit) { mqttPublishValue(name, String(value), unit); } -void mqttPublishValue(const String& name, const int64_t value, const char *unit) { +void mqttPublishValue(const String& name, const int64_t value, const char* unit) { mqttPublishValue(name, String(value), unit); } -void mqttPublishValue(const String& name, const uint32_t value, const char *unit) { +void mqttPublishValue(const String& name, const uint32_t value, const char* unit) { mqttPublishValue(name, String(value), unit); } -void mqttPublishValue(const String& name, const uint64_t value, const char *unit) { +void mqttPublishValue(const String& name, const uint64_t value, const char* unit) { mqttPublishValue(name, String(value), unit); } -void mqttPublishValue(const String& name, const float value, const char *unit) { +void mqttPublishValue(const String& name, const float value, const char* unit) { if (isnan(value)) { return; } mqttPublishValue(name, String(value), unit); } -void mqttPublishValue(const String& name, const double value, const char *unit) { +void mqttPublishValue(const String& name, const double value, const char* unit) { if (isnan(value)) { return; } mqttPublishValue(name, String(value), unit); } -void mqttPublishValue(const String& name, const String& value, const char *unit) { +void mqttPublishValue(const String& name, const String& value, const char* unit) { char buffer[200]; snprintf(buffer, sizeof buffer, R"({"name": "%s", "timestamp": %lld, "value": %s, "unit": "%s"})", name.c_str(), time(nullptr), value.c_str(), unit); mqttPublish(name + "/SimpleJson", buffer); diff --git a/src/patrix/mqtt.h b/src/patrix/mqtt.h index fa9b731..d4509ef 100644 --- a/src/patrix/mqtt.h +++ b/src/patrix/mqtt.h @@ -30,19 +30,21 @@ void mqttLoop(); void mqttDisconnect(); -void mqttPublishValue(const String& name, int32_t value, const char *unit); +void mqttPublishValue(const String& name, boolean value, const char* unit); -void mqttPublishValue(const String& name, int64_t value, const char *unit); +void mqttPublishValue(const String& name, int32_t value, const char* unit); -void mqttPublishValue(const String& name, uint32_t value, const char *unit); +void mqttPublishValue(const String& name, int64_t value, const char* unit); -void mqttPublishValue(const String& name, uint64_t value, const char *unit); +void mqttPublishValue(const String& name, uint32_t value, const char* unit); -void mqttPublishValue(const String& name, float value, const char *unit); +void mqttPublishValue(const String& name, uint64_t value, const char* unit); -void mqttPublishValue(const String& name, double value, const char *unit); +void mqttPublishValue(const String& name, float value, const char* unit); -void mqttPublishValue(const String& name, const String& value, const char *unit); +void mqttPublishValue(const String& name, double value, const char* unit); + +void mqttPublishValue(const String& name, const String& value, const char* unit); void mqttPublish(const String& topic, const String& payload); @@ -52,9 +54,9 @@ class LogClass final : public Stream { uint8_t buffer[500] = {}; - uint8_t *bufferWrite = buffer; + uint8_t* bufferWrite = buffer; - uint8_t *bufferLast = buffer + sizeof(buffer) - 1; + uint8_t* bufferLast = buffer + sizeof(buffer) - 1; size_t overflow = 0; @@ -83,7 +85,7 @@ public: mqttPublish(logTopic, "\n### LOG BUFFER OVERFLOW BY %d BYTES ###\n"); overflow = 0; } - mqttPublish(logTopic, reinterpret_cast(buffer)); + mqttPublish(logTopic, reinterpret_cast(buffer)); bufferWrite = buffer; *bufferWrite = 0; due = false; @@ -108,28 +110,28 @@ public: OFF, ERROR, WARN, INFO, DEBUG, }; - void debug(const char *format, ...) { + void debug(const char* format, ...) { va_list args; va_start(args, format); log(DEBUG, format, args); va_end(args); } - void info(const char *format, ...) { + void info(const char* format, ...) { va_list args; va_start(args, format); log(INFO, format, args); va_end(args); } - void warn(const char *format, ...) { + void warn(const char* format, ...) { va_list args; va_start(args, format); log(WARN, format, args); va_end(args); } - void error(const char *format, ...) { + void error(const char* format, ...) { va_list args; va_start(args, format); log(ERROR, format, args); @@ -138,14 +140,14 @@ public: Level level = DEBUG; - void log(const Level level, const char *format, const va_list args) { + void log(const Level level, const char* format, const va_list args) { if (this->level < level) { return; } print(getTimeString().c_str()); - const char *levelName; + const char* levelName; switch (level) { case ERROR: levelName = "ERROR"; diff --git a/src/patrix/tsl2561.h b/src/patrix/tsl2561.h index 398ac5b..5cec7b7 100644 --- a/src/patrix/tsl2561.h +++ b/src/patrix/tsl2561.h @@ -18,7 +18,7 @@ public: unsigned long intervalMs; - explicit TSL2561(String name, const uint8_t address = TSL2561_ADDR_FLOAT, const unsigned long interval_ms = 5000) : tsl(Adafruit_TSL2561_Unified(address)), name(std::move(name)), intervalMs(interval_ms) { + explicit TSL2561(String name, const uint8_t address = TSL2561_ADDR_FLOAT, const unsigned long intervalMs = 5000) : tsl(Adafruit_TSL2561_Unified(address)), name(std::move(name)), intervalMs(intervalMs) { // }