Sonoff4ChPro/src/Relay.h

215 lines
6.0 KiB
C++

#ifndef RELAY_H
#define RELAY_H
#include "config.h"
#include "Output.h"
#include "mqtt.h"
class Relay final : public Output {
String nameFallback;
String topicFallback;
const uint8_t index;
String topic;
bool gridPowerDeltaOffEnabled = false;
long gridPowerDeltaOnThreshold = 0;
long gridPowerDeltaOnDelay = 0;
bool gridPowerDeltaOnEnabled = false;
long gridPowerDeltaOffThreshold = 0;
long gridPowerDeltaOffDelay = 0;
unsigned long gridPowerDeltaLast = 0;
public:
Relay(const uint8_t index, const String &topic, const char *name, const uint8_t pin, const bool inverted, const bool logState) : Output(name, pin, inverted, logState), nameFallback(name), topicFallback(topic), index(index), topic(topic) {
//
}
void setup() override {
Output::setup();
Output::setName(loadString(path("name"), nameFallback));
Output::setInitial(loadInitial(path("initial"), INITIAL_OFF));
Output::setOnMillis(loadLong(path("onMillis"), 0L));
Output::setOffMillis(loadLong(path("offMillis"), 0L));
topic = loadString(path("topic"), topicFallback);
gridPowerDeltaOnEnabled = loadBool(path("gridPowerDeltaOnEnabled"), false);
gridPowerDeltaOnThreshold = loadLong(path("gridPowerDeltaOnThreshold"), 0L);
gridPowerDeltaOnDelay = loadLong(path("gridPowerDeltaOnDelay"), 0L);
gridPowerDeltaOffEnabled = loadBool(path("gridPowerDeltaOffEnabled"), false);
gridPowerDeltaOffThreshold = loadLong(path("gridPowerDeltaOffThreshold"), 0L);
gridPowerDeltaOffDelay = loadLong(path("gridPowerDeltaOffDelay"), 0L);
_applyInitial();
}
void loop() override {
Output::loop();
doGridPowerDelta();
}
void setName(const String &value) override {
Output::setName(value);
storeString(path("name"), nameFallback, value);
}
void setInitial(const Initial value) override {
Output::setInitial(value);
storeInitial(path("initial"), INITIAL_OFF, value);
}
void setOnMillis(const unsigned long value) override {
Output::setOnMillis(value);
storeLong(path("onMillis"), 0L, value);
}
void setOffMillis(const unsigned long value) override {
Output::setOffMillis(value);
storeLong(path("offMillis"), 0L, value);
}
void setTopic(const String &value) {
topic = value;
storeString(path("topic"), topicFallback, value);
}
void setGridPowerDeltaOnEnabled(const bool value) {
gridPowerDeltaOnEnabled = value;
storeBool(path("gridPowerDeltaOnEnabled"), false, value);
}
void setGridPowerDeltaOnThreshold(const long value) {
gridPowerDeltaOnThreshold = value;
storeLong(path("gridPowerDeltaOnThreshold"), 0L, value);
}
void setGridPowerDeltaOnDelay(const long value) {
gridPowerDeltaOnDelay = value;
storeLong(path("gridPowerDeltaOnDelay"), 0L, value);
}
void setGridPowerDeltaOffEnabled(const bool value) {
gridPowerDeltaOffEnabled = value;
storeBool(path("gridPowerDeltaOffEnabled"), false, value);
}
void setGridPowerDeltaOffThreshold(const long value) {
gridPowerDeltaOffThreshold = value;
storeLong(path("gridPowerDeltaOffThreshold"), 0L, value);
}
void setGridPowerDeltaOffDelay(const long value) {
gridPowerDeltaOffDelay = value;
storeLong(path("gridPowerDeltaOffDelay"), 0L, value);
}
void json(const JsonObject json) const {
json["name"] = name;
json["initial"] = initialToString(initial);
json["onCount"] = onCount;
json["onMillis"] = onMillis;
json["offMillis"] = offMillis;
json["topic"] = topic;
json["gridPowerDeltaOffEnabled"] = gridPowerDeltaOffEnabled;
json["gridPowerDeltaOnThreshold"] = gridPowerDeltaOnThreshold;
json["gridPowerDeltaOnDelay"] = gridPowerDeltaOnDelay;
json["gridPowerDeltaOnEnabled"] = gridPowerDeltaOnEnabled;
json["gridPowerDeltaOffThreshold"] = gridPowerDeltaOffThreshold;
json["gridPowerDeltaOffDelay"] = gridPowerDeltaOffDelay;
json["state"] = get();
json["stateAgeMillis"] = millis() - stateMillis;
}
void set(const bool state) override {
Output::set(state);
gridPowerDeltaLast = 0;
}
protected:
void publish() override {
JsonDocument doc;
json(doc.to<JsonObject>());
mqttPublish(topic, doc);
}
private:
String path(const char *name) const {
char path[64];
snprintf(path, sizeof(path), "/relay%d/%s", index, name);
return String(path);
}
void doGridPowerDelta() {
if (get()) {
gridPowerDeltaOff();
} else {
gridPowerDeltaOn();
}
}
bool gridPowerDeltaConfigInvalid() {
return gridPowerDeltaOffThreshold < gridPowerDeltaOnThreshold;
}
void gridPowerDeltaOff() {
if (!gridPowerDeltaOffEnabled) {
return;
}
const auto invalid = isnan(gridPowerDeltaValue) || millis() - gridPowerDeltaMillis > 10000 || gridPowerDeltaConfigInvalid();
if (gridPowerDeltaValue > gridPowerDeltaOffThreshold || invalid) {
if (gridPowerDeltaLast == 0 && gridPowerDeltaOffDelay > 0) {
Serial.printf("[RELAY] \"%s\": CONSUMING TOO MUCH: Preparing to power OFF...\n", name.c_str());
gridPowerDeltaLast = max(1UL, millis());
} else {
if (millis() - gridPowerDeltaLast > gridPowerDeltaOffDelay) {
set(false);
}
}
} else if (gridPowerDeltaLast > 0) {
Serial.printf("[RELAY] \"%s\": Powering off CANCELED!\n", name.c_str());
gridPowerDeltaLast = 0;
}
}
void gridPowerDeltaOn() {
if (!gridPowerDeltaOnEnabled) {
return;
}
if (gridPowerDeltaValue < gridPowerDeltaOnThreshold && !gridPowerDeltaConfigInvalid()) {
if (gridPowerDeltaLast == 0 && gridPowerDeltaOnDelay > 0) {
Serial.printf("[RELAY] \"%s\": PRODUCING TOO MUCH: Preparing to power ON...\n", name.c_str());
gridPowerDeltaLast = max(1UL, millis());
} else {
if (millis() - gridPowerDeltaLast > gridPowerDeltaOnDelay) {
set(true);
}
}
} else if (gridPowerDeltaLast > 0) {
Serial.printf("[RELAY] \"%s\": Powering on CANCELED!\n", name.c_str());
gridPowerDeltaLast = 0;
}
}
};
#endif