Kategoria: HEOMF

  • Case: oma talo — Osa 16: Kun kukaan ei katso: vahtikoira hiljaisille vioille

    Tämä on kuudestoista osa sarjasta, joka dokumentoi EnergyHub-kotiautomaatiojärjestelmän rakentamisen vanhaan rintamamiestaloon. Edellinen osa kertoi systemaattisesta vikojen läpikäynnistä ennen käyttöönottoa. Se päättyi lupaukseen kertoa seuraavaksi operoinnista — siitä, miten energianhallintajärjestelmää pidetään pystyssä silloin, kun kukaan ei aktiivisesti katso.

    Tämä osa on siitä. Se alkaa viasta, jota en huomannut kahteen viikkoon — ja päättyy samaan vikaan, mutta toisella lopputuloksella.

    Varmuuskopio, joka oli hiljaa rikki

    Järjestelmästä otetaan automaattinen varmuuskopio joka yö kello kolme. Arkisto pakataan, tarkistussumma lasketaan, tiedosto ladataan pilveen. Olin rakentanut tämän varmuuskopioinnin kuukausia sitten ja lakannut ajattelemasta sitä — juuri niin kuin varmuuskopion kuuluukin toimia.

    Sitten eräänä päivänä satuin katsomaan varmuuskopiohakemistoa. Tuorein arkisto oli kahden viikon takaa.

    Skripti oli ajautunut joka yö. Ajastin oli tehnyt työnsä. Mutta itse varmuuskopiointi epäonnistui hiljaa: eräs komento vaati oikeuksia, joita ajastettu ajo ei voinut antaa, ja koska skriptistä puuttui rivi joka olisi pysäyttänyt sen ensimmäiseen virheeseen, se jatkoi loppuun asti ja raportoi onnistuneensa. Loki näytti siistiltä. Paluukoodi oli nolla — merkki onnistumisesta. Vain tiedostojen puuttuminen kertoi, ettei mitään ollut oikeasti tallennettu kahteen viikkoon.

    Tämä on täsmälleen sama vikaluokka josta edellinen osa kertoi: hiljainen epäonnistuminen. Mikään ei kaadu, mikään ei hälytä, ja virhe elää niin kauan kuin kukaan ei satu katsomaan oikeaa paikkaa oikeaan aikaan. Erona vain se, että nyt vika ei ollut ohjauslogiikassa vaan ylläpidossa — ja se osui juuri siihen mekanismiin, jonka koko tarkoitus on suojata katastrofilta.

    Korjasin varmuuskopiointiskriptin. Mutta oikea opetus ei ollut korjaus. Se oli kysymys, jonka vika nosti esiin: mitä muuta on hiljaa rikki, mistä en tiedä?

    Se mitä ei mittaa, ei ole olemassa

    Kotiautomaatiojärjestelmä koostuu joukosta osasia, jotka kaikki voivat pettää itsenäisesti. Home Assistant integroi laitteet. Node-RED tekee optimointipäätökset. MQTT-viestiväylä välittää tiedot. InfluxDB tallentaa historian, Grafana piirtää sen. Kaikki pyörii pienessä palvelimessa nurkassa, eikä kukaan katso sitä päivittäin — se on koko pointti. Automaation kuuluu olla näkymätön.

    Mutta näkymättömyydellä on hinta. Jos järjestelmä ei kerro itsestään mitään, ainoa tapa tietää että se voi hyvin on tarkistaa se käsin. Ja käsin tarkistaminen ei skaalaudu — sitä ei yksinkertaisesti tule tehtyä, ennen kuin jokin menee niin pahasti pieleen että se huomataan muuta kautta. Kylmä suihku, pimeä huone, kahden viikon aukko varmuuskopioissa.

    Ratkaisu ei ole katsoa useammin. Ratkaisu on rakentaa monitorointi, joka on osa järjestelmää itseään: järjestelmä joka kertoo omasta voinnistaan — ja erillinen valvoja, joka huomaa jos se lakkaa kertomasta.

    Sydämensyke

    Ensimmäinen kerros on sydämensyke. Node-RED — järjestelmän aivot, joka tekee energianhallinnan optimointipäätökset — julkaisee säännöllisin väliajoin viestin, joka kertoo yhden asian: minä olen elossa.

    Mutta pelkkä ”olen elossa” ei riitä, ja tämä on tärkeä oivallus. Prosessi voi olla pystyssä ja silti kyvytön tekemään työnsä, jos sen syötteet ovat pysähtyneet. Jos sähkön hintatieto on tunteja vanhaa tai lämpöpumpun mittaukset ovat lakanneet päivittymästä, järjestelmä on teknisesti hengissä mutta käytännössä sokea. Se tekisi päätöksiä vanhentuneen tiedon varassa — mikä on usein vaarallisempaa kuin päätösten tekemättä jättäminen.

    Siksi sydämensyke kertoo prosessin hengissäolon lisäksi sen, kuinka tuoretta jokainen keskeinen syöte on: milloin sähkömittarilta tuli viimeksi lukema, milloin sähkön pörssihinnat päivittyivät, milloin lämpöpumppu ja aurinkopaneelit raportoivat, ja milloin optimointilogiikka viimeksi ajoi läpi. Syke ei ole ”olen elossa” vaan ”olen elossa ja näen”. Se julkaistaan viestiväylälle muutaman sekunnin välein, ja se on perusta kaikelle mitä seuraa.

    Vahtikoira järjestelmän ulkopuolella

    Toinen kerros on valvoja — vahtikoira, joka on tarkoituksella järjestelmän ulkopuolella.

    Tämä sijoittelu on olennainen, ja se on monitoroinnin tärkein yksittäinen suunnitteluperiaate. Sydämensyke tulee Node-REDistä, mutta juuri Node-REDin kaatuminen on yksi tärkeimmistä asioista jotka pitää havaita. Jos valvoja eläisi saman prosessin sisällä jota se valvoo, se kaatuisi yhdessä sen kanssa eikä kukaan saisi tietää. Siksi vahtikoira ajaa palvelimella itsenäisenä käyttöjärjestelmän ajastamana prosessina, Node-REDin, Home Assistantin ja koko muun konttipohjaisen järjestelmän ulkopuolella. Se herää minuutin välein, tarkistaa terveyden ja kirjaa havaintonsa.

    Mitä se tarkistaa? Ovatko kaikki palvelut pystyssä. Onko sydämensyke tuore vai onko se vaiennut. Ovatko syötteet ajan tasalla. Milloin viimeisin varmuuskopio syntyi — se sama tarkistus, jonka puuttuminen aloitti tämän koko tarinan. Ja paljonko levytilaa on jäljellä, koska täyttyvä levy on hidas, hiljainen tapa kaataa koko kotiautomaatiojärjestelmä.

    Tärkein sääntö: vahtikoira ei pure — vielä

    Vahtikoiran voisi kuvitella toimivan: se havaitsee ongelman ja korjaa sen — käynnistää kaatuneen palvelun uudelleen, palauttaa laitteet turvatilaan. Se on lopullinen tavoite. Mutta se ei ole se, mistä aloitin, ja syy on periaatteellinen.

    Valvoja, joka tekee automaattisia korjauksia, on itsessään vaarallinen, jos sen käsitys ”ongelmasta” on väärä. Väärin viritetty vahtikoira, joka käynnistää palveluita uudelleen turhaan tai palauttaa laitteita turvatilaan silloin kun kaikki on kunnossa, aiheuttaa enemmän häiriötä kuin se estää. Ja ennen kuin sille antaa vallan toimia, pitää tietää tarkalleen miltä normaali näyttää — muuten se ei osaa erottaa normaalia poikkeavasta.

    Siksi ensimmäinen versio on tarkoituksella hampaaton. Se katsoo, se kirjaa, se raportoi — mutta se ei kajoa mihinkään. Sen ainoa tehtävä on kerätä tietoa siitä, miten järjestelmä käyttäytyy tavallisesti: kuinka tuoreita syötteet ovat normaalisti, kuinka paljon ne vaihtelevat, mikä on tavallista ja mikä poikkeavaa.

    Ja tämä maltti osoittautui heti hyödylliseksi. Kun annoin vahtikoiran kerätä dataa vuorokauden yli ja katsoin sitten mitä se oli nähnyt, syötteiden tuoreudesta paljastui selkeä kuvio: normaalitilassa mittaustiedot olivat lähes aina alle minuutin vanhoja, ja jakauman yläraja asettui johdonmukaisesti noin 59 sekuntiin — ei koskaan sen yli. Jos olisin arvannut varoitusrajan etukäteen, olisin todennäköisesti asettanut sen 60 sekuntiin, mikä on juuri normaalin ylärajalla — ja se olisi tuottanut turhia hälytyksiä lähes joka päivä. Datan perusteella nostin varoitusrajan 90 sekuntiin ja varsinaisen vikarajan 180 sekuntiin, kolmeen mittaussykliin. Nyt raja laukeaa vasta aidosta poikkeamasta, ei normaalin vaihtelun huipusta. Tätä ei olisi voinut päätellä pöydän takana — se piti mitata.

    Tämä on sama periaate jolla koko järjestelmä otettiin käyttöön: havainnoi ensin, toimi vasta sitten. Vahtikoira aloittaa katsojana, ei tekijänä.

    Mitä testi paljasti

    Ennen kuin luotin vahtikoiraan, testasin sen: pysäytin Node-REDin tahallani ja katsoin, mitä tapahtuu.

    Vahtikoira huomasi katkon välittömästi ja merkitsi tilan vialliseksi. Ja mikä tärkeintä — se ei tehnyt mitään muuta. Node-RED pysyi alhaalla, koska tässä vaiheessa vahtikoiralla ei ole valtaa käynnistää sitä. Se on juuri se käyttäytyminen jonka halusin varmistaa: valvoja havaitsee, mutta ei toimi. Käynnistin Node-REDin itse takaisin, ja sydämensyke palasi.

    Tämä testi oli tärkeä paitsi toimivuuden varmistamiseksi, myös siksi että se pakotti minut näkemään vian sellaisena kuin vahtikoira sen näkee. Kun katko oli päällä, palvelu näkyi alhaalla, sydämensykkeen ”viimeksi nähty” -aika alkoi kasvaa, ja optimointilogiikan viimeisin ajo jäi taakse. Kaikki kolme osaa kertoivat saman tarinan eri kulmasta — ja juuri se moniulotteisuus on syy, miksi rakensin sykkeen kertomaan muutakin kuin pelkän hengissäolon. Yksi signaali voi valehdella; kolme rinnakkaista signaalia piirtää totuuden.

    Kun yksi mittari nikottelee

    Yksi hienovarainen suunnittelukysymys ansaitsee oman huomionsa, koska se on juuri sellainen kohta jossa naiivi toteutus pettää.

    Kun vahtikoira valvoo useaa syötettä — sähkömittari, hinnat, lämpöpumppu, aurinkopaneelit — herää kysymys: milloin se hälyttää? Ilmeinen vastaus olisi ”kun ne kaikki ovat vanhentuneet”. Mutta se olisi vaarallinen virhe. Jos vaatisin että kaikki syötteet vanhenevat yhtä aikaa ennen hälytystä, niin tilanne jossa vain yksi integraatio kuolee — vaikkapa lämpöpumpun tiedonsiirto katkeaa mutta kaikki muu jatkaa normaalisti — jäisi täysin huomaamatta. Ja juuri se on todennäköisin vikatapaus: yksittäinen yhteys irtoaa, ei koko väylä kerralla.

    Ratkaisu on kaksitasoinen. Jos yksittäinen syöte vanhenee, se on varoituksen arvoinen — jokin integraatio on pulassa, ja vahtikoira kertoo tarkalleen mikä. Jos kaikki syötteet vanhenevat yhtä aikaa, se on vakavampi merkki: koko optimointisykli tai viestiväylä on jumissa. Molemmat havaitaan, mutta eri painoarvolla. Sokea piste, jossa yksittäisen laitteen hiljainen kuolema katoaa muiden terveyden taakse, on suljettu.

    Samaan tapaan yksittäinen hetkellinen piikki ei saa laukaista hälytystä. Jos jokin syöte sattuu olemaan hetken tavallista vanhempi yhden tarkistuksen ajan, se on kohinaa, ei vikaa. Vahtikoira vaatii että poikkeava tila jatkuu useamman peräkkäisen tarkistuksen ajan ennen kuin se nostaa hälytyksen — ja vastaavasti se ei julista tilaa terveeksi heti ensimmäisestä normaalista lukemasta, jottei vilkkuva, epävakaasti nikotteleva vika pääse piiloutumaan hälytyksen ja normaalin väliin sahaamalla. Nämä ovat pieniä yksityiskohtia, mutta juuri ne erottavat monitorointijärjestelmän joka on hyödyllinen sellaisesta joka huutaa sudesta niin usein, ettei sitä enää kuunnella.

    Nyt kaikki jää talteen

    Yksi asia puuttui vielä. Vahtikoira raportoi terveyden minuutin välein, mutta raportti katosi heti — se oli hetken tilannekuva, ei historiaa. Jos halusin tietää miten syötteet käyttäytyivät viime yönä, tietoa ei ollut mistä katsoa.

    Niinpä kytkin sekä sydämensykkeen että vahtikoiran raportit samaan aikasarjatietokantaan, johon järjestelmä muutenkin tallentaa historiansa — InfluxDB:hen, jonka päälle Grafana piirtää kuvaajat. Nyt jokainen syke ja jokainen terveystarkistus jää talteen, ja niistä syntyy oma valvontanäkymänsä: järjestelmän terveyden kojelauta, joka näyttää yhdellä silmäyksellä ovatko palvelut pystyssä, kuinka tuoreita syötteet ovat, milloin viimeisin varmuuskopio otettiin ja paljonko levytilaa on jäljellä.

    KUVA 1: System Health -kojelauta yleisnäkymänä — palvelut, telemetria-ikien aikasarja, varmuuskopion ikä, levytila

    Juuri tätä kertyvää dataa valvojan rajojen asettaminen vaatii — ja kuten edellä kuvattu varoitusrajan tarina osoitti, sitä ei voi arvata etukäteen. Se pitää mitata. Kojelauta teki myös oman hyödyllisen palveluksensa: kun näkee järjestelmän terveyden piirrettynä, huomaa myös monitoroinnin omat aukot. Muutama puute paljastui vasta siinä vaiheessa kun data piirtyi ruudulle — mikä on hyvä muistutus siitä, että näkyvyyden rakentaminen tekee näkyväksi myös sen, mitä ei vielä mitata.

    Ja sitten, ennen kuin ehdin edes julkaista tätä artikkelia, vahtikoira teki ensimmäisen aidon löytönsä.

    Ensimmäinen aito saalis

    Ajattelin, että ensimmäinen todellinen havainto antaisi odottaa itseään viikkoja. Se tuli päivissä — ja tavalla, joka oli melkein liian osuva ollakseen totta.

    Osana tätä samaa työtä tein tietoturvasiivouksen: järjestelmän tietokantaan oli aikanaan luotu yksi ylioikeuksinen pääsytunniste, jota useampi palvelu käytti yhteisesti, ja se korvattiin rajatuilla, palvelukohtaisilla tunnisteilla. Oikea ja tarpeellinen parannus. Mutta sillä oli sivuvaikutus, jota en huomannut: yöllinen varmuuskopiointiskripti haki tietokantaosuuttaan varten juuri sitä vanhaa tunnistetta. Kun tunniste mitätöitiin, skripti alkoi saada joka yö kirjautumisvirheen. Ajastin ajoi, virhe kirjautui lokiin, jota kukaan ei lukenut. Täsmälleen sama hiljainen vikaluokka kuin tämän artikkelin alussa — nyt vain oman parannukseni aiheuttamana.

    Erona edelliseen kertaan: nyt joku katsoi. Huomasin vian, koska kaksi mittaria oli eri mieltä. Vahtikoiran raportoima varmuuskopion ikä kasvoi kohti 56:ta tuntia, kun kojelaudan toinen paneeli näytti tyytyväisenä vihreää kymmentä tuntia. Ristiriita itsessään oli hälytys. Selitys löytyi kaivamalla: järjestelmässä on kaksi erillistä varmuuskopioprosessia — palvelukohtainen ja koko järjestelmän kattava — ja paneeli seurasi sitä joka toimi, vahtikoira sitä joka oli rikki.

    Vahtikoira oli oikeassa, ja syy on periaatteellinen. Se ei kysynyt varmuuskopioprosessilta miten meni, vaan mittasi levyllä olevan varmuuskopiotiedoston todellisen iän. Tämä on sama periaate, joka on kulkenut läpi koko sarjan ohjauspuolella:

    Komento ei ole toteuma. Lokirivi on väite. Tiedosto levyllä on tosiasia. Valvo tosiasioita.

    Vika eli alle kaksi vuorokautta ennen kuin se jäi kiinni. Edellinen vastaava eli kaksi viikkoa — ja senkin löytyminen oli puhdasta sattumaa. Se on koko tämän monitorointikerroksen arvo yhdessä vertailussa.

    KUVA 2:Varmuuskopion ikä kasvoi, vaikka järjestelmä näytti muuten toimivan. Korjauksen jälkeen ikä putosi takaisin lähelle nollaa. Tämä on juuri se hiljainen vikaluokka, jota vahtikoiran pitää havaita.

    Korjaus itsessään tarjosi vielä yhden muistutuksen. Sen aikana yksi apuskripti kaatui virheeseen, jonka syntaksitarkistus oli jo ehtinyt hylätä — mutta ajoin skriptin silti. Tarkistus, joka ei pysäytä, ei ole tarkistus. Sama kuri, joka koskee järjestelmän muutoksia, koskee myös sen korjauksia.

    Kuka valvoo valvojaa?

    Kojelauta paljasti vielä yhden asian, joka ansaitsee rehellisen maininnan: monitoroinnin omat viat.

    Yksi kojelaudan paneeleista — sähkömittauksen valvonnan tila — alkoi vilkkua. Välillä se näytti vihreää, välillä oranssia ”ei viestiä”. Data sen takana sahasi tasaisesti kahden arvon väliä, ilman mitään yhteyttä järjestelmän todelliseen tilaan. Juurisyy ei ollut sähkömittarissa vaan valvontatavassa: valvoja katsoi, sattuuko viesti näkymään juuri sen lyhyessä kuunteluikkunassa — puhdas ajoitusarpajainen, jossa noin joka kolmas tarkistus voitti.

    Monitorointi on itsekin ohjelmisto, ja sillä on omat buginsa. Valvoja, joka välillä valehtelee, on pahempi kuin valvoja jota ei ole — koska siihen joko lakataan luottamasta, tai pahempaa, sen ilmoituksiin turrutaan. Korjaus noudattaa täsmälleen samaa mallia, joka pelasti varmuuskopiovalvonnan: oikea kysymys ei ole ”näinkö viestin juuri nyt” vaan ”kuinka vanha viimeisin luotettava viesti on”. Ja siihen asti kojelaudan puolella sama vaimennus kuin muuallakin: yksittäinen ohi mennyt näyte ei käännä tilaa — vasta jatkuva hiljaisuus.

    Näkyvyyden rakentaminen teki näkyväksi myös valvonnan omat puutteet. Se ei ole häpeä vaan ominaisuus: järjestelmä, joka paljastaa omat vikansa, on tervein mahdollinen.

    Kaksi tekoälyä, kuten ennenkin

    Kuten edellisessä osassa, käytin myös tässä kahden tekoälyavustajan työnjakoa: toinen auttoi toteutuksessa, toinen katselmoi suunnitelmia ja etsi sokeita pisteitä. Useampi tämän osan tärkeimmistä yksityiskohdista — kaksitasoinen hälytyslogiikka yksittäisen ja yhtäaikaisen vanhenemisen välillä, sekä vaatimus ettei vilkkuva tila jää piiloon — nousi nimenomaan katselmoinnista. Lopulliset päätökset ja testit jäivät ihmiselle, mutta yhden hengen projektissa toinen näkökulma on arvokas — varsinkin silloin, kun rakennetaan turvakerroksia, joiden pitää toimia myös silloin kun muu järjestelmä ei toimi.

    Operointi on oma taitonsa

    Tämän sarjan alkuosat kertoivat järjestelmän rakentamisesta: miten laitteet liitetään, miten ohjauslogiikka kirjoitetaan, miten optimointi tehdään. Tämä osa kertoi jostain muusta — järjestelmän pitämisestä pystyssä sen jälkeen kun se on rakennettu. Ne ovat eri taitoja, ja jälkimmäinen jää usein huomiotta, kunnes jokin menee hiljaa rikki.

    Hiljainen vika on operoinnin keskeisin vihollinen, koska se ei ilmoita itsestään. Kylmä suihku, kahden viikon aukko varmuuskopioissa, pysähtynyt integraatio jota kukaan ei huomaa — ne kaikki jakavat saman piirteen: mikään ei kaadu, mikään ei huuda. Ratkaisu ei ole valppaus, koska ihminen ei jaksa katsoa loputtomiin. Ratkaisu on rakenne: järjestelmä joka kertoo omasta voinnistaan, ja valvoja joka huomaa hiljaisuuden. Ja rakenne ehti todistaa arvonsa ennen kuin tämä artikkeli ehti julkaisuun — sen ensimmäinen aito saalis oli hiljaa rikkoutunut varmuuskopiointi, täsmälleen se vika, jota vastaan se rakennettiin.

    Tärkein periaate koko työssä oli silti maltti: valvoja aloittaa katsojana, ei tekijänä, ja saa hampaat vasta kun normaali on mitattu.

    Se seuraava askel — hampaiden antaminen valvojalle — on oma tarinansa. Kun järjestelmä osaa luotettavasti havaita että jokin on vialla, seuraava kysymys on: saako se korjata sen itse? Ja jos saa, miten varmistetaan ettei korjaus itse aiheuta vahinkoa — ettei vahtikoira pure väärää jalkaa? Se on fail-safe-arkkitehtuurin aihe, ja se on tulevan osan tarina.


    Seuraavaksi: Osa 17 — lämpöpumppu siirtyy final gate -polkuun. Kolme tapaa epäonnistua täysin hiljaa, yksi onnenkantamoinen jossa Thermia validoi koko päätösketjun itse kesken testien — ja miksi mikään ei ole valmista ennen kuin se on todennettu restartin yli.

  • Case: oma talo — Osa 15: Kun käyttöönotto paljasti piiloviat: FMA-kovennus

    Tämä on viidestoista osa sarjasta, joka dokumentoi EnergyHub-kotiautomaatiojärjestelmän rakentamisen vanhaan rintamamiestaloon. Edellinen osa pysähtyi hetkeen ennen live-käyttöönottoa: Home Assistant- ja Node-RED-pohjainen energianhallintajärjestelmä oli pyörinyt shadow-moodissa viikkoja, päätöslogiikka oli käyty läpi, ja vaiheistettu käyttöönottosuunnitelma oli valmis. Lupasin kertoa seuraavaksi, miten vaiheistus eteni käytännössä ja mitä tapahtui ensimmäisten viikkojen aikana.

    Lyhyt vastaus: vaiheistus eteni jokseenkin suunnitellusti. Mutta käyttöönotto paljasti vikoja, joita shadow-moodi ei voinut näyttää — eikä siksi, että ne olisi tehty huolimattomasti, vaan siksi, että ne olivat luonteeltaan sellaisia, että ne aktivoituvat vasta kun järjestelmä ottaa oikean kontrollin oikeista laitteista.

    Tämä osa kertoo niistä vioista ja siitä, miten ne käytiin systemaattisesti läpi. Se on tarina menetelmästä nimeltä FMA — failure mode analysis — ja siitä, miksi se kannatti tehdä juuri käyttöönoton kynnyksellä eikä vasta sitten, kun jokin oli mennyt pahasti pieleen.

    Miksi shadow-moodi ei riitä

    Shadow-moodi on hyvä turvaverkko. Järjestelmä laskee päätökset mutta ei toteuta niitä; jos logiikassa on virhe, se näkyy lokissa eikä laitteen käyttäytymisessä. Viikkojen shadow-ajo antoi luottamuksen siihen, että päätöslogiikan iso kuva on kunnossa.

    Mutta shadow-moodilla on sokea piste. Se ei voi paljastaa vikoja, jotka syntyvät vuorovaikutuksesta oikean laiteohjauksen kanssa. Kun järjestelmä vain laskee eikä ohjaa, se ei koskaan joudu tilanteeseen, jossa lähetetty komento ja toteutunut tila eroavat toisistaan. Se ei joudu palautumaan turvakatkaisusta, koska se ei koskaan laukaise sellaista. Se ei joudu käsittelemään tilannetta, jossa vanha retained-viesti elää MQTT-brokerissa ohjauspäivityksen jälkeen, koska shadow-moodissa kukaan ei reagoi siihen viestiin.

    Toisin sanoen: vaarallisin vikaluokka tällaisessa älykodin ohjausjärjestelmässä on hiljainen vika. Mikään ei kaadu. Lokissa ei näy virhettä. Laite vain käyttäytyy väärin — tai jää käyttäytymättä — ja jos kukaan ei satu katsomaan oikeaa mittaria oikealla hetkellä, virhe voi elää päiviä.

    Juuri tällaisten vikojen löytämiseksi tein FMA:n.

    Mikä FMA on

    FMA — failure mode analysis eli vika- ja vaikutusanalyysi — on menetelmä, joka on tuttu teollisuusautomaatiosta ja turvallisuuskriittisestä suunnittelusta. Idea on yksinkertainen: sen sijaan että odotetaan vikojen ilmenevän itsestään, käydään järjestelmä läpi ja kysytään jokaisesta osasta järjestelmällisesti, miten tämä voi epäonnistua. Ei ”epäonnistuuko”, vaan ”miten”.

    Kävin EnergyHubin läpi tällä kysymyksellä ja tunnistin 17 erillistä vikatilaa — failure modea, joista käytän merkintää F1–F17. Ne priorisoitiin ja toteutettiin seitsemässä erässä. Jokainen korjaus tehtiin omana muutoksenaan, omalla testillään, ja jokainen katselmoitiin erikseen. Käytin tähän kahden tekoälyn työnjakoa: toinen analysoi ja toteutti muutokset, toinen teki arkkitehtuurikatselmuksen ja staattisen tarkistuksen. Tästä työnjaosta lisää myöhemmin.

    Vioista hahmottui kolme toistuvaa perusluokkaa. Ne ovat tämän artikkelin punainen lanka, koska ne paljastavat jotain olennaista siitä, millaisia ovat hajautetun ohjausjärjestelmän tyypilliset heikkoudet.

    Vikaluokka 1: jämähtänyt viesti

    MQTT — viestiväylä, jolla kotiautomaation osat puhuvat keskenään — tukee niin sanottuja retained-viestejä. Kun viesti merkitään retained-tilaan, broker säilyttää sen ja antaa sen jokaiselle uudelle tilaajalle, joka liittyy kanavalle. Tämä on erinomainen ominaisuus tilatiedolle: kun järjestelmä käynnistyy uudelleen, se saa heti tietää viimeisimmän tunnetun moodin, eikä jää sokeaksi siihen asti, kunnes seuraava päivitys sattuu tulemaan.

    Mutta sama ominaisuus on miina. Jos retained-viesti kantaa vanhaa, väärää tilaa, se ei katoa itsestään. Se elää brokerissa, kunnes joku julkaisee tilalle uuden. Ja jos järjestelmän jokin osa lukee tuon vanhan viestin ja toimii sen mukaan, syntyy se mitä kutsun zombieksi: tila, joka on jo nollattu yhdessä paikassa mutta herää henkiin toisesta.

    Tämä luokka tuli näkyviin dramaattisimmin turvakatkaisun yhteydessä, johon palaan tuonnempana. Mutta sen perusmuoto oli yksinkertainen, ja sen korjaus opetti periaatteen, joka toistui läpi koko työn.

    Vikaluokka 2: hiljainen epäonnistuminen

    Tämä on se vaarallisin luokka, jonka jo mainitsin. Hiljainen epäonnistuminen tarkoittaa tilannetta, jossa toiminto ei tee mitä piti, mutta mikään ei ilmoita siitä.

    Otetaan konkreettinen esimerkki. Järjestelmä lämmittää käyttöveden kerran päivässä, ja se pitää kirjaa siitä, onko vesi jo lämmitetty (dhw_heated_today). Tämä lippu nollataan joka yö, jotta seuraavana päivänä vesi taas lämmitetään. Alkuperäisessä toteutuksessa nollaus tapahtui ajastettuna kello 00:05.

    Mutta entä jos Node-RED — ohjelmisto, joka tämän nollauksen tekee — sattuu olemaan käynnistymässä uudelleen juuri kello 00:05? Päivitys, uudelleenkäynnistys, mikä tahansa. Silloin nollaus jää tapahtumatta. Lippu jää eilisen true-arvoon. Ja seuraavana päivänä järjestelmä päättelee, että vesi on jo lämmitetty — eikä lämmitä sitä. Mikään ei kaadu. Lokissa ei lue virhettä. Vain kylmä suihku seuraavana aamuna kertoo, että jokin meni pieleen.

    Korjaus oli muuttaa nollaus ajastetusta päivämääräpohjaiseksi: järjestelmä tarkistaa joka ohjaussyklillä, onko päivä vaihtunut edellisestä nollauksesta, ja nollaa liput silloin. Tämä tarkistus selviää uudelleenkäynnistyksestä, koska se ei riipu yhdestä ainoasta hetkestä.

    Tämän luokan korjauksia oli useita. Sähkön hintaohjauksen tyyppisuojaus: tyhjä hintalista johti aiemmin tilanteeseen, jossa vertailu ”onko nyt halpa tunti” palautti aina epätoden, ja sähköauton lataus jäi tapahtumatta halvalla — hiljaa. Käyttövesiboostin uusintayrityksen esto: jos boost epäonnistui, sen laukaisuehdot jäivät voimaan ja se yritti käynnistyä uudelleen loputtomasti. Lämpöpumpun asetusarvon vahvistus: lämpöpumpulle lähetetty comfort wheel -arvo merkittiin ”lähetetyksi” jo lähetyshetkellä, ei silloin kun lämpöpumppu oikeasti vahvisti ottaneensa sen vastaan — joten jos komento ei mennyt perille, sitä ei lähetetty uudelleen.

    Kaikilla näillä on sama rakenne: toiminto epäonnistuu tavalla, joka ei näy mitenkään, ellei satu katsomaan oikeaa arvoa oikealla hetkellä.

    Vikaluokka 3: kaksi omistajaa

    Kolmas luokka on hienovaraisin ja arkkitehtonisesti opettavaisin. Se syntyy, kun samalla tilatiedolla on kaksi lähdettä.

    EnergyHubissa järjestelmän toimintamoodi — normaali, loma, hätätila — kirjoitettiin alun perin kahdesta paikasta. Oli oma dedikoitu kanava moodille, ja sen lisäksi moodi kulki mukana isommassa ”koontiviestissä”, joka kokosi yhteen järjestelmän eri tilatietoja. Kaksi kirjoittajaa, sama muuttuja.

    Ongelma syntyy ristiriidassa. Jos moodi vaihtui omalla kanavallaan, mutta koontiviesti ehti tulla vielä vanhalla moodilla, lopputulos riippui siitä, kumpi viesti sattui saapumaan viimeisenä. Moodi saattoi flipata takaisin vanhaan arvoon ilman, että kukaan oli sitä pyytänyt. Epädeterministinen tila — eli tila, jota ei voi luotettavasti ennustaa — on ohjausjärjestelmässä myrkkyä.

    Korjaus oli periaatteessa yksinkertainen: yksi tila, yksi omistaja. Moodille määrättiin yksi ainoa lähde — sen oma dedikoitu kanava — ja koontiviestin moodikenttä jäi pelkäksi raportoinniksi, jota mikään ohjauslogiikka ei enää lue. Perustelu omistajan valinnalle oli vahva: oma kanava julkaistaan retained-tilassa, joten se selviää uudelleenkäynnistyksestä omillaan eikä tarvitse koontiviestiä varmistuksekseen.

    Tämä periaate — yksi totuuslähde per tila — osoittautui työn tärkeimmäksi opetukseksi. Ja kuten kohta näkyy, sen rikkomukset olivat sitkeämpiä kuin uskoin.

    Huipentuma: turvakatkaisu, joka ei vapautunut

    Sitten tuli oikea tapahtuma, joka kokosi kaikki kolme vikaluokkaa yhteen.

    Eräänä kesäkuun päivänä sauna ja auton lataus olivat päällä yhtä aikaa. L1-vaihe ylitti rajan, ja järjestelmän sulakevalvonta (Safety Guardian) teki täsmälleen oikein: laukaisi turvakatkaisun, esti sähköauton latauksen ja siirsi lämpöpumpun suojaavaan tilaan. Tämä oli järjestelmän tärkein tehtävä, ja se onnistui.

    Mutta sitten ylikuormitus poistui — sauna sammui — eikä järjestelmä palautunut normaaliin. Seuraavana päivänä se oli yhä hätätilassa: lataus estetty, lämpöpumppu lukittu suojaavaan tilaan, vaikka mitään ylivirtaa ei enää ollut. Turvakatkaisu oli tehnyt työnsä, mutta vapautus ei toiminut.

    Tässä tuli kiinnostava osa. Vian juuria ei ollut yksi vaan kolme, ja ne edustivat kukin eri vikaluokkaa.

    Ensimmäinen oli looginen umpikuja. Turvavalvonnan koodissa oli ehto, joka sanoi käytännössä ”jos turvakatkaisu on aktiivinen, älä tee mitään muuta”. Mutta automaattinen vapautuslogiikka oli sijoitettu tämän ehdon jälkeen. Eli niin kauan kuin katkaisu oli päällä, koodi ei koskaan päässyt riville, joka olisi vapauttanut sen. Klassinen kuollut koodi: looginen lukko, joka esti oman avaimensa käytön.

    Toinen oli zombie — vikaluokka 1 puhtaimmillaan. Se sama koontiviesti kantoi turvakatkaisun tilaa, ja eräs Node-REDin osa luki sitä takaisin järjestelmän globaaliin tilaan. Niinpä vaikka turvakatkaisu nollattiin omalla kanavallaan, vanha koontiviesti herätti sen henkiin. Tämä oli täsmälleen sama arkkitehtuurivirhe kuin moodin kaksoisomistus — yksi tila, kaksi lähdettä — vain eri muuttujassa.

    Kolmas oli ajoitusvirhe vapautuksessa. Kun vapautuslogiikka vihdoin korjattiin toimivaksi, se lähetti välittömästi luvan lataukselle. Mutta jos sauna oli yhä päällä, tämä olisi voinut laukaista uuden ylivirran heti — vapautus olisi aiheuttanut juuri sen tilanteen, jota vastaan se suojasi.

    Kaikki kolme korjattiin. Vapautuslogiikka siirrettiin ulos umpikujasta. Zombie-lähde katkaistiin niin, että turvakatkaisua luetaan vain sen omalta kanavalta. Ja vapautus tehtiin asteittaiseksi, niin ettei se palauta täyttä kuormaa kerralla.

    Tämä yksi tapahtuma on koko artikkelin tiivistymä. Se osoitti, että hyväkin järjestelmä voi epäonnistua monella tavalla yhtä aikaa, että viat eivät aina ole riippumattomia toisistaan, ja että sama arkkitehtuurivirhe voi piileskellä useassa paikassa odottamassa eri laukaisinta.

    Sama virhe kolmessa kerroksessa

    Turvakatkaisun zombie oli sukua moodin kaksoisomistukselle, ja sen korjaaminen paljasti, miten sitkeitä nämä arkkitehtuurivirheet ovat.

    Ensin korjattiin moodin kaksoisomistus. Sitten korjattiin turvakatkaisun lukija — Node-RED ei enää lukenut sitä koontiviestistä. Tämä riitti poistamaan toiminnallisen vaaran. Mutta koontiviesti julkaisi yhä turvakatkaisun tilaa, vaikka kukaan ei enää sitä lukenut ohjaukseen. Kenttä oli muuttunut vaarattomaksi, mutta se rikkoi yhä periaatetta — ja niin kauan kuin se oli viestissä mukana, mikä tahansa tuleva lukija voisi vahingossa herättää saman zombien henkiin.

    Niinpä se poistettiin kokonaan. Sama arkkitehtuurivirhe oli siis korjattava kolmessa kerroksessa: moodissa, Node-REDin lukijassa ja koontiviestin julkaisussa. Ja jokainen kerros löytyi vasta, kun edellinen oli korjattu — kuin sipulin kuoria.

    Tästä jäi käteen periaate, jota pidän nyt yhtenä työn arvokkaimmista: kun korjaat tilan, jolla on ollut useita lähteitä, tarkista kaikki lähteet — sekä julkaisu- että lukupuoli — älä vain sitä, jossa oire ensin näkyi. Yhden kerroksen korjaaminen tuntuu valmiilta, mutta jos toinen kerros yhä elää, vika palaa eri laukaisimella.

    Kahden tekoälyn työnjako

    Mainitsin aiemmin, että käytin kahta tekoälyä eri rooleissa. Tämä osoittautui yllättävän tehokkaaksi tavaksi tehdä tällaista työtä, ja se ansaitsee oman huomionsa.

    Claude AI toimi toteuttajana: se analysoi viat, kirjoitti korjaukset, ajoi ne kohdejärjestelmään etäyhteyden yli ja varmensi tulokset oikeasta järjestelmästä. ChatGPT toimi katselmoijana: se teki staattisen arkkitehtuurikatselmuksen, etsi epäkohtia rajapinnoista ja haastoi toteuttajan ratkaisuja.

    Työnjako tuotti aitoa lisäarvoa. Useita olennaisia tarkennuksia tuli nimenomaan katselmoijalta. Esimerkiksi käyttöveden todellisen toteuman tunnistaminen ei saanut nojata pelkkään yhteen signaaliin, vaan useamman mittauksen yhdistelmään — tämä oli katselmoijan huomio, ja se esti virhepäätelmiä. Samoin periaate, että muutosskriptin pitää kaatua äänekkäästi, jos se ei löydä korjattavaa kohtaa, sen sijaan että jatkaisi hiljaa kuin mitään ei olisi — tämä oli katselmoijan oivallus, ja se esti tilanteita, joissa olisi luultu korjauksen menneen läpi, vaikka tiedosto jäi muuttumatta.

    En väitä, että kaksi tekoälyä korvaa kokeneen ihmiskatselmoijan. Mutta yhden hengen projektissa, jossa toista paria silmiä ei muuten ole, kahden eri mallin vastakkainasettelu on selvästi parempi kuin yksi malli, joka katselmoi omaa työtään.

    Mitä tästä jäi käteen

    FMA-työ käytiin loppuun: kaikki 17 vikatilaa käsiteltiin. Lopputulos ei ole ”valmis järjestelmä” — sellaista ei olekaan — vaan järjestelmä, jonka tunnetut heikkoudet on käyty läpi ja korjattu yksi kerrallaan, ja jonka korjausten perustelut on dokumentoitu niin, että ne voi jäljittää.

    Läpileikkaava periaate kiteytyi yhteen lauseeseen: päätöksenteon pitää perustua mitattuun tai vahvistettuun toteumaan, ei oletettuun komentoon. Järjestelmä ei saa luottaa siihen, että koska se lähetti käskyn, käsky myös toteutui. Sen pitää katsoa, mitä oikeasti tapahtui — lukea mittari, vahvistaa rele, tarkistaa toteuma — ja tehdä päätöksensä sen perusteella.

    Tämä kuulostaa itsestäänselvyydeltä. Se ei ole. Suuri osa hiljaisista vioista syntyi nimenomaan siitä, että jossain kohden oletettiin komennon riittävän todisteeksi toteumasta. Ero komennon ja toteuman välillä on koko tämän työn ydin.

    Ja ehkä tärkein metatason opetus: ”JSON kelpaa” ei riitä. Useamman kerran kävi niin, että korjaus näytti oikealta — tiedosto validoitui, viesti näytti numeroita — mutta tulos oli silti väärä, koska sitä ei verrattu todellisuuteen. Eräskin aikavyöhykevirhe paljastui vain siksi, että tarkistin kellonajan oikeasta järjestelmästä ennen kuin hyväksyin muutoksen. Lopputulos pitää aina verrata todellisuuteen, ei pelkkään muotoon.

    Mitä on vielä edessä

    FMA teki järjestelmästä turvallisemman, mutta ei vielä täysin käytettävän eikä optimaalista. Kolme isoa kokonaisuutta on yhä edessä, ja ne määräävät, milloin EnergyHub voi todella korvata vanhan järjestelmän.

    Operaattorin näkymä — hallintapaneeli, jolla järjestelmää voi ohjata ja resetoida ilman komentoriviyhteyttä — on käytettävyyden ehto. Tämän turvakatkaisutapaus teki kipeän selväksi: vapautus vaati käsityönä komentoja, joita kenenkään ei pitäisi joutua muistamaan ulkoa.

    Manuaaliset ohitukset — mahdollisuus ottaa yksittäinen laite hetkeksi pois automatiikalta — tekevät järjestelmästä käytettävän arjessa, jossa kaikkea ei voi eikä pidä automatisoida.

    Lämmityskauden ohjaus — sääennusteen, ulkolämpötilan, talon lämpömassan ja lämpöpumpun hyötysuhteen yhdistäminen päätöslogiikkaan — on se, mikä tekee järjestelmästä täyden korvaajan vanhalle. Se on talven aihe, ja siihen palataan myöhemmissä osissa.

    Näistä jälkimmäinen — lämmityskauden ohjaus — on samalla suurin ja kiinnostavin. Se vie kodin energianhallinnan reaaliaikaisesta reagoinnista kohti ennakointia: ei vain ”onko sähkö nyt halpaa”, vaan ”kannattaako lämmittää nyt varastoon, koska huomenna on kylmää ja kallista”.

    Lopuksi

    Aloin tätä sarjaa dokumentoidakseni järjestelmän rakentamisen. Tämä osa kertoo jostain hieman toisesta: siitä hetkestä, kun valmiilta näyttävä järjestelmä joutuu kosketuksiin todellisuuden kanssa ja paljastaa, ettei se ollutkaan niin valmis. Se ei ole epäonnistumisen tarina. Se on tarina siitä, miten vioista tehdään näkyviä ennen kuin ne ehtivät tehdä vahinkoa — ja miten yksi systemaattinen läpikäynti tuotti enemmän luottamusta järjestelmään kuin viikkojen huoleton ajo olisi koskaan tuottanut.

    Käyttöönotto ei paljastanut, että järjestelmä oli huono. Se paljasti, mitä järjestelmästä ei voinut tietää ennen kuin se otti vastuun. Ja sen tiedon hankkiminen — hallitusti, kerros kerrokselta — oli juuri se, mihin koko vaiheistettu käyttöönotto tähtäsi.

    FMA:n jälkeen työ jatkui suoraan seuraavaan puutteeseen, jonka se paljasti. Jos Node-RED kaatuu tai viestiväylä katkeaa, laitteet jäävät viimeiseen ohjattuun tilaan — eikä mikään huomaa sitä. Tätä varten järjestelmään rakennettiin vahtikoira: ensin sydämensyke, jolla ohjauslogiikka kertoo säännöllisesti olevansa hengissä ja syötteidensä olevan tuoreita, ja sen päälle erillinen valvoja, joka seuraa koko järjestelmän terveyttä. Nämä ovat seuraavan osan aihe.


    Seuraavaksi: Osa 16 — Operointi. Varmuuskopiot, vahtikoirat ja hiljaiset viat: miten kotiautomaatiojärjestelmää pidetään pystyssä, kun kukaan ei katso.

  • Case: oma talo — Osa 14: Ennen käyttöönottoa — ohjauslogiikan läpikäynti ja kehityskohteet

    Tämä on neljästoista osa sarjasta joka dokumentoi EnergyHub-järjestelmän rakentamisen vanhaan rintamamiestaloon. Edelliset osat ovat kuvanneet arkkitehtuurin, komponentit ja integraatiot. Tässä osassa pysähdytään ennen live-käyttöönottoa: käydään läpi mitä on rakennettu, missä on tunnettuja puutteita ja mitä pitää vielä tehdä ennen kuin uusi järjestelmä ottaa täyden kontrollin.


    Järjestelmä on pyörinyt shadow-moodissa useita viikkoja. Home Assistant ja Node-RED tekevät päätöksiä — mutta eivät toteuta niitä. Vanhat automaatiot ohjaavat laitteita edelleen. Uusi järjestelmä seuraa, laskee ja kirjaa.

    Tämä on tarkoituksellinen valinta. Shadow-moodi on turvaverkko: jos päätöslogiikassa on virhe, se näkyy lokissa eikä laitteen käyttäytymisessä. Ennen live-käyttöönottoa on hyvä pysähtyä ja katsoa mitä on opittu.

    Mikä toimii hyvin

    Datarkerros on vakaa. Kaikki mittaukset kulkevat luotettavasti: P1-mittari, Sungrow Modbus, Thermia Modbus, Shelly-mittarit ja Nissan API. MQTT-väylä välittää tiedot Node-REDille ja InfluxDB tallentaa historian Grafana-visualisointia varten.

    Safety Guardian toimii. Vaihevirtojen valvonta 10 sekunnin syklissä on osoittautunut toimivaksi. 25.5.2026 tapahtuma — L1-vaihe nousi 23,8 ampeerin, Guardian laukaisi peak_protection-moodin, EV-lataus estettiin — meni täsmälleen suunnitelman mukaan. Laukaisu 23,8 ampeerin kohdalla voi herättää kysymyksen miksi reagoitiin ennen 25 ampeerin pääsulakkeen rajaa. Vastaus on ennakointi: Safety Guardian toimii ennakkovaran varassa, ei sulakkeen nimellisrajan mukaan. 25 ampeerin gG-sulake kestää lyhyet ylitykset hyvin — tavoitteena on estää pitkäkestoinen kuormitus, ei reagoida sulakkeen palamiseen. Laukaisu tapahtui jo 23,8 ampeerin kohdalla vaikka pääsulakkeet ovat 25 ampeeria: tämä on tarkoituksellista. Safety Guardian perustuu ennakoivaan rajaan, ei sulakkeen nimellisrajan ylittymiseen. Konservatiivinen varoitusraja 22,5 ampeeria antaa aikaa reagoida ennen kuin todellinen sulakeriski syntyy.

    PV-rajoituslogiikka on testattu. Sungrow-invertterin Modbus-ohjaus toimii. Dynaaminen rajoituslaskenta omakäytön perusteella on validoitu käytännössä. DC-potentiaaliaukko on dokumentoitu ja ymmärretty.

    EV-telemetria on kunnossa. Kolmen tietolähteen arkkitehtuuri — Nissan API, ShellyPro3EM63, ShellyPro1 — toimii suunnitelman mukaan. Tapering-käyrä on mitattu: lataus täydellä 3,6 kW teholla SOC 97 %:iin asti, sen jälkeen ~75 minuutin laskeva vaihe.

    Thermia-integraatio on validoitu. EVU/Boost-ohjaus Shelly Pro 2:n kautta toimii. Boost trigger-and-release on testattu käytännössä. Comfort wheel kirjoitetaan Modbus-rekisteriin suoraan.

    Tunnettuja puutteita ja kehityskohteita

    1. Ohjauslogiikan parametrit ovat hajallaan

    Hintakynnykset, lämpötilatavoitteet ja muut ohjauspisteet ovat tällä hetkellä osittain Node-REDin koodissa, osittain 00_core.yaml:ssa. Ennen live-käyttöönottoa kaikki moodikohtaiset parametrit pitää koota yhteen paikkaan josta käyttäjä voi muuttaa niitä ilman koodin muokkaamista.

    Tavoitetila: 00_core.yaml sisältää kaikki säädettävät parametrit selkeästi dokumentoituna. Node-RED lukee ne telemetrian kautta. Ei hardkoodattuja arvoja. Koska kaikki säädöt ovat yhdessä paikassa, virhekin vaikuttaa laajasti — parametrimuutokset versioidaan ja dokumentoidaan ennen käyttöönottoa. Koska kaikki säädöt ovat yhdessä paikassa, yksittäinen virhe vaikuttaa laajasti — siksi parametrimuutokset dokumentoidaan ja versioidaan.

    2. Operating moodit eivät ole viimeisteltyjä

    Normal, peak_protection ja emergency toimivat. Mutta vacation, guest, cheap_energy ja solar_maximize ovat osittain toteutettuja. Erityisesti vacation-moodi — joka tarvitsee omat lämpötilaminimit käyttövedelle ja huonelämpötilalle — on kesken.

    3. EV-latauksen ajoitusoptimointi puuttuu

    Nykyinen logiikka reagoi reaaliaikaiseen tilanteeseen: hintaan, aurinkoon, sulakkeeseen. Se ei osaa vastata kysymykseen ”milloin kannattaa aloittaa lataus jotta akku on täynnä klo 7:00”. Tähän tarvitaan lähtöaikaohjaus ja tapering-mallin integrointi päätöslogiikkaan.

    Tämä on tiedostettu rajoite. Se ei estä live-käyttöönottoa — nykyinen kynnyslogiikka toimii — mutta se on selkeä kehityskohde.

    4. Watchdog puuttuu — live-käyttöönoton ehto

    Jos Node-RED kaatuu tai MQTT-yhteys katkeaa, laitteet jäävät viimeiseen ohjattuun tilaan. Tällä hetkellä ei ole mekanismia joka havaitsisi tämän ja palautuisi turvalliseen tilaan automaattisesti. Watchdog on suunniteltu mutta ei toteutettu.

    Tämä on lähes ehdoton vaatimus ennen EV- ja HP-ohjauksen live-käyttöönottoa. Ilman watchdogia järjestelmähäiriö voi jättää lämpöpumpun EVU-tilaan tai EV-latauksen estetyksi ilman että kukaan huomaa. Watchdog toteutetaan ennen vaihetta 2.

    5. Sääennusteet ja lämpöinertia eivät ole mukana

    Optimointi perustuu tämän hetken dataan. Huomisen kylmyys ei vaikuta tämän päivän lämmityspäätöksiin. Talon lämpömassa — kuinka kauan se pysyy lämpimänä ilman lämmitystä — ei ole mallinnettu. Nämä ovat seuraavan kehitysvaiheen aiheita.

    Shadow-moodin havainnot

    Muutaman viikon shadow-moodi on tuottanut ensimmäisiä vertailuhavaintoja.

    Hintaohjauksen ero: Uusi järjestelmä olisi useammin estänyt lämpöpumpun kalliina tunteina. Vanha järjestelmä reagoi hintaan hitaammin koska sillä ei ole yhtä tarkkaa hintadataa käytössä reaaliajassa.

    EV-latauksen ero: Uusi järjestelmä ottaa sulaketilanteen huomioon ennen latauksen sallimista. Vanhassa järjestelmässä EV-lataus on yksinkertaisempi ON/OFF-päätös ilman vaihevirtatietoisuutta.

    PV-rajoitus: Vanha järjestelmä rajoittaa invertteria negatiivisilla hinnoilla kiinteällä prosentilla. Uusi laskee rajoituksen dynaamisesti omakäytön perusteella — tulos on useimmiten erilainen.

    Nämä erot ovat pieniä yksittäisinä päivinä. Kumulatiivinen vaikutus näkyy vasta kuukausien datasta.

    Live-käyttöönoton suunnitelma

    Live-käyttöönotto tehdään vaiheittain, ei yhdellä kertaa.

    Vaihe 1: PV-rajoitus live Ensimmäisenä otetaan live-tilaan PV-rajoitus negatiivisilla hinnoilla. Se on yksisuuntainen — rajoittaa invertteria — eikä ohjaa mitään fyysistä relettä. Pienin riski.

    Vaihe 2: HP EVU live Toisena lämpöpumpun EVU-ohjaus kalliina tunteina. Tämä on suurin yksittäinen vaikutus taloudelliseen optimointiin. EVU on konservatiivinen — käytännön testien perusteella ohjaus toimii ennakoivasti eikä ole aiheuttanut äkillisiä katkaisuja käynnissä olevalle kompressorille.

    Vaihe 3: EV-lataus live Kolmantena EV-latauksen ohjaus. Tässä vaiheessa Safety Guardian on jo osoittanut toimivuutensa ja EV-telemetria on vakiintunut.

    Vaihe 4: HP Boost live Viimeisenä lämpöpumpun Boost-ohjaus käyttöveden ajoittamiseen. Tämä vaatii eniten luottamusta järjestelmän logiikkaan koska se aktiivisesti käynnistää toimenpiteitä eikä vain estä niitä.

    Jokaisen vaiheen jälkeen seurataan vähintään viikko ennen seuraavaa vaihetta ja tarkistetaan hyväksymiskriteerit:

    • ei virheellisiä ohjauksia viikon aikana
    • observability-loki vastaa toteutunutta laitekäyttäytymistä
    • manuaalinen ohitus toimii odotetusti
    • vanha automaatio ei taistele uutta vastaan Jokaiselle vaiheelle on rollback-suunnitelma: jos poikkeama havaitaan — virheellinen ohjaus, odottamaton laitekäyttäytyminen tai lokin ja todellisuuden ristiriita — kyseinen live-flag palautetaan false-tilaan ja vanha automaatio jatkaa ohjausta. Palautus on yhden muuttujan asia ja tapahtuu sekunteissa.

    Mitä live-käyttöönotto ei tarkoita

    Live-käyttöönotto ei tarkoita että vanha järjestelmä sammutetaan. Molemmat pyörivät rinnakkain — uusi ottaa kontrollin yksi osa-alue kerrallaan. Shadow/live-mekanismi on juuri tätä varten: energyhub_hp_live_control ja energyhub_ev_live_control -flagit ohjaavat kumpi järjestelmä on aktiivinen.

    Live-käyttöönotto ei myöskään tarkoita että optimointi on valmis. Se tarkoittaa että arkkitehtuuri on riittävän vakaa kantaakseen vastuun — ja että voidaan alkaa kerätä oikeaa dataa oikeista päätöksistä.

    Live-käyttöönoton tärkein tavoite ei ole säästö. Se on ohjausvastuun siirto hallitusti yhdelle arkkitehtuurille — pois hajautetuista automaatioista, kohti keskitettyä päätöksentekoa joka tietää mitä tekee ja miksi.

    Teoria ja todellisuus kohtaavat vasta kun järjestelmä ohjaa oikeita laitteita oikeilla päätöksillä. Tässä vaiheessa EnergyHub ei ole enää kokeilu, mutta se ei ole vielä valmis optimointijärjestelmä. Se on hallitusti käyttöönotettava ohjausarkkitehtuuri.


    Seuraavaksi: Osa 15 — Live-käyttöönotto. Miten vaiheistus eteni käytännössä ja mitä tapahtui ensimmäisten viikkojen aikana.

  • Case: oma talo — Osa 13: Sähköauton latauksen optimointi EnergyHubissa

    Tämä on kolmastoista osa sarjasta joka dokumentoi EnergyHub-järjestelmän rakentamisen vanhaan rintamamiestaloon. Edellisessä osassa käsiteltiin Thermia-lämpöpumpun Modbus-ohjaus. Tässä osassa tarkastellaan kahta toisiinsa kytkeytyvää kokonaisuutta: sähköauton latausta ja aurinkoinvertterin ohjausta — ja sitä miten ne toimivat yhdessä energiajärjestelmässä.


    Sähköauto on kotitalouden energiankäytön kannalta poikkeuksellinen kuorma. Se on suuri — tyypillisesti 11 kW kolmivaiheisena, tässä asennuksessa 3,6 kW Nissan Leafin yksivaiheisen latauksen vuoksi — mutta täysin siirrettävissä. Toisin kuin lämmitys tai valaistus, auton lataus ei ole sidottu kellonaikaan. Se voidaan tehdä milloin tahansa yön tai päivän aikana, kunhan auto on kotona ja johdossa.

    Tämä joustavuus tekee EV-latauksesta optimoinnin kannalta kiinnostavimman yksittäisen kuorman. Mutta se tekee siitä myös vaikeimman — koska ajoituksen optimointi vaatii tietoa jota ei aina ole saatavilla: milloin auto tarvitaan seuraavaksi, paljonko akkua tarvitaan, ja miten latausteho käyttäytyy akun loppupuolella.

    Kolme tietolähdettä

    EnergyHubin EV-integraatio perustuu kolmeen tietolähteeseen joilla on tarkasti rajatut roolit.

    Nissan API tarjoaa akun varaustason (SOC), arvioidun latausajan ja auton yleisen tilan. Se ei ole reaaliaikainen — tiedot päivittyvät vain kun auto on hereillä: latauksen alussa ja lopussa, HVAC-käynnistyksen yhteydessä tai kun update-nappia painetaan manuaalisesti. Nissan API:n lataus-tila (charging) on epäluotettava — se voi näyttää ”ei lataa” vaikka auto lataa.

    ShellyPro3EM63 mittaa EV-pistokkeen todellisen latausvirran reaaliajassa. Tämä on latauksen luotettava tilan lähde. Kun Phase A teho ylittää 100 W ja ohjausrele on päällä, auto lataa. Kun teho on lähellä nollaa mutta rele on edelleen päällä, akku on täynnä tai lataus on estynyt.

    ShellyPro1 ohjaa erillistä 25 ampeerin relettä joka sallii tai estää latauksen fyysisesti. Node-RED lähettää ohjauskomennon MQTT:n kautta ShellyPro1:lle, joka kytkee releen. Laturi on Walle 16 (3-vaiheinen 11 kW), mutta Nissan Leaf latautuu yksivaiheisesti — kaikki latausteho tulee Phase A:lta, noin 3,6 kW.

    Nissan API    → SOC, arvioitu latausaika (ei reaaliaikainen)
    ShellyPro3EM63 → todellinen latausteho (reaaliaikainen, luotettava)
    ShellyPro1     → latauksen ohjausrele

    Kolmen lähteen yhdistelmä ratkaisee ongelman jota mikään niistä ei yksin ratkaise.

    Nissan API:n rajoitteet käytännössä

    29.5.2026 klo 15:20 EV-telemetria näytti:

    json

    {
      "soc_pct": 70,
      "charging": false,
      "shelly_power_w": 3699,
      "shelly_relay_on": true
    }

    Nissan API sanoi charging: false. ShellyPro3EM63 mittasi 3699 W. Auto latasi täydellä teholla.

    Tämä ei ole bugi — se on Nissan API:n suunniteltu toiminta. API päivittää latauksen tilan vain kun auto raportoi muutoksesta pilveen. Shelly mittaa pistokkeen tehon jatkuvasti.

    Tämä on se syy miksi EnergyHubissa latauksen tila ei koskaan perustu Nissan API:n charging-arvoon. Se perustuu Shellyn mittaukseen.

    Pääsulakkeet — turvallisuus ennen hintaa

    EV on kotitalouden suurin yksittäinen kuorma. Walle 16 -laturi Nissan Leafin yksivaiheisella latauksella ottaa ~3,6 kW yhdeltä vaiheelta — noin 16 ampeeria. Kun tähän lisätään talon muu kulutus, 25 ampeerin pääsulake on jo lähellä.

    Tämä on yksi tärkeimmistä syistä miksi EV-latausta pitää ohjata älykkäästi eikä vain kytkeä päälle halvalla tunnilla. Jos lämpöpumppu käy täydellä teholla ja EV lataa yhtä aikaa, L1-vaihe voi ylittää 25 ampeerin rajan.

    EnergyHubissa vaihekohtainen virta mitataan 10 sekunnin välein. Safety Guardian valvoo rajoja:

    • 22,5 A — varoitustaso, peak_protection aktivoituu
    • 24,5 A — turvalaukaisin, EV-lataus katkaistaan välittömästi

    EV-lataus on ensimmäinen kuorma joka pudotetaan kun sulake uhkaa — se on suuri, ei-kriittinen ja helposti ohjattava. Turvallisuus menee aina hinnan edelle.

    Latauspäätöslogiikka

    Priority Resolver (EnergyHubin keskitetty päätöksentekokerros) tekee EV-latauksen päätöksen samassa syklissä kaiken muun kanssa. Logiikka etenee tuttuun tapaan — turvallisuus ensin, talous viimeisenä.

    javascript

    // Luotettava latauksen tila Shellystä
    s.evActuallyCharging = s.shellyPowerW > 100 && s.shellyRelayOn
    s.evFull = s.shellyPowerW < 100 && s.shellyRelayOn
    
    // Latauspäätös
    if (!s.cap.evChargeAllowed) {
        decisions.ev = false  // capability estää
    } else if (s.isPeakLoad) {
        decisions.ev = false  // sulake uhkaa
    } else if (s.isNegativePrice) {
        decisions.ev = true   // negatiivinen hinta — lataa
    } else if (s.isSolarExcess && s.evSocPct < 95) {
        decisions.ev = true   // aurinkoylijäämä — käytä itse
    } else if (s.isCheapPrice && s.evSocPct < 90) {
        decisions.ev = true   // halpa hetki — lataa
    } else if (s.evSocPct < 20) {
        decisions.ev = true   // akku liian tyhjä — lataa aina
    } else {
        decisions.ev = false  // ei tarvetta
    }

    SOC-raja on tärkeä: lataus ei jatku jos akku on jo riittävän täynnä. ”Halpa hinta” ei tarkoita että ladataan vaikka akussa on jo 85 % — se tarkoittaa että käytetään halpa hetki hyväksi jos latausta tarvitaan.

    Aurinkoylijäämä ja EV

    Aurinkoylijäämä on EV-latauksen kannalta paras tilanne. Aurinko tuottaa enemmän kuin talo kuluttaa, ylijäämä menisi verkkoon — EV voi käyttää sen.

    EnergyHub laskee aurinkoylijäämän reaaliajassa:

    javascript

    // gridPowerW on negatiivinen kun myydään verkkoon
    s.solarExcessW = Math.max(0, -s.gridPowerW)  // vienti verkkoon = ylijäämä
    s.isSolarExcess = s.solarExcessW > 2000       // yli 2 kW ylijäämä

    Kun ylijäämää on yli 2 kW ja EV tarvitsee latausta, lataus sallitaan. EV:n 3,6 kW kulutus nostaa talon omaa kulutusta — verkkoon menevä ylijäämä pienenee ja aurinko kattaa suuremman osan omasta kulutuksesta.

    Tässä on aurinkoinvertterin ja EV-latauksen koordinoinnin ydin: ne optimoidaan yhdessä, ei erikseen. Sama Priority Resolver joka päättää PV-rajoituksesta päättää myös EV-latauksesta. Ne eivät taistele keskenään.

    PV-rajoitus ja EV yhtä aikaa

    Negatiivisilla hinnoilla tilanne on mielenkiintoinen. PV-rajoitus on aktiivinen — invertteri rajoitettu esimerkiksi 25 %:iin. Samaan aikaan EV haluaa ladata.

    Priority Resolver ratkaisee tämän koordinoidusti: jos EV lataa, se nostaa talon omaa kulutusta. Kasvanut omakäyttö tarkoittaa että PV-rajoitusta voidaan löysätä — invertteri saa tuottaa enemmän koska enemmän menee omaan käyttöön eikä verkkoon.

    javascript

    // Laske PV-rajoitus ottaen huomioon EV-lataus
    const evLoad = decisions.ev ? 3600 : 0
    const ownLoad = Math.max(300, s.pvPowerW + Math.min(0, s.gridPowerW) + evLoad)
    const pct = Math.max(10, Math.min(95, Math.round((ownLoad / s.pvPowerW) * 100)))
    decisions.pvCurtailPct = pct

    Käytännössä algoritmi arvioi kuinka paljon aurinkotuotannosta käytetään paikallisesti — oma kulutus plus EV-lataus — ja säätää invertterin tehorajan sen mukaan. Mitä enemmän omaa kulutusta, sitä korkeammalle rajoitus asetetaan ja sitä enemmän aurinko saa tuottaa.

    EV-lataus ja PV-rajoitus lasketaan samassa päätössyklissä. Tulos: aurinko tuottaa enemmän, EV lataa aurinkosähköllä, verkkoon ei mene negatiivisella hinnalla myytävää sähköä.

    Latauksen ajoittaminen — nykyinen tila

    Nykyisessä toteutuksessa EV-lataus perustuu reaaliaikaiseen tilanteeseen: hintaan, aurinkoon ja sulaketilanteeseen. Järjestelmä tekee päätöksen joka minuutti sen hetkisen datan perusteella.

    Tämä on toimiva mutta ei optimaalinen ratkaisu. Se ei osaa vastata kysymykseen: ”milloin kannattaa aloittaa lataus jotta akku on täynnä klo 7:00 halvimmilla tunneilla?”

    Vastaukseen tarvitaan kaksi asiaa jotka ovat vielä kehitysvaiheessa:

    Tapering-malli — Nissan Leaf 39 kWh ei lataudu tasaisella 3,6 kW teholla koko ajan. Latausteho laskee akun loppupuolella, arviolta noin 90 % SOC:n jälkeen. Ilman tätä mallia ei voi laskea tarkasti milloin lataus valmistuu.

    Lähtöaikaohjaus — käyttäjä asettaa milloin auto tarvitaan. Järjestelmä laskee milloin lataus pitää viimeistään aloittaa jotta akku on täynnä ajoissa. Tätä varten tarvitaan kolme ominaisuutta:

    • ”Täysi akku klo 06:00” -painike
    • Säädettävä lähtöaika
    • ”Lataa nyt täyteen” -ohitus

    Nämä ominaisuudet odottavat tapering-mallin valmistumista.

    Tapering — mitattu käyrä

    29.5.2026 tehtiin täydellinen latausmittaus ShellyPro3EM63:lla. Data kattaa SOC 85 %:sta täyteen. Lataus alkoi noin 70 %:sta mutta jatkui keskeytymättä loppuun.

    SOCLataustehoHuomio
    85–95 %~3 710–3 780 WTasainen täysi teho
    98 %~2 870 WTapering alkaa
    100 %~630 WLoppuvaihe, jatkuu ~60 min

    Tapering alkaa noin 97–98 % SOC:ssa. Tämä on huomattavasti myöhemmin kuin monilla muilla EV:llä — Leaf lataa täydellä teholla poikkeuksellisen pitkään. Tapering-vaiheen kesto on noin 60–75 minuuttia.

    Datan perusteella voidaan rakentaa kaksivaiheinen malli:

    javascript

    function estimateChargeTime(socPct, targetPct) {
        const capacity = 39       // kWh
        const taperingStart = 97  // % — mitattu
        const fullPower = 3.75    // kW — mitattu keskiarvo
        const taperingDuration = 75  // min — mitattu
    
        if (targetPct <= taperingStart) {
            // Tasainen lataus
            const energyNeeded = (targetPct - socPct) / 100 * capacity
            return energyNeeded / fullPower * 60  // minuuttia
        } else {
            // Tasainen osuus + tapering
            const flatEnergy = Math.max(0, taperingStart - socPct) / 100 * capacity
            const flatTime = flatEnergy / fullPower * 60
            const taperingPct = targetPct - Math.max(socPct, taperingStart)
            const taperingTime = taperingPct / (100 - taperingStart) * taperingDuration
            return flatTime + taperingTime
        }
    }
    
    // Esimerkki: SOC 70 % → 100 %
    // Tasainen osuus: (97-70)/100 * 39 / 3.75 * 60 = ~168 min
    // Tapering: 75 min
    // Yhteensä: ~243 min = noin 4h (Nissan API näytti 4.5h — linjassa)

    Tämä malli on riittävän tarkka lähtöaikaohjauksen laskentaan. Yksittäinen mittaus ei riitä lopulliseksi malliksi — tarvitaan useampi lataus eri SOC-tasoilta — mutta suuntaviivat ovat selvillä.

    Miksi EV on vaikein kuorma optimoida

    Lämpöpumppua optimoidaan talon lämpömassaa vasten — rakennuksen lämpötila muuttuu hitaasti ja puskuri on suuri. Aurinkoenergiaa optimoidaan hetkellistä tilannetta vasten — päätökset tehdään minuuteissa.

    EV on erilainen. Optimointihorisontti on tunteja — ”milloin auto tarvitaan seuraavaksi” — mutta tieto tulevaisuudesta on epävarmaa. Käyttäjä voi muuttaa suunnitelmiaan. Auto voi olla poissa odottamatta.

    Tämä tekee EV-optimoinnista ajoitusongelman eikä pelkän kynnysongelman. Ratkaisu vaatii:

    • Tietoa nykyisestä SOC:sta (Nissan API)
    • Tietoa latausdynamiikasta (tapering-malli)
    • Tietoa tulevista hinnoista (Nordpool day-ahead)
    • Tietoa auton tarvitsimisjasta (käyttäjän syöte)

    Kolme ensimmäistä on saatavilla tai rakenteilla. Neljäs odottaa käyttöliittymää.

    Mitä on rakennettu, mitä tulee

    Toimii nyt:

    • EV-latauksen sallinta/esto MQTT-komennolla
    • Reaaliaikainen latauksen tila Shellystä
    • SOC-tietoisuus Nissan API:sta
    • Aurinkoylijäämän hyödyntäminen lataukseen
    • Hintaohjattu lataus (kynnyslogiikka)
    • Automaattinen Leaf-tietojen päivitys latauksen alkaessa ja loppuessa

    Kehitysvaiheessa:

    • Tapering-malli (tarvitaan mittausdata)
    • Lähtöaikaohjaus (tarvitaan tapering-malli)
    • EV-UI: ”täysi klo 06:00”, säädettävä lähtöaika, ”lataa nyt” -ohitus

    Arkkitehtuurinen johtopäätös: EV-lataus on yksinkertaiselta näyttävä ongelma joka piilottaa sisäänsä ajoitusongelmat, epäluotettavat tietolähteet ja koordinointitarpeen muiden kuormien kanssa. Yksittäinen automaatio ei riitä — tarvitaan Priority Resolver joka näkee koko tilanteen.


    Seuraavaksi: Osa 14 — Käyttöönotto ja häiriöt. Mitä tapahtui kun järjestelmä otettiin käyttöön — ja mitä opittiin.

  • Case: oma talo — Osa 12: Thermia Modbus-ohjaus

    Tämä on kahdestoista osa sarjasta joka dokumentoi EnergyHub-järjestelmän rakentamisen vanhaan rintamamiestaloon. Edellisessä osassa käytiin läpi konfliktit ja niiden ratkaisu. Tässä osassa tarkastellaan maalämpöpumpun ohjauksen käytännön toteutusta — mitä Modbus antaa, mitä EVU/Boost-signaalit tekevät ja missä kulkee raja jonka yli ei pidä mennä.


    Maalämpöpumppu on kotitalouden energiankäytön kannalta yksi tärkeimmistä laitteista. Se lämmittää talon, tuottaa käyttöveden ja kuluttaa merkittävän osan sähköstä. Siksi se on myös yksi houkuttelevimmista ohjauksen kohteista — ja samalla yksi varovaisimmin lähestyttävistä.

    Thermia Calibra 12 on osoittautunut hyväksi kumppanina EnergyHub-ajattelulle. Se ei ole suljettu musta laatikko — Modbus TCP antaa laajan näkymän pumpun sisälle. Mutta se on myös opettanut tärkeän läksyn: ohjaaminen ja hallitseminen ovat eri asioita. Sama periaate pätee muidenkin valmistajien pumppuihin: esimerkiksi Nibe, Daikin, Mitsubishi ja Vaillant tarjoavat vastaavia Smart Grid Ready -tuloja ja Modbus-rajapintoja, joten tämän osan ajattelumalli on siirrettävissä laitemerkistä riippumatta — rekisteriosoitteet ja tilakoodit vain vaihtuvat.

    Mitä Modbus antaa

    Thermian Modbus-integraatio tarjoaa huomattavan määrän dataa. Luettavissa on muun muassa:

    • Ulkolämpötila, menovesi, paluuvesi, käyttöveden lämpötila
    • Kompressorin kierrosnopeus prosentteina
    • Nykyinen käyttötila: lämmitys, käyttövesi, sulatus, anti-legionella, valmiustila
    • Jonossa olevat vaatimukset prioriteettijärjestyksessä
    • Käyttötuntilaskurit: kompressori, käyttövesi, lisälämmitin
    • Comfort wheel -asetus (sisälämpötilan tavoitearvo)

    Käyttötila on erityisen arvokas. Rekisteristä näkee reaaliajassa onko pumppu lämmitysajolla (prioriteetti 4), käyttövesiajolla (3), sulatuksessa (2) vai anti-legionella-syklissä (7). Käytetyt prioriteettiarvot perustuvat Thermian viralliseen Modbus-dokumentaatioon sekä käytännön validointiin tässä järjestelmässä. Tämä mahdollistaa älykkään ohjauksen joka ei taistele pumpun omaa logiikkaa vastaan — se seuraa mitä pumppu tekee ja toimii sen mukaan. Jos pumppu on jo anti-legionella-syklissä (rekisteri 30002 palauttaa arvon 7) tai käyttövesiajolla (arvo 3), EnergyHub ei käynnistä uutta Boost-ohjausta. Ulkoinen automaatio ei taistele sisälogiikkaa vastaan — se näkee sen tilan ja väistää.

    EM3-laajennusmoduuli ja neljä tilaa

    Thermia Calibra 12:ssa on EM3-laajennusmoduuli joka tarjoaa älykkään sähköverkkotoiminnon — neljä eri ohjaustilaa kahden digitaalisen tulon (SG1 ja SG2) yhdistelmillä:

    SG1=0, SG2=0  →  Normal    — normaali toiminta
    SG1=1, SG2=0  →  EVU       — esto: kompressori ja lisälämmitin pysäytetään
    SG1=0, SG2=1  →  Comfort   — käyttövesi korkeammilla lämpötiloilla
    SG1=1, SG2=1  →  Boost     — käynnistää käyttöveden korkeat lähtöarvot,
                                  laukaisee bakteerineston tarvittaessa

    EnergyHubissa nämä signaalit tuotetaan Shelly Pro 2 -releellä joka kytkee EM3-moduulin tuloja. SG1 on output_0, SG2 on output_1.

    Aktiivinen Smart Grid -tila on luettavissa myös Modbusista: rekisteri 30083 (Comfort mode) palauttaa arvon 1=EVU, 4=Normal, 5=Comfort, 6=Boost. Tämä mahdollistaa tilan varmistamisen ohjelman puolelta — ei tarvitse olettaa että rele on mennyt oikeaan asentoon. Tämä readback-mahdollisuus osoittautui myöhemmin arvokkaammaksi kuin kirjoitushetkellä ymmärsin: FMA-kovennuskierroksen jälkeen kaikki tilan palautuspolut varmistavat rekisteristä 30083 että Normal todella tuli voimaan, ja yrittävät uudelleen jos ei tullut. Komento ei ole sama kuin toteuma — tästä lisää sarjan osassa 15.

    EVU — esto joka odottaa

    EVU (SG1=1, SG2=0) on yksinkertaisin tila: se estää normaalisti kompressorin käynnistymisen ja rajoittaa lämmitystoimintaa valmistajan Smart Grid -logiikan mukaisesti. Käytetään kalliina tunteina tai sulakevaaratilanteissa.

    Tärkeä yksityiskohta: EVU ei katkaise käynnissä olevaa kompressoria välittömästi. Kompressorin saa käynnistää vähintään viisi minuuttia ennen pysähtymistä — EVU-signaali odottaa kunnes tämä ehto täyttyy. Tämä suojaa kompressoria lyhyiltä käynnistys-sammutus-sykliltä.

    Viive on luettavissa suoraan Modbusista: rekisteri 30061 (Compressor temporarily blocked, start restriction timer) kertoo onko kompressori estoajassaan. Ohjauslogiikka voi seurata tätä rekisteriä eikä sen tarvitse olettaa milloin esto päättyy.

    Käytännössä EVU:n vaikutus näkyy vasta minuuttien kuluessa, ei sekunteina. Ohjauslogiikka ei saa olettaa välitöntä pysähtymistä. Tällä viiveellä on käytännön seuraus myös kuormanpudotuksessa: kun sulakeraja uhkaa ja Thermia pudotetaan EVU:lla, vaikutus verkkovirtaan näkyy vasta minuuttien päästä — pudotuslogiikan on siis toimittava iteratiivisesti eikä olettaa että yksi komento riittää.

    Boost — trigger and release

    Boost (SG1=1, SG2=1) on tehokkain tila: se käynnistää käyttöveden lämmityksen korkeammilla käynnistys- ja pysäytyslämpötiloilla, ja laukaisee tarvittaessa bakteerineston jos säiliö on liian kylmä.

    Käytännön testaus paljasti fiksuimman tavan käyttää Boostia:

    1. Aseta Boost — SG1=1, SG2=1
    2. Odota kunnes käyttövesiajo on käynnistynyt (running_priority = 3) — pumppu on tarttunut tehtävään
    3. Palauta Normal — SG1=0, SG2=0
    4. Pumppu jatkaa käyttövesiboostin loppuun itse

    Tämä ”trigger and release” -malli on turvallinen koska Boost-tila kytketään pois heti kun tiedetään että pumppu on tarttunut tehtävään. Rele ei jää Boost-tilaan pidemmäksi aikaa kuin välttämätöntä — ja mikä tärkeintä, lämmityksen tahaton boostaus estyy. Käytännön testien perusteella Boost ei välttämättä käynnistä käyttövesiajoa jos käyttövesi on jo riittävän lämmin. Tällöin pumppu ei reagoi Boost-signaaliin ja tila voidaan palauttaa Normaliin ilman vaikutuksia — trigger-and-release toimii myös tässä tilanteessa oikein.

    Comfort wheel — pehmein ohjausmetodi

    Comfort wheel on arkkitehtuurisesti puhtain tapa ohjata maalämpöpumppua. Se ei pakota tilaa päälle tai pois — se muuttaa pumpun käyttäytymistä sen omien rajojen sisällä.

    Tässä on syytä oikaista yleinen väärinkäsitys, johon itsekin aluksi sorruin: Thermian comfort wheel ei ole lämpökäyrän siirto, vaan sisälämpötilan tavoitearvo celsiuksina. Rekisteriin kirjoitetaan esimerkiksi 2200, joka tarkoittaa 22,00 °C:n tavoitetta. Käytännön vaikutus hintaohjauksessa on samankaltainen — tavoitteen laskeminen vähentää lämmitystä, nostaminen lisää sitä — mutta yksikkö ja mekanismi ovat eri asia kuin perinteinen käyräsiirto.

    Vanhassa HA:ssa ohjaus oli toteutettu kolmella tasolla:

    • Solar boost — kun P1-mittari näyttää yli 1500 W vientiä ja huonelämpötila on alle 22,3 °C: tavoitearvoa nostetaan. Aurinko tuottaa ylimääräistä — hyödynnetään se lämmitykseen ennen kuin se menee verkkoon.
    • Normaali — perustila, tavoitearvo asetetun arvon mukaan.
    • Eco — kahdeksan kalleinta tuntia vuorokaudessa: tavoitearvoa lasketaan. Rakennuksen lämpömassa toimii puskurina — sisälämpötila ei laske heti vaikka lämmitystä vähennetään.

    Comfort wheel kirjoitetaan Modbus-rekisteriin 40006 (scale 100). Home Assistantin YAML:ssa tämä on address: 5, input_type: holding — tästä lisää alla osoitteistusta käsittelevässä huomiossa. Muutos vaikuttaa pumpun ohjaukseen välittömästi — ei tarvita releohjausta.

    Nykyisessä EnergyHubissa myös comfort wheel -kirjoitus noudattaa komento ≠ toteuma -periaatetta: Node-RED pitää kirjaa pyydetystä arvosta (pending) ja pitää sitä voimassa olevana (confirmed) vasta kun rekisteristä luettu arvo vastaa pyydettyä. Näin hiljainen kirjoitusvirhe — esimerkiksi Modbus-katkon aikana hukkunut kirjoitus — ei jää huomaamatta.

    Mitä Modbus-kirjoitus ei tee

    Käytännön testaus opetti myös rajoitteen jota ei dokumentaatiosta selvästi löydy.

    Käyttöveden käynnistyslämpötilaa yritettiin muuttaa Modbus-kirjoituksella — tavoitteena käynnistää käyttövesiajo halutuilla hetkillä. Rekisteri kirjoitettiin, arvo muuttui. Mutta mitään ei tapahtunut. Vaikka odotettiin useita tunteja, pumppu ei käynnistänyt käyttövesiajoaan.

    Todennäköinen selitys: pumpun sisäinen logiikka tarvitsee käynnistysehdon täyttymisen — riittävän nopean lämpötilanpudotuksen — ennen kuin se reagoi muuttuneeseen käynnistysarvoon. Pelkkä rekisterin arvon muuttaminen ei riitä.

    Johtopäätös: käytännön kokeissa Boost-rele osoittautui luotettavimmaksi tavaksi käynnistää käyttövesijakso haluttuna ajankohtana. Modbus-kirjoitus sopii comfort wheel -ohjaukseen, mutta ei käyttövesilämmityksen pakottamiseen halutulle hetkelle.

    Viitteeksi: käyttöveden käynnistys- ja pysäytyslämpötilat ovat rekistereissä 40023 (start, scale 100) ja 40024 (stop, scale 100). Arvot voi lukea ja kirjoittaa — mutta pelkkä arvon muuttaminen ei riitä käynnistämään uutta käyttövesijaksoa ilman riittävää lämpötilanpudotusta.

    Legionella — seurataan, ei ohjata

    Thermia Calibra 12 ajaa anti-legionella-syklin automaattisesti noin 14 päivän välein. Syklin aikana käyttövesi lämmitetään korkeaan lämpötilaan. Sykli näkyy selvästi datassa: kompressori pyörii täydellä teholla, käyttöveden lämpötila nousee poikkeuksellisen korkeaksi.

    Tässä järjestelmässä legionellasykli näkyy myös lisälämmittimen aktivoitumisena — mutta vain silloin. Pumppu on sopivasti mitoitettu eikä lisävastuksia tarvita normaaliolosuhteissa edes kovimmilla pakkasilla.

    Thermia Calibra 12:n firmware 17.03.145 toi mukanaan käytännön parannuksen: legionellasyklin kuumennusväli on säädettävissä suoraan pumpun näytöltä. Oletusarvo on 14 päivää, mutta liukusäätimellä voi asettaa pidemmän tai lyhyemmän välin. Samasta valikosta näkyy viimeisin ajo ja seuraavan ajon ajankohta — ja halutessa syklin voi käynnistää manuaalisesti ”Käynnistä bakteerinestotoiminto” -napista.

    EnergyHub seuraa legionellasykliä: Node-REDin State Collector johtaa tilan suoraan prioriteettirekisteristä (running_priority = 7 → m_hp_legionella_active). Alkamis- ja päättymisajat kirjataan, laskuri kasvaa. Näin nähdään jälkikäteen milloin syklejä on ajettu — ja mikä tärkeintä, käynnissä oleva legionella-ajo estää EnergyHubin oman Boost-ohjauksen.

    Mutta ulkoisesta automaatiosta sitä ei voi ohjata. Legionellasuojaus on valmistajan toteuttama turvallisuustoiminto. Välin säätö ja manuaalinen käynnistys tapahtuvat pumpun omasta paneelista — ei Modbusista.

    Huomio Modbus-osoitteistuksesta

    Thermian dokumentaatio käyttää De Facto -osoitteita jotka alkavat luvuista 40001 (holding), 30001 (input) ja 10001 (discrete input). Esimerkiksi comfort wheel on dokumentaatiossa osoitteessa 40006.

    Osa Modbus-ohjelmistoista — mukaan lukien Home Assistantin Modbus-integraatio — käyttää nollapohjaisia osoitteita. Tällöin sama rekisteri on address: 5 YAML-konfiguraatiossa.

    Käytännössä:

    Dokumentaation De FactoHA YAML addressTyyppi
    400065holding
    4002322holding
    3001615input
    10202201discrete input

    Tämä on yksi yleisimmistä Thermia-integraation virhelähteistä. Jos rekisteri ei vastaa odotetusti, ensimmäinen tarkistus on osoitemuoto — ei rekisterin sisältö.

    Miksi ON/OFF-ohjaus on väärä lähestymistapa

    Ensimmäinen ajatus lämpöpumpun optimoinnista on usein koko laitteen sähkönsyötön katkominen kontaktorilla tai älyreleellä. Käytännössä tämä on huono ratkaisu — riippumatta siitä onko kyseessä Thermia, Nibe, Daikin, Mitsubishi vai Vaillant.

    Kompressorin minimikäyntiajat rikkoutuvat pakkosammutuksessa. Sisäinen logiikka menettää tilatietonsa. Sulatus- ja käyttövesisyklit keskeytyvät kesken ajon. Käynnistysmäärät kasvavat ja jokainen käynnistys rasittaa kompressoria. Valmistajan suojauslogiikka — se joka oikeasti suojelee laitetta — ohitetaan kokonaan.

    Thermian EM3- ja Modbus-rajapinnat mahdollistavat huomattavasti elegantimman lähestymistavan. Lämpöpumpulle ei anneta käskyä ”sammu” — sen käyttäytymistä ohjataan sen omien rajojen sisällä. EVU pysäyttää kompressorin valmistajan suunnittelemalla tavalla. Comfort wheel muuttaa sisälämpötilan tavoitearvoa ilman tilakoneen rikkomista. Boost käynnistää käyttövesilämmityksen oikeaan aikaan — ja pumppu hoitaa loput itse.

    Arkkitehtuurinen johtopäätös

    Thermia-ohjauksen kokemus tiivistyy yhteen lauseeseen: maalämpöpumppua ei etäohjata — sen toimintaa ohjataan rajojen sisällä.

    Käytännössä tämä tarkoittaa kolmea toimenpidettä:

    1. EVU kalliina tunteina tai sulakevaarassa — kompressori ei käynnisty, sulakeriski pienenee.
    2. Boost halvalla tai aurinkoylijäämällä — käyttövesi lämmitetään optimaaliseen aikaan trigger-and-release -mallilla.
    3. Comfort wheel hintaohjauksella — sisälämpötilan tavoitetta nostetaan halvalla, lasketaan kalliilla. Pehmeä muutos joka ei stressaa laitetta.

    Mitä ei tehdä: kompressorin pakkokäynnistystä, jatkuvaa ON/OFF-ohjausta tai valmistajan suojausten ohittamista.

    Ja neljäs periaate, joka kirjoitushetkellä oli vasta itämässä mutta on sittemmin osoittautunut koko järjestelmän kulmakiveksi: jokainen tilanvaihto varmistetaan lukemalla toteutunut tila takaisin — releen kytkeminen ei vielä todista että pumppu on halutussa tilassa. Miten tämä periaate syntyi ja mitä sen laiminlyönnistä seurasi, käsitellään osassa 15.

    Tämä on HEOMF-ajattelun ydin lämpöpumpun kohdalla: optimointi ei tarkoita täyttä kontrollia — se tarkoittaa älykkäämpää yhteistyötä laitteen oman logiikan kanssa.

    Tarkemmat ohjeet löytyvät artikkeleista Modbus käytännössä — Home Assistantin integraatio, Thermia Modbus + EVU/Boost-ohjaus ja Käyttöveden älykäs lämmitys aurinkosähköllä.


    Seuraavaksi: Osa 13 — Sungrow + EV-lataus. Miten aurinkoinvertterin ohjaus ja sähköauton lataus toimivat yhdessä ja miten negatiiviset hinnat vaikuttavat kumpaankin.

  • Case: oma talo — Osa 11: Konfliktit — kun kolme tavoitetta taistelee

    Tämä on yhdestoista osa sarjasta joka dokumentoi EnergyHub-järjestelmän rakentamisen vanhaan rintamamiestaloon. Edellisissä osissa rakennettiin päätöslogiikka, MQTT-viestintä ja aurinkoinvertterin ohjaus. Tässä osassa käsitellään tilannetta joka on arkkitehtuurin todellinen koetinkivi: mitä tapahtuu kun useampi tavoite haluaa samaa asiaa yhtä aikaa — tai estää toisiaan.


    Kello on 14:00. Aurinko tuottaa 11 kW. Sähkön hinta on 1,2 senttiä — halpa. EV on kytkettynä ja haluaa ladata. Lämpöpumppu on juuri käynnistynyt käyttöveden boostin. L1-vaihe on 23,8 ampeeria.

    Kolme asiaa haluaa tapahtua. Yksi pakottaa toisen pois.

    Tämä on konflikti. Ja konflikti ei ole poikkeustilanne — se on normaalitila kaikissa energiajärjestelmissä joissa on useampi ohjattava kuorma.

    Miksi konfliktit ovat vaikeita

    Yksittäinen automaatio ei näe konflikteja. Se näkee vain oman ehtonsa: ”jos hinta alle X, lataa auto.” Se ei tiedä että samaan aikaan lämpöpumppu boostaa, sulake on jo 90 %:lla ja aurinkoinvertteri on rajoitustilassa.

    Kun järjestelmässä on kolme automaatiota jotka kaikki yrittävät ohjata samaa relettä tai samaa kokonaiskulutusta, tuloksena on arvaamaton käyttäytyminen. Automaatio A sallii latauksen. Automaatio B estää sen. Automaatio C sallii sen taas. Rele flippaa minuutin välein — tai pahimmillaan sekunnin välein.

    Tätä kutsutaan control fightiksi. Se ei näy virheenä logeissa. Se näkyy vain käyttäytymisessä — satunnaisena, selittämättömänä toimintana.

    EnergyHubissa control fight on estetty arkkitehtuurisesti: yksi komponentti tekee kaikki päätökset, muut toteuttavat. Node-REDin Priority Resolver on se yksi komponentti. Se ei kilpaile muiden kanssa — ei ole muita. Konfliktia ei ratkaista siellä missä se syntyy, vaan yhdessä keskitettyssä päätöspisteessä.

    Konfliktityypit

    EnergyHubissa on kolme tyypillistä konfliktirakennetta.

    Resurssikonflikti — kaksi kuormaa haluaa samaa rajallista resurssia. Tyypillisin tapaus: EV ja lämpöpumppu haluavat molemmat ladata/boostata samaan aikaan, mutta sulake ei kestä kumpaakin. Toisen pitää väistyä.

    Tavoitekonflikti — kaksi optimointitavoitetta osoittavat eri suuntiin. Tyypillisin tapaus: hinta on halpa joten lämpöpumppu haluaa boostata (kuluta enemmän), mutta samaan aikaan aurinko ylituottaa ja invertteri on rajoitustilassa (tuotetaan vähemmän). Boostaaminen olisi järkevää — mutta rajoitustilassa se merkitsee verkkosähkön ostamista eikä aurinkosähkön käyttöä.

    Aikakonflikti — päätös on oikea nyt mutta väärä viiden minuutin päästä. Tyypillisin tapaus: EV-lataus sallitaan koska hinta on halpa, mutta aurinko on laskemassa ja viidentoista minuutin päästä verkkosähkön hinta nousee huipputunnille.

    Miten Priority Resolver ratkaisee konfliktit

    Priority Resolver ei neuvottele. Se käy tilanteen läpi kiinteässä järjestyksessä ja ensimmäinen osuma ratkaisee.

    Turvallisuus voittaa aina. Jos sulake on uhattuna, kuormat pudotetaan prioriteettijärjestyksessä riippumatta hinnasta, aurinkotilanteesta tai käyttäjän toiveista. EV menee ensin pois koska se on suurin yksittäinen kuorma. Kiuas menee toisena. Lämpöpumppu blokataan vain jos kompressori pyörii yli 60 %:lla — alle sen se saa jatkaa.

    Tämä ei ole optimointipäätös — se on fyysinen rajoite. Sulake ei jousta.

    Moodi määrittää kehyksen. Kun operating mode on peak_protection, hintaoptimointia ei tehdä lainkaan. Kun moodi on vacation, mukavuus väistyy minimikulutuksen tieltä. Moodi ei ole yksityiskohta — se on koko päätöskehys.

    Capability on portti. Ennen kuin yksikään optimointipäätös tehdään, tarkistetaan onko toimenpide ylipäätään sallittu. c_ev_charge_allowed: false sulkee EV-latauksen kokonaan riippumatta muista olosuhteista. Tämä on käyttäjän hallintapiste — ei optimoinnin asia.

    Hinta ja aurinko ovat viimeisenä. Vasta kun turvallisuus on varmistettu, moodi tarkistettu ja capabilityt selvitetty, päästään varsinaiseen optimointiin: onko hinta halpa, onko aurinkoylijäämää, kumpi kuorma hyötyy enemmän.

    Resurssikonflikti käytännössä: EV vs lämpöpumppu

    25.5.2026 klo 14:05 tilanne oli tämä:

    • L1-vaihe: 23,8 A (sulakemaksimi 25 A, varoitusraja 22,5 A)
    • EV latautui täydellä 3,6 kW teholla
    • Lämpöpumppu käynnisti käyttöveden boostiin

    Varoitusraja ylittyi heti kun lämpöpumppu käynnistyi. Safety Guardian havaitsi tilanteen 10 sekunnin sisällä ja laukaisi peak_protection-moodin.

    Priority Resolver sai tiedon moodinvaihdosta. Päätökset:

    • EV: off — suurin yksittäinen kuorma, poistuu ensin
    • HP: normal — kompressori alle 60 %, saa jatkaa

    EV:n sammuminen vapautti noin 16 ampeeria L1-vaiheelta (3,6 kW yksivaiheisena ≈ 16 A). Virta laski 16,2 ampeerin. Kun virta oli pysynyt alle 18,75 ampeerin (75 % sulakerajasta) riittävän kauan, Safety Guardian palautti normal-moodin.

    Koko tapahtuma kesti 15 minuuttia. Käyttäjä ei tehnyt mitään.

    Tavoitekonflikti: aurinko vs halpa hinta

    Tämä on hienosyisempi konflikti jota ei aina huomata.

    Tilanne: spot-hinta on 1 senttiä — halpa. Aurinko tuottaa 10 kW mutta talossa kulutus on vain 2 kW. Ylijäämä on 8 kW joka menee verkkoon. Hinta on positiivinen joten myynti on edelleen tuottoisaa — PV-rajoitusta ei aktivoida.

    Lämpöpumppu haluaa boostata koska hinta on halpa. Järjestelmä sallii sen.

    Mutta boostin käynnistyminen nostaa kulutusta 2 kW:lla. Se pienentää verkkoon menevää ylijäämää — mutta se myös tarkoittaa että aurinko kattaa boostin ilman verkkosähkön ostoa. Tulos: sama sähkölasku, lämpimämpi käyttövesi. Konflikti ratkesi luontevasti.

    Eri tilanne: spot-hinta on -0,5 senttiä — negatiivinen. PV-rajoitus on aktiivinen, invertteri rajoitettu 25 %:iin. Lämpöpumppu haluaa boostata käyttövettä.

    Tässä on tavoitekonfliktin ydin. Jos boosti tehdään nostamatta PV-rajoitusta, invertteri tuottaa edelleen vain 25 % — ja boostin tarvitsema lisäenergia ostetaan verkosta. Maksetaan verkkoon myymisestä ja ostetaan samaan aikaan verkkosähköä. Molemmat suunnat ovat tappiollisia.

    Oikea ratkaisu on säätää PV-rajoitusta boostin tarpeen mukaan. Jos lämpöpumppu tarvitsee lisää tehoa, rajoitusta nostetaan — invertteri saa tuottaa enemmän ja boosti katetaan omalla aurinkosähköllä. Tämä on sama metodi jota käytetään muulloinkin: rajoitusta säädetään dynaamisesti omakäytön perusteella, ei kiinteällä arvolla.

    EnergyHubissa Priority Resolver tekee tämän koordinoinnin: se laskee sekä PV-rajoituksen että lämpöpumpun ohjaustarpeen samassa päätössyklissä, ei erikseen. Boostin ja rajoituksen välinen tasapaino löytyy yhdessä laskennassa.

    Aikakonflikti: oikea päätös väärään aikaan

    Aikakonflikti on vaikein hallita koska se vaatii tulevaisuuden ennustamista.

    Yksinkertainen esimerkki: klo 13:55 hinta on halpa, EV-lataus sallitaan. Klo 14:00 hinta nousee kalliiseen — mutta EV on jo latauksessa eikä järjestelmä reagoi ennen seuraavaa minuuttisykliä.

    EnergyHubissa tähän ei ole täydellistä ratkaisua — ja sen myöntäminen on tärkeä osa realistista arkkitehtuurikuvausta. Minuuttisykli tarkoittaa että järjestelmä voi ”jäädä kiinni” väärään tilaan enintään minuutin ajaksi.

    Pahempi tapaus: EV-lataus aloitetaan koska tuntihinta on halpa, mutta varttihinta — joka on tullut käyttöön 2025 — on jo noussut kalliiseen. Tähän tarvitaan varttitason hintadata — ja logiikka joka osaa toimia sillä. Tuntipohjainen logiikka ei riitä kun markkina- ja mittausjakso siirtyy 15 minuuttiin.

    Toinen pahempi tapaus: aurinkoylijäämä on suuri juuri nyt, mutta pilvi on tulossa. Järjestelmä ei tiedä tätä ellei sääennustedataa integroida.

    Nämä ovat tunnettuja rajoitteita. Ne eivät estä järjestelmää toimimasta — ne rajoittavat sen optimaalisuutta reunatapauksissa.

    Ownership — kuka saa päättää

    Konfliktien hallinta ei ole vain logiikkakysymys. Se on omistajuuskysymys.

    EnergyHubissa omistajuus on eksplisiittinen: Node-RED päättää, HA toteuttaa, kenttälaitteet toimivat. Ketjussa ei ole rinnakkaisia päätöksentekijöitä. Ei ole HA-automaatiota joka ohittaa Node-REDin. Ei ole Node-RED-flow’ta joka kirjoittaa suoraan Modbus-rekisteriin ohi HA:n.

    Tämä on se asia jonka puuttuminen tekee useimmista kotiautomaatiojärjestelmistä hallitsemattomia. Kymmenen automaatiota voivat kaikki olla oikein yksin — mutta yhdessä ne luovat konflikteja joita kukaan ei suunnitellut.

    Shadow/live-mekanismi on toinen omistajuuden ilmentymä. Kun kaksi järjestelmää on käynnissä samanaikaisesti — vanha ja uusi — vain toinen saa ohjata kutakin laitetta. Raja on eksplisiittinen eikä se riipu siitä kumpi ”ehtii ensin.”

    Konfliktit ovat tietoa

    Lopuksi näkökulma joka muuttaa suhtautumisen konflikteihin.

    Konflikti ei ole virhe — se on signaali. Kun Priority Resolver estää EV-latauksen sulakeongelman takia, se kertoo jotain tärkeää: talo kuluttaa liikaa yhdellä vaiheella. Kun lämpöpumpun boosti estetään negatiivisen hinnan aikana, se kertoo että aurinkotuotanto ja kulutus eivät ole tasapainossa.

    EnergyHubin observability-kerros tallentaa nämä signaalit. InfluxDB:stä näkee jälkikäteen kuinka usein Peak Protection laukesi, milloin EV-lataus estettiin ja mistä syystä. Nämä eivät ole häiriöitä jotka pitää piilottaa — ne ovat dataa joka kertoo miten järjestelmää pitää kehittää.

    Konflikti jota ei näe ei katoa. Se vain toimii äänettömästi väärällä tavalla.


    Seuraavaksi: Osa 12 — Thermia Modbus-ohjaus. Miten maalämpöpumpun EVU- ja Boost-signaalit toimivat käytännössä ja miten ne integroidaan EnergyHubiin.

  • Case: oma talo — Osa 10: Aurinko ja teho Node-REDissä

    Tämä on kymmenes osa sarjasta joka dokumentoi EnergyHub-järjestelmän rakentamisen vanhaan rintamamiestaloon. Edellisessä osassa käytiin läpi hintaohjauksen päätöslogiikka Node-REDissä. Tässä osassa tarkastellaan kahta toisiinsa kytkeytyvää kokonaisuutta: aurinkoinvertterin tehonrajoitusta negatiivisilla hinnoilla ja vaihevirtojen reaaliaikaista valvontaa.


    Aurinkopaneeli tuottaa sähköä aina kun aurinko paistaa. Se ei kysy onko hinta hyvä tai huono. Ilman ohjausta kaikki ylijäämä menee verkkoon — myös silloin kun hinta on negatiivinen ja jokainen myyty kilowattitunti maksaa omistajalle.

    Tämä oli EnergyHubin yksi keskeisimmistä motivaatioista: rakentaa logiikka joka reagoi negatiivisiin hintoihin automaattisesti, rajoittaa vientiä älykkäästi ja ohjaa ylijäämä ensin omaan käyttöön.

    Aurinkoylijäämä — mitä se tarkoittaa käytännössä

    Aurinkoylijäämä on se osa tuotannosta joka ylittää talon hetkellisenkulutuksen. Jos aurinko tuottaa 8 kW ja talo kuluttaa 2 kW, ylijäämä on 6 kW — se menee verkkoon ellei sitä ohjata muualle.

    EnergyHubissa ylijäämä lasketaan reaaliajassa:

    javascript

    s.solarExcessW = Math.max(0, s.pvPowerW - Math.max(0, s.gridPowerW))
    s.isSolarExcess = s.solarExcessW > s.solarExcessThresholdW  // oletusarvo 2000 W

    gridPowerW on positiivinen kun ostetaan verkosta ja negatiivinen kun myydään. Kaava ottaa tämän huomioon: jos verkosta ostetaan (gridPowerW > 0), ylijäämää ei ole vaikka aurinko tuottaisi.

    Ylijäämä ohjataan ensisijaisesti omaan kulutukseen — EV-lataukseen tai lämpöpumpun boostiin. Vasta sen jälkeen, ja vain jos hinta on negatiivinen, rajoitetaan invertterin tehoa.

    PV-rajoitus negatiivisilla hinnoilla

    Kun spot-hinta laskee alle p_negative_price-kynnyksen ja aurinko tuottaa yli 500 W, Priority Resolver laskee sopivan rajoitusprosentin:

    javascript

    if (s.isNegativePrice && s.pvPowerW > 500) {
        const ownLoad = Math.max(300, s.pvPowerW + Math.min(0, s.gridPowerW));
        const pct = Math.max(10, Math.min(95,
            Math.round((ownLoad / s.pvPowerW) * 100)
        ));
        decisions.pvCurtailPct = pct;
    }

    ownLoad on talon hetkellinen omakäyttö — kuinka paljon aurinkosähköä kuluu itse. Rajoitusprosentti on tämän suhde invertterin nimellistehoon (15 kW). Jos talo kuluttaa 3 kW, rajoitus asetetaan 20 %:iin — invertteri saa tuottaa enintään 3 kW jotta vienti minimoidaan.

    Normaalitilassa invertteri on asetettu 110 %:iin — Sungrowin tapa ilmaista ”ei rajoitusta, käytä kaikki mitä paneeleilla on”. Kun negatiivinen hinta aktivoituu, rajoitus lasketaan dynaamisesti ja asetetaan esimerkiksi 24 %:iin. Kun hinta palaa normaaliksi, palataan 110 %:iin.

    Rajoituslaskennassa minimiarvo on 10 % eikä 0 %. Täysi sammutus aiheuttaa invertterin uudelleenkäynnistyksen ja voi johtaa ohjausongelmiin — 10 % on turvallinen alaraja joka pitää invertterin aktiivisena. Maksimiarvo rajoituslaskennassa on 95 % — tämä estää tilanteen jossa laskettu rajoitusarvo heiluisi juuri 100 %:n tuntumassa pienten kulutusvaihteluiden mukana. Täyteen tehoon palataan aina 110 %:n kautta, ei 100 %:n.

    Modbus-ohjaus käytännössä

    Komento kulkee Node-REDistä HA:lle MQTT:n kautta: energyhub/command/pv/curtail_pct: 24. HA vastaanottaa sen ja kirjoittaa Modbus-rekistereihin.

    Sungrow SG15RT -invertterissä rajoitus tapahtuu kahdella rekisterillä:

    • Rekisteri 5006 — Power Limitation Switch. Tämä on bittikenttä, ei yksinkertainen 0/1-kytkin. SG15RT:llä se on pysyvästi tilassa 170 (”Enabled”) — invertteri hyväksyy rajoituskomennot eikä rekisteriin tarvitse koskea.
    • Rekisteri 5007 — rajoitusarvo (0–1100, yksikkö 0,1 % nimellistehosta. Tähän rajoitus kirjoitetaan.

    24 % rajoitus tarkoittaa arvoa 240 rekisterissä 5007. Rajoitus aktivoituu pelkällä tällä kirjoituksella — 5006 pysyy koko ajan tilassa 170. Täyteen tehoon palataan kirjoittamalla 5007:ään arvo 1100 (= 110 %).

    Tämä on Sungrow-spesifinen toteutus — SMA, Fronius, ABB ja Huawei SUN2000 käyttävät omia rekisterikarttojaan, mutta SunSpec-standardia tukevat laitteet jakavat yhteisen osoitteiston. Rekisteritason yksityiskohdat on kuvattu tarkemmin ohjeessa Sungrow Modbus + tehonrajoitus.

    DC-potentiaaliaukko — mitä tapahtuu invertterin sisällä

    25.5.2026 tehdyssä testissä havaittiin jotain odottamatonta. Kun invertteri rajoitettiin 24 %:iin, MPPT-jännite nousi 501 voltista 544 volttiin — nousu noin 43 volttia. Virta laski vastaavasti 11,7 ampeerista 7,0 ampeeriin.

    Tämä paljastaa miten invertteri toteuttaa rajoituksen: se ei leikkaa AC-puolelta vaan siirtää paneelien toimintapisteen pois maksimitehopisteestä (MPP). Invertteri nostaa DC-jännitettä tarkoituksella, jolloin paneelit tuottavat vähemmän virtaa ja siten vähemmän tehoa.

    Käytännön seuraus: kun invertteri on rajoitustilassa, DC-rekisterit eivät kerro saatavilla olevaa paneelipotentiaalia — ne kertovat vain invertterin valitseman toimintapisteen. Testissä todellinen saatavilla oleva paneeliteho oli noin 11 kW, mutta rajoitustilan DC-teho näytti vain noin 3,8 kW. Jos haluaa tietää paljonko aurinkoa ”oikeasti” olisi saatavilla, pitää tehdä lyhyt testipulssi jossa rajoitus nostetaan hetkellisesti 110 %:iin ja mitataan toteutuva teho.

    30 päivän historiadatasta laskettu normaali MPPT-jännite on 474–515 V (keskiarvo 494 V, hajonta 20,8 V). Rajoituksen aikana mitattu 544 V on yli kaksi standardipoikkeamaa normaalin yläpuolella päiväaikaan — tilastollisesti selvästi poikkeava tapahtuma.

    Taloudellinen realismi

    Negatiivisten hintojen aiheuttama tappio on tällä hetkellä Suomessa pieni mutta kasvava.

    Vuonna 2025 tehdyn analyysin tulokset olivat yllättävän maltilliset. Negatiivisilla hinnoilla myytiin noin 651 kWh sähköä 115 tunnin aikana — kokonaistappio oli noin 2 euroa. Painotettu myyntihinta näillä tunneilla oli -0,344 snt/kWh. Suhteessa kokonaisuuteen — koko vuoden myyntitulo oli noin 359 € 8 632 myydystä kilowattitunnista — negatiivisten hintojen vaikutus oli pieni.

    Mutta analyysi paljasti tärkeän asian: suurin osa tappiosta syntyi lievästi negatiivisilla hinnoilla, ei äärimmäisissä piikeissä. Yksittäiset -500 EUR/MWh -hetket ovat dramaattisia mutta harvinaisia. Lievästi negatiivisia tunteja on paljon enemmän — ja niiden määrä kasvaa joka vuosi. Nolla- tai negatiivisen hinnan tunteja oli Suomessa vuonna 2024 peräti 994 — lähes 41 vuorokautta.

    Yksittäisenä päivänä 25.5.2026 tappio ilman rajoitusta olisi ollut noin 0,5 euroa. Trendi on selvä: rajoituksen taloudellinen hyöty kasvaa suoraan negatiivisten tuntien määrän mukana. Jos 2026 jatkaa samaa trendiä, vuositason tappio ilman rajoitusta voi olla helposti 10–30 euroa 15 kW järjestelmällä. Ei suuri summa — mutta automatisoitu suojaus ei myöskään maksa mitään käytön jälkeen.

    Safety Guardian — vaihevirtojen reaaliaikainen valvonta

    PV-rajoitus on proaktiivinen toimenpide — se reagoi hintaan ennen kuin ongelma syntyy. Safety Guardian on reaktiivinen — se reagoi vaihevirtoihin kun ne jo ovat korkealla.

    Safety Guardian pyörii erillisessä Node-RED-flow’ssa ja kuuntelee energyhub/telemetry/phases-topicia joka päivittyy 10 sekunnin välein. Se ei odota minuuttisykliä.

    Logiikka on yksinkertainen mutta tehokas:

    javascript

    const maxA = Math.max(Math.abs(l1), Math.abs(l2), Math.abs(l3));
    const warnLimit = 30;   // A → peak_protection
    const reduceLimit = 36; // A → kuormanpudotus
    const tripLimit = 40;   // A → safety trip
    const hysteresis = 25;  // A → paluu normal
    
    if (maxA >= tripLimit) {
        // SAFETY TRIP — välitön toiminta
        return safety_trip: true
    }
    if (maxA >= warnLimit && mode !== 'peak_protection') {
        // Pyydä moodinvaihtoa
        return mode: 'peak_protection'
    }
    if (mode === 'peak_protection' && maxA < hysteresis) {
        // Paluu normaaliin
        return mode: 'normal'
    }

    Nämä kynnykset eivät olleet alusta asti tällaiset. Suunnitteluvaiheessa lähdettiin konservatiivisista arvoista — varoitus jo 22,5 ampeerissa ja laukaisu 24,5 ampeerissa, mikä on 90 % ja 98 % 25 ampeerin sulakkeesta. Käytännön käytössä nämä osoittautuivat liian herkiksi: järjestelmä reagoi normaaleihin kulutuspiikkeihin turhan usein. Kynnyksiä nostettiin tuotantokäyttöön arvoihin 30 / 36 / 40 A, jotka antavat enemmän pelivaraa normaalille kuormalle mutta puuttuvat silti tilanteeseen selvästi ennen sulakkeen todellista laukeamista.

    Hystereesi on tärkeä: moodiin ei palata heti kun virta laskee alle varoitusrajan — vasta kun se laskee selvästi alle sen. Tämä estää moodin flippaamisen edestakaisin pienten vaihteluiden mukana.

    Toimintaperiaate näkyi käytännössä jo aikaisin: kun L1 nousi varoitusrajan yli, Guardian laukaisi peak_protection-moodin ja EV-lataus estettiin. Kun virta laski hystereesirajan alle, Guardian palautti normal-moodin. Koko tapahtuma hoitui ilman käyttäjän toimenpiteitä — juuri kuten reaktiivisen suojan kuuluu toimia.

    Aurinko ja sulakkeet — sama ongelma eri suunnista

    Aurinkoinvertteri ja sulakevalvonta ratkaisevat saman ongelman eri suunnista.

    Sulakevalvonta katsoo kuinka paljon verkosta ostetaan ja pudottaa kuormia kun raja lähestyy. Aurinkoinvertteri vaikuttaa siihen kuinka paljon verkkoon myydään ja siten epäsuorasti myös siihen paljonko talo nettona kuluttaa.

    Yhdessä ne muodostavat kaksisuuntaisen tehonhallinnan: Safety Guardian estää liian suuren oston, PV-rajoitus minimoi turhan myynnin. Kumpikaan ei yksin riitä — yhdessä ne pitävät talon tehotasapainon hallinnassa sekä ostopuolella että myyntipuolella.

    Mitä testistä opittiin — arkkitehtuurin synty

    Käytännön testi vuonna 2025 paljasti jotain odottamatonta. Kun invertterin tehoa alettiin rajoittaa Modbusin kautta, huomattiin että rajoitus ei ole irrallinen toiminto — se muuttaa koko järjestelmän dynamiikan.

    Kun aurinkotuotantoa rajoitettiin, EV-latauksen logiikka muuttui. Lämmityksen optimointi muuttui. Ylijäämäenergian hyödyntäminen muuttui. Useat automaatiot alkoivat vaikuttaa toisiinsa tavalla jota kukaan ei ollut suunnitellut.

    Johtopäätös oli selvä: invertterin tehorajoitus ei voi olla yksittäinen automaatio. Se vaatii keskitetyn tilannekuvan, prioriteetit, ohjauksen omistajuuden ja eri järjestelmien koordinoinnin. Tarvitaan EnergyHub-arkkitehtuuria.

    Tästä havainnosta syntyi koko sarjan kantava teema:

    Energian optimointi ei ole yksittäinen automaatio-ongelma — se on arkkitehtuuri-ongelma.

    Miksi tämä ei onnistu pelkällä ajastimella

    Yksinkertaisempi ratkaisu olisi ajastaa invertteri pois päältä kun hinta on negatiivinen. Se toimisi — mutta karkeasti.

    Ongelma on että negatiivinen hinta ei tarkoita automaattisesti että rajoitus on järkevää. Jos talo kuluttaa paljon — kiuas käy, EV latautuu, lämpöpumppu boostaa — invertteri voi tuottaa täydellä teholla eikä mitään mene verkkoon. Rajoitus olisi turha.

    EnergyHubin logiikka laskee reaaliaikaisesti paljonko vientiä oikeasti on ja rajoittaa sen verran kuin tarpeen. Ei enemmän. Tämä on tarveperustaista ohjausta — ei kynnysohjausta.


    Seuraavaksi: Osa 11 — Konfliktit. Kun aurinko tuottaa, hinta on halpa ja sulake uhkaa yhtä aikaa — miten järjestelmä ratkaisee kolmen tavoitteen ristiriidan.

    Tekninen toteutus: PV-rajoitus Modbus-ohjauksella on kuvattu tarkemmin ohjeessa Sungrow Modbus + tehonrajoitus.

  • Case: oma talo — Osa 9: Hintaohjauksen flow Node-REDissä

    Tämä on yhdeksäs osa sarjasta joka dokumentoi EnergyHub-järjestelmän rakentamisen vanhaan rintamamiestaloon. Edellisessä osassa käytiin läpi MQTT-viestintäkerros — miten tieto kulkee komponenttien välillä. Tässä osassa katsotaan mitä Node-RED tekee sillä tiedolla: miten hintaohjauksen päätöslogiikka rakentuu käytännössä.


    Node-RED on EnergyHubin optimointikerros. Se vastaanottaa kaiken telemetrian, ylläpitää tilannekuvaa ja tekee päätökset. Mutta Node-RED ei ole yksi iso automaatio — se on kolme erillistä flow’ta joilla on omat vastuunsa.

    State Collector kerää kaiken datan ja pitää tilannekuvan ajan tasalla. Se ei tee päätöksiä.

    Decision Engine ajaa päätöslogiikan minuutin välein. Se kysyy: mitä pitää tehdä, kenen vuoro on, miksi.

    Safety Guardian valvoo sulakerajoja 10 sekunnin välein ja reagoi välittömästi. Se ei optimoi — se suojelee.

    Tässä osassa keskitytään Decision Engineen — siihen miten hintatieto muuttuu päätöksiksi.

    State Collector — tilannekuvan ylläpito

    Ennen kuin Decision Engine voi päättää mitään, sen täytyy tietää missä ollaan. State Collector kuuntelee kaikkia energyhub/#-topiceja ja päivittää flow-kontekstin aina kun uusi viesti saapuu.

    Global context toimii Node-REDin yhteisenä tilamuistina — kaikki flow’t voivat lukea ja kirjoittaa siihen. Avainten etuliitteet kertovat mistä on kyse: m_ on mitattu arvo (Layer 2 -abstraktio), c_ capability- tai ohjaussignaali, p_ keskitetty parametri, sys_ järjestelmän tila. Se sisältää kaiken tarvittavan:

    javascript

    global.get('m_grid_power_w')       // verkkoteho tällä hetkellä (mitattu)
    global.get('m_pv_power_w')         // aurinkotuotanto (mitattu)
    global.get('m_spot_price_eur_kwh') // spot-hinta
    global.get('m_phase_l1_a')         // L1-vaihevirta
    global.get('m_hp_tap_water_top_c') // käyttöveden lämpötila
    global.get('sys_operating_mode')   // järjestelmän tila
    global.get('c_ev_charge_allowed')  // onko EV-lataus sallittu
    global.get('p_fuse_limit_a')       // sulakearvo (parametri)

    State Collector myös laskee johdetut arvot jotka helpottavat päätöksentekoa:

    javascript

    s.maxPhaseA = Math.max(Math.abs(l1), Math.abs(l2), Math.abs(l3))
    s.solarExcessW = Math.max(0, pvPowerW - Math.max(0, gridPowerW))
    s.isSolarExcess = s.solarExcessW > solarExcessThresholdW
    s.isCheapPrice = s.spotPrice < cheapPriceThreshold
    s.isNegativePrice = s.spotPrice < negativePriceThreshold
    s.isPeakLoad = s.maxPhaseA > peakLoadThresholdA
    s.isTapWaterLow = s.tapWaterC < tapWaterMinC

    Nämä boolean-arvot tekevät päätöslogiikasta luettavaa. s.isSolarExcess on helpompi ymmärtää kuin pvPowerW – Math.max(0, gridPowerW) > 2000. Kaikki kynnysarvot — solarExcessThresholdW, cheapPriceThreshold, peakLoadThresholdA ja muut — luetaan keskitetystä EH Parameters -nodesta, ei kovakoodattuna jokaiseen funktioon. Tämä on sarjassa aiemmin esitelty periaate: yksi paikka jossa kaikki säädettävät arvot elävät.

    Decision Engine — päätöslogiikka

    Decision Engine käynnistyy minuutin välein. Se lukee tilannekuvan, ajaa Priority Resolverin ja julkaisee komennot MQTT:hen.

    Rakenne on yksinkertainen:

    [Inject: 1 min] → [Lue tila] → [Priority Resolver] → [Julkaise komennot]
                                            ↓
                                   [Kirjaa päätökset]

    Priority Resolver on koko järjestelmän tärkein funktio. Se käy tilanteen läpi kiinteässä järjestyksessä — ensimmäinen osuma ratkaisee. Järjestys ei ole sattuma: ylimpänä ovat turvallisuus ja erikoistilat, alimpana talous.

    Priority Resolver käytännössä

    Koodi etenee hierarkkisesti. Turvallisuus ensin, talous viimeisenä. Tasoja on käytännössä useampi kuin tässä näytetään — täysi ketju on emergency → manual_override → fallback → peak protection → vacation → normaali optimointi. Manual_override palauttaa tyhjän päätöksen (ei muutoksia mihinkään) ja fallback ajaa minimiparametreilla, kun tilannekuva on puutteellinen. Keskitytään tässä turvallisuuden ja talouden kannalta oleellisimpiin tasoihin.

    Taso 1: Emergency

    javascript

    if (s.safetyTrip || s.mode === 'emergency') {
        return {
            ev: false,
            hpMode: 'block',
            hpImmersion: false,    // lisävastus pois
            pvCurtailPct: null,    // aurinko saa tuottaa vapaasti
            saunaAllowed: false,   // kiuas estetty
            comfortWheel: 17       // lattialämmitys minimiin
        };
    }

    Emergency-tilassa ei optimoida. Kaikki ei-kriittiset kuormat alas — EV, lisävastus, kiuas — ja lattialämmitys minimiin. Aurinko jätetään vapaaksi, koska se vain pienentää verkkokuormaa.

    Taso 2: Peak protection

    javascript

    if (s.mode === 'peak_protection' || s.isPeakLoad) {
        decisions.ev = false;
        decisions.saunaAllowed = false;
        decisions.hpImmersion = false;
        decisions.hpMode = s.hpCompressorPct > 60 ? 'block' : 'normal';
        decisions.pvCurtailPct = null; // ei rajoiteta — aurinko pienentää verkkokuormaa
        decisions.comfortWheel = 17;
        return decisions;
    }

    Sulake uhkaa — pudota kuormat. Huomaa: PV:tä ei rajoiteta koska se pienentää verkkokuormaa, ei kasvata sitä.

    Taso 3: Normaali optimointi

    Tässä haarassa tehdään varsinainen hintaohjaus. Jokainen kuorma käsitellään erikseen, ja turvallisuustarkistukset tulevat aina ensin.

    EV-latauksen päätös alkaa kahdella suojalla ennen hintalogiikkaa:

    javascript

    if (s.phasesStale) {
        decisions.ev = false;  // F15: ilman tuoretta vaihevirtatietoa EV voisi
                               // ylikuormittaa sulakkeen huomaamatta
    } else if (s.evManualOverride) {
        decisions.ev = true;   // manuaaliohitus pakottaa latauksen päälle
    } else if (!s.cap.evAllowed) {
        decisions.ev = false;  // capability estää
    } else if (s.mode === 'solar_maximize' && s.isSolarExcess) {
        decisions.ev = true;   // aurinkoylijäämä — käytä itse
    } else if (s.isVeryCheap) {
        decisions.ev = true;   // alle 1 snt/kWh — lataa aina
    } else if (s.isCheapPrice || s.mode === 'cheap_energy') {
        decisions.ev = true;   // halpa hetki — lataa
    } else if (s.mode === 'guest') {
        decisions.ev = true;   // vierastila — mukavuus prioriteetiksi
    } else {
        // normaali tilanne — laske onko perusteltua, viiveiden kanssa
        decisions.ev = s.isCheapPrice || s.isSolarExcess;
    }

    Ensimmäinen tarkistus on vaihevirtadatan tuoreus. Jos Safety Guardian ei ole saanut tuoretta vaihevirtatietoa, EV-lataus estetään — ilman tätä lataus voisi ylikuormittaa sulakkeen ilman että järjestelmä huomaa. Tämä sama suoja toistuu vielä komentokerroksessa viimeisenä porttina.

    Lämpöpumpun päätös:

    javascript

    if (s.mode === 'solar_maximize' || s.mode === 'cheap_energy') {
        decisions.hpMode = s.cap.hpBoostAllowed ? 'boost' : 'normal';
    } else if (s.isNegativePrice && s.cap.hpBoostAllowed) {
        decisions.hpMode = 'boost';  // negatiivinen hinta — käytä kaikki itse
    } else if (s.spotPrice > evuThreshold && s.cap.hpEvuAllowed) {
        decisions.hpMode = 'block';  // kallis — säästä (EVU)
    } else {
        decisions.hpMode = 'normal';
    }

    Tässä block ei tarkoita lämpöpumpun täyttä sammutusta vaan Thermian EVU-signaalia (SG1=ON, SG2=OFF), jolla pumppu lykkää lämmitystä kalliin hinnan yli. EVU:lla on noin 5 minuutin reagointiviive — kyse on lykkäyksestä, ei kovasta katkaisusta. Muiden valmistajien pumpuissa (Nibe, Vaillant, Mitsubishi) vastaava toiminto löytyy SG Ready -rajapinnasta hieman eri muodossa. evuThreshold tulee EH Parametersista (oletus 0,15 €/kWh).

    PV-rajoituksen päätös:

    javascript

    if (s.isNegativePrice && s.pvPowerW > pvCurtailMinW) {
        const ownLoad = Math.max(300, s.pvPowerW + Math.min(0, s.gridPowerW));
        const pct = Math.max(10, Math.min(95,
            Math.round((ownLoad / s.pvPowerW) * 100)
        ));
        decisions.pvCurtailPct = pct;
    } else {
        decisions.pvCurtailPct = null;  // ei rajoitusta
    }

    PV-rajoitus lasketaan dynaamisesti omakäytön perusteella — ei kiinteällä prosentilla. Rajoitusprosentti on invertterin nimellistehosta (tässä 15 kW). Jos talo kuluttaa 3 kW ja aurinko tuottaa 12 kW, omakäyttö on 3 kW — rajoitus asetetaan noin 20 %:iin nimellistehosta (3 kW / 15 kW) jotta vienti minimoidaan mutta oma kulutus katetaan edelleen aurinkosähköllä.

    Tarveperustainen ajoitus — ei pelkkiä kynnyksiä

    Pelkkä hintakynnys ei riitä älykkääseen ohjaukseen. EV-latauksen tapauksessa järjestelmä ei vain tarkista ”onko hinta alle X” — se arvioi onko lataus ylipäätään tarpeen ja milloin se kannattaa tehdä.

    Käytännössä tämä tarkoittaa että Decision Engine arvioi:

    1. Onko tarve? — onko EV kytkettynä, tarvitseeko akku latausta
    2. Mikä on aikahorisontti? — milloin auto tarvitaan seuraavan kerran
    3. Mikä on halvin hetki tässä ikkunassa? — ei välttämättä juuri nyt

    Sama periaate lämpöpumpussa: boosti ei laukea vain koska hinta on halpa — se laukea jos käyttövesi on viilenemässä tai huomisen sääennuste lupaa kylmää. Halpa hinta on mahdollisuus, tarve on perustelu.

    Tässä on keskeinen ero tavalliseen kynnysohjaukseen: järjestelmä optimoi aikaikkunan sisällä eikä reagoi yksittäiseen hetkeen. Optimointi ei ole vain ON/OFF-päätös — se on ajoitusongelma.

    Komennot ulos — ja miksi ne ovat yksinkertaisia

    Kun Priority Resolver on tehnyt päätöksensä, komennot julkaistaan MQTT:hen:

    javascript

    node.send({ topic: 'energyhub/command/ev/allowed', payload: String(d.ev), retain: false });
    node.send({ topic: 'energyhub/command/hp/mode', payload: d.hpMode, retain: false });
    if (d.pvCurtailPct !== null) {
        node.send({ topic: 'energyhub/command/pv/curtail_pct', payload: String(d.pvCurtailPct), retain: false });
    }

    Komennot ovat tarkoituksella yksinkertaisia, eikä niitä julkaista retain-lipulla — komento on hetkellinen, kuten osassa 8 käytiin läpi. Node-RED ei tiedä miten EV-lataus teknisesti toteutetaan — se tietää vain haluaako se sallia sen vai ei. HA hoitaa loput: Shelly-releen ohjauksen, Modbus-kirjoitukset, automaatioiden laukeamisen.

    Tämä on kerrosmallin konkretiaa: optimointikerros päättää, integraatiokerros toteuttaa.

    Päätösten kirjaus — observability

    Jokainen Decision Enginen päätös kirjataan observability-topiciin:

    javascript

    node.send({
        topic: 'energyhub/observability/decisions',
        payload: {
            ts: new Date().toISOString(),
            mode: s.mode,
            grid_w: s.gridPowerW,
            pv_w: s.pvPowerW,
            spot_eur: s.spotPrice,
            max_phase_a: s.maxPhaseA,
            decisions: { ev: d.ev, hp_mode: d.hpMode, pv_curtail_pct: d.pvCurtailPct },
            reasons: r  // miksi kukin päätös tehtiin
        },
        retain: false
    });

    reasons-objekti on se mikä tekee tästä oikeasti hyödyllistä. Se ei kirjaa vain mitä tehtiin — se kirjaa miksi.

    javascript

    reasons.ev = 'PEAK: vaihevirta 23.8A'
    reasons.hpMode = 'Negatiivinen hinta: -0.001 EUR/kWh'
    reasons.pvCurtail = 'Negatiivinen hinta: rajoitus 24%'

    Kun jälkikäteen kysytään miksi EV ei latautunut tiistaina klo 14 — vastaus on tallessa InfluxDB:ssä täsmällisesti kirjattuna.

    Mitä Decision Engine ei tee

    On yhtä tärkeää ymmärtää mitä Decision Engine ei tee kuin mitä se tekee.

    Se ei ohjaa releitä suoraan. Se ei kirjoita Modbus-rekistereihin. Se ei tiedä mikä laite on fyysisesti kytkettynä mihinkin. Kaikki tämä on HA:n vastuulla.

    Se ei myöskään säilytä päätöshistoriaa optimointimielessä — jokainen minuuttisykli lukee tilannekuvan uudelleen eikä ”muista” mitä se päätti tunti sitten edukseen tai haitakseen. Mutta täysin tilaton se ei ole, eikä saa olla: Decision Engine ylläpitää eksplisiittistä tilakonetta hystereesiä, viiveitä ja toteumahavaintoja varten. EV-latauksella on minimiajoaika ja päälle/pois-viiveet, jotta lataus ei pätki minuutin välein hinnan heilahdellessa. DHW-boostilla on oma elinkaarensa (käynnistys → vahvistus mitatusta tehosta → palautus). Erillinen havaintokerros vertaa jokaisella syklillä mitä järjestelmä päätti siihen mitä fyysisesti tapahtui. Tämä tila tekee logiikasta vakaata — ilman sitä sama tilannekuva tuottaisi nopeaa edestakaista vaihtelua. Ennakoitavuus ei siis synny tilattomuudesta vaan siitä, että tila on hallittua ja kirjattua: hystereesi, operating modet ja capability-flagien hitaampi muutosrytmi vaimentavat heilahtelun.


    Seuraavaksi: Osa 10 — Aurinko ja teho Node-REDissä. Miten PV-tuotanto, aurinkoylijäämä ja tehonrajoitus toimivat yhdessä päätöksenteossa.

    Tekninen toteutus: Node-RED-flowt ja Priority Resolver -koodi on kuvattu ohjeessa HA:n valmistelu integraatiokerrokseksi sekä Node-RED flowt — rakenne ja toteutus.

  • Case: oma talo — Osa 8: MQTT — viestintäkerros

    Tämä on kahdeksas osa sarjasta joka dokumentoi EnergyHub-järjestelmän rakentamisen vanhaan rintamamiestaloon. Edellisessä osassa käytiin läpi hinta ja sulakkeet — kaksi keskeisintä rajoitetta jotka ohjaavat energiapäätöksiä. Tässä osassa tarkastellaan sitä mikä pitää kaikki kerrokset yhdessä: MQTT-viestintäkerros.


    Kenttälaitteet kommunikoivat Home Assistantin kanssa omilla protokollillaan — Sungrow-invertteri Modbus TCP:llä, Thermia-lämpöpumppu Modbus RTU:lla, P1-mittari omalla rajapinnallaan. Mutta ylempien kerrosten — Home Assistantin ja Node-REDin — välinen viestintä tarvitsi oman väylän. Vaihtoehtoina olisi ollut suorat API-kutsut, tietokantakyselyt tai jaettu muisti. EnergyHubissa valittiin MQTT.

    Valinta ei ole sattuma. MQTT on suunniteltu juuri tähän: hajautettuun, epäluotettavaan ympäristöön jossa komponentit käynnistyvät ja sammuvat eri tahtiin, yhteydet katkeavat ja palautuvat, ja jokaisen komponentin pitää selviytyä itsenäisesti myös silloin kun muut eivät vastaa.

    Mitä MQTT on ja miksi se toimii tässä

    MQTT on kevyt julkaise/tilaa-protokolla. Lähettäjä julkaisee viestin brokerille tiettyyn topiciin — vastaanottajat jotka ovat tilanneet kyseisen topicin saavat viestin. Lähettäjä ja vastaanottaja eivät tiedä toisistaan. Ne tietävät vain topicin.

    Tämä löyhä kytkentä on keskeinen ominaisuus. Home Assistant ei lähetä komentoa suoraan Node-REDille — se julkaisee mittauksen MQTT-brokerille. Node-RED lukee sen kun haluaa. Jos Node-RED on poissa käynnissä puoli tuntia ja palaa takaisin, se lukee viimeisimmän retain-viestin ja jatkaa siitä. HA:n ei tarvitse tietää kuka viestin kuluttaa.

    Sama toimii toiseen suuntaan. Node-RED julkaisee komennon energyhub/command/ev/allowed: true — HA kuuntelee topicia ja reagoi. Node-RED ei kutsu HA:n API:a suoraan. Se ei tiedä miten HA on konfiguroitu tai mitä automaatiota siellä pyörii.

    EnergyHubissa MQTT-brokeri on Mosquitto, joka pyörii samalla Lenovo ThinkCentrellä Docker-kontissa. Se on yksinkertainen, luotettava ja tarkoitukseen sopiva.

    Topicrakenne — neljä suuntaa

    EnergyHubin MQTT-topicit on jaettu neljään kategoriaan jotka kuvaavat tiedon kulkusuunnan ja tarkoituksen:

    energyhub/telemetry/    HA → Node-RED    mittaukset, hinnat, lämpötilat
    energyhub/command/      Node-RED → HA    ohjauskomennot laitteille
    energyhub/system/       molemmat suunnat järjestelmätilan viestit
    energyhub/observability/ Node-RED → kaikki  päätösloki auditointia varten

    Telemetria on HA:n julkaisemaa dataa. Se sisältää kaiken mitä Node-RED tarvitsee päätöksentekoon: verkkotehon, vaihevirrat, aurinkotuotannon, spot-hinnan, lämpöpumpun lämpötilat, capability-flagit ja operating moodin. Telemetria lähtee minuutin välein, vaihevirrat 10 sekunnin välein Safety Guardiania varten.

    Komennot ovat Node-REDin päätöksiä. Ne kulkevat aina samaan suuntaan — Node-REDistä HA:lle. HA ei tee omia optimointipäätöksiä, se vain toteuttaa komennot.

    Järjestelmäviestit ovat poikkeustapauksia: safety trip, moodinvaihto, watchdog-signaalit. Nämä voivat kulkea molempiin suuntiin ja niillä on korkein prioriteetti.

    Observability on päätösloki — ei ohjausta, ei komentoja. Jokainen Node-REDin päätös kirjataan tähän topiciin syineen. InfluxDB tallentaa ne ja Grafana visualisoi.

    Ilman observabilityä automaatio näyttää satunnaiselta. Päätös tapahtui joskus, jossain YAML:ssa, jollain ehdolla. Observability tekee päätöksestä jäljitettävän: ”Tiistaina klo 14:05 EV-lataus estettiin koska peak_protection oli aktiivinen ja L1-vaihe oli 23,8 ampeeria.” Tämä on se kerros joka erottaa hallittavan järjestelmän hallitsemattomasta.

    Retain — viimeinen tunnettu totuus

    Retain on MQTT:n tärkeimpiä ominaisuuksia hajautetussa järjestelmässä. Kun viesti julkaistaan retain-lipulla, broker tallentaa sen. Uusi tilaaja saa sen heti liittyessään — vaikka alkuperäinen julkaisija olisi sammunut tunteja sitten.

    EnergyHubissa retain-politiikka on tarkoin harkittu:

    TopicRetainSyy
    energyhub/telemetry/*❌ eiMittaus on tuore tai sitä ei ole — vanha arvo ei saa jäädä elämään brokeriin
    energyhub/system/capabilities✅ kylläOperating mode ja capability-tila säilyvät uudelleenkäynnistyksen yli
    energyhub/command/*❌ eiKomento on hetkellinen — vanha komento ei saa toistua
    energyhub/system/safety_trip✅ kylläTurvatila säilyy kunnes se eksplisiittisesti nollataan
    energyhub/observability/*❌ eiLokidata ei tarvitse persistenssiä brokkerissa

    Retain-viestit ovat EnergyHubin muisti — mutta vain järjestelmätilan osalta. Kun Node-RED käynnistyy uudelleen huollon jälkeen, se ei aloita tyhjältä pöydältä tilan osalta: se lukee capabilities- ja safety_trip-topicit retain-viesteistä ja tietää heti missä moodissa ollaan ja onko turvatila päällä. Mittaukset se sen sijaan odottaa tuoreina — ensimmäinen telemetriasykli täydentää kuvan sekunneissa.

    Tässä on nimittäin sudenkuoppa, joka tekee telemetrian retainista vaarallisen: retain-viesti voi jäädä brokeriin väärässä tilassa. Jos vanha mittaus jäisi retain-viestiksi, uusi tilaaja saisi sen heti — eikä voisi tietää onko se sekunnin vai tunnin vanha. Siksi mittaukset eivät ole retained. Sama ilmiö koskee tilatietoa, mutta siellä se on hallittu: jos safety_trip julkaistiin true-arvolla mutta järjestelmä ei koskaan nollaa sitä, se jää retain-viestiksi joka toistuu jokaiselle uudelle tilaajalle. EnergyHubissa opittiin tämä kantapään kautta — Safety Guardian laukaisi turvatilan, mutta retain-viesti jäi true:ksi vaikka tilanne oli jo ohitse. Ratkaisu: turvatilan nollaus on eksplisiittinen toimenpide, ei automaattinen.

    QoS — kuinka tärkeä viesti on

    MQTT:ssä on kolme palvelutasoa:

    QoS 0 — lähetä ja unohda. Ei kuittausta, ei uudelleenlähetystä. Viesti voi kadota.

    QoS 1 — toimita vähintään kerran. Broker kuittaa vastaanoton. Viesti voi tulla useammin kuin kerran.

    QoS 2 — toimita täsmälleen kerran. Neljän viestin kättely, korkein luotettavuus.

    EnergyHubissa QoS-valinta on tarkoituksellinen:

    • Telemetria: QoS 0. Jos yksi minuuttimittaus katoaa, seuraava tulee pian. Parempi nopeus kuin varmuus.
    • Komennot: QoS 1. Komento menee perille vähintään kerran. Jos se tulee vahingossa kahdesti, ei haittaa — ”salli EV-lataus” kahdesti tuottaa saman lopputuloksen kuin kerran.
    • Safety trip: QoS 1. Turvatilan viesti on kriittinen ja sen pitää mennä perille. QoS 2 olisi teknisesti puhtain valinta, mutta käytännössä kotijärjestelmässä QoS 1 yhdistettynä retain-lippuun ja tilapohjaiseen logiikkaan on riittävä — ja yksinkertaisempi.

    MQTT ja vikasietoisuus

    MQTT:n löyhä kytkentä tekee järjestelmästä vikasietoisen — mutta ei automaattisesti. Vikasietoisuus pitää suunnitella.

    Broker kaatuu: kaikki kommunikaatio lakkaa. Laitteet jäävät viimeiseen ohjattuun tilaan. Mosquitto käynnistyy Docker-kontin mukana automaattisesti — tyypillinen katkos on sekunteja.

    Node-RED käynnistyy uudelleen: se lukee retain-viesteistä viimeisimmän tilan ja jatkaa. Ensimmäinen minuuttisykli päivittää tilanteen täysin.

    HA käynnistyy uudelleen: Node-RED odottaa uusia telemetriaviestejä. Safety Guardian saa vaihevirtatiedot vasta kun HA alkaa julkaista uudelleen — tämä on tiedostettu rajoite.

    Verkkoyhteys katkeaa: jos Mosquitto ja Node-RED ovat samalla koneella, ne kommunikoivat paikallisesti riippumatta internetyhteydestä. Nordpool-hintadata ei päivity, mutta viimeisin tunnettu hinta säilyy Node-REDin omassa kontekstissa.

    Topicit käytännössä

    Koko EnergyHubin MQTT-liikenne on tarkasteltavissa yhdellä komennolla:

    bash

    mosquitto_sub -h localhost -t "energyhub/#" -v

    Tämä on yksi järjestelmän tärkeimmistä debuggaustyökaluista. Kun jokin ei toimi, ensimmäinen tarkistus on katsoa mitä MQTT:ssä liikkuu. Onko telemetria päivittymässä? Lähettääkö Node-RED komentoja? Onko safety_trip jäänyt retain-viestiksi?

    Käytännön esimerkki 25.5.2026: Safety Guardian laukaisi safety_trip: true kun L1-vaihe ylitti 24,5 ampeeria. Viesti kulki energyhub/system/safety_trip-topiciin QoS 1:lla ja retain-lipulla. HA vastaanotti sen ja siirtyi emergency-moodiin. Kun tilanne raukesi, false-viesti lähetettiin eksplisiittisesti. Koko tapahtumaketju näkyi reaaliajassa mosquitto_sub-komennolla.

    MQTT ei ole ratkaisu kaikkeen

    MQTT sopii erinomaisesti asynkroniseen, tapahtumaohjattuun viestintään. Se ei sovi kaikkeen.

    Modbus-kommunikaatio kenttälaitteiden kanssa tapahtuu HA:n sisällä — ei MQTT:n kautta. Sungrow-invertteri ja Thermia-lämpöpumppu puhuvat Modbusia, ja HA toimii Modbus-masterina. Tämä on integraatiokerroksen sisäinen asia joka ei näy MQTT-väylässä.

    Historiadatan tallennus on InfluxDB:n vastuulla — ei MQTT:n. MQTT on viestintäväylä, ei tietokanta. Observability-topicin viestit tallennetaan InfluxDB:hen, mutta MQTT ei pidä niistä kirjaa pidempään kuin retain-viesti kestää.

    Näiden rajojen pitäminen selkeinä on osa arkkitehtuurin hallittavuutta. MQTT tekee yhden asian hyvin: välittää viestejä löyhästi kytkettyjen komponenttien välillä. Se ei yritä tehdä enempää.


    Seuraavaksi: Osa 9 — Hintaohjauksen flow Node-REDissä. Miten päätöslogiikka rakentuu käytännössä ja miten Priority Resolver tekee valintansa.

    Tekninen toteutus: MQTT-topicrakenne ja Mosquitto-konfiguraatio on kuvattu ohjeessa HA:n valmistelu integraatiokerrokseksi sekä Node-RED flowt — rakenne ja toteutus.

  • Case: oma talo — Osa 7: Hinta ja sulakkeet

    Tämä on seitsemäs osa sarjasta joka dokumentoi EnergyHub-järjestelmän rakentamisen vanhaan rintamamiestaloon. Edellisessä osassa käytiin läpi HA:n rooli ja entiteettimalli — miten data organisoidaan niin että se pysyy hallittavana. Tässä osassa tarkastellaan kahta keskeisintä rajoitetta jotka ohjaavat kaikkia energiapäätöksiä: sähkön hintaa ja sulakerajoja.


    Kaksi asiaa rajoittaa kotitalouden energiankäyttöä enemmän kuin mikään muu: kuinka paljon sähkö maksaa juuri nyt, ja kuinka paljon virtaa sulake sietää. Ne ovat luonteeltaan täysin erilaisia — hinta on taloudellinen rajoite, sulake on fyysinen rajoite. Mutta päätöksenteossa ne toimivat yhdessä ja niillä on selkeä prioriteetti: sulake voittaa aina.

    Spot-hinta — mistä se tulee ja mitä se oikeasti maksaa

    Pohjoismaisilla sähkömarkkinoilla spot-hinta määräytyy tunneittain Nord Pool -pörssissä. Hinta julkaistaan seuraavalle päivälle yleensä klo 13 aikoihin. EnergyHubissa Nordpool-integraatio hakee hinnat automaattisesti ja tallentaa ne HA:han.

    Mutta spot-hinta ei ole se hinta jonka kuluttaja maksaa. Todellinen ostohinta on monimutkaisempi:

    ostohinta = spot × 1,255 (ALV 25,5 %)
               + siirtomaksu (€/kWh)
               + marginaali (€/kWh)

    EnergyHubissa tämä lasketaan kanonisessa mittauskerroksessa m_buy_price_eur_kwh-sensorissa. Node-RED käyttää tätä arvoa — ei raakaa spot-hintaa. Tämä on tärkeä ero: optimointilogiikka vertaa todellista ostohintaa kynnysarvoihin, ei pörssihintaa.

    Myyntihinta on rakenteeltaan yksinkertaisempi kuin ostohinta. Se on aina spot-hinta ilman ALV:ia ja ilman siirtomaksua — nämä kuuluvat ostajan puolelle. Jotkut sähkön ostajat veloittavat pienen provision tai palvelumaksun joka vähennetään spot-hinnasta, mutta se on tyypillisesti marginaalinen. Negatiivisella spot-hinnalla myyntihinta on negatiivinen: jokaisesta verkkoon myydystä kilowattitunnista maksetaan.

    Hintakynnykset ja tarveperustainen optimointi

    Pelkät hintakynnykset ovat karkea ohjausmekanismi. ”Jos hinta on alle X, lataa auto” toimii yksinkertaisessa tapauksessa — mutta se ei kysele onko lataus tarpeen, onko akku jo täynnä tai onko jokin muu kuorma tärkeämpi juuri nyt.

    EnergyHubissa hintakynnykset ovat osa laajempaa logiikkaa: ensin kysytään onko toimenpide tarpeellinen, sitten etsitään sille sopiva ajankohta annetun aikajakson sisällä. Lämpöpumppua ei boostata vain koska hinta on halpa — se boostataan jos käyttöveden lämpötila on laskemassa tai jos huominen ennuste lupaa kylmää. EV-lataus ei käynnisty vain koska hinta alittaa kynnyksen — se ajoitetaan kyseisen latausjakson halvimpiin hetkiin tarpeen ja lähtöajan puitteissa.

    Optimointi ei ole vain ON/OFF-päätös — se on ajoitusongelma. Järjestelmä kysyy: mitä tarvitaan, milloin se viimeistään pitää tehdä, ja mikä on halvin hetki tehdä se tässä aikaikkunassa. Hintakynnykset toimivat tässä mallissa signaalina eikä absoluuttisena laukaisimena. Ne kertovat missä tilanteessa toimenpide on taloudellisesti perusteltua — mutta tarve ja ajoitus ratkaisevat lopullisen päätöksen.

    EnergyHubissa on kolme hintakynnystä. Kaikki ovat säädettäviä parametreja — ei hardkoodattuja lukuja.

    Negatiivinen hinta (p_negative_price, oletusarvo -0,02 EUR/kWh)

    Kun spot-hinta laskee alle tämän kynnyksen, verkkoon myynti on haitallista. Jokainen myyty kilowattitunti maksaa. Tässä tilanteessa EnergyHub rajoittaa aurinkoinvertterin tehoa — ei sammuta sitä, vaan rajoittaa vientiä niin että tuotanto vastaa paremmin omaa kulutusta. Samalla muut kuormat saavat vihreän valon: jos EV tarvitsee latausta tai lämpöpumppu tarvitsee boostia, nyt on oikea hetki.

    Negatiiviset hinnat olivat pitkään harvinaisuus. Nyt ne ovat arkipäivää. 25.5.2026 Etelä-Ruotsissa SE4-alueella hinta kävi yli 1 300 SEK/MWh:ssa illalla ja päivällä oltiin -160 SEK/MWh tasolla — sama alue, sama päivä, hintaero lähes 1 500 SEK/MWh. Hollannissa hinta kävi -86 EUR/MWh.

    Suomessa kehitys on ollut dramaattinen. Kirjoittajan opinnäytetyötä varten kerätyn ENTSO-E-datan perusteella nolla- tai negatiivisia tunteja oli vuosina 2020–2021 vain murto-osa — 16 tuntia vuonna 2020 ja 7 tuntia vuonna 2021. Energiakriisin aikana 2022 luku pysyi matalana, 37 tuntia. Sen jälkeen muutos on ollut jyrkkä: nolla- tai negatiivisen hinnan tunteja kertyi vuonna 2023 jo 603, vuonna 2024 peräti 994 — lähes 41 vuorokautta. Vuonna 2025 tammi–syyskuun ajalta kertyi jo 614 tuntia. Kasvu selittyy uusiutuvan tuotannon — erityisesti tuulivoiman — nopealla lisääntymisellä ja siirtoyhteyksien rajoitteilla. Se on sama rakenteellinen ilmiö joka näkyy koko Pohjois-Euroopassa.

    Halpa hinta (p_cheap_price, oletusarvo 0,04 EUR/kWh)

    Tämän kynnyksen alapuolella sähkö on riittävän edullista että kulutuksen siirtäminen tälle hetkelle on perusteltua — vaikka tarve ei olisi akuutti. Lämpöpumppu saa boostata käyttövettä ennakolta, EV saa ladata vaikka akussa olisi vielä puolet jäljellä. Logiikka ei kuitenkaan pakota toimenpidettä: jos capability-flag on pois tai sulake on uhattuna, halpa hinta ei ohita näitä rajoitteita.

    Kallis hinta (p_expensive_price, oletusarvo 0,15 EUR/kWh)

    Tämän kynnyksen yläpuolella ei-kriittistä kulutusta vähennetään. Lämpöpumppu blokataan EVU-signaalilla jos käyttövesi ja huonelämpötila ovat riittävällä tasolla. EV-lataus estetään. Järjestelmä minimoi ostoa — mutta ei leikkaa lämmitystä jos talo uhkaa jäähtyä alle tavoitelämpötilan. Tarve menee talouden edelle.

    Kaikki kolme kynnystä ovat parametreja — arkkitehtuurissa ei ole kovakoodattuja hintarajoja. Kynnykset ovat lähtöarvoja joita säädetään sopimuksen, siirtomaksun ja omien prioriteettien mukaan.

    Sulakkeet — fyysinen rajoite

    Kolmivaiheinen 25 ampeerin liittymä asettaa absoluuttisen rajan. Sulake ei neuvottele. Se ei katso sähkön hintaa. Se laukeaa kun virta ylittää rajan — ja sen jälkeen talo on pimeänä.

    EnergyHubissa vaihevirrat mitataan erikseen jokaiselta vaiheelta. L1, L2 ja L3 voivat olla hyvin erilaiset. Tässä talossa EV lataa L1-vaiheella — ja se näkyy suoraan: kun EV lataa, L1 on 16–24 ampeeria kun L2 ja L3 ovat 1–2 ampeeria.

    Päätöksenteossa käytetään maksimivaihevirran periaatetta: sulakeriski on siinä vaiheessa joka on eniten kuormitettuna. Ei kokonaisvirran keskiarvossa — siinä vaiheessa joka laukeaa ensin.

    Kotitalouksissa käytettävä gG-sulake sallii hetkellisiä ylityksiä — lyhyt virtapiikki ei laukaise sitä välittömästi. Mutta jatkuva ylikuormitus johtaa väistämättä laukaisuun, ja sen ajoitus riippuu ylityksen suuruudesta. EnergyHub ei odota sulakkeen fysiikkaa — se reagoi ennakoivasti.

    Safety Guardian valvoo vaihevirrat 10 sekunnin välein. Kun maksimivaihevirta ylittää 90 % sulakerajasta — 22,5 ampeeria — Guardian laukaisee peak_protection-moodin välittömästi. Paluu normaaliin tapahtuu vasta kun virta laskee alle 75 % — 18,75 ampeeria. Hystereesi estää moodin flippaamisen edestakaisin.

    25.5.2026 tämä tapahtui oikeasti. Klo 14:05 L1-vaihe nousi 23,8 ampeerin. Guardian laukesi. EV-lataus estettiin. Klo 14:20 virta laski 16,2 ampeerin, järjestelmä palasi normaaliin. Koko tapahtuma kestää 15 minuuttia ja se hoitui automaattisesti.

    Miten hinta ja sulake toimivat yhdessä

    Sulake voittaa aina. Tämä ei ole optimointipäätös — se on fyysinen rajoite joka ei jousta.

    Käytännössä tämä tarkoittaa että Priority Resolver tarkistaa sulaketilanteen ennen hintapäätöksiä. Jos peak_protection on aktiivinen, hintaoptimointia ei tehdä lainkaan — riippumatta siitä onko sähkö halpaa tai kallista.

    Normaalitilanteessa hinta ja sulakkeet toimivat yhdessä näin:

    Onko sulake uhattuna?
      Kyllä → peak_protection, pudota kuormat, älä optimoi
      Ei →
        Onko capability sallittu?
          Ei → älä tee toimintoa riippumatta hinnasta
          Kyllä →
            Onko hinta negatiivinen?
              Kyllä → rajoita PV-vientiä, käytä ylijäämä itse
            Onko hinta halpa?
              Kyllä → lataa EV, boostaa lämpöpumppu
            Onko hinta kallis?
              Kyllä → blokkaa lämpöpumppu, estä EV-lataus
            Muuten →
              Onko aurinkoylijäämää?
                Kyllä → ohjaa ylijäämä omaan kulutukseen
                Ei → jätä laitteet normaalitilaan

    Tämä järjestys on tärkeä. Sulake on ensimmäinen tarkistus — ei hinta. Hintaoptimointia tehdään vain kun sulake ei ole uhattuna.

    Aurinkoinvertterin tehonrajoitus negatiivisilla hinnoilla

    Negatiivisilla hinnoilla aurinkoinvertterin tehonrajoitus on yksi keskeisimmistä toimenpiteistä. Tässä Sungrow SG15RT -invertterissä rajoitus tapahtuu Modbus TCP -yhteydellä — rekisterit 5006 ja 5007 — mutta sama periaate toimii muidenkin valmistajien inverttereillä. Fronius, SMA, ABB, Huawei SUN2000 ja GoodWe tukevat kaikki tehonrajoitusta omilla rajapinnoillaan, ja SunSpec-standardia tukevat laitteet käyttävät yhtenäistä rekisterikarttaa.

    Rajoitus ei tarkoita invertterin sammuttamista. Se tarkoittaa että tuotantoa rajoitetaan niin että vienti verkkoon minimoidaan mutta oma kulutus katetaan edelleen aurinkosähköllä.

    25.5.2026 tehdyssä testissä rajoituksen aikana MPPT-jännite nousi 501 voltista 558 volttiin. Tämä osoittaa että invertteri siirsi paneelien toimintapisteen pois maksimitehopisteestä — se tuotti vähemmän tarkoituksella. Rajoitettu teho oli 3,86 kW kun ilman rajoitusta se olisi ollut noin 12 kW. Rajoitettua tuotantopotentiaalia oli noin 8 kilowattia — mutta tuo 8 kilowattia olisi mennyt verkkoon negatiivisella hinnalla. Energia ei kadonnut — sitä ei yksinkertaisesti tuotettu.

    Hintakynnykset ovat parametreja — ei totuuksia

    Yksi tärkeä periaate EnergyHubissa on se että hintakynnykset ovat säädettäviä parametreja. Mikä on ”halpa” riippuu siirtosopimuksesta, laitteen tehontarpeesta ja omasta kulutusprofiilista.

    Jos sähkösopimus muuttuu tai siirtomaksu nousee, p_electricity_transfer-parametri päivitetään — ja kaikki laskenta päivittyy automaattisesti. Jos haluaa olla aggressiivisempi halvan sähkön hyödyntämisessä, p_cheap_price-kynnystä nostetaan. Jos sulake on tiukempi tai haluaa enemmän turvamarginaalia, p_fuse_limit_a-arvoa lasketaan.

    Logiikka ei muutu — parametrit muuttuvat.

    Sulakepriorisointi kolmivaiheisessa liittymässä

    Kolmivaiheinen liittymä tuo mukanaan yhden mielenkiintoisen haasteen: kuormat eivät jakaudu tasaisesti vaiheille. EV lataa yhdellä vaiheella, lämpöpumppu käyttää kolmea, kiuas yhtä tai kolmea.

    Tässä talossa L1-vaihe on selvästi kuormitetuin — EV, osa valaistuksesta ja osa pistorasioista. Sulakeriski on L1:ssä, ei kokonaisvirrassa. EnergyHub valvoo jokaista vaihetta erikseen ja reagoi siihen vaiheeseen joka on lähimpänä rajaa.

    Tulevaisuudessa tähän liittyy myös tehomaksu. Jos siirtotariffeihin tulee tehomaksukomponentti — kuten monissa maissa on jo käytössä — maksimivirran minimointi muuttuu suoraan taloudelliseksi hyödyksi eikä pelkästään sulakesuojaukseksi.


    Seuraavaksi: Osa 8 — MQTT. Miten viestintäkerros rakentuu, miksi retain-viestit ovat tärkeitä ja miten MQTT-rakenne tukee koko järjestelmän vikasietoisuutta.

    Tekninen toteutus: Nordpool-integraatio, hintaparametrit ja sulakevalvonta on kuvattu ohjeessa HA:n valmistelu integraatiokerrokseksi.