Termostato
Le applicazioni dei termostati sono svariate, in questo caso partiamo con la realizzazione di un termostato per il controllo della caldaia di casa che può comunque essere ampliato con sensori o attuatori aggiuntivi ad esempio per il controllo del condizionatore.
Per rendere il termostato più flessibile la gestione è modulare perciò i dati vengono salvati su redis per la sua velocità, e la possibilità di sincronizzazione master/slave.
Per rendere più facile la gestione viene utilizzata una interfaccia web implementata sul server web nginx con php e librerie Flotr2 per la rappresentazione grafica dei dati.
Indice |
Schema di massima
Sensori utilizzati
Per la misura della temperatura si possono uitlizzare i sensori DALLAS vedi voce Raspberry Pi-Lettura Temperatura per la semplicità d'uso e la possibilità di collegamento su un bus digitale in modo da usare pochi pin del GPIO.
Questi sensori utilizzano un pin del gpio, possono essere collegati su bus lineare o a stella la lunghezza massima del collegamento arriva a 200 metri.
Possono essere utilizzati anche altri sensori grazie alla modularità del sistema basta infatti che i dati vengano inseriti in redis.
Installazione del software
Innanzitutto modificare il file /etc/modules inserendo i moduli per la gestioe del bus 1 wire:
echo 'wire' >> /etc/modules echo 'w1_gpio' >> /etc/modules echo 'w1_therm' >> /etc/modules
Riavviare il Raspberry ed installare i sensori.
Al riavvio nella dir /sys/bus/w1/devices/ si trovano i files relativi ai sensori:
root@raspberrypi:~/termostato# ls -l /sys/bus/w1/devices/ totale 0 drwxr-xr-x 2 root root 0 mar 21 21:33 ./ drwxr-xr-x 4 root root 0 mar 21 21:33 ../ lrwxrwxrwx 1 root root 0 mar 21 21:33 28-0000040520d3 -> ../../../devices/w1_bus_master1/28-0000040520d3/ lrwxrwxrwx 1 root root 0 mar 21 21:33 28-000004052c94 -> ../../../devices/w1_bus_master1/28-000004052c94/ lrwxrwxrwx 1 root root 0 mar 21 21:38 w1_bus_master1 -> ../../../devices/w1_bus_master1/
Se anche dopo aver verificato i collegamenti questo non funziona, modificare il file /boot/config.txt aggiungendo la seguente istruzione e riavviare (vedi riferimenti in fondo).
dtoverlay=w1-gpio,gpiopin=4
Si può procedere all'installazione vera e propria del software:
il server redis per la memorizzazione dei dati
sudo apt-get install redis-server bc
il comando elink per la lettura della temperatura esterna da internet
sudo apt-get install elinks
il software per la gestione via web
sudo apt-get install nginx php5-fpm php5-cli php5-curl php5-cgi php-pear php5-gd php5-dev
Lettura sensori e salvataggio su redis
Per la lettura si utilizza uno script in bash (/root/termostato/04_leggi_temperatura.sh):
#!/bin/bash sensori[0]='28-000004052c94' sensori[1]='28-0000040520d3' #controllo che lo script venga lanciato con 1 parametro if [ $# != 1 ] then echo -n "Lancia lo script: $0 [all" for i in "${sensori[@]}" do echo -n "|$i" done echo ']' else if [ $1 == "all" ] # Se lanciato con il parametro all visualizza la lettura di tutti i sensori then for i in "${sensori[@]}" do $0 $i done else sensore=$1 for x in 1 2 3 4 do lettura=`paste -s /sys/bus/w1/devices/${sensore}/w1_slave | grep YES` # esegue la lettura verificando il CRC # echo $? # echo lettura if [ $? == 0 ] then temp=$lettura; break else temp='ERR' ; break fi done temperatura=`echo $temp | paste -s | awk -F "=" '{print $3/1000}'` echo $temperatura fi fi
Per la memorizzazione su Redis si lancia uno script che richiama il precedente per ogni sensore e lo associa alla zona da monitorare inoltre memorizza la data corrente(/root/termostato/05_memorizza_temp.sh):
#!/bin/bash sensore[0]='28-000004052c94' sensore[1]='28-0000040520d3' d_sensore[0]='cucina' d_sensore[1]='camera' x=0 for i in "${sensore[@]}" do temp=`/root/termostato/04_leggi_temperatura.sh $i` if [ "$temp" != "-0.062" ] then if [ "$temp" != "85" ] then /usr/bin/redis-cli rpush ${d_sensore[${y}]} $temp fi fi y=`expr $y + 1` done /usr/bin/redis-cli rpush lettura "`date "+%Y-%m-%d %H:%M:%S"`" /usr/bin/redis-cli rpush timestamp "`date "+%s"`"
Per la lettura della temperatura esterna nel mio caso ho fatto riferimento alla centralina meteo più vicina e leggo i dati via web (/root/termostato/06_display_letture.sh):
#!/bin/bash temp=`/usr/bin/elinks -dump "http://www.wunderground.com/weatherstation/WXDailyHistory.asp?ID=IITALIAB2&format=1"|awk -F "," '{print $2}'| grep '[0-9]\.[0-9]'| tail -1` /usr/bin/redis-cli rpush temp_esterna $temp
Una volta lanciati gli script precedenti si può verficare se vengono memorizzati correttamente su Redis:
#!/bin/bash echo "Visualizzazione elementi lista in redis" redis-cli keys "*" echo "Display valori lista primo sensore: cucina" redis-cli lrange cucina -10 -1 echo "Display valori lista primo sensore: camera" redis-cli lrange camera -10 -1 echo "Display valori lista temperatura esterna" redis-cli lrange temp_esterna -10 -1
Configurazione
Per il setup dei valori su redis si può utilizzare questo script che crea le variabili in cui memorizzare la programmazione settimanale creando due fasce orarie G=giorno e N=notte ognuna con temperatura minima e massima. Vengono create anche le variabili per lo stato del rele` ed altre variabili di appoggio per gli script successivi:
#!/bin/bash for x in `seq 0 6` do redis-cli rpush lun N redis-cli rpush mar N redis-cli rpush mer N redis-cli rpush gio N redis-cli rpush ven N redis-cli rpush sab N redis-cli rpush dom N done for x in `seq 7 23` do redis-cli rpush lun G redis-cli rpush mar G redis-cli rpush mer G redis-cli rpush gio G redis-cli rpush ven G redis-cli rpush sab G redis-cli rpush dom G done redis-cli lrange lun 0 23 redis-cli lrange mar 0 23 redis-cli lrange mer 0 23 redis-cli lrange gio 0 23 redis-cli lrange ven 0 23 redis-cli lrange sab 0 23 redis-cli lrange dom 0 23 redis-cli set t_min_giorno 21 redis-cli set t_max_giorno 21.5 redis-cli set t_min_notte 21 redis-cli set t_max_notte 21.5 redis-cli get t_min_giorno redis-cli get t_max_giorno redis-cli get t_min_notte redis-cli get t_max_notte redis-cli lpush rele 0 redis-cli lrange rele 0 -1 redis-cli lpush timestamp 0 redis-cli lrange timestamp 0 -1 redis-cli rpush min 0 redis-cli rpush max 0 redis-cli lrange min 0 -1 redis-cli lrange max 0 -1
Script di gestione del termostato
Lo script legge i dati da redis e decide in base all'ora di sistema la fascia di temperature da usare per il confronto con l'ultima lettura. La tolleranza sulla temperatura impostata di più o meno 0.25 grado, viene memorizzata su Redis anche una stringa che contiene tutti i dati utilizzati per le decisione presa.
/root/termostato/termostato.sh
#!/bin/bash ora=`date "+%H"` camera=`redis-cli lrange camera -1 -1` cucina=`redis-cli lrange cucina -1 -1` rele=`redis-cli lrange rele -1 -1` t_min_notte=`redis-cli get t_min_notte` t_max_notte=`redis-cli get t_max_notte` t_min_giorno=`redis-cli get t_min_giorno` t_max_giorno=`redis-cli get t_max_giorno` data_ora=`date "+%H:%M:%S"` giorni[1]="lun" giorni[2]="mar" giorni[3]="mer" giorni[4]="gio" giorni[5]="ven" giorni[6]="sab" giorni[7]="dom" gg_sett=`date "+%u"` n_giorno=${giorni[$gg_sett]} #ricavo la temperatura per l'ora corrente temp_att=`redis-cli lindex ${n_giorno} ${ora}` #case "$temp_att" in #N) echo "Programma attuale: notte" #controllo="${data_ora} Temp camera= ${camera} - Invariato - notte - min ${t_min_notte}/max ${t_max_notte} - Temperature: ${camera}/${cucina}" case "$temp_att" in N) echo "Programma attuale: notte" min=${t_min_notte} max=${t_max_notte} if (( `echo "$camera<${t_min_notte}" | bc -l` )) then rele=1 controllo="${data_ora} Temp camera= ${camera} < ${t_min_notte} - notte - min ${t_min_notte}/max ${t_max_notte} - Temperature: ${camera}/${cucina}" fi if (( `echo "$camera>${t_max_notte}" | bc -l` )) then rele=0 controllo="${data_ora} Temp camera= ${camera} > ${t_max_notte} - notte - min ${t_min_notte}/max ${t_max_notte} - Temperature: ${camera}/${cucina}" fi ;; G) echo "Programma attuale: giorno" min=${t_min_giorno} max=${t_max_giorno} if (( `echo "$cucina<${t_min_giorno}" | bc -l` )) then rele=1 controllo="${data_ora} Temp cucina= ${cucina} < ${t_min_giorno} - giorno - min ${t_min_giorno}/max ${t_max_giorno} - Temperature: ${camera}/${cucina}" fi if (( `echo "$cucina>${t_max_giorno}" | bc -l` )) then rele=0 controllo="${data_ora} Temp cucina= ${cucina} > ${t_max_giorno} - giorno - min ${t_min_giorno}/max ${t_max_giorno} - Temperature: ${camera}/${cucina}" fi ;; S) echo "Programma attuale: spento" min=0 max=0 controllo="${data_ora} Temp camera= ${camera},Temp cucina= ${cucina} - termo spento" rele=0 ;; esac /usr/bin/redis-cli rpush rele $rele > /dev/null #echo "d4=$rele" | /usr/bin/telnet localhost 2000 if [ ! -d /sys/class/gpio/gpio25 ] then echo "25" > /sys/class/gpio/export echo "out" > /sys/class/gpio/gpio25/direction fi if [ $rele -eq 1 ] then echo "0" > /sys/class/gpio/gpio25/value else echo "1" > /sys/class/gpio/gpio25/value fi /usr/bin/redis-cli rpush controllo "$controllo" > /dev/null /usr/bin/redis-cli rpush min "$min" > /dev/null /usr/bin/redis-cli rpush max "$max" > /dev/null #echo "camera=${camera} cucina=${cucina}" echo "Rele: $rele" echo "Controllo: $controllo"
Lo script che regola la temperatura è in bash e va schedulato con la giusta frequenza in crontab in modo che la caldaia non si accenda e spenga in continuazione ad esempio ogni 10 minuti.
crontab -e
ed aggiungere la seguenti righe
* * * * * /root/termostato/05_memorizza_temp.sh; /root/termostato/06_display_letture.sh > /dev/null */10 * * * * /root/termostato/termostato.sh > /dev/null
redis_2_csv.sh
Questo script è utile per il debug, viene anche utilizzato dalla pagina che visualizza il grafico per analizzare meglio il comportamento del termostato.
#!/bin/bash if [ $# == 2 ] then start=$1 stop=$2 else start=-72 stop=-1 fi redis-cli lrange uptime $start $stop > /tmp/uptime redis-cli lrange lettura $start $stop > /tmp/lettura redis-cli lrange timestamp $start $stop > /tmp/timestamp redis-cli lrange min $start $stop > /tmp/min redis-cli lrange max $start $stop > /tmp/max redis-cli lrange lettura $start $stop > /tmp/lettura redis-cli lrange temp_esterna $start $stop > /tmp/temp_esterna if [ $TERM == 'dumb' ] then redis-cli lrange temp_1 $start $stop > /tmp/temp_1 redis-cli lrange temp_2 $start $stop > /tmp/temp_2 redis-cli lrange temp_3 $start $stop > /tmp/temp_3 else redis-cli lrange temp_1 $start $stop | sed 's:^:\o033\[31m:g' | sed 's/$/\o033\[0m/g' > /tmp/temp_1 redis-cli lrange temp_2 $start $stop | sed 's:^:\o033\[32m:g' | sed 's/$/\o033\[0m/g' > /tmp/temp_2 redis-cli lrange temp_3 $start $stop | sed 's:^:\o033\[34m:g' | sed 's/$/\o033\[0m/g' > /tmp/temp_3 fi redis-cli lrange rele $start $stop > /tmp/rele redis-cli lrange controllo $start $stop > /tmp/controllo #88256 2013-01-05 09:20:01 1357374001 8.0 21.25 21.75 20.875 21.312 24.125 1 Invariato - giorno - min 21.25/max 21.75 if [ $TERM == 'dumb' ] then echo -e "uptime data ora T est T min T max camera camerina cucina rel decisione del termostato" echo -e " 28-000004052dbd 40506c2 4056005" else echo -e "uptime data ora T est T min T max \e[1;31mcamera\e[0m \e[1;32mcamerina\e[0m \e[1;34mcucina\e[0m rel decisione del termostato" echo -e " 28-00000\e[1;31m4052dbd\e[0m \e[1;32m40506c2\e[0m \e[1;34m4056005\e[0m" fi tabella=`paste -d\| /tmp/uptime /tmp/lettura /tmp/temp_esterna /tmp/min /tmp/max /tmp/temp_1 /tmp/temp_2 /tmp/temp_3 /tmp/rele /tmp/controllo | column -t -s"|"` if [ $TERM == 'dumb' ] then echo "$tabella" | tac else echo "$tabella" fi rm /tmp/uptime /tmp/lettura /tmp/temp_esterna /tmp/min /tmp/max /tmp/temp_1 /tmp/temp_2 /tmp/temp_3 /tmp/rele /tmp/controllo if [ $TERM == 'dumb' ] then echo -e "uptime data ora T est T min T max camera camerina cucina rel decisione del termostato" fi
Configurazione del software installato
Va configurato il server web nginx editando il file:
/etc/nginx/sites-enabled/default
aggiungere index.php nella riga 33:
index index.php index.html index.htm index.nginx-debian.html;
Nel file di configurazione è già prevista la gestione di files php, infatti ci sono alcune righe commentate, noi però andiamo ad aggiungere la gestione delle pagine php con le seguenti instruzioni sempre all'interno del blocco server racchiuso tra parentesi graffe:
location ~ \.php$ { try_files $uri =404; fastcgi_split_path_info ^(.+\.php)(/.+)$; # NOTE: You should have "cgi.fix_pathinfo = 0;" in php.ini # With php5-cgi alone: # With php5-fpm: fastcgi_pass unix:/var/run/php5-fpm.sock; fastcgi_index index.php; include fastcgi.conf; }
Restartare ngnix per fargli leggere le modifiche
/etc/init.d/nginx restart
vi /etc/php5/fpm/php.ini
Settare a zero il parametro cgi.fix_pathinfo=0 per la gestione del path per gli script cgi come indicato nella parte commentata che abbiamo aggiunto al file /etc/nginx/sites-enabled/default
cgi.fix_pathinfo=0
Installare phpredis facendo riferimento alle istruzioni sulla pagina dei sorgenti: https://github.com/nicolasff/phpredis
Modificare del php.ini inserendo
extension=redis.so.
(a seconda della versione di raspbian la libreria potrebbe gia' essere caricata, eventualmente controllare ad esempio su phpinfo o sui log, non dovrebbe comunque causare problemi un doppio caricamento)
Installare redis da pecl
sudo pecl install redis
Riavviare php5-fpm e nginx per applicare le modifiche.
A questo punto il server web dovrebbe essere funzionante.
Interfaccia web
A questo punto si tratta di creare qualche pagina php per la visualizzazione e modifica dei dati.
cd /tmp git clone https://github.com/dcast78/Termostato/
ora spostiamo le pagine web sotto /var/www e cambiamo il proprietario dei files
mv /tmp/Termostato/www/* /var/www/html/ chown -R www-data:www-data /var/www/html/
Per la visualizzazione grafica si usa la libreria Flotr2.
Quindi basta clonare l'archivio git
cd /var/www/html git clone https://github.com/HumbleSoftware/Flotr2
Riferimenti
- Come indicato sopra l'archivio dei files si trova su github
- Modifica del file /boot/config.txt [1] se 1wire non funziona.