Slider in Tasmota folosind BerryScript

Read this post in English

Share on:

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:

termostat cu bratara

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.

Sonoff TH Elite

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ă pe Create and Edit new file.

Introdu numele fișierului sus autoexec.be, șterge conținutul fișierului și apasă pe Save. 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 la Tools > Berry Scripting console.

Introdu load('autoexec.be') și apasă pe Run code (or press ‘Enter’ twice). Ar trebui să fie afișat output-ul true.

Executie cod

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.

Setarea temperaturii

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:

Tasmota Sonoff TH Elite

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.