Előzmények
E rövid, frappáns bevezetésben megtudjátok, hogy már 2022 óta okosítom a hagyományos kazán vezérlését.
Okok, előzmények, építés (ha érdekel és nem olvastad) erre, 2024-es ráncfelvarrás itt.

Wemos D1 mini vs ESP32-C3 Supermini (banana 4 scale), AI kép
Erre az évre a jól szolgáló ESP8266 nyugdíjazása és az ESP32-C3 Supermini beüzemelése volt a fő feladat.
A vezetékelés és a nyák egyszerűsítve lett, más HW változás nincs.
A feladat is maradt: az okos otthonnal (Home Assistant) együttműködve, de mégis függetlenül vezérelje a keringtetőszivattyút. Mivel csak két kör van (fürdő+WC, illetve minden más), a szobánkénti hőfokokat a Home Assistant igazgatja.
Firmware továbbra is az ESPEasy. Ez egy jó keretrendszer, minden alap modult tartalmaz, van webui, MQTT, stb. Szenzorok, modulok, kijelző, gombok, kapcsolók és rengeteg egyéb bizgentyű pár kattintással hozzáadható. MQTT-n tud Home Assistantnak adatot küldeni, onnan adatot fogadni.
Maradtak a bemenetek:
- 3 db Dallas DS18B20 szenzor: puffer tartály előremenő, puffer visszatérő és udvar hőfokok mérése
- Computherm RF termosztát: az adó bent van (a ház kb. leghidegebb pontján), a vevő kint van a kamrában. Az esp egyik bemenetén van a Computherm vevő szárazkontakt relé, "kapcsoló"-ként
- MQTT: Home Assistant-ból. Az ESPEasy négy adatot tud a cmd topikból elcsípni, jelenleg csak a szellőztetés állapotát veszi át.
Kimenetek is változatlanok:
- 0,96" Oled kijelző: gombnyomásra pár fontos adatot kiír (hőfokok, állapot)
- SSR relé: ez kapcsolja a keringtetőt
- MQTT: Home Assistant-ba adatokat küld (hőfokok, állapot)

A program ESPEasy-ben a szabályok (rules), ezzel is sok minden megoldható, ha nem akarunk vagy nincs időnk komolyabb programnyelvbe időt fektetni.
Hirdetés
Mi változott a rules-ban? Legfontosabb, hogy az esemény alapú vezérlés heartbeat-re lett cserélve.
Korábban sem volt összeakadás (köszi ESPEasy programozók
), de a sok időzítő és a kód futásának nehéz követhetősége kívánta, hogy variáljak.
Belekerült egy téli/nyári beállítás, optimalizálva lett az MQTT üzenetek küldése és más apróságok.

A teljesebb képhez itt a devices (eszközök) oldal.
A hardware fülön is be kell állítani pl. az MCU belső felhúzó ellenállásait a kapcsolókra
Jöjjön a rules, extra sok kommenttel... majd utána a működés részletesen.
Rules
// Keringető szivattyú vezérlés// Heartbeat alapú időzítés
on System#Boot do // csak a boot-nál fut, alap változók megadása TaskValueSet,1,1,34 // dtemp#tmin min. vízhőfok TaskValueSet,1,2,89 // dtemp#tmax biztonsági hőfok TaskValueSet,2,1,455 // dtime#kering keringetés idő sec TaskValueSet,2,2,15 // dtime#keringp induláskor szünet x10 sec// változók resetelése: nincs rá szükség, de így látszik egyben, hogy mit hol használtam Let,1,0 // időzítő Let,2,0 // heartbeat Let,3,0 // MQTT dummy1 Let,4,0 // MQTT dummy2 Let,5,0 // heartbeat téli-nyári mód Let,6,0 // Protect Let,7,0 // keringetési idő Let,8,0 // szünet idő Let,9,0 // MQTT dummy3// Start: loopTimerSet,5,3600 // Protect/szivattyúvédelem 1 órás loop indul loopTimerSet,10,10 // heartbeat indulendon
//// Protect loop / szivattyúvédelem: óránként 1-el nő az értékeon Rules#Timer=5 do Let,6,[var#6]+1 // számláló növelése TaskValueSet,4,3,[VAR#6] if [var#6]>=24 // indítás 24 óránként (ha nem üzemelt a szivattyú), de kinek mi a szimpatikus. Publish keri/s, 'Keringetés' // MQTT üzenet: HA-ban látom, hogy nyáron is néha bekapcsolja.
// lehet erre HA automatizmust írni, ami riaszt, ha pl. 3 napig elmarad a keringetés. oled,7,1,Protect // oled kiíratás gpio,6,1 // szivattyú be TaskValueSet,4,1,1 // státusz ON Let,1,60 // protect keringetési idő TimerSet,3,1 // időzítő loopba endifendon
//// időzítő loop: ide kerül az, aminek le kell futnia: pl. fűtéskor vagy túlfűtéskor a keringetéson Rules#Timer=3 do TimerSet,10,0 // heartbeat stop, nem fogja felülbírálni a keringetést if [VAR#1]<2 // ha az időzítő lejár event,hoff // hof, fűtés leállítás hívása else Let,1,[VAR#1]-2 // az időtartam csökkentése, 2 sec-es lépésekben TaskValueSet,4,2,[VAR#1] // oled kiíráshoz kell TimerSet,3,2 //# folytatja az időzítőt 2 sec múlva. Lehet más érték is, ezen frissül az oled jól endifendon
// // Termosztát kikapcsoláskor: ez maradt eseményhez kötött,
// mert az ESP vezérlős rendszer pont a fűtés túllövéseinek elkerülésére lett kitalálva on termo#state=0 do if [owt#t1]<[dtemp#tmax] // leáll, ha nincs túlfűtés: a túlfűtés védelmet nem akadályozza event,hoff // heating off event hívása. A teljes név korábban a rövidítések áldozata lett else loopTimerSet,10,10 // heartbeat ciklus újraindul endifendon
// // Bekapcsolás (keringetés indul)on hon do TimerSet,10,0 // heartbeat stop, nem fogja felülbírálni a keringetést.
// Ez egy kicsit lassú rész, ha ez nincs itt, akkor az MQTT-t a heartbeat felül tudja írni. Publish keri/s, 'Keringetés' // MQTT üzenet oled,7,1,Heating! gpio,6,1 // szivattyú be TaskValueSet,4,1,1 // státusz ON, OLED kiíráshoz kell// Let,7,[dtime#kering]-([owt#t1]*2)-([owt#ext]*3) // keringetési idő számítása // Az alap adatokban megadott kb. ideális keringetési időt módosítjuk// Egyik módosító az előremenő víz hőfoka [owt#t1], másik a külső hőmérséklet [owt#ext]// A szorzóval lehet állítani, hogy milyen "súlyozással" vegye számításba.
// Végül egy egyszerűbb képletet használtam, jobb ezzel a matek: Let,7,[dtime#kering]-(([owt#t1]+[owt#ext])*3) // előremenő hőmérsékletével csökken, // kint ha hidegebb van, akkor nő a keringetési idő. Let,1,{constrain:[var#7]:210:420} // keringetési idő beállítása: constrain nekem új volt, // kivált néhány if-else ciklust. Qwen3 AI javasolta. Constrain-ban nem lehet művelet, // ezért az értéket előtte var 7 változóba számolja ki. // A lényeg, hogy igy érték:minimum:maximum formában korlátozzuk a fűtési idő hosszát. // ez hasznos, ha biztosan szeretnénk, hogy lefusson akkor is, ha hiba van a számításban. Let,8,60-([var#1]/10) // szünet idő, a keringetési idővel kalkulálva
Let,8,{constrain:[var#8]:18:39} //constrain: var8 értéke 18 és 39 közötti lehet csak
TaskValueSet,2,2,[var#8] // szünet idő beállítása TimerSet,3,1 // időzítő loopbaendon
// Keringetés végeon hoff do gpio,6,0 // szivattyú ki TaskValueSet,4,1,0 // státusz OFF TimerSet,3,0 // timer reset: megállítja az időzítő loop-ot Let,2,0 // számláló reset: heartbeat nullázódik // a fűtési ciklusok közé iktatott szünetnek Let,3,0 // MQTT reset: ha ez nincs, akkor pl. szünet után fűtés majd újra // szünet esetén az MQTT és az OLED nem frissülne, mert azt átugorja Let,6,0 // Protect loop reset loopTimerSet,10,10 // vissza heartbeat ciklusbaendon//// Túlfűtés eseténon hover do TimerSet,10,0 // heartbeat stop Publish keri/s, 'Túlfűtés' oled,7,1,OVERHEAT gpio,6,1 // szivattyú be TaskValueSet,4,1,1 // státusz ON Let,1,600 // keringetési idő TimerSet,3,1 // időzítő loopbaendon//// Heartbeat loopon Rules#Timer=10 do Let,2,[var#2]+1 // számláló növelés TaskValueSet,4,2,[var#2] // oled kiírás // túlfűtéskor hover hívása if [owt#t1]>[dtemp#tmax] event,hover endif// // Fűtés: feltételek if [termo#state]!=0 and [ha#ha]!=1 // termosztát és szellőztetés // fontos a != (nem egyenlő), biztosabb, "hibatűrőbb" a rendszer: // ha a termosztát nincs kikapcsolva és ha az ablakok nincsenek nyitva if [owt#t1]>[dtemp#tmin] and [var#2]>=[dtime#keringp] // min hőfokot elérte és nincs szünetben event,hon endif endif// // --- oled, MQTT--- if [ha#ha]!=0 // ha a HA jelezte a nyitott ablakokat Let,3,1 if [var#3]!=[var#4] Publish keri/s, 'Ablakok' oled,7,1,Ablakok gpio,6,0 // szivattyú ki TaskValueSet,4,1,0 // státusz OFF endif endif if [pump#state]=0 and [ha#ha]=0 and [var#2]<=[dtime#keringp] // keringetés szünetel Let,3,2 if [var#3]!=[var#4] // ha var 3 és var 4 nem egyenlő, akkor fut. // eredmény: csak változáskor frissül az MQTT és az OLED Publish keri/s, 'Szünet' oled,7,1,Pause endif endif if [pump#state]=0 and [ha#ha]=0 and [var#2]>[dtime#keringp] // watch Let,3,3 if [var#3]!=[var#4] Publish keri/s, 'Watch' oled,7,1,Watch endif endif If [var#3]=[var#4] Let,9,[var#9]+1 // kell egy újabb számláló... else Let,4,[var#3] // var 3 értéket var 4-be másoljuk, ez kell a változásonkénti MQTT kiíráshoz endif If [var#9]>=12 // ~120 sec-ként MQTT újraküldés mindenképp Let,4,0 // MQTT dummy reset Let,9,0 // MQTT dummy számláló reset endif// // --- Téli-Nyári mód --- if [owt#t1] >= 26 and [var#5] != 1 // Meleg víz → gyors figyelés (10 mp) Let,5,1// var 5-el nézi, hogy ha már a nyári mód aktív, akkor a timer reset-et átugorja loopTimerSet,10,10 elseif [owt#t1] < 26 and [var#5] != 2 // Hideg víz → lassú figyelés (300 mp) Let,5,2 loopTimerSet,10,300 endifendon
Működése
Meg tudom magyarázni! 
Systemboot-ban pár alap adatot dummy device-ba mentünk, majd indul a két párhuzamos loop timer (ismétlődő időzítő? Vagy mi ez Magyarul?).
Az első a protect loop, a szivattyú leragadás elleni védelem. Óránként növel egy számlálót (var 6, igen... az új firmware-el már lehetne rendes nevük is, de nincs kedvem elnevezni és átírni minden változót...
), ha 24 órán keresztül nem kapcsolt be a szivattyú, akkor elindítja egy percre. Ha keringtet a rendszer, akkor a számlálót nullázza. Nem kellene ilyen sűrűn elvileg, de így akkor sincs gond, ha valamiért kimarad pár megmozgatás.
A második loop a heartbeat maga. Boot után 10 másodperces ciklussal kezd. Ezen lehet változtatni, de puffertartályos rendszerrel ez a sebesség még vállalható.
Heartbeat-ben az első ellenőrzés a kimenő vízhőmérséklet. Ha a beállított maximumon túl van, akkor azonnal a túlfűtésre lép és a szivattyút bekapcsolja.
A keringtetéseket a timerset 3 időzítő végzi, amihez var#1 (1-es változó) a túlfűtés, keringetés, vagy szivattyúvédelem "modulból" kapott idő értékkel számol.
Hogy ne lehessen keveredés, rögtön le is állítjuk a heartbeat-et... 
Az ESP kímélésére két másodperces ciklusok vannak, a számláló is kettővel csökken, így kvázi másodperc pontosságú az időzítő és a kijelzés is tudja követni. Ha lejár, akkor a heating off (hof, mert mindent is rövidítenem kellett korábban) event következik.
event, hof:
MQTT és az OLED frissül, szivattyút és timerset 3 időzítőt leállítja. Erre elvileg nincs szükség, de ha valamit elszámol, vagy hiba van és még pörögne, akkor itt megállítja. Végül a heartbeat-et újraindítja.
A heartbeat a túlfűtés után azt nézi meg, hogy kell-e fűteni. Ha a termosztát jele "nem ki" és az ablakok állapota nem nyitott, akkor halad tovább...
Az if ciklusokban több helyen is != (nem egyenlő)-re lettek cserélve a feltételek.
Hasznos, ha valahol hiba van, egy szenzor rossz értéket ad vissza,
vagy csak kiesik az MQTT és ezzel az egyik "bemenet", ami a fűtéshez kell.
A következőkben megvizsgálja, hogy az előremenő víz van-e olyan meleg, hogy érdemes keringtetni, illetve, hogy szünetben van-e még. Szünetek vannak beiktatva minden keringtetés után, ezzel is próbálom a fűtés túllövéseit kezelni. Buta termosztátnál és a hagyományos vegyestüzelésű kazánnál a néha 70+ °C vízzel nem szabad megvárni, hogy a termosztát szerint elég legyen a szobahőmérséklet... Fűtűnk, várunk. Ha kell fűteni még, akkor ismét fűtünk.
Ennyi.

Home Assistant dashboardon a legfontosabb adatok
A ciklus végén az MQTT és az OLED frissítése jön. Programozásban jártasak mosolyognak, minek ennyi if feltétel...
Hát ezzel a résszel voltak kalandok. Cél, hogy stabil legyen, az MQTT biztosan frissüljön, de ne szórja tele üzenetekkel és ne terhelje az ESP-t sem.
Próbáltam összevonva, ahogy logikus lenne... de az ESPEasy nem szeret egy if-ben több feltételt vizsgálni, 2-3 feltételig stabil. A több mélységben beágyazott if vagy If-else ciklusok száma is véges. Elvileg 3 szint lehet, de volt, hogy 2 szintet sem ugrott meg és nem találtam az okát, bugreportot sem. Végül egyszerűen szétbontottam ezt a részt... külön-külön vizsgáljuk, hogy milyen státuszban van. A stabilitáson túl érdekesség, hogy az ESP CPU load is csökkent, 54-58%-ról ~51%-ra.
Első lépcsőben a szellőztetés állapota a kérdés: ha szellőztetés van, akkor a keringtetést kikapcsolja. Túlfűtésnél természetesen nem áll le a keringtetés, ezért is kell a keringtetés timerset időzítőben a heartbeat ciklust megállítani.
var 3 változó értéke 1-re változik. Ha var 3 és var 4 változók értéke azonos, akkor az MQTT és az OLED frissítés elmarad. Ha eltérnek, akkor frissíti az adatokat.

Részletesebb adatok HA history-ban
Második lépcső a szünet, harmadik lépcső a figyelés.
Működésükben hasonlóak az előzőhöz, de var 3 más-más értéket kap.
Szünet vs. figyelés: azért választottam két felé, mert ha a termosztát be állásban van és a rendszer nem fűt, akkor a szünet állapot ezt indokolja, a watch/figyelés állapotnál viszont ez hibát jelent. Ha nem lenne két állapot, akkor nehéz lenne megállapítani, hogy "be" jelnél miért nem keringtet.
Hol a hiba? Ha ennyi lenne, akkor Home Assistant újraindításnál nem jönnének friss adatok, mert az MQTT a legutolsó állapot szerint indul újra. Így ha pl. keringtetés alatt volt újraindítva, akkor az maradt az üzenet, pedig már Watch módban volt, de ez az üzenet nem érkezett meg. Igen QOS beállításokkal lehetne finomítani, de van jobb ötletem...
Ez:
If [var#3]=[var#4] Let,9,[var#9]+1 else Let,4,[var#3] endif If [var#9]>=12 // ~120 sec-ként MQTT újraküldés mindenképp Let,4,0 // MQTT dummy reset Let,9,0 // MQTT dummy számláló reset endif
Ez a kis szakasz szintén megvizsgálja, hogy var 3 és 4 azonosak-e.
Ha igen, akkor MQTT üzenet nem volt küldve, a var 9 számlálót növeli. Ha nem, akkor var 4 változó értéke var 3 értékére módosul.
Ha var 9 számláló eléri a 12-őt (~10 sec looptimerrel ez kb. 2 percet jelent), akkor a var 4 és 9 változót is nullázza, így a következő heartbeat körben az aktuális állapot szerinti MQTT üzenetet újraküldi.

Mindenki boldog: wifi, NTP és MQTT van, 50% körül pöntyög és a kis dobozban ez a hőfok se vészes
Végül a téli/nyári mód váltás. Sok jelentősége nincs a működés szempontjából, egyszerűen a heartbeat lassul, ha hideg a pufferben a víz és ilyenkor ritkábban küld MQTT üzenet.
// --- Téli-Nyári mód --- if [owt#t1] >= 26 and [var#5] != 1 // Meleg víz → gyors figyelés (10 mp) Let,5,1// var 5-el nézi, hogy ha már a nyári mód aktív, akkor a timer reset-et átugorja loopTimerSet,10,10 elseif [owt#t1] < 26 and [var#5] != 2 // Hideg víz → lassú figyelés (300 mp) Let,5,2 loopTimerSet,10,300 endif
Az előremenő vízhőmérséklet alapján 10 vagy 300 másodperces heartbeat ciklusidőt állít be.
Ha a 300 sec looptimerre áll, akkor a "mindenképp MQTT üzenet küldés" 12×300 másodpercenként következik be. Ez a Home Assistant history-nak és a hosszú távú adatbázisnak is kedvezőbb (az MQTT "kímélésének" ez a fő célja, nem szeretném az adatbázist felesleges adatokkal tömni).
Összegzés:
Az alapok már megvoltak, a frissítést és az új funkciókat először a régi rules bővítésével próbáltam hozzáadni... de nem volt igazán követhető, hogy mikor fog történni, néhány időzítőnél átfedés volt és a kommentelést is hanyagoltam sok helyen. 
Így végül átírásra került szinte minden, egy átlátható, követhető formára. A feltöltött verzióban természetesen kevesebb a komment, de most nem törekedtem a minél rövidebb rules-re, az újabb ESP erősebb is, elfér...
Kipróbáltam az AI asszisztenciát is, nagyon sokat segített, de a tapasztalataim vegyesek...
Sajnos a népszerű ChatGPT hamar elvérzett, Qwen3 sokkal jobb, nem a github/reddit az elsődleges forrása. Első körben csak ellenőriztettem a (fél)kész részeket, de javaslatokat is kértem. Így lett a timerből looptimer, a constrain, a miről csak akkor olvastam a doksiban, mikor felhívta rá a figyelmem... egy év alatt sok mindent fejlesztettek az ESPEasy-n, nem követtem.
Nagyon jól lehetett "szimulációkat" készíteni: megadtam feltételeket, hőfokokat, stb... és ezek variációira végigfutott a rules-en, kielemezve, hogy mikor mi történik. Néha apróságok kimaradtak, pl. olyanra nem gondoltunk, hogy Home Assistant újraindul (pl. frissítem, vagy ilyesmi) és "beragad" az MQTT üzenet.

Október eleje óta van némi fűtés, hibátlanul teszi a dolgát. Remélem ez így is marad még további szezonokra. 
Ha lesz igazi hideg, akkor valószínűleg majd finomítani kell a szünet-keringtetés időkön és még biztosan kitalálok valamit...
Köszönöm, hogy benéztél. 



