Compare commits

..

7 Commits

11 changed files with 390 additions and 63 deletions

View File

@ -6,68 +6,99 @@ build.filesystem = littlefs
lib_deps = bblanchon/ArduinoJson @ 7.4.2 lib_deps = bblanchon/ArduinoJson @ 7.4.2
knolleary/PubSubClient knolleary/PubSubClient
[Sonoff4ChPro] [ESP8285]
platform = espressif8266 platform = espressif8266
board = esp8285 board = esp8285
build_flags = -D Sonoff4ChPro -D WIFI_HOSTNAME_FALLBACK=\"PatrixSonoff4ChPro\" framework = ${common.framework}
upload_speed = ${common.upload_speed}
monitor_speed = ${common.monitor_speed}
build.filesystem = ${common.build.filesystem}
lib_deps = ${common.lib_deps}
board_build.ldscript = eagle.flash.1m64.ld
[GosundSP111] [Ch4Pro]
platform = espressif8266 platform = ${ESP8285.platform}
board = esp8285 board = ${ESP8285.board}
build_flags = -D GosundSP111 -D WIFI_HOSTNAME_FALLBACK=\"PatrixGosundSP111\" framework = ${ESP8285.framework}
upload_speed = ${ESP8285.upload_speed}
monitor_speed = ${ESP8285.monitor_speed}
build.filesystem = ${ESP8285.build.filesystem}
lib_deps = ${ESP8285.lib_deps}
board_build.ldscript = ${ESP8285.board_build.ldscript}
build_flags = -D Ch4Pro
[SP111]
platform = ${ESP8285.platform}
board = ${ESP8285.board}
framework = ${ESP8285.framework}
upload_speed = ${ESP8285.upload_speed}
monitor_speed = ${ESP8285.monitor_speed}
build.filesystem = ${ESP8285.build.filesystem}
lib_deps = ${ESP8285.lib_deps}
board_build.ldscript = ${ESP8285.board_build.ldscript}
build_flags = -D SP111
[ESP32_TEST] [ESP32_TEST]
platform = espressif32 platform = espressif32
board = esp32dev board = esp32dev
framework = ${common.framework}
upload_speed = ${common.upload_speed}
monitor_speed = ${common.monitor_speed}
build_type = debug build_type = debug
debug_tool = esp-prog debug_tool = esp-prog
monitor_filters = esp32_exception_decoder monitor_filters = esp32_exception_decoder
build.filesystem = ${common.build.filesystem}
lib_deps = ${common.lib_deps}
build_flags = -D ESP32_TESTBOARD -D CORE_DEBUG_LEVEL=0 build_flags = -D ESP32_TESTBOARD -D CORE_DEBUG_LEVEL=0
[env:Sonoff4ChPro] [env:ESP32_Ch4Pro]
platform = ${Sonoff4ChPro.platform} platform = ${ESP32_TEST.platform}
board = ${Sonoff4ChPro.board} board = ${ESP32_TEST.board}
framework = ${common.framework} framework = ${ESP32_TEST.framework}
upload_speed = ${common.upload_speed} upload_speed = ${ESP32_TEST.upload_speed}
monitor_speed = ${common.monitor_speed} monitor_speed = ${ESP32_TEST.monitor_speed}
build.filesystem = ${common.build.filesystem} build_type = ${ESP32_TEST.build_type}
lib_deps = ${common.lib_deps} debug_tool = ${ESP32_TEST.debug_tool}
monitor_filters = ${ESP32_TEST.monitor_filters}
build.filesystem = ${ESP32_TEST.build.filesystem}
lib_deps = ${ESP32_TEST.lib_deps}
build_flags = ${Ch4Pro.build_flags} -D WIFI_HOSTNAME_FALLBACK=\"ESP32_Test_Ch4Pro\" ${ESP32_TEST.build_flags}
[env:ESP32_SP111]
platform = ${ESP32_TEST.platform}
board = ${ESP32_TEST.board}
framework = ${ESP32_TEST.framework}
upload_speed = ${ESP32_TEST.upload_speed}
monitor_speed = ${ESP32_TEST.monitor_speed}
build_type = ${ESP32_TEST.build_type}
debug_tool = ${ESP32_TEST.debug_tool}
monitor_filters = ${ESP32_TEST.monitor_filters}
build.filesystem = ${ESP32_TEST.build.filesystem}
lib_deps = ${ESP32_TEST.lib_deps}
build_flags = ${SP111.build_flags} -D WIFI_HOSTNAME_FALLBACK=\"ESP32_Test_SP111\" ${ESP32_TEST.build_flags}
[env:Gewaechshaus]
platform = ${Ch4Pro.platform}
board = ${Ch4Pro.board}
framework = ${Ch4Pro.framework}
upload_speed = ${Ch4Pro.upload_speed}
monitor_speed = ${Ch4Pro.monitor_speed}
build.filesystem = ${Ch4Pro.build.filesystem}
lib_deps = ${Ch4Pro.lib_deps}
board_build.ldscript = ${Ch4Pro.board_build.ldscript}
build_flags = ${Ch4Pro.build_flags} -D WIFI_HOSTNAME_FALLBACK=\"Gewaechshaus\"
upload_protocol = espota upload_protocol = espota
upload_port = 10.0.0.178 upload_port = 10.0.0.178
build_flags = ${Sonoff4ChPro.build_flags}
[env:Sonoff4ChPro_ESP32] [env:Infrarotheizung]
platform = ${ESP32_TEST.platform} platform = ${SP111.platform}
board = ${ESP32_TEST.board} board = ${SP111.board}
framework = ${common.framework} framework = ${SP111.framework}
upload_speed = ${common.upload_speed} upload_speed = ${SP111.upload_speed}
monitor_speed = ${common.monitor_speed} monitor_speed = ${SP111.monitor_speed}
build_type = ${ESP32_TEST.build_type} build.filesystem = ${SP111.build.filesystem}
debug_tool = ${ESP32_TEST.debug_tool} lib_deps = ${SP111.lib_deps}
monitor_filters = ${ESP32_TEST.monitor_filters} board_build.ldscript = ${SP111.board_build.ldscript}
build.filesystem = ${common.build.filesystem} build_flags = ${SP111.build_flags} -D WIFI_HOSTNAME_FALLBACK=\"Infrarotheizung\"
lib_deps = ${common.lib_deps} upload_protocol = espota
build_flags = ${Sonoff4ChPro.build_flags} ${ESP32_TEST.build_flags} upload_port = 10.0.0.179
[env:GosundSP111]
platform = ${GosundSP111.platform}
board = ${GosundSP111.board}
framework = ${common.framework}
upload_speed = ${common.upload_speed}
monitor_speed = ${common.monitor_speed}
build.filesystem = ${common.build.filesystem}
lib_deps = ${common.lib_deps}
build_flags = ${GosundSP111.build_flags}
[env:GosundSP111_ESP32]
platform = ${ESP32_TEST.platform}
board = ${ESP32_TEST.board}
framework = ${common.framework}
upload_speed = ${common.upload_speed}
monitor_speed = ${common.monitor_speed}
build_type = ${ESP32_TEST.build_type}
debug_tool = ${ESP32_TEST.debug_tool}
monitor_filters = ${ESP32_TEST.monitor_filters}
build.filesystem = ${common.build.filesystem}
lib_deps = ${common.lib_deps}
build_flags = ${GosundSP111.build_flags} ${ESP32_TEST.build_flags}

41
src/Property.h Normal file
View 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
View 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
View 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
View 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

View File

@ -95,7 +95,7 @@ void httpStatus() {
const auto relays = json["relays"].to<JsonArray>(); const auto relays = json["relays"].to<JsonArray>();
relay0.json(relays.add<JsonObject>()); relay0.json(relays.add<JsonObject>());
#ifdef Sonoff4ChPro #ifdef Ch4Pro
relay1.json(relays.add<JsonObject>()); relay1.json(relays.add<JsonObject>());
relay2.json(relays.add<JsonObject>()); relay2.json(relays.add<JsonObject>());
relay3.json(relays.add<JsonObject>()); relay3.json(relays.add<JsonObject>());
@ -117,7 +117,7 @@ void httpSet() {
httpString("mqttPassword", mqttSetPassword); httpString("mqttPassword", mqttSetPassword);
httpRelay(0, relay0); httpRelay(0, relay0);
#ifdef Sonoff4ChPro #ifdef Ch4Pro
httpRelay(1, relay1); httpRelay(1, relay1);
httpRelay(2, relay2); httpRelay(2, relay2);
httpRelay(3, relay3); httpRelay(3, relay3);

View File

@ -1,6 +1,6 @@
#include "io.h" #include "io.h"
#ifdef GosundSP111 #ifdef SP111
#ifndef ESP32_TESTBOARD #ifndef ESP32_TESTBOARD
#define STATUS_PIN 0 #define STATUS_PIN 0
@ -11,13 +11,13 @@ Button button0(13, true, true, [](const ButtonEvent event) { buttonCallback(rela
Relay relay0(0, "fallback/relay0", "RELAY #0", 15, false, true); Relay relay0(0, "fallback/relay0", "RELAY #0", 15, false, true);
#ifdef GosundSP111 #ifdef SP111
Output relay0Led("relay0Led", 2, true, false); Output relay0Led("relay0Led", 2, true, false);
#endif #endif
#endif #endif
#ifdef Sonoff4ChPro #ifdef Ch4Pro
#ifndef ESP32_TESTBOARD #ifndef ESP32_TESTBOARD
#define STATUS_PIN 13 #define STATUS_PIN 13

View File

@ -3,6 +3,7 @@
#include "Relay.h" #include "Relay.h"
#include "Button.h" #include "Button.h"
#include "Relay2.h"
void buttonCallback(Output &output, ButtonEvent event); void buttonCallback(Output &output, ButtonEvent event);
@ -10,13 +11,15 @@ extern Output status;
extern Button button0; extern Button button0;
extern Relay2 relay99;
extern Relay relay0; extern Relay relay0;
#ifdef GosundSP111 #ifdef SP111
extern Output relay0Led; extern Output relay0Led;
#endif #endif
#ifdef Sonoff4ChPro #ifdef Ch4Pro
extern Button button1; extern Button button1;
@ -36,10 +39,10 @@ inline void ioSetup() {
status.setup(); status.setup();
button0.setup(); button0.setup();
relay0.setup(); relay0.setup();
#ifdef GosundSP111 #ifdef SP111
relay0Led.setup(); relay0Led.setup();
#endif #endif
#ifdef Sonoff4ChPro #ifdef Ch4Pro
button1.setup(); button1.setup();
button2.setup(); button2.setup();
button3.setup(); button3.setup();
@ -53,11 +56,11 @@ inline void ioLoop() {
status.loop(); status.loop();
button0.loop(); button0.loop();
relay0.loop(); relay0.loop();
#ifdef GosundSP111 #ifdef SP111
relay0Led.set(relay0.get()); relay0Led.set(relay0.get());
relay0Led.loop(); relay0Led.loop();
#endif #endif
#ifdef Sonoff4ChPro #ifdef Ch4Pro
button1.loop(); button1.loop();
button2.loop(); button2.loop();
button3.loop(); button3.loop();

13
src/log.cpp Normal file
View 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);
}

6
src/log.h Normal file
View File

@ -0,0 +1,6 @@
#ifndef LOG_H
#define LOG_H
void info(const char *format, ...);
#endif

View File

@ -7,8 +7,10 @@ minify index.html | sed 's|http://10.42.0.204||g' > index.html.min || exit 2
#curl -s 'http://10.42.0.204/upload/index' -F "file=@index.html.min" #curl -s 'http://10.42.0.204/upload/index' -F "file=@index.html.min"
#curl -s 'http://10.42.0.204/upload/icon' -F "file=@icon.svg" #curl -s 'http://10.42.0.204/upload/icon' -F "file=@icon.svg"
#curl -s 'http://10.0.0.178/upload/index' -F "file=@index.html.min" # Greenhouse
curl -s 'http://10.0.0.178/upload/index' -F "file=@index.html.min"
#curl -s 'http://10.0.0.178/upload/icon' -F "file=@icon.svg" #curl -s 'http://10.0.0.178/upload/icon' -F "file=@icon.svg"
curl -s 'http://10.0.0.179/upload/index' -F "file=@index.html.min" # InfraredHeater
#curl -s 'http://10.0.0.179/upload/index' -F "file=@index.html.min"
#curl -s 'http://10.0.0.179/upload/icon' -F "file=@icon.svg" #curl -s 'http://10.0.0.179/upload/icon' -F "file=@icon.svg"