<style>
#devices {
display: flex;
flex-wrap: wrap;
gap: 15px;
}
.device {
flex: 1 1 100px;
max-width: 180px;
padding: 10px;
border: 1px solid #003366;
border-radius: 12px;
box-shadow: 2px 2px 5px rgba(0,0,0,0.2);
color: white;
}
.device h3 {
margin: 5px 0 10px 0;
font-size: 14px;
text-align: center;
}
.btn {
color: white;
width: 100%;
height: 38px;
margin: 4px 0;
border: none;
border-radius: 8px;
font-size: 11px;
cursor: pointer;
}
.btn-on { background: green; }
.btn-off { background: red; }
</style>
<div id="devices"></div>
<script>
// Raumfarben (so belassen wie gewünscht)
const roomColors = {
"Arbeitszimmer": "#444a97",
"Schlafzimmer": "#d2cc19",
"Wohnzimmer": "#1c5a1b",
"Terrasse": "#7f19d2",
"Esszimmer": "#19bcd2",
"Küche": "#7e1161",
"Bad": "#3fe23c",
"Flur": "#3ce2d7"
};
// EG – alle Räume & Geräte
const devices = [
{
room: "Arbeitszimmer",
devices: [
{ ip: "192.168.178.60", relays: [{id:0,name:"Licht"}] },
{ ip: "192.168.178.61", relays: [{id:0,name:"Rollo Auf"},{id:1,name:"Rollo Zu"}] },
{ ip: "192.168.178.62", relays: [{id:0,name:"Steckdose 1"}] },
{ ip: "192.168.178.63", relays: [{id:0,name:"Steckdose 2"}] }
]
},
{
room: "Schlafzimmer",
devices: [
{ ip: "192.168.178.64", relays: [{id:0,name:"Licht"}] },
{ ip: "192.168.178.65", relays: [{id:0,name:"Rollo Auf"},{id:1,name:"Rollo Zu"}] },
{ ip: "192.168.178.66", relays: [{id:0,name:"Steckdose 1"}] },
{ ip: "192.168.178.67", relays: [{id:0,name:"Steckdose 2"}] },
{ ip: "192.168.178.68", relays: [{id:0,name:"Steckdose 3"}] },
{ ip: "192.168.178.69", relays: [{id:0,name:"Steckdose 4"}] }
]
},
{
room: "Wohnzimmer",
devices: [
{ ip: "192.168.178.70", relays: [{id:0,name:"Licht"}] },
{ ip: "192.168.178.71", relays: [{id:0,name:"Rollo 1 Auf"},{id:1,name:"Rollo 1 Zu"}] },
{ ip: "192.168.178.72", relays: [{id:0,name:"Rollo 2 Auf"},{id:1,name:"Rollo 2 Zu"}] },
{ ip: "192.168.178.73", relays: [{id:0,name:"Steckdose 1"}] },
{ ip: "192.168.178.74", relays: [{id:0,name:"Steckdose 2"}] },
{ ip: "192.168.178.75", relays: [{id:0,name:"Steckdose 3"}] },
{ ip: "192.168.178.76", relays: [{id:0,name:"Steckdose 4"}] },
{ ip: "192.168.178.77", relays: [{id:0,name:"Steckdose 5"}] }
]
},
{
room: "Terrasse",
devices: [
{ ip: "192.168.178.78", relays: [{id:0,name:"Licht"}] },
{ ip: "192.168.178.79", relays: [{id:0,name:"Markise Rein"},{id:1,name:"Markise Raus"}] },
{ ip: "192.168.178.80", relays: [{id:0,name:"Steckdose 1"}] },
{ ip: "192.168.178.81", relays: [{id:0,name:"Steckdose 2"}] }
]
},
{
room: "Esszimmer",
devices: [
{ ip: "192.168.178.82", relays: [{id:0,name:"Licht"}] },
{ ip: "192.168.178.83", relays: [{id:0,name:"Rollo 1 Auf"},{id:1,name:"Rollo 1 Zu"}] },
{ ip: "192.168.178.84", relays: [{id:0,name:"Rollo 2 Auf"},{id:1,name:"Rollo 2 Zu"}] },
{ ip: "192.168.178.85", relays: [{id:0,name:"Steckdose 1"}] },
{ ip: "192.168.178.86", relays: [{id:0,name:"Steckdose 2"}] },
{ ip: "192.168.178.87", relays: [{id:0,name:"Steckdose 3"}] }
]
},
{
room: "Küche",
devices: [
{ ip: "192.168.178.88", relays: [{id:0,name:"Licht"}] },
{ ip: "192.168.178.89", relays: [{id:0,name:"Rollo Auf"},{id:1,name:"Rollo Zu"}] },
{ ip: "192.168.178.90", relays: [{id:0,name:"Dunstabzug"}] },
{ ip: "192.168.178.91", relays: [
{id:0,name:"Herd Phase 1"},
{id:1,name:"Herd Phase 2"},
{id:2,name:"Herd Phase 3"}
] },
{ ip: "192.168.178.92", relays: [{id:0,name:"Steckdose 1"}] },
{ ip: "192.168.178.93", relays: [{id:0,name:"Steckdose 2"}] }
]
},
{
room: "Bad",
devices: [
{ ip: "192.168.178.94", relays: [{id:0,name:"Licht"}] },
{ ip: "192.168.178.95", relays: [{id:0,name:"Rollo Auf"},{id:1,name:"Rollo Zu"}] },
{ ip: "192.168.178.96", relays: [{id:0,name:"Spiegel Licht"}] }
]
},
{
room: "Flur",
devices: [
{ ip: "192.168.178.97", relays: [{id:0,name:"Licht Innen"}] },
{ ip: "192.168.178.98", relays: [{id:0,name:"Treppe Licht 1"}] },
{ ip: "192.168.178.99", relays: [{id:0,name:"Treppe Rollo Auf"},{id:1,name:"Treppe Rollo Zu"}] },
{ ip: "192.168.178.100", relays: [{id:0,name:"Treppe Licht 2"}] },
{ ip: "192.168.178.101", relays: [{id:0,name:"Rollo Garderobe Auf"},{id:1,name:"Rollo Garderobe Zu"}] },
{ ip: "192.168.178.102", relays: [{id:0,name:"Steckdose Haustür"}] },
{ ip: "192.168.178.103", relays: [{id:0,name:"Haustür Licht"}] }
]
}
];
const devicesDiv = document.getElementById("devices");
// Erzeuge UI & starte WebSockets
devices.forEach(roomBlock => {
const block = document.createElement("div");
block.className = "device";
block.style.backgroundColor = roomColors[roomBlock.room] || "#4169E1";
const title = document.createElement("h3");
title.innerText = roomBlock.room;
block.appendChild(title);
roomBlock.devices.forEach(device => {
// Buttons anlegen
device.relays.forEach(relay => {
const btn = document.createElement("button");
btn.id = `relay_${device.ip}_${relay.id}`;
btn.className = "btn btn-off";
btn.innerText = relay.name + " AUS";
btn.onclick = () => {
fetch(`http://${device.ip}/rpc/switch.toggle?id=${relay.id}`)
.catch(err => console.error("Toggle-Fehler:", err));
};
block.appendChild(btn);
});
// WebSocket je Gerät
initWebSocket(device);
});
devicesDiv.appendChild(block);
});
// WebSocket-Funktion inkl. einfacher Reconnect-Logik
function initWebSocket(device, attempt = 0) {
try {
const ws = new WebSocket(`ws://${device.ip}/rpc`);
ws.onopen = () => {
// Initialen Status anfordern
ws.send('{"id":1,"src":"grafana_panel","method":"Shelly.GetStatus"}');
};
ws.onmessage = (event) => {
try {
const obj = JSON.parse(event.data);
const status = obj.result || obj.params;
if (!status) return;
device.relays.forEach(relay => {
const sw = status[`switch:${relay.id}`];
if (sw && typeof sw.output === "boolean") {
updateButton(device.ip, relay, sw.output);
}
});
} catch(e) {
console.error("WS-Parse-Fehler:", e);
}
};
ws.onclose = () => {
// Leichter Backoff für Reconnect
const next = Math.min(10000, 1000 * (attempt + 1));
setTimeout(() => initWebSocket(device, attempt + 1), next);
};
ws.onerror = () => {
try { ws.close(); } catch(_) {}
};
} catch (err) {
console.error(`WebSocket zu ${device.ip} fehlgeschlagen:`, err);
}
}
// Button-UI aktualisieren
function updateButton(ip, relay, isOn) {
const btn = document.getElementById(`relay_${ip}_${relay.id}`);
if (!btn) return;
if (isOn) {
btn.className = "btn btn-on";
btn.innerText = `${relay.name} EIN`;
} else {
btn.className = "btn btn-off";
btn.innerText = `${relay.name} AUS`;
}
}
</script>
Alles anzeigen