[UNTESTED] Dallas, data-cache, debugLog

This commit is contained in:
Patrick Haßel 2024-04-10 09:39:53 +02:00
parent e0e80dedad
commit 35af48211e
15 changed files with 320 additions and 31 deletions

View File

@ -1,9 +1,10 @@
#include <Arduino.h> #include "base.h"
#include <Patrix.h> #include <Patrix.h>
#include <wifi.h> #include <wifi.h>
#include <console.h> #include <console.h>
#include "mqtt.h" #include "mqtt.h"
#include "log.h" #include "log.h"
#include "data.h"
void setup() { void setup() {
delay(500); delay(500);
@ -17,5 +18,6 @@ void setup() {
void loop() { void loop() {
consoleLoop(); consoleLoop();
mqttLoop(); mqttLoop();
dataLoop();
patrixLoop(); patrixLoop();
} }

View File

@ -1,6 +1,8 @@
#ifndef SENSOR3_PATRIX_H #ifndef SENSOR3_PATRIX_H
#define SENSOR3_PATRIX_H #define SENSOR3_PATRIX_H
#include "base.h"
void patrixSetup(); void patrixSetup();
void patrixLoop(); void patrixLoop();

6
lib/patrix/base.h Normal file
View File

@ -0,0 +1,6 @@
#ifndef SENSOR3_BASE_H
#define SENSOR3_BASE_H
#include <Arduino.h>
#endif

View File

@ -50,6 +50,7 @@ void consoleHandle(const char *cmd) {
info("CONSOLE", "reboot : reboot system"); info("CONSOLE", "reboot : reboot system");
info("CONSOLE", "wifi : reconnect wifi"); info("CONSOLE", "wifi : reconnect wifi");
info("CONSOLE", "mqtt : reconnect mqtt"); info("CONSOLE", "mqtt : reconnect mqtt");
info("CONSOLE", "debug : toggle debug log");
} else if (strcmp(cmd, "net") == 0) { } else if (strcmp(cmd, "net") == 0) {
info("CONSOLE", "MAC: %17s", WiFi.macAddress().c_str()); info("CONSOLE", "MAC: %17s", WiFi.macAddress().c_str());
info("CONSOLE", "IP: %17s", WiFi.localIP().toString().c_str()); info("CONSOLE", "IP: %17s", WiFi.localIP().toString().c_str());
@ -68,6 +69,9 @@ void consoleHandle(const char *cmd) {
} else if (strcmp(cmd, "mqtt") == 0) { } else if (strcmp(cmd, "mqtt") == 0) {
info("CONSOLE", "Reconnecting MQTT..."); info("CONSOLE", "Reconnecting MQTT...");
mqttDisconnect(); mqttDisconnect();
} else if (strcmp(cmd, "debug") == 0) {
setDebugEnabled(!isDebugEnabled());
info("CONSOLE", "DEBUG: %s", isDebugEnabled() ? "ON" : "OFF");
} else { } else {
info("CONSOLE", "Unknown command: %s", cmd); info("CONSOLE", "Unknown command: %s", cmd);
} }

44
lib/patrix/data.cpp Normal file
View File

@ -0,0 +1,44 @@
#include "data.h"
#include "ArduinoJson.h"
#include "mqtt.h"
#define ENTRY_COUNT 1500
struct Entry {
const char *name = "";
time_t timestamp = 0;
double value = NAN;
};
Entry data[ENTRY_COUNT];
Entry *dataRead = data;
Entry *dataWrite = data;
size_t dataCount = 0;
bool dataAdd(const char *name, const time_t timestamp, const double value) {
if (dataCount >= ENTRY_COUNT) {
return false;
}
dataWrite->name = name;
dataWrite->timestamp = timestamp;
dataWrite->value = value;
dataWrite = (dataWrite - data + 1) % ENTRY_COUNT + data;
dataCount++;
return true;
}
void dataLoop() {
if (dataCount == 0) {
return;
}
JsonDocument json;
json["timestamp"] = dataRead->timestamp;
json["value"] = dataRead->value;
if (mqttPublishData(dataRead->name, json)) {
dataRead = (dataRead - data + 1) % ENTRY_COUNT + data;
dataCount--;
}
}

10
lib/patrix/data.h Normal file
View File

@ -0,0 +1,10 @@
#ifndef SENSOR3_DATA_H
#define SENSOR3_DATA_H
#include "base.h"
bool dataAdd(const char *name, const time_t timestamp, const double value);
void dataLoop();
#endif

View File

@ -4,6 +4,8 @@
#define SEPARATOR " | " #define SEPARATOR " | "
bool debugEnabled = false;
void getDateTime(char *buffer, size_t size) { void getDateTime(char *buffer, size_t size) {
time_t now; time_t now;
time(&now); time(&now);
@ -23,7 +25,17 @@ void log(const char *level, const char *module, const char *format, ...) {
va_end(vl); va_end(vl);
const size_t len = Serial.print(datetime) + Serial.print(SEPARATOR) + Serial.print(module) + Serial.print(SEPARATOR) + Serial.print(level) + Serial.print(SEPARATOR) + Serial.print(message) + Serial.println(); const size_t len = Serial.print(datetime) + Serial.print(SEPARATOR) + Serial.print(module) + Serial.print(SEPARATOR) + Serial.print(level) + Serial.print(SEPARATOR) + Serial.print(message) + Serial.println();
mqttLog(len, SEPARATOR, datetime, module, level, message); mqttPublishLog(len, SEPARATOR, datetime, module, level, message);
}
void debug(const char *module, const char *format, ...) {
if (!debugEnabled) {
return;
}
va_list vl;
va_start(vl, format);
log("DEBUG", module, format, vl);
va_end(vl);
} }
void info(const char *module, const char *format, ...) { void info(const char *module, const char *format, ...) {
@ -39,3 +51,11 @@ void error(const char *module, const char *format, ...) {
log("ERROR", module, format, vl); log("ERROR", module, format, vl);
va_end(vl); va_end(vl);
} }
void setDebugEnabled(const bool enabled) {
debugEnabled = enabled;
}
bool isDebugEnabled() {
return debugEnabled;
}

View File

@ -1,8 +1,14 @@
#ifndef SENSOR3_LOG_H #ifndef SENSOR3_LOG_H
#define SENSOR3_LOG_H #define SENSOR3_LOG_H
void debug(const char *module, const char *format, ...);
void info(const char *module, const char *format, ...); void info(const char *module, const char *format, ...);
void error(const char *module, const char *format, ...); void error(const char *module, const char *format, ...);
void setDebugEnabled(bool enabled);
bool isDebugEnabled();
#endif #endif

View File

@ -8,32 +8,23 @@
#define CONNECT_TIMEOUT_MILLISECONDS 5000 #define CONNECT_TIMEOUT_MILLISECONDS 5000
#define TOPIC_LOG_FORMAT "log/%s"
#define TOPIC_CMD_FORMAT "cmd/%s"
#define TOPIC_DATA_FORMAT "data/%s/%s"
unsigned long mqttLastConnectTry = 0; unsigned long mqttLastConnectTry = 0;
WiFiClient espClient; WiFiClient espClient;
PubSubClient mqtt(espClient); PubSubClient mqtt(espClient);
char logTopic[32] = "log/UNSET"; char logTopic[64] = "log/UNSET";
char cmdTopic[64] = "cmd/UNSET"; char cmdTopic[64] = "cmd/UNSET";
void mqttSetup() { void mqttSetup() {
snprintf(logTopic, sizeof logTopic, "%s/%s", "log", HOSTNAME); snprintf(logTopic, sizeof logTopic, TOPIC_LOG_FORMAT, HOSTNAME);
snprintf(cmdTopic, sizeof cmdTopic, "%s/%s", "cmd", HOSTNAME); snprintf(cmdTopic, sizeof cmdTopic, TOPIC_CMD_FORMAT, HOSTNAME);
}
void mqttLog(const size_t len, const char *separator, const char *datetime, const char *module, const char *level, const char *message) {
if (mqtt.beginPublish(logTopic, len, false)) {
mqtt.print(datetime);
mqtt.print(separator);
mqtt.print(module);
mqtt.print(separator);
mqtt.print(level);
mqtt.print(separator);
mqtt.print(message);
mqtt.endPublish();
}
} }
void mqttDisconnect() { void mqttDisconnect() {
@ -69,11 +60,26 @@ void mqttLoop() {
mqtt.loop(); mqtt.loop();
} }
bool mqttPublish(const char *topic, const JsonDocument &doc) { void mqttPublishLog(const size_t len, const char *separator, const char *datetime, const char *module, const char *level, const char *message) {
if (!mqtt.connected()) { if (mqtt.beginPublish(logTopic, len, false)) {
return false; mqtt.print(datetime);
mqtt.print(separator);
mqtt.print(module);
mqtt.print(separator);
mqtt.print(level);
mqtt.print(separator);
mqtt.print(message);
mqtt.endPublish();
} }
char buffer[512]; }
const size_t size = serializeJson(doc, buffer);
return mqtt.publish(topic, buffer, size); bool mqttPublishData(const char *name, const JsonDocument &doc) {
if (mqtt.connected() != 0) {
char topic[128];
snprintf(topic, sizeof topic, TOPIC_DATA_FORMAT, HOSTNAME, name);
char payload[512];
const size_t size = serializeJson(doc, payload);
return mqtt.publish(topic, payload, size);
}
return false;
} }

View File

@ -9,8 +9,8 @@ void mqttLoop();
void mqttDisconnect(); void mqttDisconnect();
void mqttLog(size_t len, const char *separator, const char *datetime, const char *module, const char *level, const char *message); void mqttPublishLog(const size_t len, const char *separator, const char *datetime, const char *module, const char *level, const char *message);
bool mqttPublish(const char *topic, const JsonDocument &doc); bool mqttPublishData(const char *name, const JsonDocument &doc);
#endif #endif

View File

@ -0,0 +1,90 @@
#ifndef SENSOR2_DALLAS_H
#define SENSOR2_DALLAS_H
#include "wifi.h"
#include "log.h"
#include "OneWire.h"
#include "DallasTemperature.h"
#define DALLAS_TIMEOUT_MILLISECONDS 3000
class Dallas {
private:
OneWire oneWire;
DallasTemperature sensors;
time_t timestamp = 0;
unsigned long lastMillis = 0;
bool converting = false;
bool converted = false;
bool first = true;
public:
explicit Dallas(int pin) : oneWire(pin), sensors(&oneWire) {
sensors.begin();
sensors.setWaitForConversion(false);
}
void loop() {
if (converting) {
if (sensors.isConversionComplete()) {
if (first) {
first = false;
uint8_t count = sensors.getDeviceCount();
if (count == 0) {
error("DALLAS", "No devices found!");
} else {
debug("DALLAS", "Found %d devices:", count);
uint64_t address;
for (int index = 0; index < count; ++index) {
sensors.getAddress((uint8_t *) &address, index);
debug("DALLAS", " - 0x%016llX = %5.1f C", address, sensors.getTempC((uint8_t *) &address));
}
}
}
converting = false;
converted = true;
} else if (millis() - lastMillis > DALLAS_TIMEOUT_MILLISECONDS) {
error("DALLAS", "Timeout!");
converting = false;
converted = false;
}
} else {
sensors.requestTemperatures();
timestamp = getTime();
lastMillis = millis();
converting = true;
converted = false;
}
}
double read(uint64_t address) {
float value = sensors.getTempC((uint8_t *) &address);
if (value <= DEVICE_DISCONNECTED_C) {
return NAN;
}
return value;
}
time_t getTimestamp() const {
return timestamp;
}
bool isConverted() const {
return converted;
}
};
#endif

View File

@ -0,0 +1,90 @@
#ifndef SENSOR2_DALLAS_SENSOR_H
#define SENSOR2_DALLAS_SENSOR_H
#include "base.h"
#include "Dallas.h"
#include "wifi.h"
#include "mqtt.h"
#include "data.h"
class DallasSensor {
private:
Dallas &sensors;
uint64_t address;
const char *name;
const double valueThreshold;
const time_t timeoutSec;
const time_t minIntervalSec;
double lastValue = NAN;
time_t lastTimestamp = 0;
double lastValidValue = NAN;
time_t lastValidTimestamp = 0;
public:
DallasSensor(Dallas &sensors, const uint64_t address, const char *name, const double valueThreshold, const time_t timeoutSec, const time_t minIntervalSec) :
sensors(sensors),
name(name),
address(address),
valueThreshold(valueThreshold),
timeoutSec(timeoutSec),
minIntervalSec(minIntervalSec) {
// -
}
void loop() {
const time_t now = getTime();
if (now - lastTimestamp > timeoutSec) {
lastTimestamp = 0;
lastValue = NAN;
}
if (sensors.isConverted()) {
const double value = sensors.read(address);
const time_t timestamp = sensors.getTimestamp();
const bool doPublish = !isnan(value) && (abs(lastValue - value) >= valueThreshold || now - lastTimestamp >= minIntervalSec);
if (doPublish) {
dataAdd(name, timestamp, value);
}
lastValue = value;
lastTimestamp = timestamp;
if (!isnan(value)) {
lastValidValue = value;
lastValidTimestamp = timestamp;
}
}
}
const char *getName() const {
return name;
}
double getLastValue() const {
return lastValue;
}
time_t getLastTimestamp() const {
return lastTimestamp;
}
double getLastValidValue() const {
return lastValidValue;
}
time_t getLastValidTimestamp() const {
return lastValidTimestamp;
}
};
#endif

View File

@ -1,7 +1,7 @@
#ifndef GAERBOX_WIFI_H #ifndef GAERBOX_WIFI_H
#define GAERBOX_WIFI_H #define GAERBOX_WIFI_H
#include <ctime> #include "base.h"
void wifiSetup(); void wifiSetup();

View File

@ -11,5 +11,7 @@ monitor_port = /dev/ttyUSB0
monitor_speed = 115200 monitor_speed = 115200
monitor_filters = esp32_exception_decoder monitor_filters = esp32_exception_decoder
build_flags = -D HOSTNAME=\"Fermenter\" -D WIFI_SSID=\"HappyNet\" -D WIFI_PKEY=\"1Grausame!Sackratte7\" -D OTA_PASSWORD=\"OtaAuthPatrixFermenter\" -D BOOT_DELAY=true build_flags = -D HOSTNAME=\"Fermenter\" -D WIFI_SSID=\"HappyNet\" -D WIFI_PKEY=\"1Grausame!Sackratte7\" -D OTA_PASSWORD=\"OtaAuthPatrixFermenter\" -D BOOT_DELAY=true
lib_deps = knolleary/PubSubClient lib_deps = milesburton/DallasTemperature
bblanchon/ArduinoJson knolleary/PubSubClient
bblanchon/ArduinoJson
paulstoffregen/OneWire

View File

@ -1,9 +1,16 @@
#include <Patrix.h> #include <Patrix.h>
#include "sensors/Dallas.h"
#include "sensors/DallasSensor.h"
Dallas dallas(2);
DallasSensor temperatur(dallas, 0xAA0121125E4A7528, "temperatur", 0.5, 5, 60); // TODO wrong address
void patrixSetup() { void patrixSetup() {
} }
void patrixLoop() { void patrixLoop() {
dallas.loop();
temperatur.loop();
} }