HA:n rooli ja entiteettimalli

Tämä on kuudes osa sarjasta joka dokumentoi EnergyHub-järjestelmän rakentamisen vanhaan rintamamiestaloon. Edellisessä osassa käytiin läpi prioriteetit, tilakoneet ja fallback-logiikka — miten järjestelmä päättää kuka saa sähköä ja mitä tapahtuu kun yhteys katkeaa. Tässä osassa katsotaan miten data organisoidaan Home Assistantissa niin että se pysyy hallittavana kun järjestelmä kasvaa.
Energiajärjestelmässä on paljon entiteettejä. Modbus-rekisterit, hintatiedot, vaihevirrat, lämpöpumpun anturit, capability-flagit, parametrit, ohjaussignaalit — kaikki asuvat Home Assistantissa ja kaikki tarvitsevat selkeän paikan.
Ilman rakennetta tämä kertyy nopeasti kasaksi entiteettejä joiden nimet eivät kerro mitään, joiden yksiköt vaihtelevat integraatiosta toiseen ja joita ei kukaan enää muista mistä tulevat. EnergyHubissa rakenne on tehty etukäteen — ei jälkikäteen siivoamalla.
Neljä roolia, neljä etuliitettä
Jokainen EnergyHub-entiteetti alkaa etuliitteellä joka kertoo sen roolin järjestelmässä. Tämä ei ole pelkkä nimeämiskäytäntö — se on tietomalli joka tekee näkyväksi mitä kukin entiteetti tekee ja kuka saa käyttää sitä.
m_ — mittaukset
Kanoniset, normalisoidut arvot joita kaikki muut järjestelmän osat käyttävät. sensor.m_grid_power_w, sensor.m_pv_power_w, sensor.m_spot_price_eur_kwh. Nämä ovat template-sensoreita jotka normalisoivat raakadatan yhtenäiseen muotoon — oikea yksikkö, oikea etumerkki, oikea skaalaus.
Node-RED käyttää abstrahoitua järjestelmämallia, ei integraatiokohtaista raakadataa. Se ei tiedä tuleeko tieto Nordpool-integraatiosta, P1-mittarilta vai Modbus-rekisteristä — eikä sen tarvitse tietää. Se lukee m_buy_price_eur_kwh ja saa aina oikean arvon.
p_ — parametrit
Kaikki säädettävät kynnysarvot ja raja-arvot. input_number.p_fuse_limit_a, input_number.p_cheap_price, input_number.p_solar_excess_w. Nämä eivät ole hardkoodattuja lukuja automaatioissa tai Node-RED-funktioissa — ne ovat HA:n käyttöliittymässä säädettäviä liukusäätimiä ja syöttökenttiä.
Kun sulakerajaa pitää muuttaa — esimerkiksi liittymäkoko kasvaa 25:stä 35 ampeerin — muutos tehdään yhteen paikkaan. Node-RED lukee arvon MQTT-telemetrian kautta ja käyttää sitä automaattisesti.
c_ — capabilityt ja tilaohjaukset
Capability-flagit ja tilaohjaukset. input_boolean.c_ev_charge_allowed, input_select.c_hp_mode. Kuten aiemmissa osissa selitettiin, c_-etuliite kattaa sekä käyttöoikeudet (c_ev_charge_allowed — saako EV ladata) että tilaohjaukset (c_hp_mode — missä tilassa lämpöpumppu on). Nimestä näkee kumpi on kyseessä: _allowed-päätteiset ovat käyttöoikeuksia, muut ovat tilaohjausta. Nämä eivät ole eksplisiittisiä komentoja — komennot tulevat Node-REDiltä MQTT:n kautta.
d_ — diagnostiikka
Ihmisluettavat selitykset järjestelmän päätöksistä. input_text.d_ev_last_reason, input_text.d_hp_last_reason. Nämä eivät ohjaa mitään — ne kertovat miksi viimeisin päätös tehtiin. ”EV estetty: peak_protection, L1=23.8A”. Diagnostiikkaentiteetit tekevät näkymättömästä logiikasta näkyvää ilman että tarvitsee avata Node-REDiä.
sys_ — järjestelmätila
Globaalit tilaentiteetit. input_boolean.sys_safety_trip, input_boolean.sys_optimization_enabled, input_select.sys_operating_mode. Nämä ovat koko järjestelmän tila-arvoja joita useat komponentit lukevat.
Pakettipohja — yksi tiedosto per vastuu
Entiteetit eivät asu yhdessä suuressa tiedostossa. Ne on jaettu paketteihin loogisten vastuurajojen mukaan:
00_core.yaml p_-parametrit, sys_-boolean-arvot
00_core_modes.yaml sys_operating_mode, c_-flagit ja moodit
10_integrations.yaml Modbus, Nordpool, P1-mittari — raakadata
20_measurements.yaml m_-sensorit — normalisoitu data
30_load_ev.yaml EV-latauksen tilakone, d_ev_last_reason
31_load_heatpump.yaml HP EVU/Boost, d_hp_last_reason
40_optimization.yaml MQTT-rajapinta Node-REDiin
50_reporting.yaml Energiamittarit, utility_meter
Rakenne muistuttaa modulaarista ohjelmistoarkkitehtuuria: core, integrations, measurements, optimization, reporting. Jokainen kerros on toisistaan riippumaton — 20_measurements.yaml voi muuttua ilman että 40_optimization.yaml:iin tarvitsee koskea.
Kun EV-latauksen logiikkaan tarvitaan muutos, avataan 30_load_ev.yaml. Kun Modbus-rekisteriin tulee korjaus, avataan 10_integrations.yaml. Tiedoston nimi kertoo suoraan mitä se sisältää.
Pieni mutta tärkeä täsmennys raportoinnista: 50_reporting.yaml:n utility_meter on operatiivinen raportointikerros — se laskee kuinka paljon sähköä on ostettu tai myyty päivässä, kuukaudessa, vuodessa. Se ei ole sama asia kuin observability. InfluxDB ja Grafana ovat observability-kerros — ne tallentavat aikasarjadatan ja tekevät jälkikäteisanalyysin mahdolliseksi. Molemmat ovat tarpeen, mutta eri tarkoituksiin.
Kanoninen mittauskerros käytännössä
20_measurements.yaml on koko järjestelmän tärkein tiedosto vaikka se ei ohjaa mitään. Se on se kerros joka tekee raakadatasta luotettavia mittauksia.
Raakadata ei ole sama asia kuin luotettava mittaus. P1-mittarin arvo voi olla positiivinen tai negatiivinen riippuen integraatiosta. Nordpool voi palauttaa arvon senttiä tai euroa. Modbus-rekisteri voi palauttaa unknown jos yhteys on poikki. Kanoninen kerros ratkaisee nämä kaikki yhdessä paikassa.
Esimerkki ostosähkön hintalaskennasta:
yaml
- name: "m_buy_price_eur_kwh"
state: >
{% set spot = state_attr('sensor.nordpool_kwh_fi_eur_3_00_0',
'current_price') | float(0) %}
{% set marginaali = states('input_number.p_electricity_margin')
| float(0.004) %}
{% set siirto = states('input_number.p_electricity_transfer')
| float(0.048) %}
{{ ((spot * 1.255) + marginaali + siirto) | round(4) }}
Jos Nordpool-integraation rakenne muuttuu tai siirrytään toiseen hintalähteeseen, korjaus tehdään tähän yhteen templateen. Node-RED ei tarvitse muutosta.
Signaalin etumerkki — yksi konventio kaikkialle
m_grid_power_w > 0 tarkoittaa että ostetaan verkosta. m_grid_power_w < 0 tarkoittaa että myydään verkkoon. Sama konventio kaikkialla — ei erikoistapauksia, ei poikkeuksia.
Tämä tuntuu pieneltä asialta mutta se on yksi niistä päätöksistä joka pitää tehdä kerran ja pitää kiinni aina. Jos jossain kohtaa arvo onkin toisin päin, koko optimointilogiikka tekee vääriä päätöksiä — ja vika on vaikea löytää koska jokainen yksittäinen arvo näyttää oikealta.
float(0) — hiljainen ongelma ja eri fallback-politiikat
Template-sensoreissa on yksi yleinen kompromissi: | float(0) muuntaa unknown– ja unavailable-tilat hiljaisesti nollaksi.
Nolla ei aina tarkoita nollaa. Joskus se tarkoittaa että data puuttuu.
Kriittinen havainto on se että fallback-oletus riippuu mittauksen kriittisyydestä — kaikilla mittauksilla ei ole sama turvallinen oletusarvo.
Jos Modbus-yhteys katkeaa ja Sungrow-invertteri menee unavailable-tilaan, m_pv_power_w palauttaa 0. Node-RED tulkitsee sen niin että aurinko ei tuota. Tämä on turvallinen oletus — parempi olettaa nollatuotanto kuin tehdä päätöksiä datalla jonka alkuperä on tuntematon.
Mutta jos P1-mittari menee unavailable-tilaan ja m_grid_power_w palauttaa 0, tilanne on eri. Node-RED tulkitsee sen niin että verkosta ei osteta eikä myydä. Se voi johtaa väärään päätökseen — esimerkiksi EV-latauksen sallimiseen tilanteessa jossa verkkoteho on oikeasti korkea ja sulake uhkaa laueta.
PV missing → 0 on turvallinen. Grid missing → 0 ei välttämättä ole turvallinen.
Kriittisille arvoille kannattaa lisätä diagnostiikkasensori joka havaitsee unavailable-tilan erikseen ja kirjaa sen — ja fallback-politiikka pitää valita mittauksen roolin mukaan. Tämä ei ole vielä EnergyHubissa täysin toteutettu — se on yksi niistä asioista jotka rakentuvat käytön myötä.
Yksikkö nimessä — ei arvata
Entiteetin nimi sisältää aina yksikön kun se ei ole itsestään selvä:
sensor.m_grid_power_w — watteina, ei kilowatteinasensor.m_phase_l1_a — ampeereinasensor.m_spot_price_eur_kwh — euroina per kilowattitunti, ei senttiäsensor.m_hp_tap_water_top_c — celsiusasteina
Kun Node-RED-funktiossa lukee s.gridPower_W, tietää heti että se on watteina. Ei tarvitse avata integraatiodokumentaatiota tarkistamaan.
Mitä HA ei sisällä
HA:n entiteettimalli on tarkoituksella rajattu. Siellä ei ole:
- Optimointilogiikkaa — se on Node-REDissä
- Päätöksiä siitä milloin ladata tai lämmittää — ne tulevat Node-REDiltä komennolla
- Historiadataa aikasarjoina — se on InfluxDB:ssä
HA on mittaus- ja ohjausrajapinta. Se tekee tehtävänsä hyvin kun se pysyy siinä roolissa.
Entiteettimalli kasvaa hallitusti
Kun järjestelmään lisätään uusi laite — olkoon se akku, latauspiste tai uusi lämpöpumppu kuten Nibe, Mitsubishi tai Daikin — se liitetään samaan malliin. Uudet Modbus-rekisterit tulevat 10_integrations.yaml:iin. Normalisoidut mittaukset tulevat 20_measurements.yaml:iin m_-etuliitteellä. Ohjauslogiikka saa oman paketin 3x_-numeroväliin. MQTT-rajapinta laajenee 40_optimization.yaml:ssa.
Rakenne ei muutu — se laajenee.
Tämä on se hetki jolloin etukäteen tehty arkkitehtuuripäätös maksaa itsensä takaisin. Uuden laitteen lisääminen on ennakoitavaa työtä, ei arvausta siitä mihin se kuuluu. Harrasteprojekti muuttuu ylläpidettäväksi järjestelmäksi.
Seuraavaksi: Osa 7 — Hinta ja sulakkeet. Miten spot-hintadata kulkee järjestelmään, miten se yhdistetään sulakerajoihin ja miten nämä kaksi rajoitetta toimivat yhdessä päätöksenteossa.
Tekninen toteutus: Entiteettimalli, nimeämiskäytäntö ja pakettipohja on kuvattu tarkemmin ohjeessa HA:n valmistelu integraatiokerrokseksi.