#include #include #include #include #include #include #include "Config.ino" #include #include // Globale Deklarationen für alle Tabs ESP8266WebServer server(80); const byte DNS_PORT = 53; DNSServer dnsServer; String sketchName() { // Dateiname für den Admin Tab ab EspCoreVersion 2.6.0 char file[sizeof(__FILE__)] = __FILE__; char * pos = strrchr(file, '.'); *pos = '\0'; return file; } #define AMOUNTOFPORTS 16 // currently max 16 ports are supported #define EXPANDER1ADDRESS 0x21 // address of expander 1 struct PortConfig { String name; bool enabled; }; PCF8575 expander1(EXPANDER1ADDRESS); uint8_t portStates[AMOUNTOFPORTS]; uint8_t lastStates[AMOUNTOFPORTS] = {0}; PortConfig portConfigs[AMOUNTOFPORTS]; byte number=0; extern Adafruit_NeoPixel* pixels; void loadPortConfig() { File file = LittleFS.open("/portconfig.json", "r"); if (file) { DynamicJsonDocument doc(1024); DeserializationError error = deserializeJson(doc, file); file.close(); if (!error) { JsonArray ports = doc["ports"]; for (size_t i = 0; i < AMOUNTOFPORTS && i < ports.size(); i++) { portConfigs[i].name = ports[i]["name"] | ("Port " + String(i)); portConfigs[i].enabled = ports[i]["enabled"] | true; } } else { // Default for (int i = 0; i < AMOUNTOFPORTS; i++) { portConfigs[i].name = "Port " + String(i); portConfigs[i].enabled = true; } } } else { // Default all enabled for (int i = 0; i < AMOUNTOFPORTS; i++) { portConfigs[i].name = "Port " + String(i); portConfigs[i].enabled = true; } } } void savePortConfig() { DynamicJsonDocument doc(1024); JsonArray ports = doc.createNestedArray("ports"); for (int i = 0; i < AMOUNTOFPORTS; i++) { JsonObject port = ports.createNestedObject(); port["name"] = portConfigs[i].name; port["enabled"] = portConfigs[i].enabled; } File file = LittleFS.open("/portconfig.json", "w"); if (file) { serializeJson(doc, file); file.close(); } } void setup() { Serial.begin(SERIAL_SPEED); delay(100); Serial.printf("\nSketchname: %s\nBuild: %s\t\tIDE: %d.%d.%d\n%s\n\n", (__FILE__), (__TIMESTAMP__), ARDUINO / 10000, ARDUINO % 10000 / 100, ARDUINO % 100 / 10 ? ARDUINO % 100 : ARDUINO % 10, ESP.getFullVersion().c_str()); Serial.printf("\nKeyPatch ESP8266 WebServer\n"); //Set UP 12C Communication Wire.begin(); for (byte adress=8; adress<120; adress++) { Wire.beginTransmission(adress); if (Wire.endTransmission()==0) { Serial.print(number+1); Serial.print(". Device: 0x"); Serial.println(adress, HEX); number++; } } Serial.print (number, DEC); Serial.println (" device(s) found."); //Setup CPF Expander Serial.print("Expander 1 at "); Serial.print(EXPANDER1ADDRESS,HEX); if (!expander1.begin()) { Serial.println(" could not initialize..."); } if (!expander1.isConnected()) { Serial.println(" => not connected"); } else { Serial.println(" => connected!!"); } //Setup NeoPixel NeoPixel_init(AMOUNTOFPORTS); // Initialisierung der NeoPixel for (uint8_t i = 0; i < AMOUNTOFPORTS; i++) { portStates[i] = 0; lastStates[i] = 0; pixels->setPixelColor(i, pixels->Color(0, 0, 0)); // aus }; pixels->show(); // SetUp WebServer setupFS(); // setupFS(); oder spiffs(); je nach Dateisystem loadPortConfig(); // Lade Port-Konfiguration connectWifi(); admin(); ArduinoOTA.onStart([]() { //save(); // Wenn Werte vor dem Neustart gespeichert werden sollen }); ArduinoOTA.begin(); server.begin(); // Handler für Port-Konfiguration server.on("/portconfig", HTTP_GET, []() { File file = LittleFS.open("/html/portconfig.html", "r"); if (file) { server.streamFile(file, "text/html"); file.close(); } else { server.send(404, "text/plain", "File not found"); } }); server.on("/portconfig/data", HTTP_GET, []() { DynamicJsonDocument doc(1024); JsonArray ports = doc.createNestedArray("ports"); for (int i = 0; i < AMOUNTOFPORTS; i++) { JsonObject port = ports.createNestedObject(); port["name"] = portConfigs[i].name; port["enabled"] = portConfigs[i].enabled; } String json; serializeJson(doc, json); server.send(200, "application/json", json); }); server.on("/portconfig", HTTP_POST, []() { DynamicJsonDocument doc(1024); DeserializationError error = deserializeJson(doc, server.arg("plain")); if (!error) { JsonArray ports = doc["ports"]; for (size_t i = 0; i < AMOUNTOFPORTS && i < ports.size(); i++) { portConfigs[i].name = ports[i]["name"] | ("Port " + String(i)); portConfigs[i].enabled = ports[i]["enabled"] | true; } savePortConfig(); } server.sendHeader("Location", "/portconfig"); server.send(303); }); // Handler für Startseite server.on("/", HTTP_GET, []() { File file = LittleFS.open("/index.html", "r"); if (file) { server.streamFile(file, "text/html"); file.close(); } else { server.send(404, "text/plain", "File not found"); } }); // Handler für Status-Daten server.on("/status/data", HTTP_GET, []() { DynamicJsonDocument doc(1024); JsonArray ports = doc.createNestedArray("ports"); for (int i = 0; i < AMOUNTOFPORTS; i++) { JsonObject port = ports.createNestedObject(); port["name"] = portConfigs[i].name; port["enabled"] = portConfigs[i].enabled; port["state"] = portStates[i]; } String json; serializeJson(doc, json); server.send(200, "application/json", json); }); Serial.println("Setup End..."); } void loop() { ArduinoOTA.handle(); server.handleClient(); if (millis() < 0x2FFF || millis() > 0xFFFFF0FF) { // Die Funktion "runtime()" wird nur für den Admin Tab gebraucht. runtime(); // Auskommentieren falls du den Admin Tab nicht nutzen möchtest. } dnsServer.processNextRequest(); reStation(); // Erst 16 Ports aus PCF8575 einlesen for (uint8_t i = 0; i < AMOUNTOFPORTS; i++) { portStates[i] = expander1.read(i); } for (uint8_t i = 0; i < AMOUNTOFPORTS; i++) { if (portStates[i] != lastStates[i]) { // Ausgabe: geänderte Ports melden Serial.print("Pin "); Serial.print(i); Serial.print(" hat sich geändert -> "); Serial.println(portStates[i]); lastStates[i] = portStates[i]; } // LED aktualisieren if (portConfigs[i].enabled) { if (portStates[i] == 0) { pixels->setPixelColor(i, pixels->Color(0, 150, 0)); // grün } else { bool globalBlinkState = (millis() / BLINK_INTERVAL) % 2; if (globalBlinkState) { pixels->setPixelColor(i, pixels->Color(150, 0, 0)); // rot } else { pixels->setPixelColor(i, pixels->Color(0, 0, 0)); // aus } } } else { pixels->setPixelColor(i, pixels->Color(0, 0, 0)); // aus } } pixels->show(); delay(50); }