Greenhouse first throw
This commit is contained in:
parent
77890778d4
commit
0cc485577c
@ -65,6 +65,20 @@ 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();
|
||||
}
|
||||
}
|
||||
|
||||
void configPrint() {
|
||||
info("Config (%s):", lastChangeMillis == 0 ? "PERSISTED" : "TRANSIENT");
|
||||
for (JsonPair pair: config.as<JsonObject>()) {
|
||||
|
||||
@ -19,6 +19,10 @@ 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);
|
||||
|
||||
void configPrint();
|
||||
|
||||
#endif
|
||||
|
||||
@ -273,3 +273,24 @@ bool setDouble(const char *name, double *destinationPtr, double min, double max)
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool setUint64_T(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,6 +1,8 @@
|
||||
#ifndef SENSOR3_CONSOLE_H
|
||||
#define SENSOR3_CONSOLE_H
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
void consoleSetup();
|
||||
|
||||
void consoleLoop();
|
||||
@ -13,4 +15,6 @@ void consolePrintUsage();
|
||||
|
||||
bool setDouble(const char *name, double *destinationPtr, double min, double max);
|
||||
|
||||
bool setUint64_T(const char *name, uint64_t *destinationPtr, uint64_t min, uint64_t max);
|
||||
|
||||
#endif
|
||||
|
||||
28
lib/patrix/sensors/DHT.h
Normal file
28
lib/patrix/sensors/DHT.h
Normal file
@ -0,0 +1,28 @@
|
||||
#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
|
||||
22
lib/patrix/sensors/Moisture.h
Normal file
22
lib/patrix/sensors/Moisture.h
Normal file
@ -0,0 +1,22 @@
|
||||
#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
|
||||
78
lib/patrix/sensors/Output.h
Normal file
78
lib/patrix/sensors/Output.h
Normal file
@ -0,0 +1,78 @@
|
||||
#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
|
||||
@ -61,3 +61,18 @@ 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
|
||||
|
||||
187
src/Gewaechshaus/Greenhouse.cpp
Normal file
187
src/Gewaechshaus/Greenhouse.cpp
Normal file
@ -0,0 +1,187 @@
|
||||
#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 patrix_command(char *first) {
|
||||
bool result = false;
|
||||
if (strcmp(first, "tempHigh") == 0 || strcmp(first, "th") == 0) {
|
||||
result = setDouble("tempHigh", &tempHigh, NAN, NAN);
|
||||
} else if (strcmp(first, "tempLow") == 0 || strcmp(first, "tl") == 0) {
|
||||
result = setDouble("tempLow", &tempLow, NAN, NAN);
|
||||
} else if (strcmp(first, "tempMillis") == 0 || strcmp(first, "tm") == 0) {
|
||||
result = setUint64_T("tempMillis", &tempMillis, NAN, NAN);
|
||||
} else if (strcmp(first, "moistHigh") == 0 || strcmp(first, "mh") == 0) {
|
||||
result = setDouble("moistHigh", &moistHigh, NAN, NAN);
|
||||
} else if (strcmp(first, "moistLow") == 0 || strcmp(first, "ml") == 0) {
|
||||
result = setDouble("moistLow", &moistLow, NAN, NAN);
|
||||
} else if (strcmp(first, "moistMillis") == 0 || strcmp(first, "mm") == 0) {
|
||||
result = setUint64_T("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
|
||||
95
src/Gewaechshaus/GreenhouseData.h
Normal file
95
src/Gewaechshaus/GreenhouseData.h
Normal file
@ -0,0 +1,95 @@
|
||||
#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