www.errorediridondanzaciclicodotcom

  • Home
  • Info Bagno
  • BACK P.P.
  • Un raspberry nel bagno


    Il box per i collegamenti


    Il connettore a 9 pin


    Le sonde con XLR

    In questa pagina descrivo come implementare un raspi nel bagno.

    Hardware:

    1. Raspberry PI2
    2. TouchScreen 7"
    3. Sonda Temperatura Umidità AM2302 (versione "wired" della DHT22)
    4. Sonda Temperatura esterna 18B20
    5. Sonda Temperatura acqua doccia 18B20
    6. Flussimetro 5volt
    7. Sensore PIR

    Software:

    Adafruit software per la lettura della sonda temperatura umidità.
    Il solito codice python per il web-scraping e per il main il cui risultato si vede in foto.

    Come si vede dalla foto della schermata, ho sul display l'ora ed il giorno attuali, la temperatura del bagno, l'umidità del bagno, la temperatura esterna, la temperatura della doccia (calda, fredda e mixata) e dati relativi il consumo di acqua della doccia.
    Sotto si vedono le previsioni del tempo per le prossime ore e un pulsante di chiusura del programma (essendo impostato pygame.NOFRAME).
    Lo scopo di questo aggeggio è quello di avere delle informazioni relative l’acqua della doccia e informazioni esterne che possono essere utili durante questi momenti.

    TEMPERATURE

    Le temperature lette sono quelle dell’acqua in doccia, con un sensore per ogni acqua: la fredda dell’acquedotto, la cada della caldaia e quella mixata che ci cade in testa. In particolare quest’ultima è utile per sapere quando si può entrare in box (chi non ha il ricircolo e il bagno è lontano dalla caldaia sa che deve aspettare un po’ prima di avere l’acqua alla temperatura desiderata). Il colore del valore indicato varia dal blu per l’acqua fredda, al verde per quella considerata accettabile, al rosso quando troppo calda.

    FLUSSO DELL’ACQUA

    Ho inserito un flussimetro non tanto per una reale utilità ma solo per un mio esercizio volto a comprendere quanti litri di acqua si consumano per le docce. Il flussimetro è quello classico che si trova ovunque. Purtroppo però è disponibile per il raspi & c. solo a 5 volt (5-18), ciò significa che non è compatibile con i microcontrollers tipo raspberry che hanno la GPIO a 3 volt. Per questo motivo si deve utilizzare un partitore di tensione. Un partitore di tensione (esiste anche quello per la corrente) non è altro che un circuito con resistenze in serie che sfrutta la legge empirica di Ohm. Il voltaggio in uscita da questo circuito è direttamente proporzionale al voltaggio in entrata moltiplicato per la resistenza da cui si preleva la tensione fratto la somma delle due resistenze in serie.

    Nel disegno sopra si può vedere una simulazione (grazie a Tinkercad di Autodesk!) utilizzando le resistenze necessarie a portare i 5 v a circa 3.3 v, cioè una da 4.7kohm e una (utilizzata per prelevare la tensione desiderata) da 10kohm.
    Il filo arancione è quello che andrà al pin della GPIO e che darà l’IN alla chiusura del contatto sul flussimetro.
    Per la taratura (modifica del valore di conversione degli impulsi in litri) si può procedere in questo modo: si legge il contatore di casa, si apre solo la doccia per un periodo a scelta, si legge nuovamente il contatore. Se i dati non coincidono si aggiusta il parametro di conversione. Se si vuole fare prima si stampa a video il counter degli impulsi e, se si deve aggiustare il risultato, si prendono i litri letti dal contatore e si dividono per gli impulsi.
    Attenzione però che nel mio script il conteggio dei litri avviene solo se la temperatura è maggiore di 20 gradi, modificare questo parametro o fare la prova con l’acqua già calda.
    Qui di seguito tutto il circuito del mio raspi.

    Il flussimetro viene gestito da uno script.py che è sempre in esecuzione, i dati registrati vengono poi prelevati da un altro script che mostrerà i valori delle misure sullo screen. Lo script del flussimetro scrive anche i dati su un file di testo che serve a riprendere i valori memorizzati del mese in caso di reboot.
    Un crontab fa il riavvio del raspi ad ogni primo giorno del mese e nello script del flussimetro c’è un controllo al riavvio dello stesso: se il giorno del riavvio è il primo del mese azzera tutti i valori del flussimetro.
    #!/usr/bin/env python3
    
    import RPi.GPIO as GPIO
    import time, sys, datetime
    import read_dallas_module
    import glob
    
    GPIO.setmode(GPIO.BCM)
    pin = 17
    GPIO.setup(pin, GPIO.IN)
    litreconv = 0.004883
    interval = 10
    counter = 0
    now=datetime.datetime.now()
    if datetime.datetime.now().day == 1:
    		
        start = now.strftime('%d %b %Y')
        with open("/home/pi/Bath/flowmeter.txt", "w") as f:
            
            seq=(str(start)+'\n','0\n', '0\n', '0\n', '0\n')
            litres_tot = 0
            minutes = 0
            litres_last_shower = 0
            shower_counter=0
            cumulative = 0
            f.writelines(seq)
    else:
        with open('/home/pi/Bath/flowmeter.txt', 'r') as f:
            
            content=f.readlines()
    
            '''initializes all variables reading values stored
               in file.txt, last_shower is initialized to 0'''
            litres_tot= round(float(content[1]), 1)
            minutes = int(content[2])
            shower_counter = int(content[3])
            cumulative = int(litres_tot/litreconv)
            litres_last_shower = 0
    
    def reading(pin):
        global counter, cumulative
        counter += 1
        cumulative += 1
    
    GPIO.add_event_detect(pin, GPIO.RISING, callback=reading, bouncetime = 20)
    ts = 1
    pause=True
    
    Nel ciclo principale prima leggo la temperatura con un modulo importato. Poi inizio a leggere i dati del flussimetro in blocchi di 60 secondi allo scopo di avere un conteggio anche dei minti di doccia.
        
    while True:
    	
        '''read temp shower for the following condition'''
        temp_shower=read_dallas_module.D18B20("temp_shower")
        temp_shower=temp_shower.read_temp()
    
    Quest'ultimo codice serve a verificare di essere alla fine della doccia e, trascorsi 3 minuti (per quelli che usano spengere la doccia per insaponarsi i capelli) senza essere stata riaperta l'acqua, procede con le memorizzazioni finali: nr di docce e litri ultima doccia.
        '''check if temp_shower is over 20 deg and flow is running'''
        if temp_shower >20 and GPIO.event_detected(pin) and counter>250:
    		
            '''keeps running'''
            pause= False       
            ts = time.time()
            
            '''loop for storing data during a fixed interval
               the interval is needed for calculate time of shower'''
            while pause == False:
                tn = time.time()+60
                
                '''litres last shower are set to 0 for each shower'''
                litres_last_shower = 0
                while time.time() <= tn:
                        print(GPIO.input(pin), end='')  #only for debugging                         
                pause=True
                
                '''this condition is for clearing the status of
                   flow meter that would replicate the reading
                   (nothing to do with bouncing!!!)'''
                not GPIO.event_detected(pin)            
            minutes+=1
    
            litres_tot = round(cumulative * litreconv, 1)
    
            time.sleep(0.2)
    
            with open('/home/pi/Bath/flowmeter.txt', 'r+') as f:
    
                content[1]=str(litres_tot)+'\n'
                content[2]=str(minutes)+'\n'
                f.writelines(content)
            
            pause=False
            
        elif temp_shower >2 and not GPIO.event_detected(pin) and time.time()>(ts+180):
    
            if pause is False:
                
                litres_last_shower = round((counter) * litreconv, 1)
                shower_counter+=1
                time.sleep(1)
                
                with open('/home/pi/Bath/flowmeter.txt', 'r+') as f:
                    
                    content[3]=str(shower_counter)+'\n'
                    content[4]=str(litres_last_shower)+'\n'
                    f.writelines(content)
    
                pause = True
                counter = 0
                litres_last_shower = 0
    			
    GPIO.cleanup()
    sys.exit()
    

    Di seguito come ho preso le informazioni per le previsioni del tempo.
    import urllib2
    import time
    from bs4 import BeautifulSoup
    import sys
    
    hdr = {'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.11 (KHTML, like Gecko) Chrome/23.0.1271.64 Safari/537.11',
           'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
           'Accept-Charset': 'ISO-8859-1,utf-8;q=0.7,*;q=0.3',
           'Accept-Encoding': 'none',
           'Accept-Language': 'en-US,en;q=0.8',
           'Connection': 'keep-alive'}
    
    url = "http://www."miosito"/"paginadimiosito""
    req = urllib2.Request(url, headers=hdr)
    page = urllib2.urlopen(req)
    soup = BeautifulSoup(urllib2.urlopen(req).read(), "lxml")
    
    def h3_with_"ParolaChiave"(tag):
      return tag.name == 'h3' and tag.text.startswith("ParolaChiave")
    f=soup.find_all(h3_with_"ParolaChiave")[0]
    
    
    h=f.findNextSibling()
    
    reload(sys)
    sys.setdefaultencoding("latin-1")
    
    file = open("/home/pi/"FilediArchiviazione".txt","w")
    file.write(h.string)
    file.close()
    

    Il codice sopra riportato sfrutta il noto BeautifulSoup, nella versione 4. Sono poche righe perchè in realtà non è particolarmente complesso il suo utilizzo, tuttavia ho riscontrato un pò di difficoltà nella terminologia giusta.
    Infatti le istruzioni possono essere diverse anche per una virgola e differiscono a secondo del contesto in cui sono scritte.
    Attenzione al "parser" che installate, nel mio caso lxml, che deve essere utilizzata la solita istruzione apt-get install python-lxml e non pip perchè così per me è stato l'unico metodo funzionante.
    La funzione "def h3_with_"ParolaChiave"(tag):" serve a cercare su tutto il sito una parola chiave per identificare il blocco di testo con le previsioni. Una volta trovata, prende la prima dell'elenco (se ci sono più parole chiave e se la prima è quella che interessa).
    L'istruzione seguente è quella che memorizza il testo successivo alla parola chiave. Per visualizzare correttamente le parole accentate della lingua italiana ho inserito la successiva istruzione con la corretta codifica.

    h=f.findNextSibling()

    A questo punto lo script apre il file di testo dove memorizzare le previsioni e vi scrive quanto rilevato.
    Un launcher di avvio di questo programma di web scraping, memorizzato nel cronotab, ripeterà ad intervalli regolari la lettura delle previsioni del tempo. Nel mio caso è solo qualche volta in 24 ore.
    Nel programma principale il loop andrà a leggere il testo di questo file e lo riporterà a video.

    Nella foto si vedono poche parole di previsioni ma in realtà le parole scorrono al fine di permettere la visualizzazione di testo anche più lungo. All'inizio avevo creato un'istruzione per visualizzare un vero e proprio scorrimmento orizzontale. Tuttavia una volta messo in azione nel programma principale, completo di lettura delle sonde, avevo dei blocchi tra un refresh e l'altro. Così, anche per pigrizia, ho deciso di fare uno scorrimento a blocchi di 700 caratteri circa. Magari tra un pò di tempo proverò a rivedere il codice e cercare una soluzione per avere lo scorrimento orizzontale continuo.

    Infine, a proposito del sensore PIR, questo serve solo a svegliare lo schermo dallo screensaver. Infatti, pur non essendoci per ora la possibilità di mettere il monitor del raspberry in stand-by, per evitare sprechi di corrente, ho utilizzato lo screensaver per risparmiare un pò di corrente, rendendo lo schermo nero. Con il sensore ho la possibilità di riattivare lo schermo al momento dell'entrata di una persona nel locale.

    TAF!