Compare commits
5 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| ba48154940 | |||
| aa357b224b | |||
| a31521cdfe | |||
| f1896d5c54 | |||
| 1cbb33600a |
41
src/Property.h
Normal file
41
src/Property.h
Normal file
@ -0,0 +1,41 @@
|
||||
#ifndef PROPERTY_H
|
||||
#define PROPERTY_H
|
||||
|
||||
#include <LittleFS.h>
|
||||
|
||||
template<class T>
|
||||
class Property {
|
||||
|
||||
public:
|
||||
|
||||
const String path;
|
||||
|
||||
T fallback;
|
||||
|
||||
void load() {
|
||||
String content = "";
|
||||
if (auto file = LittleFS.open(path, "r")) {
|
||||
content = file.readString();
|
||||
file.close();
|
||||
}
|
||||
value = toValue(content);
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
T value;
|
||||
|
||||
explicit Property(const String &path, const T fallback)
|
||||
: path(path),
|
||||
fallback(fallback),
|
||||
value(fallback) {
|
||||
//
|
||||
}
|
||||
|
||||
virtual ~Property() = default;
|
||||
|
||||
virtual T toValue(const String &content) =0;
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
34
src/PropertyBool.h
Normal file
34
src/PropertyBool.h
Normal file
@ -0,0 +1,34 @@
|
||||
#ifndef PROPERTY_BOOL_H
|
||||
#define PROPERTY_BOOL_H
|
||||
|
||||
#include <Property.h>
|
||||
|
||||
class PropertyBool final : public Property<bool> {
|
||||
|
||||
public:
|
||||
|
||||
PropertyBool(const String &name, const bool fallback)
|
||||
: Property(name, fallback) {
|
||||
//
|
||||
}
|
||||
|
||||
// ReSharper disable once CppNonExplicitConversionOperator
|
||||
operator bool() const {
|
||||
return value;
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
bool toValue(const String &content) override {
|
||||
if (content == "true") {
|
||||
return true;
|
||||
}
|
||||
if (content == "false") {
|
||||
return false;
|
||||
}
|
||||
return fallback;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
28
src/PropertyLong.h
Normal file
28
src/PropertyLong.h
Normal file
@ -0,0 +1,28 @@
|
||||
#ifndef PROPERTY_LONG_H
|
||||
#define PROPERTY_LONG_H
|
||||
|
||||
#include <Property.h>
|
||||
|
||||
class PropertyLong final : public Property<long> {
|
||||
|
||||
public:
|
||||
|
||||
PropertyLong(const String &name, const long fallback)
|
||||
: Property(name, fallback) {
|
||||
//
|
||||
}
|
||||
|
||||
// ReSharper disable once CppNonExplicitConversionOperator
|
||||
operator long() const {
|
||||
return value;
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
long toValue(const String &content) override {
|
||||
return content.toInt();
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
169
src/Relay2.h
Normal file
169
src/Relay2.h
Normal file
@ -0,0 +1,169 @@
|
||||
#ifndef RELAY2_H
|
||||
#define RELAY2_H
|
||||
|
||||
#include <Arduino.h>
|
||||
|
||||
#include "log.h"
|
||||
#include "PropertyBool.h"
|
||||
#include "PropertyLong.h"
|
||||
|
||||
class Relay2 {
|
||||
|
||||
bool state = false;
|
||||
|
||||
unsigned long stateSince = 0;
|
||||
|
||||
unsigned long manualSince = 0;
|
||||
|
||||
public:
|
||||
|
||||
const int index;
|
||||
|
||||
const int pin;
|
||||
|
||||
const bool inverted;
|
||||
|
||||
String prefix;
|
||||
|
||||
PropertyBool initialState;
|
||||
|
||||
PropertyBool maxOnEnabled;
|
||||
|
||||
PropertyLong maxOnSeconds;
|
||||
|
||||
PropertyBool maxOffEnabled;
|
||||
|
||||
PropertyLong maxOffSeconds;
|
||||
|
||||
PropertyBool buttonOnEnabled;
|
||||
|
||||
PropertyLong buttonOnSeconds;
|
||||
|
||||
PropertyBool buttonOffEnabled;
|
||||
|
||||
PropertyLong buttonOffSeconds;
|
||||
|
||||
PropertyBool powerOnEnabled;
|
||||
|
||||
PropertyLong powerOnThreshold;
|
||||
|
||||
PropertyLong powerOnSeconds;
|
||||
|
||||
PropertyBool powerOffEnabled;
|
||||
|
||||
PropertyLong powerOffThreshold;
|
||||
|
||||
PropertyLong powerOffSeconds;
|
||||
|
||||
Relay2(const int index, const int pin, const bool inverted)
|
||||
: index(index),
|
||||
pin(pin),
|
||||
inverted(inverted),
|
||||
prefix("/relay" + String(index)),
|
||||
initialState(prefix + "initialState", false),
|
||||
maxOnEnabled(prefix + "maxOnEnabled", false),
|
||||
maxOnSeconds(prefix + "maxOnSeconds", 0),
|
||||
maxOffEnabled(prefix + "maxOffEnabled", false),
|
||||
maxOffSeconds(prefix + "maxOffSeconds", 0),
|
||||
buttonOnEnabled(prefix + "buttonOnEnabled", false),
|
||||
buttonOnSeconds(prefix + "buttonOnSeconds", 0),
|
||||
buttonOffEnabled(prefix + "buttonOffEnabled", false),
|
||||
buttonOffSeconds(prefix + "buttonOffSeconds", 0),
|
||||
powerOnEnabled(prefix + "powerOnEnabled", false),
|
||||
powerOnThreshold(prefix + "powerOnThreshold", 0),
|
||||
powerOnSeconds(prefix + "powerOnSeconds", 0),
|
||||
powerOffEnabled(prefix + "powerOffEnabled", false),
|
||||
powerOffThreshold(prefix + "powerOffThreshold", 0),
|
||||
powerOffSeconds(prefix + "powerOffSeconds", 0) {
|
||||
//
|
||||
}
|
||||
|
||||
void setup() {
|
||||
pinMode(pin, OUTPUT);
|
||||
|
||||
load();
|
||||
|
||||
state = !initialState;
|
||||
setState(initialState, false);
|
||||
}
|
||||
|
||||
void loop() {
|
||||
const auto stateAge = millis() - stateSince;
|
||||
loopMax(stateAge);
|
||||
if (manualSince > 0) {
|
||||
loopManual(stateAge);
|
||||
} else {
|
||||
loopPower(stateAge);
|
||||
}
|
||||
}
|
||||
|
||||
bool getState() const {
|
||||
return state;
|
||||
}
|
||||
|
||||
void setManual(const bool newState) {
|
||||
setState(newState, false);
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
void setState(const bool newState, const bool manual) {
|
||||
if (manual) {
|
||||
manualSince = max(1UL, millis());
|
||||
} else {
|
||||
manualSince = 0;
|
||||
}
|
||||
if (state != newState) {
|
||||
info("[RELAY%d] %s", index, state ? "ON" : "OFF");
|
||||
state = newState;
|
||||
stateSince = millis();
|
||||
digitalWrite(pin, state ^ inverted ? HIGH : LOW);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
void loopMax(const long stateAge) {
|
||||
if (state && maxOnEnabled && maxOnSeconds && stateAge >= maxOnSeconds) {
|
||||
setState(false, false);
|
||||
}
|
||||
if (!state && maxOffEnabled && maxOffSeconds && stateAge >= maxOffSeconds) {
|
||||
setState(true, false);
|
||||
}
|
||||
}
|
||||
|
||||
void loopManual(const long stateAge) {
|
||||
if (state && buttonOnEnabled && buttonOnSeconds && stateAge >= buttonOnSeconds) {
|
||||
setState(false, false);
|
||||
}
|
||||
if (!state && buttonOffEnabled && buttonOffSeconds && stateAge >= buttonOffSeconds) {
|
||||
setState(true, false);
|
||||
}
|
||||
}
|
||||
|
||||
void loopPower(const long stateAge) {
|
||||
const auto valid = !isnan(gridPowerDeltaValue) && millis() - gridPowerDeltaMillis <= 10000;
|
||||
// TODO
|
||||
}
|
||||
|
||||
void load() {
|
||||
initialState.load();
|
||||
maxOnEnabled.load();
|
||||
maxOnSeconds.load();
|
||||
maxOffEnabled.load();
|
||||
maxOffSeconds.load();
|
||||
buttonOnEnabled.load();
|
||||
buttonOnSeconds.load();
|
||||
buttonOffEnabled.load();
|
||||
buttonOffSeconds.load();
|
||||
powerOnEnabled.load();
|
||||
powerOnThreshold.load();
|
||||
powerOnSeconds.load();
|
||||
powerOffEnabled.load();
|
||||
powerOffThreshold.load();
|
||||
powerOffSeconds.load();
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
3
src/io.h
3
src/io.h
@ -3,6 +3,7 @@
|
||||
|
||||
#include "Relay.h"
|
||||
#include "Button.h"
|
||||
#include "Relay2.h"
|
||||
|
||||
void buttonCallback(Output &output, ButtonEvent event);
|
||||
|
||||
@ -10,6 +11,8 @@ extern Output status;
|
||||
|
||||
extern Button button0;
|
||||
|
||||
extern Relay2 relay99;
|
||||
|
||||
extern Relay relay0;
|
||||
|
||||
#ifdef SP111
|
||||
|
||||
13
src/log.cpp
Normal file
13
src/log.cpp
Normal file
@ -0,0 +1,13 @@
|
||||
#include "log.h"
|
||||
|
||||
#include <HardwareSerial.h>
|
||||
#include <cstdio>
|
||||
|
||||
void info(const char *format, ...) {
|
||||
char message[512];
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
vsnprintf(message, sizeof(message), format, args);
|
||||
Serial.println(message);
|
||||
va_end(args);
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user