
Tämä on kolmas osa sarjasta, joka dokumentoi EnergyHub-järjestelmän rakentamista vanhaan rintamamiestaloon. Edellisessä osassa käytiin läpi arkkitehtuuripäätökset ennen koodia: miksi järjestelmä jaettiin vastuualueisiin ja mihin järjestelmätason päätöksenteko sijoitetaan. Tässä osassa tarkastelen sitä, mitä Home Assistantin rooli integraatiokerroksena tarkoitti käytännössä.
Kun EnergyHub-arkkitehtuuria suunniteltiin, yksi kysymys nousi toistuvasti esiin: pitääkö Home Assistantin päättää vai välittää?
Vanhassa järjestelmässä HA teki molempia. Se luki arvot, vertasi kynnysarvoihin ja ohjasi laitteita samojen automaatioiden sisällä. Tämä toimi pitkään, kunnes aurinkotuotanto, sähkön hinta, sähköauton lataus ja lämpöpumpun käyttö alkoivat vaikuttaa toisiinsa.
Ongelma ei ollut se, etteikö Home Assistantilla voisi tehdä monimutkaista logiikkaa. Ongelma oli, että tämän talon järjestelmätason priorisointipäätökset olivat vuosien aikana hajonneet eri automaatioihin.
EnergyHubissa päätös oli siksi selkeä: Home Assistant ei omista energian optimointiin liittyvää järjestelmätason priorisointia.
Arkkitehtuuri yhdellä silmäyksellä
┌─────────────────────────────────────────┐
│ Kenttä- ja laitetaso │
│ Sungrow · Thermia · Shelly · P1 │
└────────────────────┬────────────────────┘
│ lukee / ohjaa
┌────────────────────▼────────────────────┐
│ Home Assistant │
│ Integraatiot · normalisointi · tila │
│ käyttöliittymä · paikallinen logiikka │
└──────────┬──────────────────┬───────────┘
│ telemetria │ ohjauspyynnöt
▼ ▲
┌─────────────────────────────────────────┐
│ Node-RED │
│ priorisointi · päätös · orkestrointi │
└─────────────────────────────────────────┘
Tässä vaiheessa työnjako hahmotettiin tarkoituksella yksinkertaisena. Home Assistant yhdistää laitteet yhteiseen tilannekuvaan. Node-REDiin keskitetään talon eri tavoitteiden välinen päätöksenteko. Fyysinen laite säilyttää oman sisäisen säätönsä ja suojauksensa.
Myöhemmissä Case-osissa rajat tarkentuivat edelleen. Tämä oli lähtökohta, jonka avulla vanha hajautunut automaatiomalli saatiin ensin purettua ymmärrettäviksi vastuiksi.
Mitä integraatiokerros tässä projektissa tarkoittaa?
Home Assistantin ensimmäinen tehtävä on lukea laitteiden tilat Modbusin, P1-mittauksen ja muiden integraatioiden kautta. Toinen tehtävä on muuttaa eri lähteiden tiedot sellaiseen yhteiseen muotoon, jota muu EnergyHub voi käyttää ilman laitekohtaista tulkintaa.
Kolmas tehtävä on toimia osana ohjauspolkua. Ylemmän tason päätös voidaan välittää Home Assistantin kautta laitteelle, mutta päätös ja fyysinen toteutus pidetään käsitteellisesti erillään.
HA voi sisältää myös determinististä paikallista logiikkaa: käyttötiloja, datan validointia, aikakatkaisuja tai käyttäjän ohitusten käsittelyä. Rajaus ei siis tarkoita, että HA olisi passiivinen viestiputki. Rajaus koskee sitä, missä koko talon tavoitteiden väliset kompromissit ratkaistaan.
Miksi vastuunjako kannattaa?
Ensimmäinen hyöty on vianhaku. Kun jotain menee väärin, voidaan seurata ketjua vaihe vaiheelta:
lähdelaite
→ HA:n lukema
→ kanoninen mittaus
→ Node-REDin päätös
→ ohjauspyyntö
→ laitteen readback
→ fyysinen vaste
Jos lähdelaitteen tieto on oikein mutta kanoninen mittaus väärin, ongelma on normalisoinnissa. Jos tilannekuva on oikein mutta päätös väärä, vikaa etsitään päätöksentekologiikasta. Jos komento lähetettiin mutta fyysistä vastetta ei synny, ongelma voi olla ohjauspolussa, laitteessa tai laitteen omissa ehdoissa.
Tämä on tarkempi tapa ajatella vikaa kuin olettaa, että se kuuluu automaattisesti tietylle kerrokselle.
Toinen hyöty on testattavuus. Kun rajapinnat ovat määriteltyjä, Node-REDin päätöslogiikkaa voidaan syöttää testidatalla ilman oikeaa laitetta. Samoin Home Assistantin mittauksia ja integraatioita voidaan tarkistaa ilman, että optimointilogiiikka tekee niiden perusteella oikeita ohjauksia.
Kolmas hyöty on hallittu vikatila. Yhden komponentin vika ei saa automaattisesti tarkoittaa sitä, että jokin vanha arvo tai viimeinen komento tulkitaan turvalliseksi. Jokaiselle olennaiselle toiminnolle pitää määritellä erikseen, mitä tapahtuu tiedon, päätöksentekijän tai ohjausyhteyden kadotessa.
Kanoniset mittaukset erottavat lähteen järjestelmätason tiedosta
Yksi konkreettinen ratkaisu, joka syntyi arkkitehtuuripäätöksistä, oli kanoninen mittauskerros. Home Assistantissa järjestelmätason mittauksille käytettiin m_-etuliitettä — “measurement”.
Ajatus oli tärkeämpi kuin nimeämiskäytäntö: raakadata ei ole sama asia kuin järjestelmätason mittaus.
P1-lähteen teho voi käyttää eri etumerkkisopimusta kuin muu järjestelmä. Hintaintegraatio voi ilmoittaa arvon eri yksikössä. Modbus-arvo voi olla hetken unknown tai puuttua kokonaan yhteyshäiriössä.
Kanoninen kerros normalisoi tämän. Esimerkiksi:
sensor.m_grid_power_w
positiivinen = osto
negatiivinen = vienti
sensor.m_spot_price_eur_kwh
aina €/kWh
Muu järjestelmä käyttää kanonista suuretta eikä laitteen tai integraation alkuperäistä esitystapaa. Jos lähde myöhemmin muuttuu, korjaus tehdään integraatiorajassa eikä jokaiseen päätöksentekosääntöön.
Pelkkä arvo ei riitä
Ensimmäisessä toteutusvaiheessa huomio oli pitkälti arvon normalisoinnissa. Myöhemmin sama periaate osoittautui tarpeelliseksi myös tiedon laadulle.
Järjestelmätason mittauksesta pitää pystyä tietämään esimerkiksi:
- mistä tieto tuli
- milloin se havaittiin
- kuinka vanha se on
- onko se käyttökelpoinen kyseiseen päätökseen
Tämä ajatus kasvoi myöhemmin paljon alkuperäistä m_-sensorimallia pidemmälle, mutta sen alku on tässä: päätöksentekijän ei pitäisi joutua tulkitsemaan jokaista raakaintegraatiota erikseen.
Capability kertoo luvan – ei päätöstä
Toinen alkuvaiheen rakenne oli capability-ajattelu: erillinen tila kertoo, onko tietyn toiminnon käyttäminen sallittua.
Esimerkiksi c_ev_charge_allowed voidaan tulkita käyttöluvaksi sähköauton lataukselle. Se ei tarkoita, että auton pitäisi juuri nyt ladata, eikä se ole sama asia kuin fyysiselle releelle annettava komento.
Tässä erossa on kolme eri kysymystä:
- Saako toimintoa käyttää?
- Haluaako päätöksenteko käyttää sitä juuri nyt?
- Toteutuiko pyydetty toiminto fyysisesti?
Tämä erottelu osoittautui myöhemmin olennaiseksi. Yhden boolean-arvon ei pidä yrittää olla samanaikaisesti käyttäjän lupa, optimoinnin päätös ja fyysisen releen tila.
Operating mode kokoaa käyttäjän tavoitteen yhteen paikkaan
Toinen suunnitteluvaiheen ajatus oli keskitetty operating mode eli järjestelmän toimintatila. Sen tarkoitus oli estää tilanne, jossa esimerkiksi poissaolo, tehorajoitus ja normaali hintaoptimointi toteutetaan toisistaan tietämättöminä automaatioina.
Alkuvaiheessa käytin tiloista nimiä kuten normal, peak_protection, vacation ja emergency. Myöhemmässä toteutuksessa nimet ja tarkka vastuunjako muuttuivat, mutta periaate säilyi: järjestelmällä pitää olla eksplisiittinen tapa ilmaista, mikä käyttötilanne on voimassa ja mikä tavoite ohittaa normaalin optimoinnin.
Home Assistant oli luonteva paikka tehdä käyttötilasta käyttäjälle näkyvä ja säilyttää sen järjestelmätason tila. Päätöksentekologiikka puolestaan käyttää tätä yhtenä syötteenään.
Tärkeää on, ettei toimintatila saa yksin ohittaa fyysisiä suoja- tai laiterajoja. Esimerkiksi käyttäjän pyytämä “lataa nyt” voi ohittaa normaalin hintapäätöksen, mutta ei liittymän sallittua kuormaa.
Mitä Home Assistant ei tässä EnergyHubissa omista?
Tässä projektissa HA:han ei haluttu keskittää päätöstä siitä, onko juuri tämä vartti kokonaisuuden kannalta paras sähköauton lataukseen tai kuinka lämpöpumpun, auton ja muun jouston prioriteetit pitäisi sovittaa yhteen.
Nämä päätökset keskitettiin Node-REDiin, jossa yhteinen päätöspolku oli helpompi nähdä ja testata.
Tämä ei tarkoita, ettei HA:ssa olisi lainkaan päätöksiä. Paikalliset tilakoneet, käyttötilat, datan validointi ja muut deterministiset säännöt voivat aivan hyvin kuulua integraatio- ja automaatiokerrokseen.
Rajanveto on siis tämä: HA ei tässä toteutuksessa omista koko talon monen tavoitteen optimointia.
Uudelleenkäynnistyminen paljasti tärkeän eron tilan ja historian välillä
Alkuperäisessä suunnitelmassa ajatus oli, että Node-RED voi käynnistyä uudelleen, lukea Home Assistantin nykytilan ja jatkaa siitä. Tämä on hyvä tavoite, mutta lause “historiaa ei tarvita” oli liian vahva.
Normaalin päätöksenteon ei pitäisi riippua siitä, että koko vanha tapahtumahistoria ladataan muistista jokaisessa restartissa. Järjestelmän pitää kuitenkin säilyttää tai pystyä rekonstruoimaan sellainen tila, jolla on merkitystä tulevalle käyttäytymiselle.
Tällaista tilaa voivat olla esimerkiksi:
- aktiivinen käyttötila
- käyttäjän voimassa oleva tilapäinen ohitus
- hystereesiin tai vähimmäiskestoon liittyvä tieto
- sellainen määräaika, jota ei saa unohtaa restartissa
Sen lisäksi historiadataa tarvitaan aivan eri tarkoitukseen: päätösten jäljitettävyyteen, vianhakuun, datan laadun arviointiin ja myöhemmin mallintamiseen.
Tämä ero — päätöksenteon tarvitsema nykytila vs. auditointiin tarvittava historia — tarkentui vasta järjestelmän rakentamisen edetessä.
Mitä tapahtuu, jos Node-RED pysähtyy?
Myös tähän alkuperäinen vastaus oli liian yksinkertainen: “laitteet jäävät viimeiseen tunnettuun turvalliseen tilaan”. Viimeinen tunnettu tila ei välttämättä ole turvallinen tai tarkoituksenmukainen pitkään jatkuvassa häiriössä.
Oikea suunnittelukysymys on laitekohtainen: mikä on hyväksyttävä fallback, jos ylempi päätöksenteko katoaa?
- voiko laite palata omaan normaaliin säätöönsä
- pitääkö tilapäinen optimointipyyntö purkaa
- saako jokin kuorma jäädä päälle määräajaksi
- miten HA tai muu paikallinen kerros tunnistaa päätöksentekijän katoamisen
Tämä ajatus johti myöhemmissä Case-osissa heartbeat-, watchdog-, sallittavuus- ja final gate -ratkaisuihin. Tässä vaiheessa tärkeä päätös oli vasta se, että vikatilaa ei jätetä sattuman varaan.
Käytännön toteutus Home Assistant Containerilla
EnergyHubissa Home Assistant pyörii Docker-kontissa Lenovo ThinkCentrellä. Käytössä ei ole Home Assistant OS:ää vaan Home Assistant Container.
Tämä antaa täyden hallinnan samalle Debian-koneelle rakennettavasta Docker-kokonaisuudesta, mutta samalla HAOS:n Supervisor- ja add-on-malli ei ole käytössä. Tarvittavat muut palvelut, kuten MQTT-välittäjä, ajetaan omina kontteinaan. Yhteisön custom integration -integraatioita voidaan puolestaan asentaa HACS:n kautta.
Pakettipohjaisella konfiguraatiolla eri vastuut erotettiin jo tiedostotasolla:
00_core.yaml— järjestelmäparametrit ja yhteiset tilat10_integrations.yaml— laite- ja tietolähdeintegraatiot20_measurements.yaml— kanonisetm_-sensorit30_load_ev.yaml— sähköautoon liittyvä paikallinen tila ja ohjausrajapinta31_load_heatpump.yaml— lämpöpumpun ohjausrajapinta40_optimization.yaml— rajapinta Node-REDin suuntaan50_reporting.yaml— energia- ja raportointitiedot
Kaikki tämän vaiheen tiedostonimet tai vastuut eivät jääneet myöhemmin muuttumattomiksi. Olennaisempaa oli, että integraatiot, mittaukset, ohjausrajapinnat ja raportointi alettiin erottaa jo konfiguraation rakenteessa.
Tekninen toteutus on kuvattu tarkemmin ohjeessa Home Assistantin valmistelu integraatiokerrokseksi.
Tämän vaiheen tärkein oppi
Home Assistantin arvo EnergyHubissa ei vähentynyt, kun siltä poistettiin järjestelmätason optimoinnin omistajuus. Päinvastoin sen rooli selkeytyi.
Se toimii rajana laitteiden kirjavan maailman ja EnergyHubin yhteisen tilamallin välillä. Kun mittaukset, käyttötilat ja ohjausrajapinnat ovat yhdessä paikassa määriteltyjä, ylempi päätöksenteko voi keskittyä siihen, mitä sen oikeasti pitää ratkaista.
Integraatiokerroksen tehtävä ei ole olla mahdollisimman yksinkertainen. Sen tehtävä on tehdä muun järjestelmän riippuvuuksista hallittavia.
Seuraavaksi: kerrosmalli käytännössä
Osa 4 käy läpi kerrosmallin kokonaisuudessaan: miten Home Assistant, Node-RED ja kenttätaso keskustelevat keskenään ja mikä MQTT:n rooli tässä toteutuksessa on.
HEOMF Case: Oma talo -sarjan pääsivulta löydät kaikki sarjan osat.