diff --git a/.gitignore b/.gitignore
index 03f4a3c..03e86a6 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1 +1,2 @@
.pio
+/index.html.min
\ No newline at end of file
diff --git a/icon.svg b/icon.svg
new file mode 100644
index 0000000..5f29574
--- /dev/null
+++ b/icon.svg
@@ -0,0 +1,5 @@
+
+
\ No newline at end of file
diff --git a/index.html b/index.html
new file mode 100644
index 0000000..5b240af
--- /dev/null
+++ b/index.html
@@ -0,0 +1,167 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/Initial.h b/src/Initial.h
index 28427fa..5b81ec0 100644
--- a/src/Initial.h
+++ b/src/Initial.h
@@ -4,15 +4,15 @@
enum Initial {
INITIAL_OFF,
INITIAL_ON,
- INITIAL_BLINK,
+ INITIAL_CYCLE,
};
inline Initial stringToInitial(const String &str) {
if (str == "ON") {
return INITIAL_ON;
}
- if (str == "BLINK") {
- return INITIAL_BLINK;
+ if (str == "CYCLE") {
+ return INITIAL_CYCLE;
}
return INITIAL_OFF;
}
@@ -21,8 +21,8 @@ inline const char *initialToString(const Initial value) {
switch (value) {
case INITIAL_ON:
return "ON";
- case INITIAL_BLINK:
- return "BLINK";
+ case INITIAL_CYCLE:
+ return "CYCLE";
default:
return "OFF";
}
diff --git a/src/Output.h b/src/Output.h
index 87c83e6..0ddcc94 100644
--- a/src/Output.h
+++ b/src/Output.h
@@ -39,7 +39,7 @@ protected:
void _applyInitial() {
_write(initial != INITIAL_OFF);
- if (initial != INITIAL_BLINK) {
+ if (initial != INITIAL_CYCLE) {
onCount = 0;
} else {
onCount = -1;
@@ -72,7 +72,7 @@ public:
set(!get());
}
- void blink(const unsigned long onMillis_, const unsigned long offMillis_, const unsigned long onCount_ = -1) {
+ void cycle(const unsigned long onMillis_, const unsigned long offMillis_, const unsigned long onCount_ = -1) {
this->onMillis = onMillis_;
this->offMillis = offMillis_;
this->onCount = onCount_;
diff --git a/src/config.cpp b/src/config.cpp
index 6bd8ec7..9ca318c 100644
--- a/src/config.cpp
+++ b/src/config.cpp
@@ -26,7 +26,7 @@ bool configWrite(const String &name, const long fallback, const long value) {
if (configRead(name, fallback) == value) {
return false;
}
- Serial.printf("\"%s\" = \"%ld\"", name.c_str(), value);
+ Serial.printf("[CONFIG] \"%s\" = \"%ld\"\n", name.c_str(), value);
if (auto file = configOpen(name, "w")) {
const auto content = String(value);
file.write(reinterpret_cast(content.c_str()), content.length());
@@ -65,7 +65,7 @@ bool configWrite(const String &name, const String &fallback, const String &value
if (configRead(name, fallback) == value) {
return false;
}
- Serial.printf("\"%s\" = \"%s\"", name.c_str(), value.c_str());
+ Serial.printf("[CONFIG] \"%s\" = \"%s\"\n", name.c_str(), value.c_str());
if (auto file = configOpen(name, "w")) {
file.write(reinterpret_cast(value.c_str()), value.length());
file.close();
diff --git a/src/http.cpp b/src/http.cpp
index 76ffbf0..8595eaa 100644
--- a/src/http.cpp
+++ b/src/http.cpp
@@ -2,6 +2,7 @@
#include "io.h"
#include
+#include
#ifdef ESP8266
#include
@@ -18,6 +19,12 @@ WebServer server(80);
bool httpRunning = false;
void httpRelay(const int index, Output &relay) {
+ const auto nameKey = String("name") + index;
+ if (server.hasArg(nameKey)) {
+ const auto name = server.arg(nameKey);
+ relay.setName(name);
+ }
+
const auto stateKey = String("state") + index;
if (server.hasArg(stateKey)) {
const auto state = server.arg(stateKey);
@@ -39,12 +46,19 @@ void httpRelay(const int index, Output &relay) {
} else if (initial == "ON") {
Serial.printf("[HTTP] %s = %s\n", initialKey.c_str(), initial.c_str());
relay.setInitial(INITIAL_ON);
- } else if (initial == "BLINK") {
+ } else if (initial == "CYCLE") {
Serial.printf("[HTTP] %s = %s\n", initialKey.c_str(), initial.c_str());
- relay.setInitial(INITIAL_BLINK);
+ relay.setInitial(INITIAL_CYCLE);
}
}
+ const auto onCountKey = String("onCount") + index;
+ if (server.hasArg(onCountKey)) {
+ const auto value = server.arg(onCountKey).toInt();
+ Serial.printf("[HTTP] %s = %ld\n", onCountKey.c_str(), value);
+ relay.setOnCount(value);
+ }
+
const auto onMillisKey = String("onMillis") + index;
if (server.hasArg(onMillisKey)) {
const auto value = server.arg(onMillisKey).toInt();
@@ -58,13 +72,6 @@ void httpRelay(const int index, Output &relay) {
Serial.printf("[HTTP] %s = %ld\n", offMillisKey.c_str(), value);
relay.setOffMillis(value);
}
-
- const auto onCountKey = String("onCount") + index;
- if (server.hasArg(onCountKey)) {
- const auto value = server.arg(onCountKey).toInt();
- Serial.printf("[HTTP] %s = %ld\n", onCountKey.c_str(), value);
- relay.setOnCount(value);
- }
}
void httpRelayJson(const Output &relay, const JsonObject json) {
@@ -79,12 +86,13 @@ void httpRelayJson(const Output &relay, const JsonObject json) {
void httpStatus() {
JsonDocument json;
- json.to();
+ json["hostname"] = WiFi.getHostname();
- httpRelayJson(relay1, json["relay1"].to());
- httpRelayJson(relay2, json["relay2"].to());
- httpRelayJson(relay3, json["relay3"].to());
- httpRelayJson(relay4, json["relay4"].to());
+ const auto relays = json["relays"].to();
+ httpRelayJson(relay0, relays.add());
+ httpRelayJson(relay1, relays.add());
+ httpRelayJson(relay2, relays.add());
+ httpRelayJson(relay3, relays.add());
String response;
serializeJson(json, response);
@@ -92,27 +100,60 @@ void httpStatus() {
}
void httpSet() {
+ httpRelay(0, relay0);
httpRelay(1, relay1);
httpRelay(2, relay2);
httpRelay(3, relay3);
- httpRelay(4, relay4);
httpStatus();
}
void httpOff() {
+ relay0.set(false);
relay1.set(false);
relay2.set(false);
relay3.set(false);
- relay4.set(false);
httpStatus();
}
+File httpUploadFile;
+
+void httpUpload(const char *name) {
+ const auto upload = server.upload();
+ if (upload.status == UPLOAD_FILE_START) {
+ char path[64];
+ snprintf(path, sizeof(path), "/%s", name);
+ httpUploadFile = LittleFS.open(path, "w");
+ Serial.printf("[HTTP] Uploading: %s\n", name);
+ } else if (upload.status == UPLOAD_FILE_WRITE) {
+ if (httpUploadFile) {
+ httpUploadFile.write(upload.buf, upload.currentSize);
+ }
+ } else if (upload.status == UPLOAD_FILE_END) {
+ if (httpUploadFile) {
+ httpUploadFile.close();
+ Serial.printf("[HTTP] Upload complete: %s (%d bytes)\n", name, upload.currentSize);
+ server.send(200);
+ }
+ }
+}
+
void httpSetup() {
- server.on("", httpSet);
- server.on("/", httpSet);
+ server.enableCORS(true);
+
+ server.serveStatic("", LittleFS, "/index.html");
+ server.serveStatic("/", LittleFS, "/index.html");
+ server.serveStatic("/icon.svg", LittleFS, "/icon.svg");
+
+ server.on("/set", httpSet);
+ server.on("/set/", httpSet);
server.on("/off", httpOff);
server.on("/off/", httpOff);
+
+ server.on("/upload/index", HTTP_POST, [] { server.send(200); }, [] { httpUpload("index.html"); });
+ server.on("/upload/icon", HTTP_POST, [] { server.send(200); }, [] { httpUpload("icon.svg"); });
+
server.begin();
+
Serial.println("HTTP server started");
httpRunning = true;
}
diff --git a/src/io.cpp b/src/io.cpp
index 57b0479..a4067cb 100644
--- a/src/io.cpp
+++ b/src/io.cpp
@@ -8,23 +8,23 @@
#define STATUS_INVERT true
#endif
-Relay relay1(1, "RELAY #1", 12, false, true);
+Relay relay0(1, "RELAY #0", 12, false, true);
-Relay relay2(2, "RELAY #2", 5, false, true);
+Relay relay1(2, "RELAY #1", 5, false, true);
-Relay relay3(3, "RELAY #3", 4, false, true);
+Relay relay2(3, "RELAY #2", 4, false, true);
-Relay relay4(4, "RELAY #4", 15, false, true);
+Relay relay3(4, "RELAY #3", 15, false, true);
Output status("Status", STATUS_PIN, STATUS_INVERT, false);
-Button button1(0, true, true, [](const ButtonEvent event) { buttonCallback(relay1, event); });
+Button button0(0, true, true, [](const ButtonEvent event) { buttonCallback(relay0, event); });
-Button button2(9, true, true, [](const ButtonEvent event) { buttonCallback(relay2, event); });
+Button button1(9, true, true, [](const ButtonEvent event) { buttonCallback(relay1, event); });
-Button button3(10, true, true, [](const ButtonEvent event) { buttonCallback(relay3, event); });
+Button button2(10, true, true, [](const ButtonEvent event) { buttonCallback(relay2, event); });
-Button button4(14, true, true, [](const ButtonEvent event) { buttonCallback(relay4, event); });
+Button button3(14, true, true, [](const ButtonEvent event) { buttonCallback(relay3, event); });
void buttonCallback(Output &output, const ButtonEvent event) {
if (event == BUTTON_PRESSED) {
diff --git a/src/io.h b/src/io.h
index 1a0afad..b3add7c 100644
--- a/src/io.h
+++ b/src/io.h
@@ -6,50 +6,50 @@
void buttonCallback(Output &output, ButtonEvent event);
+extern Relay relay0;
+
extern Relay relay1;
extern Relay relay2;
extern Relay relay3;
-extern Relay relay4;
-
extern Output status;
+extern Button button0;
+
extern Button button1;
extern Button button2;
extern Button button3;
-extern Button button4;
-
inline void ioSetup() {
+ button0.setup();
button1.setup();
button2.setup();
button3.setup();
- button4.setup();
status.setup();
+ relay0.setup();
relay1.setup();
relay2.setup();
relay3.setup();
- relay4.setup();
}
inline void ioLoop() {
+ button0.loop();
button1.loop();
button2.loop();
button3.loop();
- button4.loop();
status.loop();
- relay1.loop();
+ relay0.loop();
+ relay0.loop();
relay2.loop();
relay3.loop();
- relay4.loop();
}
#endif
diff --git a/src/wifi.cpp b/src/wifi.cpp
index 4446b7d..ad057e5 100644
--- a/src/wifi.cpp
+++ b/src/wifi.cpp
@@ -24,7 +24,7 @@ void wifiConnect() {
WiFi.setAutoReconnect(false);
yield();
- status.blink(500, 500);
+ status.cycle(500, 500);
const auto hostname = configRead(CONFIG_HOSTNAME, DEFAULT_HOSTNAME);
const auto wifiSSID = configRead(CONFIG_WIFI_SSID, DEFAULT_WIFI_SSID);
diff --git a/upload.sh b/upload.sh
new file mode 100644
index 0000000..82dd930
--- /dev/null
+++ b/upload.sh
@@ -0,0 +1,8 @@
+#!/bin/bash
+
+cd "$(dirname "$0")" || exit 1
+
+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/icon' -F "file=@icon.svg"
\ No newline at end of file