#include <Freenove_WS2812_Lib_for_ESP32.h>
#include <WiFi.h>
#include <WebServer.h>
#include <ESPmDNS.h>
#include <Update.h>
#include <Ticker.h>
#include "html.h"
#define LEDS_COUNT 16
#define LEDS_PIN 2
#define SWITCH_PIN 0
#define CHANNEL 0
#define SOLAR_PIN 25
Freenove_ESP32_WS2812 strip = Freenove_ESP32_WS2812(LEDS_COUNT, LEDS_PIN, CHANNEL, TYPE_GRB);
WebServer server(80);
Ticker tkSecond;
Ticker debounce;
static uint8_t leds_on = 12;
static uint8_t led_brightness = 200;
uint8_t led_color[3] = {0xFF,0,0};
boolean solar_switch = true;
boolean switch_state = false;
boolean switch_debounce = false;
boolean dirty_bit = false;
const char *authUser = "admin";
const char *authPass = "123456";
const char *csrfHeaders[2] = {"Origin", "Host"};
static bool authenticated = false;
uint8_t otaDone = 0;
void setStrip() {
strip.setBrightness(led_brightness);
for (int i = 0; i < LEDS_COUNT; i++) {
if (i < leds_on && !switch_state) {
strip.setLedColorData(i, led_color[0], led_color[1], led_color[2]);
} else {
strip.setLedColorData(i, 0, 0, 0);
}
}
strip.show();
}
void handleRoot() {
/*
if (!authenticated) {
return server.requestAuthentication();
}
*/
char strcolor[7];
snprintf(strcolor, 7, "%02X%02X%02X", led_color[0], led_color[1], led_color[2]);
char* sendbuf = (char*)malloc(strlen(rootHtml) + 10);
snprintf(sendbuf, strlen(rootHtml) + 10, rootHtml,
LEDS_COUNT, leds_on, led_brightness, strcolor);
server.send(200, "text/html", sendbuf);
free(sendbuf);
}
void handleSet() {
/*
if (!authenticated) {
return server.requestAuthentication();
}
*/
if (server.hasArg("led_color")) {
String ledcol = server.arg("led_color");
sscanf(ledcol.substring(1,3).c_str(), "%x", &led_color[0]);
sscanf(ledcol.substring(3,5).c_str(), "%x", &led_color[1]);
sscanf(ledcol.substring(5,7).c_str(), "%x", &led_color[2]);
}
if (server.hasArg("leds_on")) leds_on = server.arg("leds_on").toInt();
if (server.hasArg("led_brightness")) led_brightness = server.arg("led_brightness").toInt();
setStrip();
//server.sendHeader("Refresh", "1");
server.sendHeader("Location", "/");
server.send(307);
}
void handleUpdateEnd() {
if (!authenticated) {
return server.requestAuthentication();
}
server.sendHeader("Connection", "close");
if (Update.hasError()) {
server.send(502, "text/plain", Update.errorString());
} else {
server.sendHeader("Refresh", "10");
server.sendHeader("Location", "/");
server.send(307);
delay(500);
ESP.restart();
}
}
void handleUpdate() {
size_t fsize = UPDATE_SIZE_UNKNOWN;
if (server.hasArg("size")) {
fsize = server.arg("size").toInt();
}
HTTPUpload &upload = server.upload();
if (upload.status == UPLOAD_FILE_START) {
authenticated = server.authenticate(authUser, authPass);
if (!authenticated) {
Serial.println("Authentication fail!");
otaDone = 0;
return;
}
String origin = server.header(String(csrfHeaders[0]));
String host = server.header(String(csrfHeaders[1]));
String expectedOrigin = String("http://") + host;
if (origin != expectedOrigin) {
Serial.printf("Wrong origin received! Expected: %s, Received: %s\n", expectedOrigin.c_str(), origin.c_str());
authenticated = false;
otaDone = 0;
return;
}
Serial.printf("Receiving Update: %s, Size: %d\n", upload.filename.c_str(), fsize);
if (!Update.begin(fsize)) {
otaDone = 0;
Update.printError(Serial);
}
} else if (authenticated && upload.status == UPLOAD_FILE_WRITE) {
if (Update.write(upload.buf, upload.currentSize) != upload.currentSize) {
Update.printError(Serial);
} else {
otaDone = 100 * Update.progress() / Update.size();
}
} else if (authenticated && upload.status == UPLOAD_FILE_END) {
if (Update.end(true)) {
Serial.printf("Update Success: %u bytes\nRebooting...\n", upload.totalSize);
} else {
Serial.printf("%s\n", Update.errorString());
otaDone = 0;
}
}
}
void webServerInit() {
server.collectHeaders(csrfHeaders, 2);
server.on("/", HTTP_ANY, []() {handleRoot();});
server.on("/set", HTTP_ANY, []() {handleSet();});
server.on("/update", HTTP_POST, []() {handleUpdateEnd();}, []() {handleUpdate();});
server.on("/favicon.ico", HTTP_GET, []() {
server.sendHeader("Content-Encoding", "gzip");
server.send_P(200, "image/x-icon", favicon_ico_gz, favicon_ico_gz_len);
});
server.onNotFound([]() {
if (!server.authenticate(authUser, authPass)) {
return server.requestAuthentication();
}
server.send(200, "text/html", rootHtml);
});
server.begin();
Serial.printf("Web Server ready at http://esp32.local or http://%s\n", WiFi.localIP().toString().c_str());
}
void everySecond() {
if (solar_switch && (millis() / 1000) % 5 == 0) {
uint32_t sunsum = 0;
for (int x = 0; x< 8; x++) {
sunsum += analogRead(25);
}
Serial.printf("sun: %lu\n", sunsum);
if (sunsum > 31000) {
switch_state = true;
dirty_bit = true;
}
if (sunsum < 27000) {
switch_state = false;
dirty_bit = true;
}
}
if (dirty_bit) {
dirty_bit = false;
setStrip();
}
if (otaDone > 1) {
Serial.printf("ota: %d%%\n", otaDone);
}
}
void IRAM_ATTR resetSwitch() {
switch_debounce = false;
}
void IRAM_ATTR switchInt() {
if (! switch_debounce) {
switch_debounce = true;
debounce.once_ms(300, resetSwitch);
switch_state = !switch_state;
dirty_bit = true;
}
}
void setup() {
Serial.begin(115200);
strip.begin();
setStrip();
pinMode(SWITCH_PIN, INPUT_PULLUP);
attachInterrupt(SWITCH_PIN, switchInt, FALLING);
tkSecond.attach(1, everySecond);
/*
WiFi.begin("Wokwi-GUEST","");
WiFi.waitForConnectResult();
webServerInit();
*/
}
void loop() {
//server.handleClient();
delay(10);
}