IOmeter bietet aktuell keinen direkten Adapter in ioBroker an, mit dem sich das Gerät nativ in die Plattform integrieren lässt. Allerdings gibt es eine Möglichkeit das IOmeter mit kleinem technischen Aufwand einzubinden. Der folgende Artikel gibt hierfür die Anleitung.
1. Den benötigten Adapter installieren
Um später ein kurzes Skript in ioBroker einbinden zu können, das mit die Kommunikation mit dem IOmeter steuert, muss zuerst der Adapter Script Engine von javascript installiert werden. Dieser kann über die Suche im Reiter Adapters gefunden werden. Anschließend kann der Adapter über das 3-Punkte-Menü und das Plus-Symbol installiert werden.
2. Den Adapter konfigurieren
Im zweiten Schritt müssen noch einige Einstellungen für den Adapter vorgenommen werden.
Hierfür wird der Instances-Reiter geöffnet und bei der javascript-Instanz das Werkzeug-Symbol geklickt. In der Oberfläche, die sich nun öffnet, muss im Feld "Additional npm modules" der Name "node-fetch" eingetragen werden und das Kästchen neben "Enable command "setObject"" angekreuzt werden. Anschließend werden die Einstellungen über "Save" gespeichert.
Unter Instances findest du die Einstellungen für den javascript-Adapter
Die Einstellungen des Adapters sollten so bei dir aussehen
3. Das Skript hinzufügen
Nachdem der der javascript-Adapter korrekt eingebunden ist, kann das Skript hinzugefügt werden. Hierfür gehst du in den Reiter Scripts und erstellst ein neue Skript über das Plus-Symbol (du kannst hier auch Ordner hinzufügen, um falls du mehrere Skripte verwalten willst).
Anschließend wählst du JavaScript für die Art des Skripts und legst den Namen fest. In dem Textfeld das jetzt erscheint kopierst du das folgende Skript:
// ============================================================
// IOmeter Bridge – Datenpunkte & Polling
// Basiert auf einem Script im ioBroker Forum (https://forum.iobroker.net/topic/84410/iometer-einbinden/)
// Standard Ablageort: 0_userdata.0.iometer.*
// Standard Intervall: alle 10 Sekunden + Sofortstart
// ============================================================
// Einstellungen ── ──────────────────────────────────────────
const BRIDGE_IP = "192.168.xxx.xxx"; // < IP der IOmeter Bridge anpassen!───
const BASE = "0_userdata.0.iometer"; // <-- Datenpunkt in ioBroker, bei mehreren Bridges z.B. "0_userdata.0.iometer.wohnung1" und
const schedule_time = 10; // <-- Abfrageinterval in Minuten einstellen
// ab hier nichts ändern, wenn du nicht weist was du tust ──
const fetch = require('node-fetch');
// Ordner-Struktur ── ──────────────────────────────────────────x
const CHANNELS = [
{ id: BASE, name: "IOmeter" },
{ id: `${BASE}.reading`, name: "Zählerstand" },
{ id: `${BASE}.status`, name: "Status" },
{ id: `${BASE}.status.bridge`, name: "Bridge" },
{ id: `${BASE}.status.core`, name: "Core" },
];
// Datenpunkte ── ──────────────────────────────────────────────
const DPS = [
// Zählerstand ------------------------------------------------
{
id: "reading.meterNumber",
common: { name: "Zählernummer", type: "string", role: "text", read: true, write: false },
},
{
id: "reading.time",
common: { name: "Zeitstempel (ISO)", type: "string", role: "text", read: true, write: false },
},
{
id: "reading.consumption_wh",
common: { name: "Gesamtverbrauch", type: "number", role: "value.energy.consumed", read: true, write: false, unit: "Wh" },
},
{
id: "reading.production_wh",
common: { name: "Gesamteinspeisung", type: "number", role: "value.energy", read: true, write: false, unit: "Wh" },
},
{
id: "reading.power_w",
common: { name: "Aktuelle Leistung", type: "number", role: "value.power", read: true, write: false, unit: "W" },
},
// Status – Bridge --------------------------------------------
{
id: "status.bridge.rssi",
common: { name: "Bridge WLAN-Signal", type: "number", role: "value", read: true, write: false, unit: "dBm" },
},
{
id: "status.bridge.version",
common: { name: "Bridge Firmware", type: "string", role: "text", read: true, write: false },
},
// Status – Core ----------------------------------------------
{
id: "status.core.connectionStatus",
common: { name: "Verbindungsstatus", type: "string", role: "text", read: true, write: false },
},
{
id: "status.core.rssi",
common: { name: "Core WLAN-Signal", type: "number", role: "value", read: true, write: false, unit: "dBm" },
},
{
id: "status.core.version",
common: { name: "Core Firmware", type: "string", role: "text", read: true, write: false },
},
{
id: "status.core.powerStatus",
common: { name: "Stromversorgung", type: "string", role: "text", read: true, write: false },
},
{
id: "status.core.batteryLevel",
common: { name: "Akkustand", type: "number", role: "value.battery", read: true, write: false, unit: "%" },
},
{
id: "status.core.attachmentStatus",
common: { name: "Montagestatus", type: "string", role: "text", read: true, write: false },
},
{
id: "status.core.pinStatus",
common: { name: "PIN-Status", type: "string", role: "text", read: true, write: false },
},
// Status – Gerät ---------------------------------------------
{
id: "status.deviceId",
common: { name: "Geräte-ID", type: "string", role: "text", read: true, write: false },
},
// Meta -------------------------------------------------------
{
id: "_lastUpdate",
common: { name: "Letztes Update", type: "number", role: "value.time", read: true, write: false },
},
{
id: "_error",
common: { name: "Fehlermeldung", type: "string", role: "text", read: true, write: false },
},
];
// Hilfsfunktion: sequenziell über Array iterieren ── ─────────
function seqMap(arr, fn, cb) {
let i = 0;
function next() {
if (i >= arr.length) { cb && cb(); return; }
fn(arr[i++], next);
}
next();
}
// Channels anlegen ── ─────────────────────────────────────────
function ensureChannels(cb) {
seqMap(CHANNELS, (ch, next) => {
setObject(ch.id, { type: "channel", common: { name: ch.name }, native: {} }, next);
}, cb);
}
// Datenpunkte anlegen ── ──────────────────────────────────────
function ensureDatapoints(cb) {
seqMap(DPS, (dp, next) => {
setObject(`${BASE}.${dp.id}`, { type: "state", common: dp.common, native: {} }, next);
}, cb);
}
// API-Abfrage ── ──────────────────────────────────────────────
async function fetchIOmeter() {
try {
// /v1/reading
const resR = await fetch(`http://${BRIDGE_IP}/v1/reading`);
if (!resR.ok) throw new Error(`Reading HTTP ${resR.status}`);
const r = await resR.json();
const regs = r.meter.reading.registers;
const byObis = (code) => regs.find(x => x.obis === code)?.value ?? null;
setState(`${BASE}.reading.meterNumber`, r.meter.number, true);
setState(`${BASE}.reading.time`, r.meter.reading.time, true);
setState(`${BASE}.reading.consumption_wh`, byObis("01-00:01.08.00*ff"), true);
setState(`${BASE}.reading.production_wh`, byObis("01-00:02.08.00*ff"), true);
setState(`${BASE}.reading.power_w`, byObis("01-00:10.07.00*ff"), true);
// /v1/status
const resS = await fetch(`http://${BRIDGE_IP}/v1/status`);
if (!resS.ok) throw new Error(`Status HTTP ${resS.status}`);
const s = await resS.json();
const bridge = s.device?.bridge ?? {};
const core = s.device?.core ?? {};
setState(`${BASE}.status.deviceId`, s.device?.id ?? "", true);
setState(`${BASE}.status.bridge.rssi`, bridge.rssi ?? null, true);
setState(`${BASE}.status.bridge.version`, bridge.version ?? "", true);
setState(`${BASE}.status.core.connectionStatus`, core.connectionStatus ?? "", true);
setState(`${BASE}.status.core.rssi`, core.rssi ?? null, true);
setState(`${BASE}.status.core.version`, core.version ?? "", true);
setState(`${BASE}.status.core.powerStatus`, core.powerStatus ?? "", true);
setState(`${BASE}.status.core.batteryLevel`, core.batteryLevel ?? null, true);
setState(`${BASE}.status.core.attachmentStatus`, core.attachmentStatus ?? "", true);
setState(`${BASE}.status.core.pinStatus`, core.pinStatus ?? "", true);
setState(`${BASE}._lastUpdate`, Date.now(), true);
setState(`${BASE}._error`, "", true);
const kWh = ((byObis("01-00:01.08.00*ff") ?? 0) / 1000).toFixed(2);
log(`IOmeter ✓ Leistung: ${byObis("01-00:10.07.00*ff")} W | Gesamt: ${kWh} kWh`, "info");
} catch (err) {
setState(`${BASE}._error`, err.message, true);
log("IOmeter Fehler: " + err.message, "error");
}
}
// Bootstrap ── ────────────────────────────────────────────────
ensureChannels(() =>
ensureDatapoints(() => {
log("IOmeter: Datenpunkte bereit – starte erste Abfrage", "info");
fetchIOmeter(); // Sofort beim Skriptstart
setInterval(() => {
fetchIOmeter(true); // "light mode"
}, schedule_time * 1000);
})
);
In diesem Skript muss unbedingt drauf geachtet werden die IP-Adresse der Bridge einzutragen. Die kann über die IOmeter App abgerufen werden und muss dann oben im Skript an der entsprechen Stelle eingefügt werden. Ebenfalls kann das Intervall für das Abfragen der Daten von Bridge konfiguriert werden. Standardgemäß steht es im Skript auf 10-sekündlich, es kann aber auf bis zu eine Sekunde reduziert werden.
4. Die Daten abrufen
Wenn das Skript eingefügt, angepasst und gestartet wurde, können die Daten im Objects-Reiter abgerufen werden. Im Ordner 0_userdata -> 0 -> iometer findest du die Ordner reading und status, die die Zahlenwerte sowie Statusdaten enthalten.
Die Ordnerstruktur in denen deine IOmetet-Daten gespeichert werden, sieht so aus
Wenn dein Zähler zusätzliche Werte wie mehrere Tarife oder Phasen ausgibt, werden die mit dem aktuellen Skript nicht in ioBroker integriert. Wenn du die Werte aber gerne in ioBroker hättest, kontaktiere einfach unsren Support und wir schicken dir die entsprechende Erweiterung für dein Skript!