NEWS
[erledigt]Skript zum Einsammeln von Batteriestatus von ...
-
Hallo Zusammen,
ich habe mehrere Zigbee Geräte am laufen, fast alle sind Batterie betrieben. Gibt es irgendwie eine Möglichkeit, eine Liste zu erzeugen, die mir z.b. für alle Zigbee eine json datei erzeugt und dort das Zigbee-Gerät und dann den Batterie Status hineinschreibt?Was meine ich? Die Zigbee Geräte sind alle mit einer Nummer aufgelistet - siehe Screenshot
Ich bekomme es nicht hin. Jemand eine Idee für einen Ansatz?
danke
Marcus -
@mguenther sagte: Geräte sind alle mit einer Nummer aufgelistet
Die Geräte-ID ist wenig hilfreich. Gibt es sinnvolle Namen? Bitte zeigen!
-
@paul53 gibts eben nicht, Paul - das ist ja mein Problem. Ich dachte irgendwie, dass man die Geräte ID irgendwie mit einem Platzhalter "*" ersetzen kann. Die Objekte unter der Objekt ID sind dann wieder identisch
-
mal als Screenshot
-
@mguenther sagte: gibts eben nicht
Auch nicht bei den Alias? Gibt es zu jedem Batterie-DP einen Alias?
-
@paul53
nicht zu allen.
Zu denen ich bis jetzt etwas gemacht habe, ja - da gibts auch nen Alias. die Objekte unter den Objekt-IDs haben den Datenpunkt "battery"zigbee.0.00158d000237039e.battery
-
@mguenther sagte: mal als Screenshot
Die Geräte haben keinen sinnvollen Namen? Wenn doch, könnte man den parentName des Batterie-DP verwenden.
-
@paul53
nicht das ich wüsste - die Geräte werden in Zigbee gepaired und bekommen diese Object ID Zuweisung. Ich wollte es mir einfach machen und quasi nen Platzhalter verwenden. Klappt aber irgendwie nicht -
@mguenther sagte: Zu denen ich bis jetzt etwas gemacht habe, ja - da gibts auch nen Alias.
Dann verwende den Alias, wenn die ID-Struktur einheitlich ist.
-
@paul53
ja, aber dann habe ich nicht alle zigbee geräte. ich wollte je eigentlich gerne alle zigbee geräte auswerten. -
@mguenther sagte in Skript zum Einsammeln von Batteriestatus von Zigbeegeräten?:
ich wollte je eigentlich gerne alle zigbee geräte auswerten.
und zu denen gibt es keine alias?
-
@homoran
hi homoran,
nein, nicht zu allen. ich habe so etwas:unter Sensordaten finde ich auch für einige Zigbeegeräte den "Batteriestatus"
-
@mguenther sagte: nein, nicht zu allen.
Das ist schlecht.
Du zeigst uns nie die Namen. Ist die Bildschirmauflösung so niedrig?Teste mal, was damit im Log erscheint:
const ids = $('zigbee.0.*.battery').toArray(); function batterien() { for(let id of ids) { const val = getState(id).val; id = id.substring(0, id.lastIndexOf('.')); // Geräte-ID log(getObject(id).common.name + ': ' + val); } } schedule('0 18 * * *', batterien); batterien();
-
@paul53
dann habe ich noch nicht verstanden, was du mit "Namen" meinst. Anbei der Log-Auszug:javascript.0 2025-09-30 14:33:24.904 info script.js.System.TEST2Batterie: registered 0 subscriptions, 1 schedule, 0 messages, 0 logs and 0 file subscriptions javascript.0 2025-09-30 14:33:24.903 info script.js.System.TEST2Batterie: Taster_Sonnenrollo: 16 javascript.0 2025-09-30 14:33:24.903 info script.js.System.TEST2Batterie: Zimmer1_Fernsehtaster_Paulina: 60 javascript.0 2025-09-30 14:33:24.902 info script.js.System.TEST2Batterie: Zimmer1_Fernsehtaster_Marcus: 60 javascript.0 2025-09-30 14:33:24.902 info script.js.System.TEST2Batterie: Garagenwand_Heizung: 83 javascript.0 2025-09-30 14:33:24.901 info script.js.System.TEST2Batterie: Garagenwand_Tor_Sued: 70 javascript.0 2025-09-30 14:33:24.901 info script.js.System.TEST2Batterie: Garagenwand_Raum_Sued: 100 javascript.0 2025-09-30 14:33:24.900 info script.js.System.TEST2Batterie: Garagenwand_Briefkasten: 0 javascript.0 2025-09-30 14:33:24.899 info script.js.System.TEST2Batterie: Tuerklingel: 0 javascript.0 2025-09-30 14:33:24.897 info script.js.System.TEST2Batterie: Technikraum: 0 javascript.0 2025-09-30 14:33:24.897 info script.js.System.TEST2Batterie: Garage: 100 javascript.0 2025-09-30 14:33:24.896 info script.js.System.TEST2Batterie: Server: 37 javascript.0 2025-09-30 14:33:24.896 info script.js.System.TEST2Batterie: Arbeitszimmer: 0 javascript.0 2025-09-30 14:33:24.893 info script.js.System.TEST2Batterie: Bad_klein: 97 javascript.0 2025-09-30 14:33:24.893 info script.js.System.TEST2Batterie: Bad_klein: 0 javascript.0 2025-09-30 14:33:24.892 info script.js.System.TEST2Batterie: WC: 83 javascript.0 2025-09-30 14:33:24.891 info script.js.System.TEST2Batterie: Garderobe: 57 javascript.0 2025-09-30 14:33:24.891 info script.js.System.TEST2Batterie: Bad_gross: 23 javascript.0 2025-09-30 14:33:24.890 info script.js.System.TEST2Batterie: Aussen: 43 javascript.0 2025-09-30 14:33:24.890 info script.js.System.TEST2Batterie: Zimmer3: 30 javascript.0 2025-09-30 14:33:24.889 info script.js.System.TEST2Batterie: EG: 17 javascript.0 2025-09-30 14:33:24.889 info script.js.System.TEST2Batterie: Zimmer2: 43 javascript.0 2025-09-30 14:33:24.889 info script.js.System.TEST2Batterie: Bad_gross: 3 javascript.0 2025-09-30 14:33:24.888 info script.js.System.TEST2Batterie: Zimmer1: 0 javascript.0 2025-09-30 14:33:24.888 info script.js.System.TEST2Batterie: Zimmer3: 100 javascript.0 2025-09-30 14:33:24.888 info script.js.System.TEST2Batterie: Zimmer2: 100 javascript.0 2025-09-30 14:33:24.887 info script.js.System.TEST2Batterie: Zimmer1_rechts: 90 javascript.0 2025-09-30 14:33:24.887 info script.js.System.TEST2Batterie: Zimmer1_links: 100 javascript.0 2025-09-30 14:33:24.802 info Start JavaScript script.js.System.TEST2Batterie (Javascript/js)
-
@mguenther sagte: Anbei der Log-Auszug:
Der sieht gut aus. Also haben die Zigbee-Geräte sinnvolle Namen. Manche Namen sind allerdings doppelt vorhanden.
Die Namen kann man auch im Tab "Objekte" zeigen: -
@paul53
aber Paul, dein Ansatz mit const ids = $('zigbee.0.*.battery').toArray(); hat geholfen. ich bastle weiter und poste dann hier das Ergebnis.danke
-
hier mein Skript - chatgpt hat mit draufgeschaut - ich schließe hier.
// ===== Einstellungen ===== const OUT = "0_userdata.0.vis.BatterieListeDebug"; // Datenpunkt für VIS const THRESH_LOW = 30; const THRESH_MED = 60; const MAX_HEIGHT = 660; const WIDTH = 405; // Gesamtbreite const STALE_HOURS = 168; // >7 Tage ohne Meldung = "nicht aktiv" // === Helfer === function colorByVal(v) { if (!isFinite(v)) return "#9e9e9e"; if (v < THRESH_LOW) return "#e53935"; // rot if (v < THRESH_MED) return "#fdd835"; // gelb return "#43a047"; // grün } function devRoot(id) { const p = id.split("."); return [p[0], p[1], p[2]].join("."); } function niceNameFromRoot(rootId) { const obj = getObject(rootId); return obj?.common?.name || rootId; } function voltageToPercent(v) { if (!isFinite(v)) return null; const min = 2.0, max = 3.0; let pct = ((v - min) / (max - min)) * 100; return Math.max(0, Math.min(100, Math.round(pct))); } // Liefert den letzten Änderungszeitpunkt aller States eines Geräts function lastSeenDevice(root) { let last = 0; $('' + root + '.*').each(id => { const st = getState(id); if (st && st.lc && st.lc > last) last = st.lc; }); return last; } // === Rendering === function render() { const map = {}; // Zigbee: echte % $('zigbee.0.*.battery').each(id => { const root = devRoot(id); const name = niceNameFromRoot(root); const raw = getState(id)?.val; const val = isFinite(raw) ? Math.max(0, Math.min(100, Math.round(Number(raw)))) : null; if (val !== null) map[root] = { type: "percent", name, val, sys: "Zigbee" }; }); // HmIP: Operating Voltage -> % $('hm-rpc.0.*.OPERATING_VOLTAGE').each(id => { const root = devRoot(id); const name = niceNameFromRoot(root); const val = voltageToPercent(getState(id)?.val); if (val !== null) map[root] = { type: "percent", name, val, sys: "HmIP" }; }); // Homematic: LOWBAT $('hm-rpc.0.*.LOWBAT').each(id => { const root = devRoot(id); const name = niceNameFromRoot(root); const lowbat = !!(getState(id)?.val); const unreach = !!(getState(root + ".0.UNREACH")?.val); const last = lastSeenDevice(root); const ageH = (Date.now() - last) / (1000 * 60 * 60); if (unreach) { map[root] = { type: "unreach", name, sys: "HM" }; } else if (ageH > STALE_HOURS) { map[root] = { type: "stale", name, sys: "HM" }; } else { map[root] = { type: "lowbat", name, lowbat, sys: "HM" }; } }); // Homematic: LOW_BAT $('hm-rpc.0.*.LOW_BAT').each(id => { const root = devRoot(id); const name = niceNameFromRoot(root); const lowbat = !!(getState(id)?.val); const unreach = !!(getState(root + ".0.UNREACH")?.val); const last = lastSeenDevice(root); const ageH = (Date.now() - last) / (1000 * 60 * 60); if (unreach) { map[root] = { type: "unreach", name, sys: "HmIP" }; } else if (ageH > STALE_HOURS) { map[root] = { type: "stale", name, sys: "HmIP" }; } else { map[root] = { type: "lowbat", name, lowbat, sys: "HmIP" }; } }); // Liste bauen let list = Object.values(map); // Sortierung (angepasst) list.sort((a, b) => { function weight(it) { if (it.type === "unreach") return 0; // HM keine Meldung if (it.type === "percent" && it.sys === "Zigbee" && it.val === 0) return 1; // Zigbee 0% if (it.type === "stale") return 2; // HM nicht aktiv if (it.type === "percent" && it.sys === "Zigbee" && it.val < THRESH_LOW) return 3; // Zigbee rot if (it.type === "lowbat" && it.lowbat === true) return 4; // HM low if (it.type === "percent" && it.sys === "Zigbee" && it.val < THRESH_MED) return 5; // Zigbee gelb if (it.type === "percent" && it.sys === "Zigbee" && it.val >= THRESH_MED) return 6; // Zigbee grün if (it.type === "lowbat" && it.lowbat === false) return 7; // HM grün return 99; } const wa = weight(a), wb = weight(b); if (wa !== wb) return wa - wb; // Falls gleiche Kategorie: nach Wert sortieren if (a.type === "percent" && b.type === "percent") { if (a.val == null) return 1; if (b.val == null) return -1; return a.val - b.val; } return 0; }); // Zeilen bauen const rows = list.map(it => { if (it.type === "percent") { return ` <tr style="border-bottom:1px solid #444;"> <td style="width:55px; color:#f5f5f5;">${it.sys}</td> <td style="width:120px; color:#f5f5f5; font-size:12px; overflow:hidden; text-overflow:ellipsis; white-space:nowrap;" title="${it.name}">${it.name}</td> <td style="width:55px; text-align:right; color:#f5f5f5;">${it.val == null ? "-" : it.val + " %"}</td> <td style="width:175px;"> <div style="width:100%; height:10px; border-radius:5px; background:#333; overflow:hidden;"> <div style="height:100%; width:${it.val ?? 0}%; background:${colorByVal(it.val)};"></div> </div> </td> </tr>`; } if (it.type === "lowbat") { const ok = it.lowbat === false; const color = ok ? "#43a047" : "#e53935"; const text = ok ? "OK" : "LOW"; return ` <tr style="border-bottom:1px solid #444;"> <td style="width:55px; color:#f5f5f5;">${it.sys}</td> <td style="width:120px; color:#f5f5f5; font-size:12px; overflow:hidden; text-overflow:ellipsis; white-space:nowrap;" title="${it.name}">${it.name}</td> <td style="width:55px; text-align:right; color:#f5f5f5;">–</td> <td style="width:175px; color:${color}; font-weight:bold;">${text}</td> </tr>`; } if (it.type === "unreach") { return ` <tr style="border-bottom:1px solid #444;"> <td style="width:55px; color:#f5f5f5;">${it.sys}</td> <td style="width:120px; color:#f5f5f5; font-size:12px; overflow:hidden; text-overflow:ellipsis; white-space:nowrap;" title="${it.name}">${it.name}</td> <td style="width:55px; text-align:right; color:#f5f5f5;">–</td> <td style="width:175px; color:#ff9800; font-weight:bold;">KEINE MELDUNG</td> </tr>`; } if (it.type === "stale") { return ` <tr style="border-bottom:1px solid #444;"> <td style="width:55px; color:#f5f5f5;">${it.sys}</td> <td style="width:120px; color:#f5f5f5; font-size:12px; overflow:hidden; text-overflow:ellipsis; white-space:nowrap;" title="${it.name}">${it.name}</td> <td style="width:55px; text-align:right; color:#f5f5f5;">–</td> <td style="width:175px; color:#ff5722; font-weight:bold;">NICHT AKTIV</td> </tr>`; } }).join(""); // HTML mit sticky Header const html = ` <div style="font-family: system-ui, Segoe UI, Roboto, Arial; font-size:13px; width:${WIDTH}px; max-height:${MAX_HEIGHT}px; overflow-y:auto; padding:0; background:transparent;"> <table style="width:${WIDTH}px; border-collapse:collapse; background:transparent;"> <thead style="background:#212121;"> <tr style="border-bottom:1px solid #666;"> <th style="width:55px; text-align:left; color:#f5f5f5; position:sticky; top:0; background:#212121;">Typ</th> <th style="width:120px; text-align:left; color:#f5f5f5; position:sticky; top:0; background:#212121;">Gerät</th> <th style="width:55px; text-align:right; color:#f5f5f5; position:sticky; top:0; background:#212121;">Batterie</th> <th style="width:175px; text-align:left; color:#f5f5f5; position:sticky; top:0; background:#212121;">Status</th> </tr> </thead> <tbody>${rows}</tbody> </table> </div>`; setState(OUT, html, true); } // === Setup === createState(OUT, "", { type: "string", role: "html", read: true, write: false }, () => { render(); $('zigbee.0.*.battery').each(id => on({ id, change: "ne" }, render)); $('hm-rpc.0.*.OPERATING_VOLTAGE').each(id => on({ id, change: "ne" }, render)); $('hm-rpc.0.*.LOWBAT').each(id => on({ id, change: "ne" }, render)); $('hm-rpc.0.*.LOW_BAT').each(id => on({ id, change: "ne" }, render)); $('hm-rpc.0.*.UNREACH').each(id => on({ id, change: "ne" }, render)); // Refresh alle 12 Stunden schedule("0 */12 * * *", render); });
Tabelle ist html und lässt sich scrollen in meiner VIS