mqtt topics as String + TSL2561 class

This commit is contained in:
Patrick Haßel 2025-02-14 12:55:12 +01:00
parent d03369e7ef
commit 70761270e2
8 changed files with 126 additions and 97 deletions

View File

@ -8,21 +8,23 @@ class BME680 {
Adafruit_BME680 bme; // NOLINT(*-interfaces-global-init) Adafruit_BME680 bme; // NOLINT(*-interfaces-global-init)
unsigned long last = 0UL;
public: public:
const char *name; const String name;
unsigned long intervalMs; unsigned long intervalMs;
explicit BME680(const char *name, const unsigned long interval_ms = 5000) : name(name), intervalMs(interval_ms) { explicit BME680(const String& name, const unsigned long interval_ms = 5000) : name(name), intervalMs(interval_ms) {
// //
} }
void setup() { void setup() {
if (bme.begin()) { if (bme.begin()) {
Log.printf("BME680: Initialized.\n"); Log.printf("BME680 \"%s\": Initialized.\n", name.c_str());
} else { } else {
Log.printf("BME680: Failed to initialize.\n"); Log.printf("BME680 \"%s\": Failed to initialize.\n", name.c_str());
} }
bme.setTemperatureOversampling(BME680_OS_8X); bme.setTemperatureOversampling(BME680_OS_8X);
bme.setHumidityOversampling(BME680_OS_2X); bme.setHumidityOversampling(BME680_OS_2X);
@ -33,10 +35,9 @@ public:
void loop() { void loop() {
const auto now = max(1UL, millis()); const auto now = max(1UL, millis());
static auto last = 0UL;
if (last == 0 || now - last >= intervalMs) { if (last == 0 || now - last >= intervalMs) {
if (bme.beginReading() == 0) { if (bme.beginReading() == 0) {
Log.print("BME680: Failed to request reading.\n"); Log.printf("BME680 \"%s\": Failed to request reading.\n", name.c_str());
setup(); setup();
} }
last = now; last = now;
@ -44,14 +45,14 @@ public:
if (bme.remainingReadingMillis() == 0) { if (bme.remainingReadingMillis() == 0) {
if (bme.endReading()) { if (bme.endReading()) {
const auto humidityAbsolute = calculateHumidityAbsolute(bme.temperature, bme.humidity); const auto humidityAbsolute = calculateHumidityAbsolute(bme.temperature, bme.humidity);
mqttPublish("garden/temperature", bme.temperature, "\xB0""C"); mqttPublish(name + "/temperature", bme.temperature, "\xB0""C");
mqttPublish("garden/pressure", bme.pressure / 100.0, "hPa"); mqttPublish(name + "/pressure", bme.pressure / 100.0, "hPa");
mqttPublish("garden/humidity/relative", bme.humidity, "%"); mqttPublish(name + "/humidity/relative", bme.humidity, "%");
mqttPublish("garden/humidity/absolute", humidityAbsolute, "mg/L"); mqttPublish(name + "/humidity/absolute", humidityAbsolute, "mg/L");
mqttPublish("garden/gas", bme.gas_resistance / 1000.0, "KOhms"); mqttPublish(name + "/gas", bme.gas_resistance / 1000.0, "KOhms");
mqttPublish("garden/altitude", bme.readAltitude(1013.25), "m"); mqttPublish(name + "/altitude", bme.readAltitude(1013.25), "m");
} else { } else {
Log.printf("Failed to complete reading\n"); Log.printf("BME680 \"%s\": Failed to complete reading\n", name.c_str());
setup(); setup();
} }
} }

View File

@ -3,23 +3,29 @@
#include "tsl2561.h" #include "tsl2561.h"
#include "wifi.h" #include "wifi.h"
BME680 garden("garden"); TSL2561 gardenTSL("garden");
BME680 greenhouse("greenhouse"); BME680 gardenBME("garden");
BME680 greenhouseBME("greenhouse");
void setup() { void setup() {
delay(500); delay(500);
Log.printf("\n\n\nStartup\n"); Log.printf("\n\n\nStartup\n");
wifiConnect(); wifiConnect();
tsl2561Setup();
garden.setup();
greenhouse.setup();
} }
void loop() { void loop() {
wifiLoop(); wifiLoop();
mqttLoop(); mqttLoop();
tsl2561Loop(); if (isSetupTimeAfterBootDelay()) {
garden.loop(); gardenTSL.setup();
greenhouse.loop(); gardenBME.setup();
greenhouseBME.setup();
}
if (isAfterBootDelay()) {
gardenTSL.loop();
gardenBME.loop();
greenhouseBME.loop();
}
} }

View File

@ -1,9 +1,7 @@
#include "mqtt.h" #include "mqtt.h"
#include <ESP8266WiFi.h>
#include "wifi.h" #include "wifi.h"
#include <ESP8266WiFi.h>
#include <PubSubClient.h> #include <PubSubClient.h>
#include <WiFiClient.h> #include <WiFiClient.h>
@ -64,41 +62,37 @@ void mqttLoop() {
} }
} }
void mqttPublish(const char *topic, const int32_t value, const char *unit) { void mqttPublish(const String& topic, const int32_t value, const char *unit) {
mqttPublish(topic, String(value), unit); mqttPublish(topic, String(value), unit);
} }
void mqttPublish(const char *topic, const int64_t value, const char *unit) { void mqttPublish(const String& topic, const int64_t value, const char *unit) {
mqttPublish(topic, String(value), unit); mqttPublish(topic, String(value), unit);
} }
void mqttPublish(const char *topic, const uint32_t value, const char *unit) { void mqttPublish(const String& topic, const uint32_t value, const char *unit) {
mqttPublish(topic, String(value), unit); mqttPublish(topic, String(value), unit);
} }
void mqttPublish(const char *topic, const uint64_t value, const char *unit) { void mqttPublish(const String& topic, const uint64_t value, const char *unit) {
mqttPublish(topic, String(value), unit); mqttPublish(topic, String(value), unit);
} }
void mqttPublish(const char *topic, const float value, const char *unit) { void mqttPublish(const String& topic, const float value, const char *unit) {
mqttPublish(topic, String(value), unit); mqttPublish(topic, String(value), unit);
} }
void mqttPublish(const char *topic, const double value, const char *unit) { void mqttPublish(const String& topic, const double value, const char *unit) {
mqttPublish(topic, String(value), unit); mqttPublish(topic, String(value), unit);
} }
bool mqttPublish(const char *topic, const String& value, const char *unit) { void mqttPublish(const String& topic, const String& value, const char *unit) {
if (!isTimeSet()) {
return true;
}
char buffer[200]; char buffer[200];
snprintf(buffer, sizeof buffer, R"({"timestamp": %lld, "value": %s, "unit": "%s"})", time(nullptr), value.c_str(), unit); snprintf(buffer, sizeof buffer, R"({"timestamp": %lld, "value": %s, "unit": "%s"})", time(nullptr), value.c_str(), unit);
mqttPublish(topic, buffer); mqttPublish(topic, buffer);
return false;
} }
void mqttPublish(const char *topic, const char *payload) { void mqttPublish(const String& topic, const String& payload) {
mqtt.publish(topic, payload); mqtt.publish(topic.c_str(), payload.c_str());
yield(); yield();
} }

View File

@ -11,21 +11,21 @@ extern const String cmdTopic;
void mqttLoop(); void mqttLoop();
void mqttPublish(const char *topic, int32_t value, const char *unit); void mqttPublish(const String& topic, int32_t value, const char *unit);
void mqttPublish(const char *topic, int64_t value, const char *unit); void mqttPublish(const String& topic, int64_t value, const char *unit);
void mqttPublish(const char *topic, uint32_t value, const char *unit); void mqttPublish(const String& topic, uint32_t value, const char *unit);
void mqttPublish(const char *topic, uint64_t value, const char *unit); void mqttPublish(const String& topic, uint64_t value, const char *unit);
void mqttPublish(const char *topic, float value, const char *unit); void mqttPublish(const String& topic, float value, const char *unit);
void mqttPublish(const char *topic, double value, const char *unit); void mqttPublish(const String& topic, double value, const char *unit);
bool mqttPublish(const char *topic, const String& value, const char *unit); void mqttPublish(const String& topic, const String& value, const char *unit);
void mqttPublish(const char *topic, const char *payload); void mqttPublish(const String& topic, const String& payload);
class LogClass final : public Stream { class LogClass final : public Stream {
@ -59,10 +59,10 @@ public:
due = true; due = true;
if (mqtt.connected()) { if (mqtt.connected()) {
if (overflow > 0) { if (overflow > 0) {
mqtt.publish(logTopic.c_str(), "\n### LOG BUFFER OVERFLOW BY %d BYTES ###\n"); mqttPublish(logTopic, "\n### LOG BUFFER OVERFLOW BY %d BYTES ###\n");
overflow = 0; overflow = 0;
} }
mqtt.publish(logTopic.c_str(), reinterpret_cast<const char *>(buffer)); mqttPublish(logTopic, reinterpret_cast<const char *>(buffer));
bufferWrite = buffer; bufferWrite = buffer;
*bufferWrite = 0; *bufferWrite = 0;
due = false; due = false;

View File

@ -1,42 +0,0 @@
#include "tsl2561.h"
#include "mqtt.h"
#include <Adafruit_Sensor.h>
#include <Adafruit_TSL2561_U.h>
#include <Wire.h>
#define TSL2561_INTERVAL_MS 5000
auto tsl = Adafruit_TSL2561_Unified(TSL2561_ADDR_FLOAT);
void tsl2561Setup() {
if (tsl.begin()) {
Log.printf("TSL2561: Initialized.\n");
} else {
Log.printf("TSL2561: Failed to initialize.\n");
}
tsl.enableAutoRange(true);
tsl.setIntegrationTime(TSL2561_INTEGRATIONTIME_402MS);
}
void sensorRead() {
uint16_t broadband;
uint16_t ir;
tsl.getLuminosity(&broadband, &ir);
const auto illuminance = tsl.calculateLux(broadband, ir);
if (illuminance == 65536) {
Log.printf("TSL2561: Failed to read.\n");
tsl2561Setup();
} else {
mqttPublish("garden/illuminance", illuminance, "lux");
}
}
void tsl2561Loop() {
const auto now = millis();
static unsigned long last = 0;
if (last == 0 || now - last >= TSL2561_INTERVAL_MS) {
last = max(1UL, now);
sensorRead();
}
}

View File

@ -1,8 +1,57 @@
#ifndef TSL2561_H #ifndef TSL2561_H
#define TSL2561_H #define TSL2561_H
void tsl2561Setup(); #include <Adafruit_TSL2561_U.h>
void tsl2561Loop(); class TSL2561 {
Adafruit_TSL2561_Unified tsl;
unsigned long last = 0UL;
public:
const String name;
unsigned long intervalMs;
explicit TSL2561(const String& name, const uint8_t address = TSL2561_ADDR_FLOAT, const unsigned long interval_ms = 5000) : tsl(Adafruit_TSL2561_Unified(address)), name(name), intervalMs(interval_ms) {
//
}
void setup() {
if (tsl.begin()) {
Log.printf("TSL2561 \"%s\": Initialized.\n", name.c_str());
} else {
Log.printf("TSL2561 \"%s\": Failed to initialize.\n", name.c_str());
}
tsl.enableAutoRange(true);
tsl.setIntegrationTime(TSL2561_INTEGRATIONTIME_402MS);
}
void loop() {
const auto now = millis();
if (last == 0 || now - last >= intervalMs) {
last = max(1UL, now);
read();
}
}
private:
void read() {
uint16_t broadband;
uint16_t ir;
tsl.getLuminosity(&broadband, &ir);
const auto illuminance = tsl.calculateLux(broadband, ir);
if (illuminance == 65536) {
Log.printf("TSL2561 \"%s\": Failed to read.\n", name.c_str());
setup();
} else {
mqttPublish(name + "/illuminance", illuminance, "lux");
}
}
};
#endif #endif

View File

@ -7,13 +7,16 @@
#define WIFI_SSID "HappyNet" #define WIFI_SSID "HappyNet"
#define WIFI_PASSWORD "1Grausame!Sackratte7" #define WIFI_PASSWORD "1Grausame!Sackratte7"
#define NTP_SERVER "107.189.12.98" /* pool.ntp.org */ #define NTP_SERVER "107.189.12.98" /* pool.ntp.org */
#define BOOT_DELAY_SEC 5
auto wifiConnected = false; auto wifiConnected = false;
auto timeSet = false; auto timeSetSince = 0UL;
unsigned long wifiConnectBeginMillis = 0; unsigned long wifiConnectBeginMillis = 0;
auto bootDelayOver = false;
void wifiConnect() { void wifiConnect() {
wifiConnectBeginMillis = max(1UL, millis()); wifiConnectBeginMillis = max(1UL, millis());
WiFi.setHostname(HOSTNAME); WiFi.setHostname(HOSTNAME);
@ -86,17 +89,24 @@ void timeLoop() {
const auto now = time(nullptr); const auto now = time(nullptr);
const auto nowHour = now / 3600; const auto nowHour = now / 3600;
static unsigned long lastHour = 0; static unsigned long lastHour = 0;
if (!timeSet) { if (timeSetSince == 0) {
if (now > 1700000000) { if (now > 1700000000) {
timeSet = true; timeSetSince = now;
lastHour = nowHour; lastHour = nowHour;
Log.printf("Got time: %s\n", getTimeString().c_str()); Log.printf("Got time: %s\n", getTimeString().c_str());
Log.printf("Delaying boot for %d seconds.\n", BOOT_DELAY_SEC);
} }
} else { } else {
if (lastHour != nowHour) { if (lastHour != nowHour) {
lastHour = nowHour; lastHour = nowHour;
Log.printf("%s\n", getTimeString().c_str()); Log.printf("%s\n", getTimeString().c_str());
} }
if (!bootDelayOver) {
bootDelayOver = time(nullptr) - timeSetSince > BOOT_DELAY_SEC;
if (bootDelayOver) {
Log.printf("Boot delay complete.\n");
}
}
} }
} }
@ -137,6 +147,15 @@ bool isWifiConnected() {
return wifiConnected; return wifiConnected;
} }
bool isTimeSet() { bool isSetupTimeAfterBootDelay() {
return timeSet; static auto needed = true;
if (needed && bootDelayOver) {
needed = false;
return true;
}
return false;
}
bool isAfterBootDelay() {
return bootDelayOver;
} }

View File

@ -11,7 +11,9 @@ String getTimeString();
bool isWifiConnected(); bool isWifiConnected();
bool isTimeSet(); bool isSetupTimeAfterBootDelay();
bool isAfterBootDelay();
uint64_t uptimeMillis(); uint64_t uptimeMillis();