-
Inroducere
Am cumpărat de curând un șemineu care poate distribui căldură și la radiatoare (pe scurt: termoșemineu). Pentru a face asta, folosește o pompă de recirculare.
Pompa ar trebui să pornească când apa atinge o anumită temperatură și să se oprească atunci când scade sub o anumită valoare. Deloc complicat până aici, sistemul folosind un termostat simplu care a funcționat acceptabil:
Erau totuși câteva neajunsuri, cum ar fi faptul că nu făcea contact destul de bine cu țeava de căldură, așa că trebuia să pornească puțin mai repede decat ar fi trebuit, ca să compenseze. Pentru că era configurat dintr-o singură setare comună, asta însemna că se și oprea un pic cam târziu, deci nu puteam configura setările cu ușurință.
O altă dorință de-a mea era ca dispozitivul să poată funcționa independent. Dacă se deconectează de la rețea dintr-un motiv oarecare, sau Home Assistant nu mai funcționează, ar trebui să pornească singur ca să nu ajungă să fiarbă apa din instalație. Să zicem că nu vreau să explodeze doar de dragul de a arată cool. Și încă un lucru: ar fi drăguț să se oprească singur, ca să nu recircule apă degeaba.
Sonoff TH Elite cu senzor de temperatură pare să acopere perfect toate cerințele, chiar are în plus și un ecran simpatic pe care se poate vedea temperatura apei. Trebuie să clarific că, din păcate pentru mine, nu sunt sponsorizat pentru acest proiect, iar dispozitivul a fost cumpărat din banii mei.
Totul era perfect, cu excepția unui singur detaliu: nu am găsit un mod de a adauga cu ușurință un slider pentru a controla temperatura. Aș fi putut hardcoda valorile, pentru că în principiu nu ar fi trebui să se schimbe în timp, dar atunci nu aș mai avea cu ce sa mă laud.
Și așa a început aventura...
Să trecem la treaba
Dispozitivul
Nu o să vorbesc despre pregătirea dispozitivului, sunt destule tutoriale despre flashing Tasmota. Codul ar trebui să funcționeze cu orice dispozitiv care rulează Tasmota, de fapt întreg codul din acest tutorial a fost scris și testat pe un controller generic Esp32 găsit într-un sertar.
Berry script
Dacă ai ajuns până aici, probabil că nu ți-ai ars nici controllerul Esp, nici casa. Felicitări, ai trecut cu succes de partea cea mai dificilă!
Toată magia vine de la Berry Script, un limbaj de scripting care permite extinderea funcționalităților Tasmota.
Din păcate, documentația nu este foarte clară când vine vorba de componente noi și există un singur exemplu. Există și un exemplu complet, dar este foarte complex și greu de urmărit.
Dar să începem. În primul rând, trebuie să facem un fișier nou care va conține codul. Pentru a face asta, conectează-te la UI-ul dispozitivului folosind IP-ul lui și mergi la
Tools
>Manage File system
și apasă peCreate and Edit new file
.Introdu numele fișierului sus
autoexec.be
, șterge conținutul fișierului și apasă peSave
. Din acest punct vom edita doar acest fișier. Când mă voi referi la editat, mă voi referi la acest fișier.Că să ne asigurăm că fișierul se compilează, din meniul principal (
Main Menu
), mergi laTools
>Berry Scripting console
.Introdu
load('autoexec.be')
și apasă peRun code (or press ‘Enter’ twice)
. Ar trebui să fie afișat output-ultrue
.Setarea componentei
Editează
autoexec.be
și introdu codul de mai jos care reprezintă o componentă de baza:1import webserver 2 3class MySlider 4 def web_add_main_button() 5 webserver.content_send("<div style='padding:0'><h3>Set pump temperature</h3></div>") 6 end 7end 8 9 10d1 = MySlider() 11tasmota.add_driver(d1)
Reîncarcă UI-ul folosind comandă
load('autoexec.be')
, așa cum a fost descris mai sus.În acest moment ar trebui să apară pe ecran textul
Set pump temperature
.Se pare că primul secret a ieșit la iveală, trebuie doar să afișăm niște HTML pentru a genera o nouă componentă.
Ne mai lipsește un lucru, trebuie să salvăm valoarea care se setează folosind slider-ul. Din fericire, lucrurile sunt destul de simple dacă folosim librăria
persist
. Putem seta și o valoare implicită atunci când componentă se încarcă prima dată:1 def init() 2 if (!persist.m_start_temp) 3 persist.m_start_temp = 55 4 end 5 6 if (!persist.m_stop_temp) 7 persist.m_stop_temp = 50 8 end 9 end
Acum avem valori implicite de start și stop pentru temperatura.
Pentru că am nevoie de două valori, una de pornire și una de oprire, voi face o funcție care poate afișa fie una din valori, fie pe cealaltă, iar valoarea se va trimite folosind
webserver.content_send
, deci acum metodăweb_add_main_button()
va deveni:1 def web_add_main_button() 2 webserver.content_send("<div style='padding:0'><h3>Set pump temperature</h3></div>") 3 webserver.content_send( 4 self._render_button(persist.m_start_temp, "Start", "start") 5 ) 6 webserver.content_send( 7 self._render_button(persist.m_stop_temp, "Stop", "stop") 8 ) 9 end
Argumentele sunt: valoarea curentă, o etichetă și un id. Prin id se va identifica elementul care s-a schimbat.
Metodă pentru afișare este:
1 def _render_button(persist_item, label, id) 2 return "<div style='padding:0'>"+ 3 "<table style='width: 100%'>"+ 4 "<tr>"+ 5 "<td><label>"..label.." </label></td>"+ 6 "<td align=\"right\"><span id='lab_"..id.."'>"..persist_item.."</span>°C</td>"+ 7 "</tr>"+ 8 "</table>"+ 9 "<input type=\"range\" min=\"20\" max=\"70\" step=\"1\" "+ 10 "onchange='la(\"&m_"..id.."_temp=\"+this.value)' "+ 11 "oninput=\"document.getElementById('lab_"..id.."').innerHTML=this.value\" "+ 12 "value='"..persist_item.."'/>"+ 13 "</div>" 14 end
oninput
este un artificiu pentru a schimba valoarea afișată când sliderul se mișcă, așa compensăm pentru faptul că elementul slider din html nu are un mod de a afișa valoarea selectată, așa că nu am ști ce a fost selectat până nu oprim selecția, adică ar fi o experiență neplacută de utilizare.De fapt
onchange
se folosește pentru a schimba valoarea, iar această folosește un pic de magie Tasmota.Acum că afișăm totul, avem nevoie de un mod de a persista valoarea, acest lucru se face folosind metodă
web_sensor
:1 def web_sensor() 2 3 if webserver.has_arg("m_start_temp") 4 var m_start_temp = int(webserver.arg("m_start_temp")) 5 persist.m_start_temp = m_start_temp 6 persist.save() 7 end 8 9 if webserver.has_arg("m_stop_temp") 10 var m_stop_temp = int(webserver.arg("m_stop_temp")) 11 persist.m_stop_temp = m_stop_temp 12 persist.save() 13 end 14 15 end
Deja putem pune totul cap la cap, avem tot ce era necesar. Totuși mai este ceva ce-mi doresc: să pot vedea valoarea selectată în Home Assistant (dacă este folosit). În caz că am uitat ce este setat, ar fi interesant să afișăm valoarea undeva prin Home Assistant. Pentru a exporta valorile trebuie implementat
json_append
:1 def json_append() 2 var start = int(persist.m_start_temp) 3 var stop = int(persist.m_stop_temp) 4 var msg = strîng.format(",\"Pump\":{\"start\":%i,\"stop\":%i}", start, stop) 5 tasmota.response_append(msg) 6 end
Acum chiar avem un exemplu complet! Să-l vedem:
1import webserver 2import persist 3import strîng 4 5class MySlider 6 7 def init() 8 if (!persist.m_start_temp) 9 persist.m_start_temp = 55 10 end 11 12 if (!persist.m_stop_temp) 13 persist.m_stop_temp = 50 14 end 15 16 end 17 18 def web_add_main_button() 19 webserver.content_send("<div style='padding:0'><h3>Set pump temperature</h3></div>") 20 webserver.content_send( 21 self._render_button(persist.m_start_temp, "Start", "start") 22 ) 23 webserver.content_send( 24 self._render_button(persist.m_stop_temp, "Stop", "stop") 25 ) 26 end 27 28 def _render_button(persist_item, label, id) 29 return "<div style='padding:0'>"+ 30 "<table style='width: 100%'>"+ 31 "<tr>"+ 32 "<td><label>"..label.." </label></td>"+ 33 "<td align=\"right\"><span id='lab_"..id.."'>"..persist_item.."</span>°C</td>"+ 34 "</tr>"+ 35 "</table>"+ 36 "<input type=\"range\" min=\"20\" max=\"70\" step=\"1\" "+ 37 "onchange='la(\"&m_"..id.."_temp=\"+this.value)' "+ 38 "oninput=\"document.getElementById('lab_"..id.."').innerHTML=this.value\" "+ 39 "value='"..persist_item.."'/>"+ 40 "</div>" 41 end 42 43 44 def web_sensor() 45 46 if webserver.has_arg("m_start_temp") 47 var m_start_temp = int(webserver.arg("m_start_temp")) 48 persist.m_start_temp = m_start_temp 49 persist.save() 50 end 51 52 if webserver.has_arg("m_stop_temp") 53 var m_stop_temp = int(webserver.arg("m_stop_temp")) 54 persist.m_stop_temp = m_stop_temp 55 persist.save() 56 end 57 58 end 59 60 def json_append() 61 var start = int(persist.m_start_temp) 62 var stop = int(persist.m_stop_temp) 63 var msg = strîng.format(",\"Pump\":{\"start\":%i,\"stop\":%i}", start, stop) 64 tasmota.response_append(msg) 65 end 66end 67 68slider = MySlider() 69tasmota.add_driver(slider)
Este destul de mult cod, dar sper că nu este foarte greu de înțeles.
Setarea automatizării
Acum că avem valorile, putem seta automatizarea efectivă. Regulile sunt foarte simple:
- când se atinge temperatura de start => pornește pompa;
- când temperatura coboară sub valoarea de oprire => oprește pompa.
1def heater_control(value) 2 3 if value >= persist.m_start_temp 4 tasmota.set_power(0, true) 5 end 6 7 if value < persist.m_stop_temp 8 tasmota.set_power(0, false) 9 end 10end 11# această este specifică senzorului Sonoff TH Elite 12tasmota.add_rule("DS18B20#Temperature", heater_control)
Dacă s-a folosit alt dispozitiv, este posibil să aibă alt nume față de
"DS18B20#Temperature"
, și probabil va trebui schimbat cu cel potrivit.Noua interfață Sonoff TH Elite ar trebui să arate cam așa:
Concluzie
Folosind cod destul de simplu, poți transforma un dispozitiv inteligent (dar nu foarte interesant) în ceva cu care să te poți lăuda la prieteni. Valorile se pot seta acum cu ușurință într-o manieră vizuală, iar rezultatul se poate vedea în Home Assistant.