Blinken der LEDs und des WebInterface in Sync

This commit is contained in:
toptah 2026-03-12 21:22:12 +01:00
parent c39fd04b07
commit 2f23c784ee
7 changed files with 78 additions and 7 deletions

View File

@ -85,7 +85,8 @@ Das System stellt einen vollständig konfigurierbaren Webserver bereit mit folge
**Port-Konfiguration:**
- Individuelle Benennung jedes Ports möglich
- Aktivieren/Deaktivieren von Ports
- Persistente Speicherung der Konfiguration in `portconfig.json`
- Globale Blinkfrequenz für fehlerhafte Ports einstellbar (in ms)
- Persistente Speicherung der Konfiguration in `portconfig.json`, inklusive Blinkintervall
### 📡 WiFi & Netzwerkverbindung

View File

@ -6,6 +6,9 @@
<link rel="stylesheet" href="style.css">
<title>Port Status</title>
<style>
:root {
--blink-duration: 1s;
}
.port {
margin: 10px;
padding: 10px;
@ -22,7 +25,7 @@
}
.missing {
background-color: red;
animation: blink 1s infinite;
animation: blink var(--blink-duration) infinite;
}
@keyframes blink {
0%, 50% { background-color: red; }
@ -43,6 +46,9 @@
try {
const response = await fetch('/status/data');
const data = await response.json();
if (data.blink_interval !== undefined) {
updateBlinkDuration(data.blink_interval);
}
const container = document.getElementById('portsContainer');
container.innerHTML = '';
data.ports.forEach((port, index) => {
@ -72,6 +78,12 @@
}
}
// blink length updater must be defined before starting
async function updateBlinkDuration(blinkInterval) {
const period = blinkInterval * 2;
document.documentElement.style.setProperty('--blink-duration', period + 'ms');
}
loadStatus();
setInterval(loadStatus, 1000); // Aktualisiere jede Sekunde
</script>

View File

@ -9,6 +9,9 @@
<body>
<h1>Port Konfiguration</h1>
<form id="portForm">
<label>
Blinkintervall (ms): <input type="number" id="blinkInput" name="blink_interval" min="1" value="">
</label><br>
<div id="portsContainer"></div>
<input type="submit" value="Speichern">
</form>
@ -19,6 +22,9 @@
try {
const response = await fetch('/portconfig/data');
const data = await response.json();
if (data.blink_interval !== undefined) {
document.getElementById('blinkInput').value = data.blink_interval;
}
const container = document.getElementById('portsContainer');
container.innerHTML = '';
data.ports.forEach((port, index) => {
@ -46,11 +52,14 @@
enabled: formData.has(`enabled${i}`)
});
}
const blink = parseInt(formData.get('blink_interval')) || null;
const payload = { ports };
if (blink !== null) payload.blink_interval = blink;
try {
await fetch('/portconfig', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ ports })
body: JSON.stringify(payload)
});
alert('Konfiguration gespeichert!');
loadConfig(); // Reload

View File

@ -4,6 +4,9 @@
#define NEOPIXEL_PIN D6
#define BRIGHTNESS 100
#define BLINK_INTERVAL 500 // Blink interval in milliseconds (0.5 seconds)
#define DEFAULT_BLINK_INTERVAL 500 // Blink interval in milliseconds (0.5 seconds)
#define SERIAL_SPEED 115200 // Serial Baudrate for ESP8266
// runtime variable - can be modified via web configuration
uint16_t blinkInterval = DEFAULT_BLINK_INTERVAL;

View File

@ -29,6 +29,10 @@ struct PortConfig {
bool enabled;
};
// global blink interval stored along with port configuration
// defined in Config.ino as a variable so it can be changed at runtime
extern uint16_t blinkInterval;
PCF8575 expander1(EXPANDER1ADDRESS);
uint8_t portStates[AMOUNTOFPORTS];
uint8_t lastStates[AMOUNTOFPORTS] = {0};
@ -49,6 +53,10 @@ void loadPortConfig() {
portConfigs[i].name = ports[i]["name"] | ("Port " + String(i));
portConfigs[i].enabled = ports[i]["enabled"] | true;
}
// read blink interval if present
if (doc.containsKey("blink_interval")) {
blinkInterval = doc["blink_interval"] | blinkInterval;
}
} else {
// Default
for (int i = 0; i < AMOUNTOFPORTS; i++) {
@ -73,6 +81,9 @@ void savePortConfig() {
port["name"] = portConfigs[i].name;
port["enabled"] = portConfigs[i].enabled;
}
// store blink interval as well
doc["blink_interval"] = blinkInterval;
File file = LittleFS.open("/portconfig.json", "w");
if (file) {
serializeJson(doc, file);
@ -181,6 +192,8 @@ void setup() {
port["name"] = portConfigs[i].name;
port["enabled"] = portConfigs[i].enabled;
}
// include current blink interval
doc["blink_interval"] = blinkInterval;
String json;
serializeJson(doc, json);
server.send(200, "application/json", json);
@ -195,6 +208,10 @@ void setup() {
portConfigs[i].name = ports[i]["name"] | ("Port " + String(i));
portConfigs[i].enabled = ports[i]["enabled"] | true;
}
// update blink interval if provided
if (doc.containsKey("blink_interval")) {
blinkInterval = doc["blink_interval"] | blinkInterval;
}
savePortConfig();
}
server.sendHeader("Location", "/portconfig");
@ -222,6 +239,9 @@ void setup() {
port["enabled"] = portConfigs[i].enabled;
port["state"] = portStates[i];
}
// include blink interval so the webpage can synchronize its animation
doc["blink_interval"] = blinkInterval;
String json;
serializeJson(doc, json);
server.send(200, "application/json", json);
@ -257,7 +277,7 @@ void loop() {
if (portStates[i] == 0) {
pixels->setPixelColor(i, pixels->Color(0, 150, 0)); // grün
} else {
bool globalBlinkState = (millis() / BLINK_INTERVAL) % 2;
bool globalBlinkState = (millis() / blinkInterval) % 2;
if (globalBlinkState) {
pixels->setPixelColor(i, pixels->Color(150, 0, 0)); // rot
} else {

View File

@ -6,6 +6,10 @@
<link rel="stylesheet" href="style.css">
<title>Port Status</title>
<style>
/* blink duration is defined via CSS variable so we can update it dynamically */
:root {
--blink-duration: 1s; /* default, will be overwritten by script */
}
.port {
margin: 10px;
padding: 10px;
@ -22,7 +26,7 @@
}
.missing {
background-color: red;
animation: blink 1s infinite;
animation: blink var(--blink-duration) infinite;
}
@keyframes blink {
0%, 50% { background-color: red; }
@ -39,10 +43,22 @@
<script>
// when status data is received we update the blink animation length
async function updateBlinkDuration(blinkInterval) {
// period is two intervals (on+off)
const period = blinkInterval * 2;
document.documentElement.style.setProperty('--blink-duration', period + 'ms');
}
async function loadStatus() {
try {
const response = await fetch('/status/data');
const data = await response.json();
// synchronize blink rate on each update
if (data.blink_interval !== undefined) {
updateBlinkDuration(data.blink_interval);
}
const container = document.getElementById('portsContainer');
container.innerHTML = '';
data.ports.forEach((port, index) => {

View File

@ -9,6 +9,9 @@
<body>
<h1>Port Konfiguration</h1>
<form id="portForm">
<label>
Blinkintervall (ms): <input type="number" id="blinkInput" name="blink_interval" min="1" value="">
</label><br>
<div id="portsContainer"></div>
<input type="submit" value="Speichern">
</form>
@ -20,6 +23,10 @@
try {
const response = await fetch('/portconfig/data');
const data = await response.json();
// fill blink interval field if provided
if (data.blink_interval !== undefined) {
document.getElementById('blinkInput').value = data.blink_interval;
}
const container = document.getElementById('portsContainer');
container.innerHTML = '';
data.ports.forEach((port, index) => {
@ -47,11 +54,14 @@
enabled: formData.has(`enabled${i}`)
});
}
const blink = parseInt(formData.get('blink_interval')) || null;
const payload = { ports };
if (blink !== null) payload.blink_interval = blink;
try {
await fetch('/portconfig', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ ports })
body: JSON.stringify(payload)
});
alert('Konfiguration gespeichert!');
loadConfig(); // Reload