248 lines
7.1 KiB
C++
248 lines
7.1 KiB
C++
#include <Wire.h>
|
|
#include <PCF8575.h>
|
|
#include <Adafruit_NeoPixel.h>
|
|
#include <ESP8266WebServer.h>
|
|
#include <ArduinoOTA.h>
|
|
#include <LittleFS.h>
|
|
#include "Config.ino"
|
|
#include <DNSServer.h>
|
|
#include <ArduinoJson.h>
|
|
|
|
// 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);
|
|
} |