Abloablesio Smart Home Zur App →

← ablesio im Smart Home

Ablo
Integrationsbeispiel · ioBroker

Balkonkraftwerk einmal pro Woche automatisch an ablesio

Der Growatt-Wechselrichter zählt den Gesamtertrag ohnehin mit. Ein kleines Skript schickt ihn jeden Sonntagabend an ablesio – dort siehst du Wochenertrag, Eigenverbrauch und Ersparnis, ganz ohne Ablesen. Beispiel: das Balkonkraftwerk an der Pergola.

Das brauchst du

Schritt 1: Token erstellen und im Adapter eintragen

In ablesio unter Profil → 🔌 Smart-Home-Integration einen Token erstellen, z.B. mit der Bezeichnung „ioBroker", und in der Instanz ablesio.0 eintragen.

Neuer API-Token
Der Token wird nur einmal angezeigt.
Token-Liste im Profil
Später im Profil: jederzeit widerrufbar.

Schritt 2: Die beiden Datenpunkte finden

Im ioBroker-Admin unter Objekte:

  1. Quelle – Gesamtertrag des Wechselrichters: growatt.0.642452.devices.FMH1B0307N.totalData.mTotal (in kWh). Anlage- und Seriennummer sind bei dir andere – gesucht ist totalData.mTotal.
  2. Ziel – der ablesio-Zähler: das Skript findet ihn über seine Zählernummer, wie in ablesio eingetragen – bei der Pergola die Seriennummer des Wechselrichters, FMH1B0307N. Im Objektbaum liegt er unter ablesio.0.meters.mtr_… (öffentliche Zähler-ID), der Datenpunkt meterNumber zeigt die Nummer.
Objektbaum mit Growatt- und ablesio-Datenpunkten
Gelb: der Gesamtertrag der Pergola. Grün: der beschreibbare Datenpunkt im ablesio-Zähler mit der Zählernummer FMH1B0307N. Schematische Darstellung

Schritt 3: Skript anlegen

Im ioBroker-Admin unter Skripte ein neues JavaScript anlegen (z.B. „Balkonkraftwerk-Wochen-Sync"), den Inhalt unten einfügen und oben unter ANLAGEN Quelle und Zählernummer eintragen. Mehrere Balkonkraftwerke? Einfach je Anlage eine Zeile ergänzen.

Skript anzeigen
/**
 * ablesio – Balkonkraftwerk einmal pro Woche an ablesio übermitteln (Beispiel: Pergola)
 * ====================================================================================
 * Für den JavaScript-Adapter von ioBroker. Liest den Gesamtertrag der Growatt-Wechselrichter
 * und schreibt ihn in den ablesio-Adapter (ablesio.0.meters.<id>.submitReading). Der Adapter
 * prüft den Wert (unverändert → übersprungen, kleiner als zuletzt → nicht gesendet) und
 * übermittelt ihn an ablesio.
 *
 * Voraussetzungen: ablesio-Adapter ≥ 0.3.0 (mit Token aus ablesio Ultimate), Growatt-Adapter.
 * Anleitung: https://ablesio.de/smart-home
 */

// ---------- Einstellungen ----------

/**
 * Welche Anlage wohin: Growatt-Datenpunkt (Gesamtertrag in kWh) → ablesio-Zähler.
 * Der ablesio-Zähler wird über seine ZÄHLERNUMMER gefunden (wie in ablesio eingetragen, z.B. die
 * Seriennummer des Wechselrichters). Alternativ: ablesioZaehler: '<ID aus Objekte → ablesio.0.meters>'.
 */
const ANLAGEN = [
    { name: 'Pergola', quelle: 'growatt.0.642452.devices.FMH1B0307N.totalData.mTotal', zaehlernummer: 'FMH1B0307N' },
    // Weitere Anlagen einfach als eigene Zeile ergänzen, z.B.:
    // { name: 'Zweite Anlage', quelle: 'growatt.0.<Anlage>.devices.<Seriennummer>.totalData.mTotal', zaehlernummer: '<Seriennummer>' },
];

/** Wann synchronisiert wird (Cron): sonntags um 20:00 Uhr, wenn der Tagesertrag drin ist */
const ZEITPLAN = '0 20 * * 0';

/** Werte, die länger nicht aktualisiert wurden, nicht übermitteln (Wechselrichter offline?) */
const MAX_ALTER_TAGE = 3;

/** Zum Testen auf true setzen: synchronisiert einmal direkt beim Speichern/Starten des Skripts */
const BEIM_START_AUSFUEHREN = false;

/** Instanz des ablesio-Adapters */
const ADAPTER = 'ablesio.0';

// ---------- ab hier nichts ändern ----------

/** ID des ablesio-Zählers: über die Zählernummer suchen (unabhängig vom ID-Schema) oder direkt angegeben */
function zaehlerIdFuer(anlage) {
    if (!anlage.zaehlernummer) {
        return anlage.ablesioZaehler != null ? String(anlage.ablesioZaehler) : null;
    }
    let gefunden = null;
    $(`state[id=${ADAPTER}.meters.*.meterNumber]`).each((id) => {
        const s = getState(id);
        if (!gefunden && s && String(s.val).trim().toUpperCase() === String(anlage.zaehlernummer).trim().toUpperCase()) {
            gefunden = id.split('.')[3];
        }
    });
    return gefunden;
}

/** Liste der Zähler, die der ablesio-Adapter kennt – als Hilfe bei falscher Zähler-ID */
function vorhandeneZaehler() {
    const liste = [];
    $(`state[id=${ADAPTER}.meters.*.label]`).each((id) => {
        const nr = id.split('.')[3];
        const s = getState(id);
        const nummer = getState(`${ADAPTER}.meters.${nr}.meterNumber`);
        liste.push(`${nr} = ${s && s.val ? s.val : (nummer && nummer.val ? nummer.val : '(ohne Bezeichnung)')}`);
    });
    return liste.length ? liste.join(', ') : `keine – läuft der ablesio-Adapter (${ADAPTER}) mit gültigem Token?`;
}

async function synchronisieren() {
    log(`ablesio: Wochen-Sync für ${ANLAGEN.length} Anlage(n) startet.`);
    // Erst prüfen, ob der ablesio-Adapter überhaupt mit ablesio verbunden ist (Token gültig?)
    const verbunden = await getStateAsync(`${ADAPTER}.info.connection`);
    if (!verbunden || !verbunden.val) {
        const fehler = await getStateAsync(`${ADAPTER}.info.lastError`);
        log(`ablesio: Sync abgebrochen – der ablesio-Adapter ist nicht mit ablesio verbunden. ` +
            (fehler && fehler.val ? `Ursache: ${fehler.val}` : `Läuft ${ADAPTER}? Token prüfen: Instanz-Einstellungen → „Token prüfen".`), 'error');
        return;
    }
    const gesendet = [];
    for (const anlage of ANLAGEN) {
        const zaehlerId = zaehlerIdFuer(anlage);
        const ziel = `${ADAPTER}.meters.${zaehlerId}.submitReading`;
        // Objekt prüfen, nicht den Wert: submitReading hat erst nach der ersten Übermittlung einen Wert
        if (!zaehlerId || !(await getObjectAsync(ziel))) {
            const was = anlage.zaehlernummer ? `mit der Zählernummer ${anlage.zaehlernummer}` : String(anlage.ablesioZaehler);
            log(`ablesio: ${anlage.name} – Zähler ${was} gibt es im ablesio-Adapter nicht. Vorhanden: ${vorhandeneZaehler()}`, 'warn');
            continue;
        }
        anlage._id = zaehlerId;
        const q = await getStateAsync(anlage.quelle);
        if (!q || q.val === null || q.val === undefined) {
            log(`ablesio: ${anlage.name} – Datenpunkt ${anlage.quelle} nicht gefunden oder leer – übersprungen.`, 'warn');
            continue;
        }
        const wert = Math.round(Number(q.val) * 100) / 100;
        if (!Number.isFinite(wert) || wert <= 0) {
            log(`ablesio: ${anlage.name} – „${q.val}" ist kein gültiger Zählerstand – übersprungen.`, 'warn');
            continue;
        }
        // Platzhalter statt Messwert (z.B. SMA per Modbus, wenn der Wechselrichter nachts schläft: 4294967295 u.ä.)
        if (wert >= 4294967295 || wert > 10000000) {
            log(`ablesio: ${anlage.name} – „${q.val}" ist ein Platzhalter des Wechselrichters (schläft er gerade?) – übersprungen.`, 'warn');
            continue;
        }
        const alterTage = (Date.now() - q.ts) / 86400000;
        if (alterTage > MAX_ALTER_TAGE) {
            log(`ablesio: ${anlage.name} – Wert ist ${Math.floor(alterTage)} Tage alt (Wechselrichter offline?) – übersprungen.`, 'warn');
            continue;
        }
        await setStateAsync(ziel, wert, false);   // ack = false → der ablesio-Adapter übermittelt
        gesendet.push(anlage);
        log(`ablesio: ${anlage.name} – ${wert} kWh an den ablesio-Adapter übergeben.`);
    }
    // Ergebnis nach kurzer Zeit ins Log schreiben (der Adapter arbeitet nacheinander ab)
    if (gesendet.length) {
        setTimeout(() => {
            for (const anlage of gesendet) {
                const s = getState(`${ADAPTER}.meters.${anlage._id}.lastSubmitStatus`);
                log(`ablesio: ${anlage.name} – Ergebnis: ${s && s.val ? s.val : 'noch offen'}`);
            }
        }, 20000);
    }
}

schedule(ZEITPLAN, synchronisieren);
if (BEIM_START_AUSFUEHREN) {
    synchronisieren();
}

Schritt 4: Testen

Zum Ausprobieren BEIM_START_AUSFUEHREN = true setzen und das Skript speichern – es läuft sofort einmal. Im Log siehst du nach etwa 20 Sekunden das Ergebnis. Danach wieder auf false stellen: ab jetzt läuft der Sync jeden Sonntag um 20:00 Uhr.

Skript im Editor mit Log-Ausgabe
Log: übergeben, übermittelt, Ergebnis „ok". Schematische Darstellung

Schritt 5: In ablesio ansehen

Beim Zähler „Pergola" erscheint jede Woche ein neuer Stand – mit Wochenertrag und der Ersparnis nach deinem Strompreis.

Wöchentliche Ablesungen der Pergola in ablesio
Jede Woche ein Stand: Ertrag und Ersparnis.
Zählerkarte Pergola
Die Zählerkarte zeigt die letzte Ablesung.

Gut zu wissen

Meldung in lastSubmitStatus / im LogBedeutung
Sync abgebrochen – … nicht mit ablesio verbundenDie Ursache steht dahinter, meist API-Token abgelehnt: im ablesio-Profil einen neuen Token erstellen und in der Instanz eintragen – mit „Token prüfen" in den Instanz-Einstellungen gleich testen.
ok: … übermitteltalles gut – der Stand ist in ablesio
übersprungen: unverändertseit dem letzten Mal kein neuer Ertrag – nichts zu tun
Fehler: kleiner als der letzte StandStimmt die Quelle (totalData.mTotal der richtigen Anlage) und die Zähler-ID? Sonst: Wechselrichter getauscht oder zurückgesetzt? Dann in ablesio einen Zählerwechsel anlegen
Fehler: Für diesen Zähler gibt es am … schon eine Ablesungablesio nimmt einen Stand pro Kalendertag und Zähler an – der wöchentliche Sonntags-Termin passt immer, auch neben Ablesungen per Hand unter der Woche. Zweimal am selben Tag geht nicht; eine falsche Ablesung korrigierst du im Bericht mit ✏️.
Wert ist … Tage altder Wechselrichter meldet sich nicht (WLAN, Growatt-Cloud) – der Stand wird erst gesendet, wenn er wieder aktuell ist

Fragen? Über das Kontaktformular – oder Ablo in der App fragen.