From d03369e7ef3a37958044b6f6d860d73c74b5fc05 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Patrick=20Ha=C3=9Fel?= Date: Fri, 14 Feb 2025 11:55:43 +0100 Subject: [PATCH] BME680 --- platformio.ini | 1 + src/bme680.h | 75 +++++++++++++++++++++++++++++++++++++++++++++++++ src/main.cpp | 15 ++++++++-- src/mqtt.cpp | 35 ++++++++++++++--------- src/mqtt.h | 8 ++++++ src/tsl2561.cpp | 6 ++-- src/tsl2561.h | 4 +-- 7 files changed, 122 insertions(+), 22 deletions(-) create mode 100644 src/bme680.h diff --git a/platformio.ini b/platformio.ini index 196111e..d8e1637 100644 --- a/platformio.ini +++ b/platformio.ini @@ -4,6 +4,7 @@ board = esp12e framework = arduino lib_deps = https://github.com/adafruit/Adafruit_TSL2561 https://github.com/knolleary/pubsubclient + https://github.com/adafruit/Adafruit_BME680 build_flags = -DHOSTNAME=\"Greenhouse\" monitor_speed = 115200 upload_protocol = espota diff --git a/src/bme680.h b/src/bme680.h new file mode 100644 index 0000000..bcaa897 --- /dev/null +++ b/src/bme680.h @@ -0,0 +1,75 @@ +#ifndef BME680_H +#define BME680_H + +#include +#include + +class BME680 { + + Adafruit_BME680 bme; // NOLINT(*-interfaces-global-init) + +public: + + const char *name; + + unsigned long intervalMs; + + explicit BME680(const char *name, const unsigned long interval_ms = 5000) : name(name), intervalMs(interval_ms) { + // + } + + void setup() { + if (bme.begin()) { + Log.printf("BME680: Initialized.\n"); + } else { + Log.printf("BME680: Failed to initialize.\n"); + } + bme.setTemperatureOversampling(BME680_OS_8X); + bme.setHumidityOversampling(BME680_OS_2X); + bme.setPressureOversampling(BME680_OS_4X); + bme.setIIRFilterSize(BME680_FILTER_SIZE_3); + bme.setGasHeater(320, 150); + } + + void loop() { + const auto now = max(1UL, millis()); + static auto last = 0UL; + if (last == 0 || now - last >= intervalMs) { + if (bme.beginReading() == 0) { + Log.print("BME680: Failed to request reading.\n"); + setup(); + } + last = now; + } + if (bme.remainingReadingMillis() == 0) { + if (bme.endReading()) { + const auto humidityAbsolute = calculateHumidityAbsolute(bme.temperature, bme.humidity); + mqttPublish("garden/temperature", bme.temperature, "\xB0""C"); + mqttPublish("garden/pressure", bme.pressure / 100.0, "hPa"); + mqttPublish("garden/humidity/relative", bme.humidity, "%"); + mqttPublish("garden/humidity/absolute", humidityAbsolute, "mg/L"); + mqttPublish("garden/gas", bme.gas_resistance / 1000.0, "KOhms"); + mqttPublish("garden/altitude", bme.readAltitude(1013.25), "m"); + } else { + Log.printf("Failed to complete reading\n"); + setup(); + } + } + + } + + static double calculateHumidityAbsolute(const double temperature, const double humidityRelative) { + constexpr auto A = 6.112; + constexpr auto m = 17.67; + constexpr auto Tn = 243.5; + constexpr auto Mw = 18.01534; + constexpr auto R = 8.314462618; + const auto Tk = temperature + 273.15; + const auto P_sat = A * exp((m * temperature) / (temperature + Tn)); + const auto P_act = P_sat * (humidityRelative / 100.0); + return (P_act * Mw) / (R * Tk); + } + +}; + +#endif diff --git a/src/main.cpp b/src/main.cpp index 96856e5..1c614cc 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,16 +1,25 @@ +#include #include "mqtt.h" #include "tsl2561.h" #include "wifi.h" +BME680 garden("garden"); + +BME680 greenhouse("greenhouse"); + void setup() { delay(500); Log.printf("\n\n\nStartup\n"); wifiConnect(); - sensorSetup(); + tsl2561Setup(); + garden.setup(); + greenhouse.setup(); } void loop() { wifiLoop(); - sensorLoop(); mqttLoop(); -} \ No newline at end of file + tsl2561Loop(); + garden.loop(); + greenhouse.loop(); +} diff --git a/src/mqtt.cpp b/src/mqtt.cpp index bd11200..4001e69 100644 --- a/src/mqtt.cpp +++ b/src/mqtt.cpp @@ -65,30 +65,37 @@ void mqttLoop() { } void mqttPublish(const char *topic, const int32_t value, const char *unit) { - if (!isTimeSet()) { - return; - } - char buffer[200]; - snprintf(buffer, sizeof buffer, R"({"timestamp": %lld, "value": %d, "unit": "%s"})", time(nullptr), value, unit); - mqttPublish(topic, buffer); + mqttPublish(topic, String(value), unit); +} + +void mqttPublish(const char *topic, const int64_t value, const char *unit) { + mqttPublish(topic, String(value), unit); } void mqttPublish(const char *topic, const uint32_t value, const char *unit) { - if (!isTimeSet()) { - return; - } - char buffer[200]; - snprintf(buffer, sizeof buffer, R"({"timestamp": %lld, "value": %d, "unit": "%s"})", time(nullptr), value, unit); - mqttPublish(topic, buffer); + mqttPublish(topic, String(value), unit); +} + +void mqttPublish(const char *topic, const uint64_t value, const char *unit) { + mqttPublish(topic, String(value), unit); } void mqttPublish(const char *topic, const float value, const char *unit) { + mqttPublish(topic, String(value), unit); +} + +void mqttPublish(const char *topic, const double value, const char *unit) { + mqttPublish(topic, String(value), unit); +} + +bool mqttPublish(const char *topic, const String& value, const char *unit) { if (!isTimeSet()) { - return; + return true; } char buffer[200]; - snprintf(buffer, sizeof buffer, R"({"timestamp": %lld, "value": %s, "unit": "%s"})", time(nullptr), isnan(value) ? "null" : String(value).c_str(), unit); + snprintf(buffer, sizeof buffer, R"({"timestamp": %lld, "value": %s, "unit": "%s"})", time(nullptr), value.c_str(), unit); mqttPublish(topic, buffer); + return false; } void mqttPublish(const char *topic, const char *payload) { diff --git a/src/mqtt.h b/src/mqtt.h index 2601413..3c6e5f5 100644 --- a/src/mqtt.h +++ b/src/mqtt.h @@ -13,10 +13,18 @@ void mqttLoop(); void mqttPublish(const char *topic, int32_t value, const char *unit); +void mqttPublish(const char *topic, int64_t value, const char *unit); + void mqttPublish(const char *topic, uint32_t value, const char *unit); +void mqttPublish(const char *topic, uint64_t value, const char *unit); + void mqttPublish(const char *topic, float value, const char *unit); +void mqttPublish(const char *topic, double value, const char *unit); + +bool mqttPublish(const char *topic, const String& value, const char *unit); + void mqttPublish(const char *topic, const char *payload); class LogClass final : public Stream { diff --git a/src/tsl2561.cpp b/src/tsl2561.cpp index 6ae3339..198a246 100644 --- a/src/tsl2561.cpp +++ b/src/tsl2561.cpp @@ -9,7 +9,7 @@ auto tsl = Adafruit_TSL2561_Unified(TSL2561_ADDR_FLOAT); -void sensorSetup() { +void tsl2561Setup() { if (tsl.begin()) { Log.printf("TSL2561: Initialized.\n"); } else { @@ -26,13 +26,13 @@ void sensorRead() { const auto illuminance = tsl.calculateLux(broadband, ir); if (illuminance == 65536) { Log.printf("TSL2561: Failed to read.\n"); - sensorSetup(); + tsl2561Setup(); } else { mqttPublish("garden/illuminance", illuminance, "lux"); } } -void sensorLoop() { +void tsl2561Loop() { const auto now = millis(); static unsigned long last = 0; if (last == 0 || now - last >= TSL2561_INTERVAL_MS) { diff --git a/src/tsl2561.h b/src/tsl2561.h index f900e84..bdbf23f 100644 --- a/src/tsl2561.h +++ b/src/tsl2561.h @@ -1,8 +1,8 @@ #ifndef TSL2561_H #define TSL2561_H -void sensorSetup(); +void tsl2561Setup(); -void sensorLoop(); +void tsl2561Loop(); #endif