Hogyan készült

Egy háztartási napelemes rendszer négy év adata, három forrásból, egy adatbázisba — és mi derült ki közben. A munkát egy AI-ügynök végezte, felügyelet mellett; a lap többek közt arról szól, hogy hol tévedett.

Utolsó frissítés: 2026. augusztus

A rendszer

Fronius Primo 5.0-1 inverter, Datamanager 2.0 adatgyűjtővel, 4,48 kWp modul két füzérben: délkeletre 3200 Wp, délnyugatra 1920 Wp. Üzembe helyezés 2019 júliusában, egyfázisú betáplálás, HMKE-szerződéssel. A monitorozás a gyártó felhőszolgáltatásán keresztül ment — ott viszont az adat mögé nem lehet benézni, és összevetni sem lehet a mérőóra adatával.

Három forrás, három nyelv

A cél az volt, hogy ugyanabban az adatbázisban legyen ott, hogy mit termelt a tető és mit mért az elszámolási mérő. Ez három, egymással semmiben nem kompatibilis forrást jelentett.

1. Az inverter helyi archívuma

A Datamanager a helyi hálózaton kiszolgál egy JSON API-t. Öt perces bontásban adja vissza a teljesítményt, a termelt energiát, az inverter hőmérsékletét, az AC feszültséget, és — ez a lényeg — füzérenként a DC áramot és feszültséget.

GET /solar_api/v1/GetArchiveData.cgi
    ?Scope=Device&DeviceClass=Inverter&DeviceId=1
    &StartDate=09.06.2024&EndDate=23.06.2024&Channel=...

Két buktató. A Scope=System hívás minden 15 napos tartományon Status.Code 255 hibával elszáll — a Scope=Device ugyanarra az adatra hibátlanul válaszol. A válaszban pedig az idősor kulcsai nem időbélyegek, hanem másodpercek a tartomány kezdetétől; ezt a hívó dolga visszafejteni.

Eredmény: 129 964 darab ötperces rekord és 259 928 füzérmérés, 2024 júniusától. Ennél korábbra a készülék nem őriz adatot.

2. Az elosztói mérőadat, OData-n

Az elosztó ügyfélportálja egy SAP OData szolgáltatás mögött ül. A negyedórás mérési sorozat lekérdezhető, ha az ember eltalálja a paraméterezést:

MeasData(Pod='…',MeasVarList='+A,-A',Interval='1',
         StartDate=datetime'…',EndDate=datetime'…')
  ?$expand=MeasDatas&$format=json

A portál felületén a mérési csatornák listája elsőre üresnek látszik. Nem hiba: a csatornák kulcsa a (csatorna, időfelbontás, szakág) hármas, tehát amíg nincs kiválasztva időfelbontás, nincs mit felkínálni. Erre a tulajdonos jött rá, nem az ügynök — az ügynök addigra már „portálhibát” állapított meg. Az API válasza utólag igazolta a tulajdonost.

Eredmény: 134 894 negyedóra, 2022 októberétől.

3. Régi e-mail mellékletek

Kiderült, hogy évekre visszamenőleg érkeztek xlsx-mellékletek ugyanezekkel az adatokkal. 198 696 mért érték és 7 991 mérőállás jött össze belőlük. Ez első ránézésre redundáns másolatnak tűnt. Nem az volt — lásd a következő szakaszt.

Amit csak két forrás összevetése mutatott meg

A betöltött hálózati adat minden formai ellenőrzésen átment. Minden napra megvolt mind a 96 negyedóra, nem volt hiányzó sor, nem volt típushiba. Ettől függetlenül 2023 első felében 151 nap adata csupa nulla volt, és 2024 decemberében további 22 napé.

Az ok egyszerű, a következménye nem: a mérőoldal a „nincs adat” állapotot üres mezővel küldi, amiből a betöltő nullát csinál. A nulla pedig legitim érték — nem hiányzik, nem gyanús, nem dob hibát. Egy lakott házban viszont nincs olyan negyedóra, amelyben egyszerre nulla a vételezés és nulla a betáplálás: 1410 napból 1357-en egyetlen ilyen negyedóra sincs.

A javítás az e-mailes archívumból jött. Utána a korábbi évek fogyasztása így módosult:

eredetileg betöltve javítás után
Éves vételezés a javítás előtt és után 9000 6000 3000 0 kWh 4064 6623 2023 +63% 7103 8137 2024 +15%
Éves hálózati vételezés. A 2025-ös év kontrollként szolgált: ott a javítás 8648,0-ról 8648,4 kWh-ra mozdított — vagyis nem írt felül jó adatot.

Utólag ellenőrizve az elosztónál sincs meg ez az adat: a 2023 márciusi közvetlen lekérdezés 768 negyedórára 768 üres értéket adott vissza, míg a kontroll-hónap teljesen kitöltött volt. Az e-mailes archívum tehát nem másodpéldány, hanem az egyetlen fennmaradt forrás.

A tanulság nem az, hogy „ellenőrizni kell az adatot”. Az ellenőrzés megvolt, és átment. A tanulság az, hogy a formai ellenőrzés egy egész osztálynyi hibát elvben sem lát meg, és ezekre csak egy független forrás derít fényt.

Amit az illesztés kikövetelt

Óraátállítás

Az exportok helyi időben érkeznek, ezért az őszi ismétlődő óra kétszer szerepel bennük, a tavaszi kimaradó óra pedig hiányzik. Az adatbázisban minden UTC-ben van, a helyi idő származtatott. Ebből következik, hogy egy nap nem mindig 96 negyedóra: tavasszal 92, ősszel 100 — ezt a teljességi ellenőrzés kiszámolja, nem beégetve tárolja.

A negyedóra két vége

Az e-mailes táblák időbélyege az intervallum végét jelöli, az adatbázisé a kezdetét. A −15 perces eltolás után 2025 júliusára 2818 negyedórából 2818 egyezett pontosan, 34 hónapon át pedig 153 358 érték — 32 összevethető hónapból 20 hibátlanul.

Az időzóna, ami átszivárog az SQL-en

A negyedórára kerekítés kézenfekvő módja UNIX_TIMESTAMP és FROM_UNIXTIME párosa. Ez viszont a kapcsolat időzónáján keresztül dolgozik, tehát az őszi ismétlődő órában kétértelmű. A helyes forma tiszta dátumaritmetika:

ts_utc - INTERVAL (MINUTE(ts_utc) % 15) MINUTE
       - INTERVAL SECOND(ts_utc) SECOND

Ez az összesítő első változatában még hibás volt, és egy RIGHT JOIN is benne volt, ami a termelést hálózati adat nélkül tartalmazó negyedórákat kidobta volna. Mindkettő felülvizsgálat közben derült ki, betöltés előtt.

Az adatbázis

18 tábla, 64,5 MB, MariaDB. A lényeg a rétegzés: nyers forrástáblák külön ( fronius_5min, fronius_string_5min, grid_15min, meter_reading_15min), fölöttük egy közös negyedórás réteg (energy_15min) forrásmaszkkal, majd napi és havi összesítők. A forrásmaszk minden negyedórára megmondja, melyik forrásból van adat — ez az, ami később lehetővé teszi, hogy a hiányt hiányként, ne nullaként közöljük.

Minden betöltő idempotens és STRICT_TRANS_TABLES mellett fut, hogy egy tartománytúllépés hibát dobjon, ne csendben csonkoljon. Ez mérve is lett: a betöltők második futása után minden sorszám és minden összeg bitre azonos maradt.

Az oldal felépítése

A nyilvános oldal egyáltalán nem nyúl az adatbázishoz. Éjjel egy cron lefuttat egy generátort, ami statikus JSON-fájlokba írja ki a tegnapig tartó napi és havi adatot; az oldal ezeket olvassa. Így nincs SQL-injekciós felület, nincs adatbázis-terhelés, és a lap statikus fájlként szolgálható ki. Az írás átmeneti fájlba megy, majd rename()-mel cserélődik, hogy az olvasó soha ne lásson fél fájlt.

A friss, 5–15 perces adat külön, tokennel védett végponton érhető el, csak a tulajdonosnak. A vágás a szerveren történik: a mai nap fizikailag nem kerül bele a nyilvános fájlokba. A nyilvános felbontás azért napi és havi, mert a negyedórás fogyasztási görbe megmutatná a háztartás napi rutinját — ébredés, távollét, autótöltés.

Ami nyitva maradt

Mit csinált az AI, és mit nem

Az ügynök írta a lekérdezéseket, a betöltőket, a sémát és ezt az oldalt; ő találta meg a nullás időszakokat, és ő futtatta le az ellenőrzéseket. Amit viszont érdemes tisztán látni:

A minta mindegyikben ugyanaz: a hasznos munka nagy részét a gép végezte, a hibák pedig ott buktak ki, ahol volt független ellenőrzés — másik adatforrás, másik jel, másik szempár. Ahol nem volt, ott a hiba magabiztosan és jól formázva jelent meg.