Fra Tibber Pulse til lokal MQTT i Home Assistant

Tibber Pulse MQTT oppsett

Jeg satte opp Tibber Pulse med MQTT i Home Assistant for flere år siden… Det fungerte knallbra.,

Kort forklart: Tibber Pulse kan kobles direkte til Home Assistant via MQTT ved å sette opp Mosquitto, konfigurere Pulse i aksesspunktmodus og dekode data i Node-RED.

Problemet?
Jeg hadde ikke dokumentasjonen fra sist.

Dermed ble dette ikke bare et oppsett – men en slags gjenoppdagelse av hele prosessen. Dette blogginnlegget er derfor like mye for meg selv neste gang, som for andre som vil gjøre det samme.

Innhold

Hvorfor jeg gikk bort fra standardoppsettet

Tibber Pulse fungerer fint rett ut av boksen, men jeg ønsket:

  • Lokal sanntidsdata (ikke via sky)
  • Raskere responstid i automasjoner
  • Full kontroll i Home Assistant

Jeg visste det var mulig – jeg hadde jo gjort det før – men detaljene var borte.

Steg 0 – Installer MQTT (Mosquitto)

Mosquitto Home Assistant installasjon

Før du begynner med Pulse må du ha en MQTT broker klar.

I Home Assistant er det enkleste å installere Mosquitto broker:

  • Gå til Settings → Add-ons
  • Installer Mosquitto broker
  • Start add-on
  • Sett opp brukernavn/passord

Dette er selve “motorveien” som dataene fra Pulse skal gå gjennom.

Steg 1 – Reset av Tibber Pulse

Første hinder var å få Pulse tilbake i “setup-modus”.

Slik gjorde jeg det:

  1. Koble fra HAN-porten
  2. Hold inne knappen på enheten
  3. Koble den til USB mens du holder knappen inne
  4. Vent til LED begynner å blinke

Da oppretter den sitt eget WiFi-nettverk igjen.

Steg 2 – Inn på konfigurasjonssiden

Når Pulse er i setup-modus:

Her får du opp konfigurasjonssiden.

Steg 3 – MQTT-oppsett (det viktigste)

MQTT-oppsett i Pulse

Dette var delen jeg måtte “grave frem” igjen.

Jeg la inn:

  • SSID – Wifinavn
  • psk – Passord til WiFi
  • IP til MQTT broker (Home Assistant). Dette må skrives på følgende måte brukernavn:passord@IP for eksempel puls:puls@192.168.1.2
  • Port (1883)
  • Topic (f.eks. pulse/ams)

Når dette var riktig, begynte dataene å strømme inn igjen.

Steg 4 – Stabil strøm (viktig erfaring)

En ting jeg lærte på den harde måten:

Jeg anbefaler å ikke kun kjøre Pulse på strøm fra HAN-porten.

Jeg opplevde:

  • Ustabil drift
  • Tilfeldige disconnects/ reboots
  • Perioder uten data

Løsningen for meg ble å koble til USB-strøm i tillegg.

Etter dette:

  • Ble forbindelsen stabil
  • MQTT-data kom jevnt
  • Ingen tilfeldige utfall

Dette er et enkelt grep som kan spare deg for mye feilsøking.

Steg 5 – Test oppsettet (Node-RED anbefales)

Før du kan begynne å lage dashboards og automasjoner, må dataene dekodes. Jeg anbefaler å bruke Node-Red for å sjekke informasjonen som kommer. Anbefaler denne artikkelen om du ikke har brukt Node-red tidligere: Node-red og Home Assistant – Enkel programmering

Node-RED enkel flyt

Først er det lurt å sjekke at data faktisk kommer fra Pulse til serveren. En enkel MQTT mottaker og rett inn på en debug i Node-Red vil vise om det kommer data fra pulsen.

Node-RED MQTT debug strømdata

Slik vil rådata se ut i debug-vinduet. Det er ikke så lett å forstå, så den må dekodes.

Den enkleste måten å få informasjonen inn i Home Assistant er å bruke en ferdig plug-in. Denne er populær: AMS HAN Home Assistant integrasjon

Men, dette ble for enkelt, så jeg laget min egen dekoder i Node-Red, og kan da lage mine egne beregninger og sensorer selv. Dette gir meg full kontroll på hvilke verdier jeg vil hente ut, hvordan de skal tolkes, og muligheten til å gjøre egne beregninger direkte i flyten.

Node-RED MQTT debug gruppert data

Bildet over viser informasjonen jeg henter ut fra Pulse, inkludert beregning av power_factor og estimert strømtrekk på L2. Energy_import og export står som undefined i enkelte meldinger. Dette er fordi målerstand ikke sendes i hver pakke fra måleren, men med jevne mellomrom.

I Node-RED ser oppsettet slikt ut:

Node-RED MQTT strømdata flyt

I Debugvinduet ser det slik ut:

Dataflyt inn i Debug

Min Node Red funksjonskode:

// ======================
// INPUT
// ======================
let buf = msg.payload;
if (!Buffer.isBuffer(buf)) return null;

// ======================
// STATE
// ======================
let state = flow.get("han_data") || {};
let meta = flow.get("han_meta") || {};
let i = 0;

// ======================
// HJELPEFUNKSJONER
// ======================
function readUInt32(buffer, offset) {
    return buffer.readUInt32BE(offset);
}

function readUInt16(buffer, offset) {
    return buffer.readUInt16BE(offset);
}

function readInt16(buffer, offset) {
    return buffer.readInt16BE(offset);
}

function round(value, decimals = 1) {
    return Math.round(value * Math.pow(10, decimals)) / Math.pow(10, decimals);
}

// ======================
// OBIS MAP
// ======================
let obisMap = {

    // Effekt
    "0100010700ff": { key: "power_import", scale: 1 },
    "0100020700ff": { key: "power_export", scale: 1 },

    // Energi
    "0100010800ff": { key: "energy_import", scale: 0.01 },
    "0100020800ff": { key: "energy_export", scale: 0.01 },

    // Spenning
    "0100200700ff": { key: "voltage_l1", scale: 0.1 },
    "0100340700ff": { key: "voltage_l2", scale: 0.1 },
    "0100480700ff": { key: "voltage_l3", scale: 0.1 },

    // Strøm
    "01001f0700ff": { key: "current_l1", scale: 0.1 },
    "0100330700ff": { key: "current_l2", scale: 0.1 },
    "0100470700ff": { key: "current_l3", scale: 0.1 },

    // Effekt per fase
    "0100150700ff": { key: "power_l1", scale: 1 },
    "0100290700ff": { key: "power_l2", scale: 1 },
    "01003d0700ff": { key: "power_l3", scale: 1 },

    // Reaktiv effekt
    "0100030700ff": { key: "reactive_import", scale: 1 },
    "0100040700ff": { key: "reactive_export", scale: 1 }
};

// ======================
// DLMS PARSER
// ======================
while (i < buf.length - 10) {

    let obis = buf.slice(i, i + 6).toString('hex');

    if (obisMap[obis]) {

        let { key, scale } = obisMap[obis];
        let type = buf[i + 6];
        let value = null;

        if (type === 0x06) {
            value = readUInt32(buf, i + 7);
            i += 11;
        }
        else if (type === 0x12) {
            value = readUInt16(buf, i + 7);
            i += 9;
        }
        else if (type === 0x10) {
            value = readInt16(buf, i + 7);
            i += 9;
        }
        else {
            i++;
            continue;
        }

        let scaled = value * scale;

        if (key.includes("voltage") || key.includes("current")) {
            state[key] = round(scaled, 1);
        } else if (key.includes("energy")) {
            state[key] = round(scaled, 2);
        } else {
            state[key] = Math.round(scaled);
        }

    } else {
        i++;
    }
}

// ======================
// SIKKER MÅLERSTAND
// ======================
if (state.energy_import !== undefined) {
    flow.set("energy_total", state.energy_import);
}
if (state.energy_export !== undefined) {
    flow.set("energy_export_total", state.energy_export);
}

state.energy_import = flow.get("energy_total") ?? state.energy_import;
state.energy_export = flow.get("energy_export_total") ?? state.energy_export;

// ======================
// BEREGNINGER
// ======================

// Effektfaktor
if (state.power_import && state.reactive_import !== undefined) {
    let p = state.power_import;
    let q = state.reactive_import;
    let s = Math.sqrt(p*p + q*q);

    state.power_factor = round(p / s, 2);
}

// Beregn L2 strøm hvis mangler
if (!state.current_l2 && state.power_import && state.voltage_l2) {

    let v = state.voltage_l2;
    let p = state.power_import;

    let current_est = p / (Math.sqrt(3) * v);

    state.current_l2_estimated = round(current_est, 1);
}

// ======================
// METADATA
// ======================
let text = buf.toString('latin1');

let firmwareMatch = text.match(/AIDON_[A-Z0-9]+/);
if (firmwareMatch) meta.firmware = firmwareMatch[0];

let meterIdMatch = text.match(/\d{10,}/);
if (meterIdMatch) meta.meter_id = meterIdMatch[0];

meta.manufacturer = "Aidon";

// ======================
// LAGRE
// ======================
flow.set("han_data", state);
flow.set("han_meta", meta);

// ======================
// OUTPUT
// ======================
msg.payload = {
    ...state,
    ...meta
};

return msg;

Erfaringen denne gangen

Det som slo meg mest var hvor mye jeg hadde glemt – men også hvor raskt det kom tilbake når jeg først var i gang.

Ekstra tips

Hvis du vil ha flere kilder og informasjon rundt oppsettet, finnes det gode beskrivelser av konfigurasjon og felter her:
https://github.com/toreamun/amshan-homeassistant/wiki/Lesere-MQTT#tibber-pulse
Les også mer hos Tibber om Pulse, her kan du også kjøpe den
Mosquitto informasjon og dokumentasjon finner du her
Les mer om Informasjon til AMS-HAN brukere fra NEK

Konklusjon

Selv om dette oppsettet krever litt teknisk innsikt, gir det til gjengjeld full kontroll over egne strømdata. For min del er dette en av de mest nyttige integrasjonene jeg har i Home Assistant – spesielt når det kombineres med automasjoner og effektstyring.

Og kanskje viktigst av alt: Dokumenter det du gjør – det sparer deg for mye tid neste gang 😅

Sjekk forøvrig oversiktsiden Home Assistant – Hjemmeautomasjon

Har du satt opp et kult dashboard med disse dataene? Del gjerne et bilde eller spør om hjelp i kommentarfeltet under!

Hvordan data sendes fra AMS-måleren

En viktig ting å være klar over er at AMS-måleren ikke sender all informasjon kontinuerlig. Data sendes med ulike intervaller, og dette påvirker hva du ser i Home Assistant og Node-RED.

Oppdatering hvert 2,5 sekund

  • Aktiv effekt (kW) – import

Oppdatering hvert 10. sekund

  • OBIS listeversjon, måler-ID og målertype
  • Aktiv effekt (kW) – import og eksport
  • Reaktiv effekt (kVAr) – import og eksport
  • Strøm (A) – L1, L2 og L3
  • Spenning (V) – alle faser

Oppdatering hver time

  • Aktiv energi (kWh) – import og eksport
  • Reaktiv energi (kVArh)
  • Klokke og dato

Dette forklarer hvorfor enkelte verdier, som energiforbruk (kWh), ikke alltid er tilgjengelige i hver melding. Disse sendes sjeldnere enn effekt- og spenningsdata.

FAQ – Vanlige spørsmål

Hvorfor får jeg ikke data fra Tibber Pulse?

Den vanligste årsaken er at HAN-porten ikke er aktivert hos nettselskapet. Det kan også skyldes feil MQTT-oppsett eller manglende nettverkstilkobling. Les for eksempel hos L-nett om HAN-porten

Hva er IP-adressen til Tibber Pulse i setup-modus?

Når Pulse er i aksesspunktmodus, finner du den på http://10.133.70.1/.

Må jeg bruke USB-strøm på Tibber Pulse?

Det anbefales. Mange opplever ustabil drift når enheten kun får strøm fra HAN-porten. USB-strøm gir en mer stabil løsning. Behovet er også avhengig av målertypen.

Hvorfor vises ikke energiforbruk (kWh) hele tiden?

Målerstand sendes ikke i hver melding fra AMS-måleren, men med jevne mellomrom. Derfor kan verdiene være midlertidig fraværende.

Hvordan kan jeg teste om MQTT fungerer?

Den enkleste måten er å bruke Node-RED med en MQTT-in node koblet til en debug node. Da ser du raskt om data strømmer inn.

Trenger jeg Tibber-abonnement for å bruke lokal MQTT?

Nei, du trenger ikke et aktivt Tibber-abonnement for å bruke Tibber Pulse med lokal MQTT. Når enheten er konfigurert til å sende data direkte via MQTT, fungerer den uavhengig av Tibber sin skyløsning

Fungerer dette på alle AMS-målere (Aidon, Kaifa, Kamstrup)?

Ja, dette oppsettet fungerer i utgangspunktet på de fleste AMS-målere som støtter HAN-port, inkludert Aidon, Kaifa og Kamstrup. Det kan likevel være små forskjeller i hvilke data som sendes og hvor ofte, avhengig av måler og nettselskap



Legg igjen en kommentar

Din e-postadresse vil ikke bli publisert. Obligatoriske felt er merket med *