Ich habedas Skript mal etwas "erweitert".
Das legt jetzt Datenpunkte unter "userdata" an. Die Daten können dann weiter in einer VIS verwendet werden.
const wrThreshold = 0.7;
const moduleThreshold = 0.7;
const minProduction = 5;
const pushoverInstance = 'pushover.0';
const warnDelay = 15 * 60 * 1000;
const groups = [
{
name: "Solaranlage",
wrs: [
{ id: "114***********", name: "WR1_HM-1000", moduleCount: 2 },
{ id: "114***********", name: "WR2_HM-1000", moduleCount: 2 },
{ id: "114***********", name: "WR3_HM-1000", moduleCount: 2 }
]
}
];
if (!globalThis.wrStatus) globalThis.wrStatus = {};
function sendPushoverMessage(message) {
sendTo(pushoverInstance, 'send', {
message,
title: 'Wechselrichter-Überwachung',
priority: 0
});
}
function checkWRs() {
let now = Date.now();
groups.forEach(group => {
let wrPowers = [];
let activeWRs = [];
group.wrs.forEach((wr, i) => {
const producingState = getState(`opendtu.0.${wr.id}.producing`).val;
const isProducing = producingState === true || producingState === 'true';
const wrPower = isProducing ? getState(`opendtu.0.${wr.id}.power_dc`).val : 0;
wrPowers[i] = wrPower;
if (isProducing) {
activeWRs.push({ index: i, ...wr, wrPower });
}
// Schreibe Status in 0_userdata
const statusText = isProducing
? (wrPower >= minProduction ? "✅ OK" : "⚠️ Schwache Produktion")
: "❌ Keine Produktion";
setState(`0_userdata.0.WR_Status.${wr.name}.Status`, { val: statusText, ack: true });
});
if (activeWRs.length > 1) {
let avgWR = activeWRs.reduce((sum, wr) => sum + wr.wrPower, 0) / activeWRs.length;
activeWRs.forEach(wr => {
let status = globalThis.wrStatus[wr.name] || { warnSince: null, warned: false };
if (wr.wrPower < avgWR * wrThreshold) {
if (!status.warnSince) status.warnSince = now;
if (!status.warned && (now - status.warnSince) >= warnDelay) {
sendPushoverMessage(`⚠️ WR-Warnung (${group.name}): ${wr.name} liefert seit 15 Minuten nur ${wr.wrPower} W (Durchschnitt: ${avgWR.toFixed(1)} W)`);
status.warned = true;
}
} else {
if (status.warned) {
sendPushoverMessage(`✅ Entwarnung (${group.name}): ${wr.name} liefert wieder ausreichend Leistung.`);
}
status.warnSince = null;
status.warned = false;
}
globalThis.wrStatus[wr.name] = status;
});
}
activeWRs.forEach(wr => {
let modulePowers = [];
for (let m = 1; m <= wr.moduleCount; m++) {
let modPower = getState(`opendtu.0.${wr.id}.dc.input_${m}.power`).val;
modulePowers[m - 1] = modPower;
}
let avgModule = modulePowers.reduce((a, b) => a + b, 0) / wr.moduleCount;
modulePowers.forEach((mp, idx) => {
const modKey = `${wr.name}_modul${idx + 1}`;
let status = globalThis.wrStatus[modKey] || { warnSince: null, warned: false };
// Modulstatus schreiben
const modStatus = mp > 0 ? "✅ OK" : "❌ Kein Ertrag";
setState(`0_userdata.0.WR_Status.${wr.name}.Modul${idx + 1}`, { val: modStatus, ack: true });
if (mp < avgModule * moduleThreshold) {
if (!status.warnSince) status.warnSince = now;
if (!status.warned && (now - status.warnSince) >= warnDelay) {
sendPushoverMessage(`⚠️ Modul-Warnung (${wr.name}): Modul ${idx + 1} liefert seit 15 Minuten nur ${mp} W (Durchschnitt: ${avgModule.toFixed(1)} W)`);
status.warned = true;
}
} else {
if (status.warned) {
sendPushoverMessage(`✅ Entwarnung (${wr.name}): Modul ${idx + 1} liefert wieder ausreichend Leistung.`);
}
status.warnSince = null;
status.warned = false;
}
globalThis.wrStatus[modKey] = status;
});
});
group.wrs.forEach((wr, i) => {
const producingState = getState(`opendtu.0.${wr.id}.producing`).val;
const isProducing = producingState === true || producingState === 'true';
let status = globalThis.wrStatus[wr.name + "_prod"] || { warnSince: null, warned: false };
if (!isProducing) {
let anyOtherProducing = group.wrs.some((otherWr, idx) => {
if (idx !== i) {
const otherState = getState(`opendtu.0.${otherWr.id}.producing`).val;
return otherState === true || otherState === 'true';
}
return false;
});
if (anyOtherProducing) {
if (!status.warnSince) status.warnSince = now;
if (!status.warned && (now - status.warnSince) >= warnDelay) {
sendPushoverMessage(`🔴 Ausfall (${group.name}): ${wr.name} produziert seit 15 Minuten nichts, obwohl andere laufen!`);
status.warned = true;
}
} else {
status.warnSince = null;
status.warned = false;
}
} else {
if (status.warned) {
sendPushoverMessage(`✅ Entwarnung (${group.name}): ${wr.name} produziert wieder!`);
}
status.warnSince = null;
status.warned = false;
}
globalThis.wrStatus[wr.name + "_prod"] = status;
});
});
}
schedule('*/2 * * * *', checkWRs);