Termostato 2.0

Da raspibo.
Jump to navigation Jump to search

Premessa

Mentre Raspibo nasceva, appena comprato il mio primo Raspberry Pi ho pensato di iniziare a sperimentare con i sensori di temperatura 1 wire.

Mi ero immaginato di creare un piccolo server casalingo su cui far girare server web e altri servizi, nel frattempo ho iniziato a sperimentare per usare il mio nuovo Raspberry come termostato con risultati interessanti.

Nel frattempo ho iniziato a frequentare questo nuovo gruppo ed ho imparato tante cose nuove, la tecnologia ha fatto passi avanti.

Il termostato funzionava cosi' bene che manometterlo per farci girare su altri esperimenti potenzialmente bloccanti non era piu' il caso, ho acquistato e messo in servizio altri Raspberry ed i lavori non si sono mai completati.

Percio' ho pubblicato su questo wiki il progetto Termostato, che ha riscosso un discreto successo, anche ora ogni tanto vengo contattato per vari motivi, qualcuno ha bisogno di chiarimenti, qualcuno mi chiede info e via dicendo.

Ora ho deciso di rimettere mano ed iniziare ex novo tenendo conto anche delle esigenze di chi mi ha contattato in questi anni, renderne piu' flessibile il funzionamento e in generale cercare di miglioralo ed ammodernarlo.

Obiettivi

  • Implementare un sistema flessibile e "facilmente" modificabile(ampliabile).
  • Rendere la presentazione semplice, e allo stesso tempo graficamente gradevole.
  • Aumentare l'affidabilita' del sistema con il monitoraggio dei procesi
  • Semplificare il controllo del sistema con un display lcd per la visualizzazione dei dati rilevati
  • Permettere il controllo da remoto in modo semplice e sicuro

Non tutti gli obiettivi sono facili da realizzare, o anche solo da testare, l'importante e' porre le basi per renderne la realizzazione non troppo complessa cercando di predisporre gia' i software(in parte anche l'hardware) nel modo migliore.

Vecchie soluzioni

Una soluzione un po' particolare adottata nella prima versione del progetto e' l'adozione di redis come "database", in realta' non si tratta di un db, ma di un data structure store, used as database, cache and message broker. I motivi della scelta erano la volonta' di provare ad untilizzare un db nosql ed esplorare le possibilita' di questo progetto.

Negli anni si e' dimostrato affidabile ed ho pensato di continuare su questa strada, per aggingere nuove funzionalita' ho dovuto studiare un po' ed ho scoperto nuove ed interessanti fetaures che avevo tralasciato.

Nuovi esperimenti

Termostato utilizza principalmente script in bash per la memorizzazione dei dati e la gestione del rele della caldaia, ma pensare di espandere il codice con questo linguaggio e' difficile.

Ho pensato di provare Python che non ho mai usato per piu' di qualche riga, ma mi risulta ben fornito di moduli per gestire una infinita' di situazioni, al momento tutto il codice di controllo e' scritto con questo linguaggio.

Per la parte web ho deciso di utilizzare un cms gia' pronto, si chiama Grav non utilizza db, ma e' tutto basato su file, non è fatto per utilizzare direttamente php e le pagine di interazione con l'utente mi hanno fatto penare un po' per trovare una soluzione, ma alla fine ce l'ho fatta e sono soddisfatto del risultato.

Ho conosciuto Monit usato da Paolo nel progetto Rmap per la verifica di funzionalità dei processi ed il loro ripristino in caso di down, ho voluto utilizzarlo anche io perchè è uno strumento interessante.

Nelle nuove release di Debian systemd ha preso il posto di init, non mi ci sono buttato a capofitto, ma ho iniziato a cercare di capire come funziona.

Per il controllo da remoto ho voluto provare a realizzare un bot con telegram, così da non dover aprire porte sul modem.

Redis

Vediamo ora in dettaglio Redis. Questo db è il centro di comunicazione e memorizzazione dei dati, passano su redis i dati di temperatura, le schedulazioni ed i dati dei sensori di input ed output (es: rele).

Redis permette di gestire più database (predefiniti 16), per selezionare un db basta specificarlo tra i parametri di connessione, ho anche previsto l'inserimento come parametro del nome del server.

Ho previsto già negli script di poter passare come parametro il db di redis (indicato da un numero), questo per permettere la gestione di più sessioni/istanze di regolazione della temperatura, un caso abbastanza comune potrebbe essere rappresentato da un impianto con una sola caldia, ma elettrovalvole distribuite su varie stanze con possibilità di aprire o chiudere il flusso di acqua calda.

Redis permette anche di sottoscrivere un canale ovvero mettere un processo in ascolto in attesa di notizie ovvero la variazione di valore di una variabile, l'ho utilizzato per pilotare il rele evitando di interrogare periodicamente il db.

Struttura

Ho creato una lista per ogni sensore, in linea di massima ogni stanza ha un sensore ed ogni sensore ha un id univoco (se utilizziamo sensori 1wire), perciò tramite parametro passato ad uno script python inserisco una lettura indicando l'id del sensore da leggere e una etichetta alfanumerica che nella maggioranza dei casi rappresenta una stanza.

Raccolta dati di temperatura

Lo script di inserimento dati è abbastanza semplice:

#!/usr/bin/python
import os
import glob
import time
import redis
import sys

if len(sys.argv) > 2:
        db_host=sys.argv[1]
        db_id=sys.argv[2]

else:
        print "Attenzione: lo script va lanciato con due argomenti!  "
        print "Lancia lo script: " + sys.argv[0] + "<db_host (es: 127.0.0.1)> <id database (es:0)>"
        db_host='termostato_m'
        db_id=0
        print "Utilizzo i parametri di default: " + db_host + " " + str(db_id)
 
os.system('modprobe w1-gpio')
os.system('modprobe w1-therm')
 
base_dir = '/sys/bus/w1/devices/'
device_folder = glob.glob(base_dir + sys.argv[4])[0]
device_file = device_folder + '/w1_slave'
 
def read_temp_raw():
    f = open(device_file, 'r')
    lines = f.readlines()
    f.close()
    return lines
 
def read_temp():
    lines = read_temp_raw()
    while lines[0].strip()[-3:] != 'YES':
        time.sleep(0.2)
        lines = read_temp_raw()
    equals_pos = lines[1].find('t=')
    if equals_pos != -1:
        temp_string = lines[1][equals_pos+2:]
        temp_c = float(temp_string) / 1000.0
	if temp_c < 50:
        	return temp_c
	
print(device_folder + " " + str(read_temp()))	
r = redis.StrictRedis(host=db_host, port=6379, db=db_id,password='Termostato_2.0')
r.rpush(sys.argv[3],float(read_temp()))

Lo script viene lanciato schedulato da crontab con una periodicità di 5 minuti del mio caso.

/root/termostato/salva_temp.py <indirizzo_server_redis> <id_db-redis> <tag/stanza> <idsensore>

esempio:

/root/termostato/salva_temp.py termostato_m 0 cucina 28-000004056005

Per ogni sensore va lanciato un comando in cui presumibilmente cambieranno il tag che indica la stanza e l'id del sensore.

Per tenere traccia del momento in cui viene lanciata la lettura:

#!/usr/bin/python
import os
import glob
import time
import redis
import sys

if len(sys.argv) > 2:
        db_host=sys.argv[1]
        db_id=sys.argv[2]
	
else:
        print "Attenzione: lo script va lanciato con due argomenti!  "
        print "Lancia lo script: " + sys.argv[0] + "<db_host (es: 127.0.0.1)> <id database (es:0)>" 
	db_host='termostato_m'
	db_id=0
	print "Utilizzo i parametri di default: " + db_host + " " + str(db_id)

r = redis.StrictRedis(host=db_host, port=6379, db=db_id,password='Termostato_2.0')
r.rpush("timestamp",time.strftime("%s"))

Si lancia semplicemente cosi:

/root/termostato/salva_tempo.py termostato_m 0

Su crontab la schedulazione si presenta così:

*/5 * * * *  /root/termostato/salva_tempo.py termostato_m 0; /root/termostato/salva_temp.py termostato_m 0 cucina 28-000004056005; /root/termostato/salva_temp.py termostato_m 0 camera 28-000004052dbd; /root/termostato/salva_temp.py termostato_m 0 studio 28-0000040506c2; /root/termostato/termostato.py termostato_m 0 > /dev/null

A questo punto su redis verranno popolate diverse liste, una per ogni sensore più una con il timestamp delle letture che servirà essenzialmente per disegnare i grafici.

L'inserimento dati non è limitato solo a sensori dati collegati al Raspberry tramite gpio, ma è possibile ricevere informazioni da varie fonti, su ESP8266/templogger#ESP8266_Redis c'è un esempio di inserimento dati tramite modulo wifi con Esp8266.

Sempre a bordo di Raspberry è anche possibile creare piccoli plugin che vadano a scaricare dati da altre fonti e li inseriscano su redis.

Schedulazioni e soglie di temperatura

E' necessario definire una o piu' soglie di temperatura da mantenere nell'ambiente percio' su Redis ho creato alcune variabili nella forma X_min ed X_max (dove X indica una label magari mnemonica).

Esempio G_min e G_max indicano una temperatura da applicare durante il Giorno e min e max indicano rispettivamente la temperatura minima sotto la quale accendere il rele' e max corrispondente alla temperatura sopra la quale spegnere l'impianto.

L'uso di due variabili distinte permette di usare range variabili di comando, posso infatti impostare una differenza di 0.5 gradi tra G_min e G_max (es: G_min=20.0 .. G_max=20.5 oppure N_min=18.0 .. N_max=19.0) piuttosto che impostare un singola temperatura e calcolarne uno scarto fisso per ricavare le due soglie.

Al momento non vedo motivi pratici per usare fasce di temperatura differenti, ma mi sembra la scelta migliore a presicndere.

Serve anche una lista che associ le fasce di temperatura alle diverse ore del giorno, prendono il loro nome dai giorni della settimana tagliati a 3 lettere. ad esempio la schedulazione del lunedi si chiama lun, nel vecchio progetto avevo creato 24 elementi, ora ho raddoppiato i valori permettendo di impostare le temperature con una granularita' di 30 minuti.

In ultimo una lista che per ogni schedulazione associa anche a quale stanza applicare la temperatura prescelta, queste 7 liste si chiamano C_xxx dove xxx indica le prime tre lettere del giorno della settimana es C_lun.

Tutte queste liste vengono gestite tramite interfaccia web.

Esplorare i dati raccolti

Per navigare nei dati su redis ho utilizzato redis-browser che lancio a richiesta con il comando:

redis-browser --url redis://:Termostato_2.0@127.0.0.1:6379/0 -B termostato.local
Redis-browser

La lista delle stanze contiene l'insieme dei sensori fra cui scegliere per regolare la temperatura e disegnare grafici.

Redis-browser

Script Termostato

Della regolazione della temperatura si occupa uno script python che estrae tutti i dati di temperature lette dai sensori e di impostazione sulle schedulazioni e decide se il rele deve essere attivato o meno. Al momento l'algoritmo in se è banale e penso di sperimentare con qualcosa di più evoluto, ma già questo funziona bene e si basa sullo stesso principio dei termostati comunemente utilizzati.

#!/usr/bin/python
import redis
import time
import calendar
import datetime
import sys

if len(sys.argv) > 2:
        db_host=sys.argv[1]
        db_id=sys.argv[2]
        
else:
        print "Attenzione: lo script va lanciato con due argomenti!  "
        print "Lancia lo script: " + sys.argv[0] + "<db_host (es: 127.0.0.1)> <id database (es:0)>" 
        db_host='termostato_m'
        db_id=0
        print "Utilizzo i parametri di default: " + db_host + " " + str(db_id)


#Dichiarazione lista con nome giorni della settimana
giorni = ["dom","lun","mar","mer","gio","ven","sab"]
ora=time.strftime("%H")
#div_tempo inidica una unita' di tempo in cui regolare la temperatura e si calcola dividendo un giorno per il numero di step_programmazioni che impostiamo
#86400 sono i secondi in un giorno, se impostiamo step_programmazione a 24 otteniamo 3600 cioe' il numero di secondi che compongono un'ora
n_step_programmazione=48
div_tempo=86400/n_step_programmazione
#Calcolo in quale unita' di tempo sta girando lo script
now = datetime.datetime.now()
midnight = now.replace(hour=0, minute=0, second=0, microsecond=0)
seconds_since_midnight = (now - midnight).seconds
#tempo_attuale e' un numero che corrisponde all'ora se ho deciso una programmazione su base oraria (step_programmazione=24) o mezz'ora (step_programmazione=48) ecc....
tempo_attuale=seconds_since_midnight//div_tempo
print ("tempo attuale: "+str(tempo_attuale))
#n_giorno contiene una stringa di tre lettere con il nome del giorno della settimana ricavata dalla lista giorni
n_giorno=giorni[int(datetime.date.today().strftime("%w"))]
#connessione a redis
r = redis.StrictRedis(host='localhost', port=6379, db=db_id, password='Termostato_2.0')
#carico da redis la lista delle stanze
i=0
camere=[]
while i < r.llen("camere"):
        camere.append(r.lrange("camere",i,i)) #Su redis per ottenere lrange ricava il range indicando start e stop degli elementi da leggere, quindi i (indice) va ripetuto due volte
        i = i + 1
print("Camere: " + str(camere))
temperature=[]
i=0
while i < len(camere):
	temperature.append(r.lrange(camere[i][0],-1,-1)) #Per ottenere la stringa corrispondente alla variabile ricavata da redis oltre all'elemento va aggiunto [0] 
	i = i + 1
print("Temperature: " + str(temperature))
#n_setpoint e' la temperatura che il termostato deve mantenere, viene espressa con un carattere G (Giorno),N (Notte), S (Spento)
n_setpoint=r.lindex(n_giorno,tempo_attuale)
print n_giorno + " " + ora + " " + n_setpoint
#stanza e' la camera in cui la temperatura e' da misurare per mantere la temperatura ad esempio giorno cucina, notte camere da letto
stanza=r.lindex("c_"+n_giorno,tempo_attuale)
print stanza
#input contiene il valore dell'ultima lettura di temperatura dal sensore posto in quella stanza
input=r.lrange(stanza,-1,-1)[0]
print "Temperatura attuale nella stanza: " + str(input)
#setpoint e' la temperatura in gradi da raggiungere
setpoint=r.get(n_setpoint+"_max")
print "Temperatura da raggiungere:" + str(setpoint)
r.rpush("setpoint",setpoint)

t_min=r.get(n_setpoint+"_min")
print "Temperatura minima: " + str(t_min)
#Routine termostato
rele=r.lrange("rele",-1,-1)[0]

if float(input) > float(setpoint) :
	rele=0
else:
	if float(input) < float(t_min):
		rele=1

#s_blocc e' un sensore in grado di inibire l'accensione della caldaia o spegnerla se e' accesa, puo' essere ad esempio piazzato su una finestra, se la finestra e' aperta e' inutile accendere la caldaia
s_blocc=r.lrange("s_blocc",-1,-1)[0]
if s_blocc==1:
	rele=0

s_forceoff=r.get("s_forceoff")
if s_forceoff==1:
	rele=0
	print "Spegnimento forzato impostato"

s_forceon=r.get("s_forceon")
if s_forceon==1:
	rele=1
	print "Accensione forzata impostata"

r.rpush("rele",rele)
#pubblica sul canale rele_ch lo stato del rele per i client che hanno sottoscritto il canale con pusub
r.publish("rele_ch", rele)
#p_blocc e' un'uscita utilizzabile per bloccare una perifarica che non deve stare accesa mentre la caldaia e' in funzione 
#r.rpush("p_blocc",not rele)

print ("rele: " + str(rele))

Pilotaggio del rele

Rispetto alla prima versione di questo progetto in cui lo script termostato dopo aver deciso come pilotare il relè applicava direttamente il comando al pin del gpio.

Ho preferito suddividere in due passaggi diversi la decisione e l'azione, questo permette di rendere modulare il sistema.

Posso decidere di utilizzare un raspberry per la parte di calcolo ed un altro per agire sul rele.

Per ridurre le interrogazioni a redis con un polling ogni x secondi ho utilizzato la funzione di pubblicazione e sottoscrizione dei canali come si fa su mqtt.

Lo stato del rele viene comunque salvato su una lista apposita per mantenere uno storico e disegnare grafici.

#!/usr/bin/python
import RPi.GPIO as GPIO
import redis
import time
import os
import sys

channel='rele_ch'

def connect():
	r = redis.Redis(host='localhost', port=6379, db=0, password='Termostato_2.0')
	return r


def data_subscribe():
	GPIO.setmode(GPIO.BCM)
	GPIO.setwarnings(False)
	GPIO.setup(25, GPIO.OUT)
	global channel
	r = connect()
	ps = r.pubsub()
	ps.subscribe(channel)
	for message in ps.listen():
		a=message
		print int(a['data'])
		GPIO.output(25, int(a['data']))

def main():
	pid = str(os.getpid())
	pidfile = "/var/run/controllo_rele_0.pid"
	file(pidfile, 'w').write(pid)
	print pid

	data_subscribe()
	GPIO.cleanup()
	os.unlink(pidfile)

main()

Al momento non ho ancora sperimentato, ma vorrei utilizzare qualcosa di simile a ESP8266/templogger#ESP8266_Redis per pilotare il rele eventuelmente anche come sistema di backup.

Schema elettrico

In questa versione del progetto ho previsto una forma di attivazione manuale del relè in caso di problemi software/hardware o esigenze particolari. Lo spegnimento manuale è già previsto sulla caldaia. Ho utilizzato un modulo già pronto che aveva due relè, uno utilizzato per pilotare dal gpio.

L'altro input libero l'ho sfruttato per attivare il relè con la tensione di alimentazione prelevata direttamente dall'alimentatore esterno a 12 volts che alimenta entrambi i rele.

Questo ha anche semplificato l'installazione avendo montato la scatola a qualche metro dal raspberry inoltre garantisce che in caso di scollegamento completo del raspberry l'attivazione manuale sia sempre garantita.

Lo schema è volutamente semplificato solo per rendere l'idea non ho riportato optoisolatori e led.

Schema elettrico di massima

Interfaccia web

Monitoraggio processi: Monit

Per il monitoraggio dei processi ho usato monit sia per i processi creati da me che per i demoni di controllo di server web, cron, redis.

Monit

Alcuni esempi:

pi@termostato:~ $ cat /etc/monit/conf.d/controllo_rele
 check process controllo_rele_0 with pidfile /var/run/controllo_rele_0.pid
   group root
   group root
   start program = "/etc/init.d/controllo_rele_0 start"
   stop program = "/etc/init.d/controllo_rele_0 stop"
pi@termostato:~ $ cat /etc/monit/conf.d/display_lcd
 check process display_lcd with pidfile /var/run/lcd.pid
   group root
   group root
   start program = "/etc/init.d/display_lcd start"
   stop program = "/etc/init.d/display_lcd stop"
pi@termostato:~ $ cat /etc/monit/conf.d/telegram-bot_0
 check process telegram-bot_0 with pidfile /var/run/telegram/telegram-bot_0.pid
   group root 
   group root 
   start program = "/etc/init.d/telegram-bot_0 start"
   stop program = "/etc/init.d/telegram-bot_0 stop"

Debug e visualizzazione

Comando a distanza: Telegram bot

Questo è il codice ancora incompleto di un bot di telegram per il controllo a distanza. Basta inserire il token di accesso per metterlo in funzione.

#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
# Simple Bot to reply to Telegram messages
# This program is dedicated to the public domain under the CC0 license.

from telegram import Updater
import logging

# Enable logging
logging.basicConfig(
        format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
        level=logging.INFO)

logger = logging.getLogger(__name__)

# Setup config redis
import redis
import time
import calendar
import datetime
import sys

if len(sys.argv) > 2:
        db_host=sys.argv[1]
        db_id=sys.argv[2]
        
else:
        print "Attenzione: lo script va lanciato con due argomenti!  "
        print "Lancia lo script: " + sys.argv[0] + "<db_host (es: 127.0.0.1)> <id database (es:0)>" 
        db_host='termostato_m'
        db_id=0
        print "Utilizzo i parametri di default: " + db_host + " " + str(db_id)
#

r = redis.StrictRedis(host='localhost', port=6379, db=db_id, password='Termostato_2.0')

import os
import subprocess

pid = str(os.getpid())
pidfile = "/var/run/telegram/telegram-bot_" + db_id + ".pid"
#if os.path.isfile(pidfile):
#    print "Processo gia attivo vedi file %s" % pidfile
#    sys.exit()
#else:
file(pidfile, 'w').write(pid)
print pid

import urllib2

try:
   u = urllib2.urlopen("https://telegram.org/")
except Exception as e:
   #inform them that a general error has occurred 
   print ("Errore generico")
   sys.exit(1024)



# Define a few command handlers. These usually take the two arguments bot and
# update. Error handlers also receive the raised TelegramError object in error.
def start(bot, update):
    bot.sendMessage(update.message.chat_id, text='Hi!')


def help(bot, update):
    bot.sendMessage(update.message.chat_id, text='/start')
    bot.sendMessage(update.message.chat_id, text='/help')
    bot.sendMessage(update.message.chat_id, text='/get_rele Richiedi lo stato del rele')
    bot.sendMessage(update.message.chat_id, text='/accendi_30_min Accende la caldaia per 30 minuti indipendentemente dalla temperatura')
    bot.sendMessage(update.message.chat_id, text='/spegni_30_min Spegne la caldaia per 30 minuti indipendentemente dalla temperatura')
    bot.sendMessage(update.message.chat_id, text='/automatico Rimuove accensione e spegnimento forzati e riabilita il funzionamento normale')
    bot.sendMessage(update.message.chat_id, text='/dettaglio Visualizza la situazione attuale')

def get_rele(bot, update):
    rele=r.lrange("rele",-1,-1)[0]
    if rele == "0":
	s_rele="Spento"
    else:
	s_rele="Acceso"
    bot.sendMessage(update.message.chat_id, text='Stato Rele=' + s_rele)

def forceoff(bot, update):
    rele=r.delete("s_forceon")
    rele=r.set("s_forceoff",1)
    rele=r.expire("s_forceoff",1800)
    rele=r.publish("rele_ch",0)
    rele=r.rpush("rele",0)
    bot.sendMessage(update.message.chat_id, text='Forzato spegnimento Rele per 30 minuti')

def forceon(bot, update):
    rele=r.delete("s_forceoff")
    rele=r.set("s_forceon",1)
    rele=r.expire("s_forceon",1800)
    rele=r.publish("rele_ch",1)
    rele=r.rpush("rele",1)
    bot.sendMessage(update.message.chat_id, text='Forzata accensione Rele per 30 minuti')

def automatico(bot, update):
    rele=r.delete("s_forceon")
    rele=r.delete("s_forceoff")
    cmd='sudo /root/termostato/termostato.py ' + db_host + ' ' + db_id
    proc = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE)
    out = proc.stdout.read()
    bot.sendMessage(update.message.chat_id, text=out)

def dettaglio(bot, update):
    cmd='sudo /root/termostato/termostato.py ' + db_host + ' ' + db_id
    proc = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE)
    out = proc.stdout.read()
    bot.sendMessage(update.message.chat_id, text=out)



def echo(bot, update):
    bot.sendMessage(update.message.chat_id, text=update.message.text)


def error(bot, update, error):
    logger.warn('Update "%s" caused error "%s"' % (update, error))


def main():
    # Create the EventHandler and pass it your bot's token.
    updater = Updater("inserire_qui_il_token_assegnato al bot")

    # Get the dispatcher to register handlers
    dp = updater.dispatcher

    # on different commands - answer in Telegram
    dp.addTelegramCommandHandler("start", start)
    dp.addTelegramCommandHandler("help", help)
    dp.addTelegramCommandHandler("get_rele", get_rele)
    dp.addTelegramCommandHandler("accendi_30_min", forceon)
    dp.addTelegramCommandHandler("spegni_30_min", forceoff)
    dp.addTelegramCommandHandler("automatico", automatico)
    dp.addTelegramCommandHandler("dettaglio", dettaglio)

    # on noncommand i.e message - echo the message on Telegram
    dp.addTelegramMessageHandler(echo)

    # log all errors
    dp.addErrorHandler(error)

    # Start the Bot
    updater.start_polling()

    # Run the bot until the you presses Ctrl-C or the process receives SIGINT,
    # SIGTERM or SIGABRT. This should be used most of the time, since
    # start_polling() is non-blocking and will stop the bot gracefully.
    updater.idle()

if __name__ == '__main__':
    main()

Riferimenti

  • cms grav link alla procedura di installazione - user termoadmin - password Termostato_2.0
  • Monit user termoadmin - password Termostato_2.0