Case: oma talo — Osa 25: Sama kysymys, eri taso: paljonko rahaa liikkui juuri siinä vartissa

Edellisessä osassa rakensin yhden rivin, joka kertoo totuuden siitä, mitä lämpöpumpun ohjauksessa oikeasti tapahtui: yhteen näytteeseen ankkuroitu, jälkikäteen auditoitava rivi, jossa komento, lupa ja fyysinen reletila ovat oikein ajallisesti kohdistettuina. Lopetin sen osan lupaukseen, että seuraava askel ei ole uutta ohjauslogiikkaa vaan datan laadun todistaminen — ja että vasta sen jälkeen voi rakentaa ylemmän kerroksen.

Tämä osa on eräänlainen sisarkappale sille. Se ei jatka lämmitysdatan tarinaa eteenpäin — se kysyy saman kysymyksen kokonaan toiselta puolelta taloa. Lämpöpumppupuolella kysymys oli ”mitä ohjauksessa todella tapahtui silloin”. Nyt kysymys on: mitä energiaa ja rahaa oikeasti liikkui juuri siinä vartissa.

Ja kävi ilmi, että se on täsmälleen sama ongelma. Eri suureet, eri lähteet, mutta sama tapa, jolla data valehtelee onnistuneelta näyttäessään — ja sama kuri, jolla se pakotetaan kertomaan totuus.

Miksi vanha aurinkolaskuri ei riittänyt

Talossa on jo pitkään ollut yksinkertainen laskuri, joka kertoo aurinkotuotannon hyödyn: paljonko tuotannosta käytettiin itse, paljonko myytiin verkkoon, mitä se euroissa tarkoittaa. Se on ollut hyödyllinen, mutta se laskee tuntitasolla ja käyttää kovakoodattuja hinnan osia, ja se vastaa vain yhteen kysymykseen: mikä oli aurinkopaneelien hyöty.

Halusin jotain isompaa ja rehellisempää. En vain kolmea aurinkohyötysensoria, vaan kokonaisen energiatalouden kirjanpidon, jossa jokainen vartti on oma auditoitava rivinsä ja jossa lukee rinnakkain: paljonko talo kulutti, paljonko aurinkoa tuotettiin, paljonko siitä käytettiin itse, paljonko ostettiin, paljonko myytiin, mikä oli vartin todellinen ostohinta, mikä myynnin arvo — ja ratkaisevasti, mikä osa laskennasta on täydellinen ja mikä jää tietoisesti puutteelliseksi.

Se viimeinen on koko idean ydin. Vanha laskuri antaa aina jonkin luvun. Uusi saa sanoa ”en tiedä” — ja sen pitää sanoa se ääneen sen sijaan, että täyttäisi aukon nollalla tai edellisellä arvolla.

Tässä on sama sähkön varttihinnoittelun logiikka kuin ohjauspuolellakin: kallis vartti ja halpa vartti eivät saa sekoittua tunnin keskiarvoon. Jos haluaa ymmärtää, mitä aurinkovoimala oikeasti säästi, sen on tapahduttava vartin tarkkuudella, samassa rytmissä kuin muukin järjestelmän ohjaus.

Ensin matematiikka, sitten vasta mitään muuta

Rakensin tämän samalla vaiheistuksella kuin lämmityksen auditrivin, ja järjestys oli tarkoituksellinen. Ensin puhdas laskentalogiikka ilman mitään yhteyttä ulkomaailmaan. Sitten lähdeadapterit, jotka kääntävät järjestelmän raakadatan laskennan ymmärtämään muotoon. Sitten puhdas laskentamoottori. Vasta sitten tuotannon lukukomponentti, joka oikeasti hakee dataa. Ja vasta aivan viimeisenä se, joka liittää kaiken tuotannon Node-REDiin.

Kanonista kirjoittajaa — sitä, joka joskus tallentaa nämä vartit pysyvästi järjestelmän viralliseksi totuudeksi — ei ole vielä olemassa. Se on tarkoituksellista. Sitä ei rakenneta ennen kuin tämä koko ketju on todistettu toimivaksi oikealla datalla.

Miksi näin verkkaisesti? Koska laskennan matematiikka on juuri se kohta, jonka on oltava horjumaton ennen kuin sen päälle rakentaa mitään. Vartin energiatase ilman akkua on yksinkertainen: kulutus on tuotanto miinus vienti plus tuonti. Oma käyttö on se osa tuotannosta, joka ei mennyt verkkoon. Mutta yksinkertaisen kaavan ympärille tarvitaan joukko sääntöjä, jotka eivät ole yhtään neuvoteltavissa: puuttuva arvo ei ole nolla, puuttuva lähde tekee koko vartista epätäydellisen, nollalla ei jaeta, ja — tämä on tärkeä — negatiivinen myyntihinta on sallittu. Kun sähköstä maksetaan verkkoon vietäessä, vienti maksaa rahaa eikä tuota sitä, ja laskennan on kestettävä se ilman että se pitää sitä virheenä.

Nämä säännöt kirjoitettiin ensin, testattiin kymmenillä keksityillä rajatapauksilla, ja lukittiin. Vasta sitten annettiin oikean datan tulla lähelle.

Arvonlisävero lisätään täsmälleen kerran

Yksi hintalaskennan periaatteista ansaitsee tulla sanotuksi erikseen, koska se on juuri sellainen kohta, jossa hiljainen tuplaus olisi helppo. Ostohinta rakentuu spot-hinnasta, johon lisätään arvonlisävero, marginaali, siirto ja verot. Nordpool antaa spotin arvonlisäverottomana. Arvonlisäkerroin on lisättävä täsmälleen kerran — ei kertaakaan, ei kahdesti.

Tämä kuulostaa itsestäänselvältä, mutta järjestelmässä on useita paikkoja, joissa hinta esiintyy eri muodoissa, ja joissakin niistä arvonlisä on jo mukana. Jos laskenta ottaisi hinnan väärästä lähteestä, se joko unohtaisi veron tai lisäisi sen kahdesti — ja kumpikin näyttäisi täysin uskottavalta luvulta. Ratkaisu oli tehdä hinnan alkuperästä nimenomainen osa dataa: laskenta ei ota ”jotain hintaa”, vaan se ottaa nimenomaisesti arvonlisäverottoman spotin ja lisää veron itse, yhden kerran, dokumentoidusti. Ja se kieltäytyy hyväksymästä vanhoja ”valmiiksi paketoituja” hintasensoreita kanonisena lähteenä, koska niiden alkuperä on hämärä.

Hankalin osa ei ollut laskenta vaan se, milloin dataa saa

Tähän asti tarina kuulostaa siistiltä. Mutta kuten aina, oikea data opetti jotain, mitä en osannut suunnitteluvaiheessa arvata — ja tällä kertaa opetus muutti koko arkkitehtuurin ajoituksen.

Alkuperäinen ajatus oli yksinkertainen: kun vartti sulkeutuu, laske se. Jos laskenta epäonnistuu, yritä hetken päästä uudelleen. Se on intuitiivinen malli, ja se on väärä.

Kun tutkin seitsemän vuorokauden todellista sähkömittarin dataa, paljastui jotain, mitä en ollut odottanut. Sähkömittari ei raportoi arvojaan säännöllisin väliajoin vaan silloin, kun ne muuttuvat — ja verkosta ostetun ja verkkoon myydyn energian laskurit voivat olla pitkiä aikoja hiljaa. Jotta vartin rajan energiamäärän voi laskea, tarvitaan mittarilukema molemmilta puolilta vartin rajaa. Ja jos mittari on ollut hiljaa rajan yli, sitä lukemaa ei yksinkertaisesti ole vielä olemassa sillä hetkellä, kun vartti sulkeutuu.

Kuinka pitkään se voi olla hiljaa? Datassa mediaani siihen, että vartti oli täydellisesti laskettavissa molempiin suuntiin, oli noin kaksi ja puoli tuntia vartin sulkeutumisesta. Yhdeksänkymmenennessä persentiilissä yli kahdeksan tuntia. Ja pahimmillaan yli yksitoista tuntia. Vasta kahdentoista tunnin kohdalla sata prosenttia vartteista oli laskettavissa.

Tämä on juuri sitä lajia löytöä, joka on koko sarjan toistuva teema. Mikään ei ollut rikki. Data oli oikein. Laskenta oli oikein. Mutta laskenta oli väärässä maailmassa ajassa: se yritti laskea vartin, jonka totuutta ei vielä ollut olemassa. ”Yritä heti uudelleen” olisi tuottanut pitkän jonon epätäydellisiä vartteja, jotka olisivat täydentyneet vasta tunteja myöhemmin — ja välissä syntynyt kohina olisi näyttänyt vialta, vaikka se oli vain kärsimättömyyttä.

Ratkaisu oli lakata kysymästä liian aikaisin

Kun mittasin, miten myöhään data oikeasti saapuu, arkkitehtuuri muuttui itsestään. Sen sijaan että vartti laskettaisiin heti sen sulkeuduttua, se lasketaan vasta kahdentoista tunnin kuluttua — silloin valtaosa dataa on jo saapunut. Ja sama vartti lasketaan uudelleen kahdenkymmenenneljän tunnin kohdalla erillisenä varmennuksena, jolloin sata prosenttia datasta on varmasti paikalla.

Tärkeää on, että tämä toinen ajokerta ei ole ”korjaus”. Se laskee täsmälleen saman vartin — saman aikaidentiteetin — uudelleen, ei uutta väliä. Jos jokin oli kahdentoista tunnin kohdalla vielä epätäydellistä, kahdenkymmenenneljän tunnin ajo joko täydentää sen tai vahvistaa, että se jää pysyvästi epätäydelliseksi. Puuttuva pysyy puuttuvana, epätäydellinen pysyy epätäydellisenä. Mikään ei täytä aukkoa arvauksella, eikä mikään kanna vanhaa mittarilukemaa keinotekoisesti eteenpäin.

Tämä on sama opetus kuin lämmityspuolella, vain toisin päin. Siellä opetus oli, ettei riviä saa rakentaa ”viimeisimmästä tunnetusta arvosta”, koska se sekoittaa eri hetkiä. Täällä opetus on, ettei varttia saa laskea liian aikaisin, koska silloin ”viimeisin tunnettu arvo” ei vielä ole se, mikä siitä lopulta tulee. Molemmissa juuri aika on se, joka valehtelee, jos sitä ei kohtele mittauksen osana.

Hintakin osoittautui monimutkaisemmaksi kuin luku

Ennen kuin lukitsin hinnan, tutkin kuudenkymmenen vuorokauden hintadataa. Odotin yksinkertaista aikasarjaa. Sain sen sijaan pienen kokoelman ristiriitoja: joukossa oli vartteja, joille löytyi kaksi eri hintaa, ja osalle näistä kaksi eri arvoa. Kaikki ristiriidat osuivat samaan kohtaan — paikalliseen keskiyöhön, vuorokauden vaihteeseen.

Tämä olisi voinut jäädä huomaamatta ja myrkyttää hiljaa hintalaskennan juuri vuorokauden rajalla. Ratkaisu oli olla luottamatta yhteen hintalähteeseen sokeasti. Järjestelmässä on kaksi tapaa tietää vartin hinta: hetkellinen hintahavainto ja päivän hinta-aikataulu, jonka Nordpool julkaisee etukäteen. Lukittu sääntö vaatii, että molemmat ovat olemassa ja että hetkellinen havainto vastaa aikataulun arvoa. Jos hetkellisiä havaintoja on ristiriitaisia, aikataulu ratkaisee, kumpi on oikea — ja ristiriita jää näkyviin todistusaineistoksi. Jos vain toinen on olemassa, vartti jää epätäydelliseksi. Hintaa ei koskaan kanneta edelliseltä vartilta eteenpäin.

Tämä on sama periaate kuin readbackin todentaminen ohjauspuolella: yksi lähde ei riitä todistamaan totuutta, kun toinenkin on saatavilla.

Kirjoitusoikeus ei ole taaskaan lukuoikeus

Kun rakensin tuotannon lukukomponentin, tuli vastaan vanha tuttu. Järjestelmässä oli ennestään tietokantatunnus, jonka luulin voivani käyttää lukemiseen. Se osoittautui käytännössä pelkäksi kirjoitustunnukseksi: sillä pystyi kirjoittamaan, mutta kysely samalla tunnuksella palautti ”ei löydy”. Sama opetus kuin läpi koko sarjan — onnistunut kirjoitus ei ole sama asia kuin luettavissa oleva data, ja niitä ei saa todistaa samalla oikeudella.

Ratkaisu oli minimioikeusperiaatteen mukainen: en laajentanut vanhaa tunnusta, vaan loin erillisen, pelkän lukuoikeuden tietokannan siihen yhteen säiliöön, josta laskenta tarvitsee dataa. Se todennettiin molempiin suuntiin: kysely toimii, mutta kirjoitusyritys sillä tunnuksella torjutaan. Nyt lukukomponentti ei rakenteellisesti pysty kirjoittamaan mitään, vaikka joku yrittäisi käskeä sitä siihen.

Havaitseva, ei ohjaava — ja se on lukittu monessa kohdassa

Koko tämä kerros on tarkoituksella pelkkä tarkkailija. Se lukee dataa, laskee vartin, ja julkaisee tuloksen kahteen tarkkailukanavaan. Se ei kirjoita järjestelmän viralliseen totuuteen, ei muuta olemassa olevia vartteja, ei koske sähköauton tai lämpöpumpun ohjaukseen, ei releisiin, ei tariffeihin.

En luottanut siihen, että ”havaitseva” olisi turvassa vain siksi, että niin oli tarkoitus. Se on lukittu useassa kohdassa peräkkäin. Laskentamoottorin tulos kantaa aina kahta lippua, jotka sanovat ”vain havaitseva” ja ”kanoninen kirjoittaja pois päältä” — eikä mikään syöte voi kääntää niitä. Se komponentti, joka päättää julkaistaanko vartti, tarkistaa nuo liput ja kieltäytyy julkaisemasta mitään, jos ne eivät ole kohdallaan. Sallittuja ulostuloja on täsmälleen kaksi, molemmat tarkkailukanavia. Ja lukuoikeus tietokantaan on fyysisesti pelkkä lukuoikeus. Mikä tahansa näistä yksinään riittäisi; yhdessä ne tekevät ohjaavasta toiminnasta rakenteellisesti mahdotonta tässä vaiheessa.

Miten tämä vietiin tuotantoon — todistaen, ei kokeillen

Kuten lämmityspuolellakin, suurin osa työstä ei ollut koodin kirjoittamista vaan sen todistamista, ettei koodi tee mitään muuta kuin mitä sen piti. Muutos tuotannon ohjelmavuohon rakennettiin niin, että kone tuotti sen automaattisesti annetusta lähtötilasta, ja riippumaton tarkistus todensi, että lopputulos oli tavulleen sama kuin katselmoitu — ja että se koski täsmälleen kahdeksaa uutta palasta eikä muuttanut yhtäkään vanhaa.

Ennen kuin sitä vietiin liveen, se ajettiin nimenomaan tuotannon oman ohjelmistoversion päällä — koska edellinen osa opetti kalliisti, että ”testit menivät läpi” ja ”toimii tuotannossa” ovat kaksi eri väitettä. Ja itse käyttöönotto tehtiin niin, että vanha tila varmuuskopioitiin ensin, muutos vietiin sisään atomisesti, ja järjestelmä olisi palautunut itsestään edelliseen tilaan, jos mikä tahansa tarkistus olisi pettänyt. Käyttöönoton jälkeen todennettiin, että tuotannossa on täsmälleen odotettu tila, ei mitään enempää.

Missä mennään nyt — ja mikä on rehellisesti vielä auki

Sanon tämän yhtä suoraan kuin edellisenkin osan lopussa, koska muuten lupaisin enemmän kuin on totta.

Se, mikä nyt on tuotannossa, on havaitseva talouskerros. Se on livenä, mutta se on tuoretta, ja se on tarkoituksella hiljainen aivan lähipäiviin asti — ensimmäinen sallittu vartti alkaa vasta erikseen asetetusta rajapäivästä, jotta laskenta ei koskaan väitä laskeneensa dataa ajalta, jolta sillä ei ole täyttä kuvaa. Ensimmäinen oikea live-vartti, sen kahdentoista tunnin tulos ja sen kahdenkymmenenneljän tunnin varmennus ovat vasta edessä. Ja jos ensimmäinen tulos on epätäydellinen, se ei ole automaattisesti vika — sähkömittarin datan hidas saapuminen todistettiin nimenomaan siksi, että epätäydellisyys osataan lukea odotettuna eikä virheenä.

Vasta kun havaitsevasta kerroksesta on kertynyt riittävästi live-dataa, seuraavat askeleet ovat erillisiä päätöksiä: uuden laskennan vertaaminen vanhaan rinnakkain usean päivän ajalta, ja vasta sen jälkeen — jos vertailu kestää tarkastelun — se kanoninen kirjoittaja, joka tekee näistä varteista järjestelmän virallisen totuuden. Sitä ei rakenneta ennen kuin havaitseva vaihe on hyväksytty. Ja kun se joskus rakennetaan, sen on perittävä täsmälleen samat periaatteet: yksi kanoninen aika, tarkka lähde, näkyvä alkuperä, puuttuva ei ole nolla, kirjoituksen onnistuminen todennetaan lukemalla, eikä historian merkitys saa muuttua jälkikäteen.

Sama laki, kaksi eri kysymystä

Kun katson lämmityksen auditriviä ja tätä talouskerrosta rinnakkain, ne näyttävät samalta ongelmalta eri tasolla. Toinen kysyy, mitä ohjauksessa todella tapahtui juuri sillä hetkellä. Toinen kysyy, mitä energiaa ja rahaa oikeasti liikkui juuri siinä vartissa. Molemmissa vastaus rakentuu samoista laeista: yksi kanoninen aika, tarkka lähde, näkyvä alkuperä, ja ennen kaikkea se, että järjestelmä saa — ja sen täytyy — sanoa ”en tiedä” silloin kun se ei tiedä, sen sijaan että keksisi uskottavan luvun.

Se on hitaampaa kuin ”laske ja katso, näyttääkö oikealta”. Mutta järjestelmässä, jonka datan varaan on tarkoitus joskus rakentaa malli, hitaus oikeassa kohdassa on halvempaa kuin nopeus. Ja tässä tapauksessa hitaus ei ollut edes valinta vaan löydös: oikea data kertoi, ettei totuutta yksinkertaisesti ole olemassa vielä silloin, kun sitä ensin haluaisi kysyä. Suurin muutos tässä koko työssä ei ollut rivi koodia. Se oli sen myöntäminen, milloin on liian aikaista kysyä.


Seuraavaksi vanhan Home Assistantin siirto uuteen järjestelmään — mutta ei varmuuskopion palautuksena vaan arkeologisena tutkimuksena. Vanha konfiguraatio käytiin läpi toiminto kerrallaan ja siirrettiin vain se, mikä oli yhä tarpeen: laiteintegraatiot siirrettiin, EnergyHubin jo korvaamat ohjaukset jätettiin tietoisesti taakse, ja seurantatoiminnot rakennetaan uudelleen nykyisen arkkitehtuurin päälle. Mukana muun muassa se, miksi vanhaa ohjauslogiikkaa ei pidä kloonata sokkona — ja mikä uusi tehtävä vanhalle Raspberry Pi:lle lopulta löytyi.