Compare commits
No commits in common. "1bde26489be476a9a7884c4dec9230a74c8e0a99" and "c59281a5257afd9c58f5d01661287a5946d251ff" have entirely different histories.
1bde26489b
...
c59281a525
@ -2,9 +2,6 @@
|
||||
#define SENSOR3_PATRIX_H
|
||||
|
||||
#include "base.h"
|
||||
#include "config.h"
|
||||
#include "console.h"
|
||||
#include "log.h"
|
||||
|
||||
void patrixSetup();
|
||||
|
||||
|
||||
@ -65,34 +65,6 @@ void configPutDouble(const char *name, double value) {
|
||||
}
|
||||
}
|
||||
|
||||
uint64_t configGetUint64_t(const char *name, uint64_t fallback) {
|
||||
if (!config.containsKey(name)) {
|
||||
return fallback;
|
||||
}
|
||||
return config[name];
|
||||
}
|
||||
|
||||
void configPutUint64_t(const char *name, uint64_t value) {
|
||||
if (config[name] != value) {
|
||||
config[name] = value;
|
||||
lastChangeMillis = millis();
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t configGetUint8_t(const char *name, uint8_t fallback) {
|
||||
if (!config.containsKey(name)) {
|
||||
return fallback;
|
||||
}
|
||||
return config[name];
|
||||
}
|
||||
|
||||
void configPutUint8_t(const char *name, uint8_t value) {
|
||||
if (config[name] != value) {
|
||||
config[name] = value;
|
||||
lastChangeMillis = millis();
|
||||
}
|
||||
}
|
||||
|
||||
void configPrint() {
|
||||
info("Config (%s):", lastChangeMillis == 0 ? "PERSISTED" : "TRANSIENT");
|
||||
for (JsonPair pair: config.as<JsonObject>()) {
|
||||
|
||||
@ -9,27 +9,16 @@ void configLoop();
|
||||
|
||||
void configReset();
|
||||
|
||||
void configLoaded();
|
||||
|
||||
String configGetString(const char *name, const char *fallback, bool allowEmpty);
|
||||
|
||||
void configPutString(const char *name, const char *value);
|
||||
|
||||
|
||||
double configGetDouble(const char *name, double fallback);
|
||||
|
||||
void configPutDouble(const char *name, double value);
|
||||
|
||||
|
||||
uint64_t configGetUint64_t(const char *name, uint64_t fallback);
|
||||
|
||||
void configPutUint64_t(const char *name, uint64_t value);
|
||||
|
||||
|
||||
uint8_t configGetUint8_t(const char *name, uint8_t fallback);
|
||||
|
||||
void configPutUint8_t(const char *name, uint8_t value);
|
||||
|
||||
|
||||
void configPrint();
|
||||
|
||||
#endif
|
||||
|
||||
@ -67,11 +67,11 @@ void consoleLoop() {
|
||||
void consoleHandle(char *cmd) {
|
||||
char *first = strtok(cmd, " ");
|
||||
if (first == nullptr) {
|
||||
consolePrintUsage();
|
||||
_usage();
|
||||
return;
|
||||
}
|
||||
if (strcmp(first, "help") == 0) {
|
||||
consolePrintUsage();
|
||||
_usage();
|
||||
} else if (strcmp(first, "wifi") == 0) {
|
||||
_wifi();
|
||||
} else if (strcmp(first, "mqtt") == 0) {
|
||||
@ -84,12 +84,12 @@ void consoleHandle(char *cmd) {
|
||||
_debug();
|
||||
} else if (strcmp(first, "config_reset") == 0) {
|
||||
configReset();
|
||||
} else if (!patrixCommand((char *) cmd)) {
|
||||
} else if (!patrix_command((char *) cmd)) {
|
||||
info("Unknown command: %s", cmd);
|
||||
}
|
||||
}
|
||||
|
||||
void consolePrintUsage() {
|
||||
void _usage() {
|
||||
info(R"(USAGE:
|
||||
help
|
||||
info
|
||||
@ -120,7 +120,7 @@ void _reboot() {
|
||||
void _mqtt() {
|
||||
char *sub = strtok(nullptr, " ");
|
||||
if (sub == nullptr) {
|
||||
consolePrintUsage();
|
||||
_usage();
|
||||
return;
|
||||
}
|
||||
if (strcmp(sub, "reconnect") == 0) {
|
||||
@ -134,7 +134,7 @@ void _mqtt() {
|
||||
void _wifi() {
|
||||
char *sub = strtok(nullptr, " ");
|
||||
if (sub == nullptr) {
|
||||
consolePrintUsage();
|
||||
_usage();
|
||||
return;
|
||||
}
|
||||
if (strcmp(sub, "reconnect") == 0) {
|
||||
@ -150,7 +150,7 @@ void _wifi() {
|
||||
void _setConfigString(const char *name, bool allowEmpty) {
|
||||
char *value = strtok(nullptr, "");
|
||||
if (value == nullptr) {
|
||||
consolePrintUsage();
|
||||
_usage();
|
||||
return;
|
||||
}
|
||||
if (!allowEmpty && strcmp(value, "") == 0) {
|
||||
@ -248,49 +248,3 @@ const char *getFlashChipMode() {
|
||||
return "[???]";
|
||||
}
|
||||
}
|
||||
|
||||
bool cmdReadDouble(const char *name, double *destinationPtr, double min, double max) {
|
||||
const char *valueStr = strtok(nullptr, "");
|
||||
if (valueStr == nullptr) {
|
||||
consolePrintUsage();
|
||||
return false;
|
||||
}
|
||||
double value = strtod(valueStr, nullptr);
|
||||
if (isnan(value)) {
|
||||
error("Failed to parse double for \"%s\": %s", name, valueStr);
|
||||
return false;
|
||||
}
|
||||
if ((!isnan(min) && value < min) || (!isnan(max) && value > max)) {
|
||||
error("Value out of range for \"%s\" [%f..%f]: %f", name, min, max, value);
|
||||
return false;
|
||||
}
|
||||
if (*destinationPtr != value) {
|
||||
*destinationPtr = value;
|
||||
info("Value for \"%s\" set to: %f", name, value);
|
||||
configPutDouble(name, value);
|
||||
} else {
|
||||
info("Value for \"%s\" unchanged: %f", name, value);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool cmdReadU64(const char *name, uint64_t *destinationPtr, uint64_t min, uint64_t max) {
|
||||
const char *valueStr = strtok(nullptr, "");
|
||||
if (valueStr == nullptr) {
|
||||
consolePrintUsage();
|
||||
return false;
|
||||
}
|
||||
uint64_t value = strtoll(valueStr, nullptr, 10);
|
||||
if ((min > 0 && value < min) || (max > 0 && value > max)) {
|
||||
error("Value out of range for \"%s\" [%f..%f]: %f", name, min, max, value);
|
||||
return false;
|
||||
}
|
||||
if (*destinationPtr != value) {
|
||||
*destinationPtr = value;
|
||||
info("Value for \"%s\" set to: %f", name, value);
|
||||
configPutUint64_t(name, value);
|
||||
} else {
|
||||
info("Value for \"%s\" unchanged: %f", name, value);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -1,20 +1,14 @@
|
||||
#ifndef SENSOR3_CONSOLE_H
|
||||
#define SENSOR3_CONSOLE_H
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
void consoleSetup();
|
||||
|
||||
void consoleLoop();
|
||||
|
||||
void consoleHandle(char *cmd);
|
||||
|
||||
bool patrixCommand(char *cmd);
|
||||
bool patrix_command(char *cmd);
|
||||
|
||||
void consolePrintUsage();
|
||||
|
||||
bool cmdReadDouble(const char *name, double *destinationPtr, double min, double max);
|
||||
|
||||
bool cmdReadU64(const char *name, uint64_t *destinationPtr, uint64_t min, uint64_t max);
|
||||
void _usage();
|
||||
|
||||
#endif
|
||||
|
||||
@ -3,17 +3,9 @@
|
||||
|
||||
#include "base.h"
|
||||
#include <ArduinoJson.h>
|
||||
#include "wifi.h"
|
||||
#include "mqtt.h"
|
||||
|
||||
struct IData {
|
||||
|
||||
time_t time;
|
||||
|
||||
explicit IData(time_t time) : time(time) {
|
||||
// -
|
||||
}
|
||||
|
||||
virtual void toJson(JsonObject &json) const = 0;
|
||||
|
||||
};
|
||||
@ -26,13 +18,16 @@ class Cache {
|
||||
|
||||
private:
|
||||
|
||||
T buffer[size];
|
||||
struct Entry {
|
||||
time_t timestamp = 0;
|
||||
T data;
|
||||
};
|
||||
|
||||
T *bufferRead = buffer;
|
||||
Entry buffer[size];
|
||||
|
||||
T *bufferWrite = buffer;
|
||||
Entry *bufferRead = buffer;
|
||||
|
||||
T last{};
|
||||
Entry *bufferWrite = buffer;
|
||||
|
||||
size_t usage = 0;
|
||||
|
||||
@ -43,26 +38,25 @@ public:
|
||||
// -
|
||||
}
|
||||
|
||||
bool add(T data) {
|
||||
if (usage < size && data.needsPublish(last)) {
|
||||
last = data;
|
||||
*bufferWrite = data;
|
||||
bufferWrite = (bufferWrite - buffer + 1) % size + buffer;
|
||||
usage++;
|
||||
return true;
|
||||
bool add(const time_t timestamp, const T &data) {
|
||||
if (usage >= size) {
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
bufferWrite->timestamp = timestamp;
|
||||
bufferWrite->data = data;
|
||||
bufferWrite = (bufferWrite - buffer + 1) % size + buffer;
|
||||
usage++;
|
||||
return true;
|
||||
}
|
||||
|
||||
void loop() {
|
||||
if (usage == 0 || !isTimeSet()) {
|
||||
return;
|
||||
}
|
||||
JsonDocument doc;
|
||||
JsonObject json = doc.to<JsonObject>();
|
||||
correctTime(bufferRead->time);
|
||||
json["timestamp"] = bufferRead->time;
|
||||
bufferRead->toJson(json);
|
||||
JsonDocument json;
|
||||
json["timestamp"] = correctTime(bufferRead->timestamp);
|
||||
JsonObject data = json["data"].to<JsonObject>();
|
||||
bufferRead->data.toJson(data);
|
||||
if (mqttPublishData(json)) {
|
||||
bufferRead = (bufferRead - buffer + 1) % size + buffer;
|
||||
usage--;
|
||||
|
||||
@ -1,28 +0,0 @@
|
||||
#ifndef SENSOR3_DHT_H
|
||||
#define SENSOR3_DHT_H
|
||||
|
||||
#include "base.h"
|
||||
|
||||
class DHT {
|
||||
|
||||
private:
|
||||
|
||||
const int pin;
|
||||
|
||||
public:
|
||||
|
||||
explicit DHT(const int pin) : pin(pin) {
|
||||
// nothing
|
||||
}
|
||||
|
||||
void begin() {
|
||||
// TODO
|
||||
}
|
||||
|
||||
void loop(float *temperatureCelsius, uint8_t *humidityRelativePercent, float *humidityAbsoluteMgL) {
|
||||
// TODO
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
@ -15,22 +15,36 @@ private:
|
||||
|
||||
uint64_t address;
|
||||
|
||||
const double valueThreshold;
|
||||
|
||||
const time_t timeoutSec;
|
||||
|
||||
const time_t minIntervalMillis;
|
||||
|
||||
double lastSentValue = NAN;
|
||||
|
||||
unsigned long lastSentMillis = 0;
|
||||
|
||||
double lastValue = NAN;
|
||||
|
||||
time_t lastTimestamp = 0;
|
||||
|
||||
double lastValidValue = NAN;
|
||||
|
||||
time_t lastValidTimestamp = 0;
|
||||
|
||||
public:
|
||||
|
||||
DallasSensor(Dallas &sensors, const uint64_t address, const time_t timeoutSec) :
|
||||
DallasSensor(Dallas &sensors, const uint64_t address, const double valueThreshold, const time_t timeoutSec, const time_t minIntervalMillis) :
|
||||
sensors(sensors),
|
||||
address(address),
|
||||
timeoutSec(timeoutSec) {
|
||||
valueThreshold(valueThreshold),
|
||||
timeoutSec(timeoutSec),
|
||||
minIntervalMillis(minIntervalMillis) {
|
||||
// -
|
||||
}
|
||||
|
||||
void loop() {
|
||||
bool loop() {
|
||||
const time_t now = getTime();
|
||||
if (now - lastTimestamp > timeoutSec) {
|
||||
lastTimestamp = 0;
|
||||
@ -39,9 +53,21 @@ public:
|
||||
if (sensors.isConverted()) {
|
||||
const double value = sensors.read(address);
|
||||
const time_t timestamp = sensors.getTimestamp();
|
||||
const unsigned long millisNow = millis();
|
||||
const bool doPublish = !isnan(value) && (abs(lastSentValue - value) >= valueThreshold || millisNow - lastSentMillis >= minIntervalMillis);
|
||||
if (doPublish) {
|
||||
lastSentValue = value;
|
||||
lastSentMillis = millisNow;
|
||||
}
|
||||
lastValue = value;
|
||||
lastTimestamp = timestamp;
|
||||
if (!isnan(value)) {
|
||||
lastValidValue = value;
|
||||
lastValidTimestamp = timestamp;
|
||||
}
|
||||
return doPublish;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
[[nodiscard]] double getLastValue() const {
|
||||
@ -52,6 +78,14 @@ public:
|
||||
return lastTimestamp;
|
||||
}
|
||||
|
||||
[[nodiscard]] double getLastValidValue() const {
|
||||
return lastValidValue;
|
||||
}
|
||||
|
||||
[[nodiscard]] time_t getLastValidTimestamp() const {
|
||||
return lastValidTimestamp;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@ -1,22 +0,0 @@
|
||||
#ifndef SENSOR3_MOISTURE_H
|
||||
#define SENSOR3_MOISTURE_H
|
||||
|
||||
class Moisture {
|
||||
|
||||
private:
|
||||
|
||||
const int pin;
|
||||
|
||||
public:
|
||||
|
||||
Moisture(const int pin) : pin(pin) {
|
||||
// TODO
|
||||
}
|
||||
|
||||
void loop(float *value) {
|
||||
// TODO
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
@ -1,78 +0,0 @@
|
||||
#ifndef SENSOR3_OUTPUT_H
|
||||
#define SENSOR3_OUTPUT_H
|
||||
|
||||
#include "base.h"
|
||||
|
||||
class Output {
|
||||
|
||||
private:
|
||||
|
||||
const int pin;
|
||||
|
||||
const bool invert;
|
||||
|
||||
uint64_t onSince = 0;
|
||||
|
||||
uint64_t offSince = 0;
|
||||
|
||||
uint64_t totalOnMillis = 0;
|
||||
|
||||
public:
|
||||
|
||||
Output(const int pin, const bool invert, const bool initial) : pin(pin), invert(invert) {
|
||||
pinMode(pin, OUTPUT);
|
||||
set(initial);
|
||||
}
|
||||
|
||||
void loop() {
|
||||
uint64_t now = getUptimeMillis();
|
||||
static uint64_t last = now;
|
||||
if (isOn()) {
|
||||
totalOnMillis += now - last;
|
||||
}
|
||||
}
|
||||
|
||||
[[nodiscard]] bool isOn() const {
|
||||
return (digitalRead(pin) == HIGH) ^ invert;
|
||||
}
|
||||
|
||||
void on() {
|
||||
set(true);
|
||||
}
|
||||
|
||||
void off() {
|
||||
set(false);
|
||||
}
|
||||
|
||||
void set(const bool newState) {
|
||||
if (isOn() != newState) {
|
||||
digitalWrite(pin, newState ^ invert ? HIGH : LOW);
|
||||
if (newState) {
|
||||
onSince = getUptimeMillis();
|
||||
} else {
|
||||
offSince = getUptimeMillis();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[[nodiscard]] uint64_t getOnSince() const {
|
||||
if (!isOn()) {
|
||||
return 0;
|
||||
}
|
||||
return getUptimeMillis() - onSince;
|
||||
}
|
||||
|
||||
[[nodiscard]] uint64_t getOffSince() const {
|
||||
if (isOn()) {
|
||||
return 0;
|
||||
}
|
||||
return getUptimeMillis() - offSince;
|
||||
}
|
||||
|
||||
[[nodiscard]] uint64_t getTotalOnMillis() const {
|
||||
return totalOnMillis;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
@ -195,10 +195,18 @@ time_t getTime() {
|
||||
return epochSeconds;
|
||||
}
|
||||
|
||||
void correctTime(time_t &value) {
|
||||
if (timeSet && value < MIN_EPOCH_SECONDS) {
|
||||
value = getTime() - preTimeOffset + value;
|
||||
time_t correctTime(const time_t value) {
|
||||
if (!timeSet) {
|
||||
return value;
|
||||
}
|
||||
if (value < MIN_EPOCH_SECONDS) {
|
||||
return getTime() - preTimeOffset + value;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
bool isOlderThan(time_t time, time_t seconds) {
|
||||
return getTime() > correctTime(time) + seconds;
|
||||
}
|
||||
|
||||
void getDateTime(char *buffer, size_t size) {
|
||||
|
||||
@ -15,7 +15,9 @@ bool isTimeSet();
|
||||
|
||||
time_t getTime();
|
||||
|
||||
void correctTime(time_t &value);
|
||||
time_t correctTime(time_t value);
|
||||
|
||||
bool isOlderThan(time_t time, time_t seconds);
|
||||
|
||||
void getDateTime(char *buffer, size_t size);
|
||||
|
||||
|
||||
@ -16,7 +16,6 @@ lib_deps = https://github.com/milesburton/Arduino-Temperature-Control-Library
|
||||
Wire
|
||||
https://github.com/phassel/ArduPID/
|
||||
https://github.com/wayoda/LedControl
|
||||
https://github.com/me-no-dev/ESPAsyncWebServer
|
||||
|
||||
[env:TEST32]
|
||||
upload_port = 10.42.0.66
|
||||
@ -31,7 +30,7 @@ monitor_port = ${COMMON.monitor_port}
|
||||
monitor_speed = ${COMMON.monitor_speed}
|
||||
monitor_filters = ${COMMON.monitor_filters}
|
||||
lib_deps = ${COMMON.lib_deps}
|
||||
build_flags = -D TEST32 -D HOSTNAME=\"TEST32\" -D WIFI_SSID=\"${COMMON.WIFI_SSID}\" -D WIFI_PKEY=\"${COMMON.WIFI_PKEY}\" -D OTA_PASSWORD=\"OtaAuthPatrixTEST32\" -D BOOT_DELAY=false -D DEBUG_LOG=true
|
||||
build_flags = -D TEST32 -D HOSTNAME=\"TEST32\" -D WIFI_SSID=\"${COMMON.WIFI_SSID}\" -D WIFI_PKEY=\"${COMMON.WIFI_PKEY}\" -D OTA_PASSWORD=\"OtaAuthPatrixTEST32\" -D BOOT_DELAY=false -D DEBUG_LOG=false
|
||||
|
||||
[env:TEST8266]
|
||||
upload_port = 10.0.0.162
|
||||
@ -61,19 +60,4 @@ monitor_port = ${COMMON.monitor_port}
|
||||
monitor_speed = ${COMMON.monitor_speed}
|
||||
monitor_filters = esp8266_exception_decoder
|
||||
lib_deps = ${COMMON.lib_deps}
|
||||
build_flags = -D FERMENTER -D HOSTNAME=\"Fermenter\" -D WIFI_SSID=\"${COMMON.WIFI_SSID}\" -D WIFI_PKEY=\"${COMMON.WIFI_PKEY}\" -D OTA_PASSWORD=\"OtaAuthPatrixFermenter\" -D BOOT_DELAY=true -D DEBUG_LOG=false
|
||||
|
||||
[env:Greenhouse]
|
||||
;upload_port = 10.0.0.
|
||||
;upload_flags = --auth=OtaAuthPatrixGreenhouse
|
||||
;upload_protocol = ${COMMON.ota_protocol}
|
||||
upload_port = ${COMMON.usb_port}
|
||||
upload_speed = ${COMMON.usb_speed}
|
||||
platform = espressif8266
|
||||
board = esp12e
|
||||
framework = ${COMMON.framework}
|
||||
monitor_port = ${COMMON.monitor_port}
|
||||
monitor_speed = ${COMMON.monitor_speed}
|
||||
monitor_filters = esp8266_exception_decoder
|
||||
lib_deps = ${COMMON.lib_deps}
|
||||
build_flags = -D GREENHOUSE -D HOSTNAME=\"Greenhouse\" -D WIFI_SSID=\"${COMMON.WIFI_SSID}\" -D WIFI_PKEY=\"${COMMON.WIFI_PKEY}\" -D OTA_PASSWORD=\"OtaAuthPatrixGreenhouse\" -D BOOT_DELAY=true -D DEBUG_LOG=false
|
||||
build_flags = -D FERMENTER -D HOSTNAME=\"Fermenter\" -D WIFI_SSID=\"${COMMON.WIFI_SSID}\" -D WIFI_PKEY=\"${COMMON.WIFI_PKEY}\" -D OTA_PASSWORD=\"OtaAuthPatrixFermenter\" -D BOOT_DELAY=true -D DEBUG_LOG=true
|
||||
|
||||
@ -1,29 +0,0 @@
|
||||
#include "FementerDisplay.h"
|
||||
|
||||
#include "LedControl.h"
|
||||
|
||||
LedControl lc = LedControl(13, 14, 15, 1);
|
||||
|
||||
void writeDecimal(int *digit, double value) {
|
||||
const int integer = (int) value;
|
||||
const int decimal = (int) ((value - integer) * 10) % 10;
|
||||
lc.setDigit(0, (*digit)++, decimal, false);
|
||||
lc.setDigit(0, (*digit)++, integer % 10, true);
|
||||
lc.setDigit(0, (*digit)++, integer / 10 % 10, false);
|
||||
}
|
||||
|
||||
void displayLoop(double temperature, double target) {
|
||||
static unsigned long lastDisplayInit = 0;
|
||||
if (lastDisplayInit == 0 || millis() - lastDisplayInit > 60 * 60 * 1000) {
|
||||
lastDisplayInit = millis();
|
||||
lc.shutdown(0, true);
|
||||
lc.shutdown(0, false);
|
||||
lc.setIntensity(0, 4);
|
||||
lc.clearDisplay(0);
|
||||
}
|
||||
int digit = 0;
|
||||
writeDecimal(&digit, temperature);
|
||||
digit++;
|
||||
digit++;
|
||||
writeDecimal(&digit, target);
|
||||
}
|
||||
@ -1,6 +0,0 @@
|
||||
#ifndef SENSOR3_FEMENTERDISPLAY_H
|
||||
#define SENSOR3_FEMENTERDISPLAY_H
|
||||
|
||||
void displayLoop(double temperature, double target);
|
||||
|
||||
#endif
|
||||
@ -1,38 +1,192 @@
|
||||
#if defined(FERMENTER) || defined(TEST8266)
|
||||
|
||||
#include <Patrix.h>
|
||||
#include "sensors/Dallas.h"
|
||||
#include "sensors/DallasSensor.h"
|
||||
#include "ArduPID.h"
|
||||
#include "config.h"
|
||||
#include "console.h"
|
||||
#include <Arduino.h>
|
||||
#include "LedControl.h"
|
||||
#include "FermenterData.h"
|
||||
#include "FementerDisplay.h"
|
||||
#include "FermenterPID.h"
|
||||
#include "FermenterSensor.h"
|
||||
|
||||
Cache<FermenterData, 800> cache;
|
||||
#define SENSOR_GPIO D4
|
||||
#define CONTROL_GPIO D2
|
||||
#define CONTROL_PWM_BITS 10
|
||||
#define CONTROL_PWM_MAX (pow(2, CONTROL_PWM_BITS) - 1)
|
||||
|
||||
#define PID_DEFAULT_P 1500
|
||||
#define PID_DEFAULT_I 0
|
||||
#define PID_DEFAULT_D 0
|
||||
#define PID_DEFAULT_TARGET 31
|
||||
#define PID_DEFAULT_OVER 5
|
||||
|
||||
Dallas dallas(SENSOR_GPIO);
|
||||
|
||||
DallasSensor sensor(dallas, 0x3D0417C1D740FF28, 0.1, 5, 60 * 1000);
|
||||
|
||||
LedControl lc = LedControl(13, 14, 15, 1);
|
||||
|
||||
ArduPID pid;
|
||||
|
||||
double proportional = PID_DEFAULT_P;
|
||||
|
||||
double integral = PID_DEFAULT_I;
|
||||
|
||||
double derivative = PID_DEFAULT_D;
|
||||
|
||||
double temperatureTarget = PID_DEFAULT_TARGET;
|
||||
|
||||
double temperatureOver = PID_DEFAULT_OVER;
|
||||
|
||||
double temperatureCurrent = NAN;
|
||||
|
||||
double heaterPWM = 0;
|
||||
|
||||
Cache<FermenterData, 500> cache;
|
||||
|
||||
void writeDecimal(int *digit, double value);
|
||||
|
||||
void displayLoop();
|
||||
|
||||
void pidLoop();
|
||||
|
||||
void patrixSetup() {
|
||||
sensorSetup();
|
||||
pidSetup(&temperature);
|
||||
dallas.begin();
|
||||
analogWriteResolution(CONTROL_PWM_BITS);
|
||||
|
||||
configLoaded();
|
||||
|
||||
pid.begin(&temperatureCurrent, &heaterPWM, &temperatureTarget, proportional, integral, derivative);
|
||||
pid.setOutputLimits(0, CONTROL_PWM_MAX);
|
||||
pid.start();
|
||||
}
|
||||
|
||||
void patrixLoop() {
|
||||
sensorLoop();
|
||||
pidLoop();
|
||||
displayLoop(temperature, target);
|
||||
cache.add({getTime(), (float) temperature, (float) target, getHeaterPercent(), (float) proportional, (float) integral, (float) derivative});
|
||||
dallas.loop();
|
||||
if (sensor.loop()) {
|
||||
const FermenterData data = {sensor.getLastValue(), temperatureTarget, proportional, integral, derivative};
|
||||
cache.add(sensor.getLastTimestamp(), data);
|
||||
}
|
||||
cache.loop();
|
||||
displayLoop();
|
||||
pidLoop();
|
||||
}
|
||||
|
||||
bool patrixCommand(char *first) {
|
||||
void pidLoop() {
|
||||
temperatureCurrent = sensor.getLastValue();
|
||||
if (!isnan(temperatureCurrent)) {
|
||||
pid.compute();
|
||||
} else {
|
||||
heaterPWM = 0;
|
||||
}
|
||||
|
||||
const char *emergencyStr = "";
|
||||
if (heaterPWM > 0 && temperatureCurrent > temperatureTarget + temperatureOver) {
|
||||
heaterPWM = 0;
|
||||
emergencyStr = "[EMERGENCY CUTOFF]";
|
||||
}
|
||||
|
||||
analogWrite(CONTROL_GPIO, (int) round(heaterPWM));
|
||||
|
||||
static unsigned long lastDebug = 0;
|
||||
unsigned long now = millis();
|
||||
if (now - lastDebug >= 1000) {
|
||||
lastDebug = now;
|
||||
int heaterPercent = (int) round(100.0 * heaterPWM / CONTROL_PWM_MAX);
|
||||
debug(
|
||||
"cache: %3d/%d | p: %f | i: %f | d: %f | target: %4.1f | heater: %3d%% | temperature: %5.2f %s",
|
||||
cache.getUsage(),
|
||||
cache.getSize(),
|
||||
|
||||
proportional == 0 ? NAN : proportional,
|
||||
integral == 0 ? NAN : integral,
|
||||
derivative == 0 ? NAN : derivative,
|
||||
|
||||
temperatureTarget,
|
||||
heaterPercent,
|
||||
temperatureCurrent,
|
||||
|
||||
emergencyStr
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
void displayLoop() {
|
||||
static unsigned long lastDisplayInit = 0;
|
||||
if (lastDisplayInit == 0 || millis() - lastDisplayInit > 60 * 60 * 1000) {
|
||||
lastDisplayInit = millis();
|
||||
lc.shutdown(0, true);
|
||||
lc.shutdown(0, false);
|
||||
lc.setIntensity(0, 4);
|
||||
lc.clearDisplay(0);
|
||||
}
|
||||
int digit = 0;
|
||||
writeDecimal(&digit, temperatureCurrent);
|
||||
digit++;
|
||||
digit++;
|
||||
writeDecimal(&digit, temperatureTarget);
|
||||
}
|
||||
|
||||
void writeDecimal(int *digit, double value) {
|
||||
const int integer = (int) value;
|
||||
const int decimal = (int) ((value - integer) * 10) % 10;
|
||||
lc.setDigit(0, (*digit)++, decimal, false);
|
||||
lc.setDigit(0, (*digit)++, integer % 10, true);
|
||||
lc.setDigit(0, (*digit)++, integer / 10 % 10, false);
|
||||
}
|
||||
|
||||
bool setDouble(const char *name, double *destinationPtr, double min, double max) {
|
||||
const char *valueStr = strtok(nullptr, "");
|
||||
if (valueStr == nullptr) {
|
||||
_usage();
|
||||
return false;
|
||||
}
|
||||
double value = strtod(valueStr, nullptr);
|
||||
if (isnan(value)) {
|
||||
error("Failed to parse double for \"%s\": %s", name, valueStr);
|
||||
return false;
|
||||
}
|
||||
if ((!isnan(min) && value < min) || (!isnan(max) && value > max)) {
|
||||
error("Value out of range for \"%s\" [%f..%f]: %f", name, min, max, value);
|
||||
return false;
|
||||
}
|
||||
if (*destinationPtr != value) {
|
||||
*destinationPtr = value;
|
||||
info("Value for \"%s\" set to: %f", name, value);
|
||||
configPutDouble(name, value);
|
||||
} else {
|
||||
info("Value for \"%s\" unchanged: %f", name, value);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool patrix_command(char *first) {
|
||||
bool result = false;
|
||||
if (strcmp(first, "p") == 0) {
|
||||
result = cmdReadDouble("p", &proportional, 0, NAN);
|
||||
} else if (strcmp(first, "i") == 0) {
|
||||
result = cmdReadDouble("i", &integral, 0, NAN);
|
||||
} else if (strcmp(first, "d") == 0) {
|
||||
result = cmdReadDouble("d", &derivative, 0, NAN);
|
||||
} else if (strcmp(first, "t") == 0) {
|
||||
result = cmdReadDouble("t", &target, -10, 60);
|
||||
if (strcmp(first, "over") == 0 || strcmp(first, "o") == 0) {
|
||||
result = setDouble("over", &temperatureOver, 0, 20);
|
||||
} else if (strcmp(first, "target") == 0 || strcmp(first, "t") == 0) {
|
||||
result = setDouble("target", &temperatureTarget, -10, 60);
|
||||
} else if (strcmp(first, "proportional") == 0 || strcmp(first, "p") == 0) {
|
||||
result = setDouble("p", &proportional, NAN, NAN);
|
||||
} else if (strcmp(first, "integral") == 0 || strcmp(first, "i") == 0) {
|
||||
result = setDouble("i", &integral, NAN, NAN);
|
||||
} else if (strcmp(first, "derivative") == 0 || strcmp(first, "d") == 0) {
|
||||
result = setDouble("d", &derivative, NAN, NAN);
|
||||
}
|
||||
if (result) {
|
||||
pid.setCoefficients(proportional, integral, derivative);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void configLoaded() {
|
||||
proportional = configGetDouble("p", PID_DEFAULT_P);
|
||||
integral = configGetDouble("i", PID_DEFAULT_I);
|
||||
derivative = configGetDouble("d", PID_DEFAULT_D);
|
||||
temperatureTarget = configGetDouble("target", PID_DEFAULT_TARGET);
|
||||
temperatureOver = configGetDouble("over", PID_DEFAULT_OVER);
|
||||
pid.setCoefficients(proportional, integral, derivative);
|
||||
}
|
||||
|
||||
#endif
|
||||
@ -1,65 +1,35 @@
|
||||
#ifndef SENSOR3_FERMENTER_DATA_H
|
||||
#define SENSOR3_FERMENTER_DATA_H
|
||||
#ifndef SENSOR3_FERMENTERDATA_H
|
||||
#define SENSOR3_FERMENTERDATA_H
|
||||
|
||||
#include "data.h"
|
||||
|
||||
struct FermenterData : IData {
|
||||
float currentCelsius;
|
||||
float targetCelsius;
|
||||
uint8_t heaterPercent;
|
||||
float p;
|
||||
float i;
|
||||
float d;
|
||||
double temperature;
|
||||
double target;
|
||||
double p;
|
||||
double i;
|
||||
double d;
|
||||
|
||||
FermenterData() : IData(0) {
|
||||
currentCelsius = NAN;
|
||||
targetCelsius = NAN;
|
||||
heaterPercent = 0;
|
||||
FermenterData() {
|
||||
temperature = NAN;
|
||||
target = NAN;
|
||||
p = NAN;
|
||||
i = NAN;
|
||||
d = NAN;
|
||||
}
|
||||
|
||||
FermenterData(
|
||||
time_t time,
|
||||
float currentCelsius,
|
||||
float targetCelsius,
|
||||
uint8_t heaterPercent,
|
||||
float p,
|
||||
float i,
|
||||
float d
|
||||
) :
|
||||
IData(time),
|
||||
currentCelsius(currentCelsius),
|
||||
targetCelsius(targetCelsius),
|
||||
heaterPercent(heaterPercent),
|
||||
p(p),
|
||||
i(i),
|
||||
d(d) {
|
||||
FermenterData(double temperature, double target, double p, double i, double d) : temperature(temperature), target(target), p(p), i(i), d(d) {
|
||||
// -
|
||||
}
|
||||
|
||||
void toJson(JsonObject &json) const override {
|
||||
json["currentCelsius"] = currentCelsius;
|
||||
json["targetCelsius"] = targetCelsius;
|
||||
json["heaterPercent"] = heaterPercent;
|
||||
json["temperature"] = temperature;
|
||||
json["target"] = target;
|
||||
json["p"] = p;
|
||||
json["i"] = i;
|
||||
json["d"] = d;
|
||||
}
|
||||
|
||||
[[nodiscard]] bool needsPublish(FermenterData &last) {
|
||||
correctTime(time);
|
||||
correctTime(last.time);
|
||||
return time - last.time >= 60
|
||||
|| this->p != last.p
|
||||
|| this->i != last.i
|
||||
|| this->d != last.d
|
||||
|| abs(this->currentCelsius - last.currentCelsius) >= 0.1
|
||||
|| this->targetCelsius != last.targetCelsius
|
||||
|| this->heaterPercent != last.heaterPercent;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@ -1,62 +0,0 @@
|
||||
#include "FermenterPID.h"
|
||||
|
||||
#include "log.h"
|
||||
#include "config.h"
|
||||
|
||||
#define CONTROL_GPIO D2
|
||||
#define CONTROL_PWM_BITS 10
|
||||
#define CONTROL_PWM_MAX (pow(2, CONTROL_PWM_BITS) - 1)
|
||||
|
||||
ArduPID pid;
|
||||
|
||||
double proportional = 0;
|
||||
|
||||
double integral = 0;
|
||||
|
||||
double derivative = 0;
|
||||
|
||||
double target = 0;
|
||||
|
||||
double heater = 0;
|
||||
|
||||
void pidSetup(double *temperature) {
|
||||
analogWriteResolution(CONTROL_PWM_BITS);
|
||||
|
||||
proportional = configGetDouble("p", 0);
|
||||
integral = configGetDouble("i", 0);
|
||||
derivative = configGetDouble("d", 0);
|
||||
target = configGetDouble("t", 0);
|
||||
pid.begin(temperature, &heater, &target, proportional, integral, derivative);
|
||||
pid.setOutputLimits(0, CONTROL_PWM_MAX);
|
||||
}
|
||||
|
||||
void pidLoop() {
|
||||
if (!isnan(*pid.input)) {
|
||||
pid.setCoefficients(proportional, integral, derivative);
|
||||
pid.compute();
|
||||
} else {
|
||||
heater = 0;
|
||||
}
|
||||
|
||||
analogWrite(CONTROL_GPIO, (int) round(heater));
|
||||
|
||||
static unsigned long lastDebug = 0;
|
||||
unsigned long now = millis();
|
||||
if (now - lastDebug >= 1000) {
|
||||
lastDebug = now;
|
||||
debug(
|
||||
"p: %f | i: %.12f | d: %.12f | target: %4.1f | heater: %3d%% | temperature: %5.2f",
|
||||
proportional == 0 ? NAN : proportional,
|
||||
integral == 0 ? NAN : integral,
|
||||
derivative == 0 ? NAN : derivative,
|
||||
|
||||
*pid.setpoint,
|
||||
getHeaterPercent(),
|
||||
*pid.input
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t getHeaterPercent() {
|
||||
return (int) round(100.0 * heater / CONTROL_PWM_MAX);
|
||||
}
|
||||
@ -1,22 +0,0 @@
|
||||
#ifndef SENSOR3_FERMENTERPID_H
|
||||
#define SENSOR3_FERMENTERPID_H
|
||||
|
||||
#include "ArduPID.h"
|
||||
|
||||
extern ArduPID pid;
|
||||
|
||||
extern double proportional;
|
||||
|
||||
extern double integral;
|
||||
|
||||
extern double derivative;
|
||||
|
||||
extern double target;
|
||||
|
||||
void pidSetup(double *temperature);
|
||||
|
||||
void pidLoop();
|
||||
|
||||
uint8_t getHeaterPercent();
|
||||
|
||||
#endif
|
||||
@ -1,22 +0,0 @@
|
||||
#include "FermenterSensor.h"
|
||||
|
||||
#include "sensors/Dallas.h"
|
||||
#include "sensors/DallasSensor.h"
|
||||
|
||||
#define SENSOR_GPIO D4
|
||||
|
||||
Dallas dallas(SENSOR_GPIO);
|
||||
|
||||
DallasSensor sensor(dallas, 0x3D0417C1D740FF28, 5);
|
||||
|
||||
double temperature = NAN;
|
||||
|
||||
void sensorSetup() {
|
||||
dallas.begin();
|
||||
}
|
||||
|
||||
void sensorLoop() {
|
||||
dallas.loop();
|
||||
sensor.loop();
|
||||
temperature = sensor.getLastValue();
|
||||
}
|
||||
@ -1,10 +0,0 @@
|
||||
#ifndef SENSOR3_FERMENTERSENSOR_H
|
||||
#define SENSOR3_FERMENTERSENSOR_H
|
||||
|
||||
extern double temperature;
|
||||
|
||||
void sensorSetup();
|
||||
|
||||
void sensorLoop();
|
||||
|
||||
#endif
|
||||
@ -1,187 +0,0 @@
|
||||
#if defined(GREENHOUSE)
|
||||
|
||||
#include <Patrix.h>
|
||||
#include "GreenhouseData.h"
|
||||
#include "sensors/DHT.h"
|
||||
#include "sensors/Output.h"
|
||||
#include "sensors/Moisture.h"
|
||||
|
||||
#define INSIDE_DHT_PIN 4
|
||||
|
||||
#define MOISTURE_PIN 5
|
||||
|
||||
#define OUTSIDE_DHT_PIN 6
|
||||
|
||||
#define VENTILATOR_PIN 7
|
||||
|
||||
#define SPRINKLER_PIN 8
|
||||
|
||||
#define TEMPERATURE_HIGH 35
|
||||
|
||||
#define TEMPERATURE_LOW 32
|
||||
|
||||
#define TEMPERATURE_MILLIS (5 * 60 * 1000)
|
||||
|
||||
#define MOISTURE_HIGH 70
|
||||
|
||||
#define MOISTURE_LOW 20
|
||||
|
||||
#define MOISTURE_MILLIS (5 * 60 * 1000)
|
||||
|
||||
GreenhouseData data{};
|
||||
|
||||
Cache<GreenhouseData, 800> cache;
|
||||
|
||||
DHT insideDHT(INSIDE_DHT_PIN);
|
||||
|
||||
Moisture insideMoisture(MOISTURE_PIN);
|
||||
|
||||
DHT outsideDHT(OUTSIDE_DHT_PIN);
|
||||
|
||||
Output ventilator(VENTILATOR_PIN, true, false);
|
||||
|
||||
Output sprinkler(SPRINKLER_PIN, true, false);
|
||||
|
||||
double tempHigh = 35;
|
||||
|
||||
double tempLow = 32;
|
||||
|
||||
uint64_t tempMillis = 5 * 60 * 1000;
|
||||
|
||||
uint64_t tempHighSince = 0;
|
||||
|
||||
uint64_t tempLowSince = 0;
|
||||
|
||||
double moistHigh = 35;
|
||||
|
||||
double moistLow = 32;
|
||||
|
||||
uint64_t moistMillis = 5 * 60 * 1000;
|
||||
|
||||
uint64_t moistHighSince = 0;
|
||||
|
||||
uint64_t moistLowSince = 0;
|
||||
|
||||
void insideLoop();
|
||||
|
||||
void outsideLoop();
|
||||
|
||||
void moistureLoop();
|
||||
|
||||
void patrixSetup() {
|
||||
insideDHT.begin();
|
||||
outsideDHT.begin();
|
||||
}
|
||||
|
||||
void patrixLoop() {
|
||||
outsideLoop();
|
||||
|
||||
insideLoop();
|
||||
moistureLoop();
|
||||
|
||||
ventilator.loop();
|
||||
data.ventilatorSeconds = ventilator.getTotalOnMillis() / 1000;
|
||||
|
||||
sprinkler.loop();
|
||||
data.sprinklerSeconds = sprinkler.getTotalOnMillis() / 1000;
|
||||
|
||||
static unsigned long now = millis();
|
||||
static unsigned long last = now;
|
||||
if (now - last >= 60 * 1000) {
|
||||
last = now;
|
||||
cache.add(getTime(), data);
|
||||
cache.loop();
|
||||
}
|
||||
}
|
||||
|
||||
void outsideLoop() {
|
||||
float temperature = NAN;
|
||||
float absolute = NAN;
|
||||
outsideDHT.loop(&temperature, &data.outsideRelativePercent, &absolute);
|
||||
data.outsideTemperatureCenti = (int16_t) round(temperature * 100);
|
||||
data.outsideAbsoluteCenti = (uint16_t) round(absolute * 100);
|
||||
}
|
||||
|
||||
void insideLoop() {
|
||||
float temperature = NAN;
|
||||
float absolute = NAN;
|
||||
insideDHT.loop(&temperature, &data.insideRelativePercent, &absolute);
|
||||
data.insideTemperatureCenti = (int16_t) round(temperature * 100);
|
||||
data.insideAbsoluteCenti = (uint16_t) round(absolute * 100);
|
||||
|
||||
if (temperature > tempHigh) {
|
||||
tempLowSince = 0;
|
||||
if (tempHighSince == 0) {
|
||||
tempHighSince = getUptimeMillis();
|
||||
}
|
||||
if (tempHighSince != 0 && getUptimeMillis() - tempHighSince > tempMillis) {
|
||||
ventilator.on();
|
||||
}
|
||||
}
|
||||
|
||||
if (temperature < tempLow) {
|
||||
tempHighSince = 0;
|
||||
if (tempLowSince == 0) {
|
||||
tempLowSince = getUptimeMillis();
|
||||
}
|
||||
if (tempLowSince != 0 && getUptimeMillis() - tempLowSince > tempMillis) {
|
||||
ventilator.off();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void moistureLoop() {
|
||||
float moisture = NAN;
|
||||
insideMoisture.loop(&moisture);
|
||||
data.insideMoisturePercent = (uint16_t) round(moisture * 100);
|
||||
|
||||
if (moisture > moistHigh) {
|
||||
moistLowSince = 0;
|
||||
if (moistHighSince == 0) {
|
||||
moistHighSince = getUptimeMillis();
|
||||
}
|
||||
if (moistHighSince != 0 && getUptimeMillis() - moistHighSince > moistMillis) {
|
||||
sprinkler.off();
|
||||
}
|
||||
}
|
||||
|
||||
if (moisture < moistLow) {
|
||||
moistHighSince = 0;
|
||||
if (moistLowSince == 0) {
|
||||
moistLowSince = getUptimeMillis();
|
||||
}
|
||||
if (moistLowSince != 0 && getUptimeMillis() - moistLowSince > moistMillis) {
|
||||
sprinkler.on();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool patrixCommand(char *first) {
|
||||
bool result = false;
|
||||
if (strcmp(first, "tempHigh") == 0 || strcmp(first, "th") == 0) {
|
||||
result = cmdReadDouble("tempHigh", &tempHigh, NAN, NAN);
|
||||
} else if (strcmp(first, "tempLow") == 0 || strcmp(first, "tl") == 0) {
|
||||
result = cmdReadDouble("tempLow", &tempLow, NAN, NAN);
|
||||
} else if (strcmp(first, "tempMillis") == 0 || strcmp(first, "tm") == 0) {
|
||||
result = cmdReadU64("tempMillis", &tempMillis, NAN, NAN);
|
||||
} else if (strcmp(first, "moistHigh") == 0 || strcmp(first, "mh") == 0) {
|
||||
result = cmdReadDouble("moistHigh", &moistHigh, NAN, NAN);
|
||||
} else if (strcmp(first, "moistLow") == 0 || strcmp(first, "ml") == 0) {
|
||||
result = cmdReadDouble("moistLow", &moistLow, NAN, NAN);
|
||||
} else if (strcmp(first, "moistMillis") == 0 || strcmp(first, "mm") == 0) {
|
||||
result = cmdReadU64("moistMillis", &moistMillis, NAN, NAN);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void configLoaded() {
|
||||
tempHigh = configGetDouble("tempHigh", TEMPERATURE_HIGH);
|
||||
tempLow = configGetDouble("tempLow", TEMPERATURE_LOW);
|
||||
tempMillis = configGetUint64_t("tempMillis", TEMPERATURE_MILLIS);
|
||||
|
||||
moistHigh = configGetDouble("moistHigh", MOISTURE_HIGH);
|
||||
moistLow = configGetDouble("moistLow", MOISTURE_LOW);
|
||||
moistMillis = configGetUint64_t("moistMillis", MOISTURE_MILLIS);
|
||||
}
|
||||
|
||||
#endif
|
||||
@ -1,95 +0,0 @@
|
||||
#ifndef SENSOR3_GREENHOUSE_DATA_H
|
||||
#define SENSOR3_GREENHOUSE_DATA_H
|
||||
|
||||
#include "data.h"
|
||||
|
||||
struct GreenhouseData : IData {
|
||||
int16_t insideTemperatureCenti;
|
||||
uint8_t insideRelativePercent;
|
||||
uint16_t insideAbsoluteCenti;
|
||||
uint8_t insideMoisturePercent;
|
||||
|
||||
int16_t outsideTemperatureCenti;
|
||||
uint8_t outsideRelativePercent;
|
||||
uint16_t outsideAbsoluteCenti;
|
||||
|
||||
bool ventilatorState;
|
||||
uint32_t ventilatorSeconds;
|
||||
|
||||
bool sprinklerState;
|
||||
uint32_t sprinklerSeconds;
|
||||
|
||||
GreenhouseData() {
|
||||
insideTemperatureCenti = 0;
|
||||
insideRelativePercent = 0;
|
||||
insideAbsoluteCenti = 0;
|
||||
insideMoisturePercent = 0;
|
||||
|
||||
outsideTemperatureCenti = 0;
|
||||
outsideRelativePercent = 0;
|
||||
outsideAbsoluteCenti = 0;
|
||||
|
||||
ventilatorState = false;
|
||||
ventilatorSeconds = 0;
|
||||
|
||||
sprinklerState = false;
|
||||
sprinklerSeconds = 0;
|
||||
}
|
||||
|
||||
GreenhouseData(
|
||||
int16_t insideTemperatureCenti,
|
||||
uint8_t insideRelativePercent,
|
||||
uint8_t insideAbsoluteCenti,
|
||||
uint8_t insideMoisturePercent,
|
||||
|
||||
int16_t outsideTemperatureCenti,
|
||||
uint8_t outsideRelativePercent,
|
||||
uint8_t outsideAbsoluteCenti,
|
||||
|
||||
bool ventilatorState,
|
||||
uint32_t ventilatorSeconds,
|
||||
|
||||
bool sprinklerState,
|
||||
uint32_t sprinklerSeconds
|
||||
) :
|
||||
insideTemperatureCenti(insideTemperatureCenti),
|
||||
insideRelativePercent(insideRelativePercent),
|
||||
insideAbsoluteCenti(insideAbsoluteCenti),
|
||||
insideMoisturePercent(insideMoisturePercent),
|
||||
|
||||
outsideTemperatureCenti(outsideTemperatureCenti),
|
||||
outsideRelativePercent(outsideRelativePercent),
|
||||
outsideAbsoluteCenti(outsideAbsoluteCenti),
|
||||
|
||||
ventilatorState(ventilatorState),
|
||||
ventilatorSeconds(ventilatorSeconds),
|
||||
|
||||
sprinklerState(sprinklerState),
|
||||
sprinklerSeconds(sprinklerSeconds) {
|
||||
// -
|
||||
}
|
||||
|
||||
void toJson(JsonObject &json) const override {
|
||||
JsonObject inside = json["inside"];
|
||||
inside["temperature"] = insideTemperatureCenti / 100;
|
||||
inside["relative"] = insideRelativePercent;
|
||||
inside["absolute"] = insideAbsoluteCenti / 100;
|
||||
inside["moisture"] = insideMoisturePercent;
|
||||
|
||||
JsonObject outside = json["outside"];
|
||||
outside["temperature"] = outsideTemperatureCenti / 100;
|
||||
outside["relative"] = outsideRelativePercent;
|
||||
outside["absolute"] = outsideAbsoluteCenti / 100;
|
||||
|
||||
JsonObject ventilator = json["ventilator"];
|
||||
ventilator["state"] = ventilatorState;
|
||||
ventilator["totalSeconds"] = ventilatorSeconds;
|
||||
|
||||
JsonObject sprinkler = json["sprinkler"];
|
||||
sprinkler["state"] = sprinklerState;
|
||||
sprinkler["totalSeconds"] = sprinklerSeconds;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
Loading…
Reference in New Issue
Block a user