domenica 28 febbraio 2016

Ricezione dati meteo da stazione Fine Offset WH1080 con Raspberry Pi (o BananaPi) e rtl-sdr (pressione compresa)


                              con  raspberry_rtl_wh1080


Una soluzione basata su rtl_433, un fantastico software che trasforma una chiavetta DVB-T USB Realtek RTL2832 in un ricevitore generico di dati. 


  • Raspberry Pi è un piccolo ed economico minicomputer dotato di una simpatica interfaccia GPIO.  
  • BananaPi è simile a RaspberryPi, ma è dual-core e dispone anche di una interfaccia SATA. Il programma è stato testato con la versione M1 (Allwinner A20 - ARM Cortex-A7 dual-core, 1GHz, Mali400MP2 GPU, 1GB DDR3 DRAM).
  • Il BMP085 è un sensore barometrico dal costo irrisorio. Si tratta di un dispositivo comune ma obsoleto, sostituito dall'altrettanto economico e pin-to-pin compatibile BMP180.
  • La Fine Offset WH1080 è una stazione meteo relativamente economica, venduta anche con altri nomi/marchi: Watson W-8681, Digitech XC0348 Weather Station, PCE-FWS 20, Elecsa AstroTouch 6975, Froggit WH1080 ed altri ancora. 




La stazione Fine Offset WH1080 è composta da un pannello di controllo LCD touchscreen (detto anche console) da tenere in casa e da un gruppo di sensori wireless da collocare all'aperto. Quest'ultimo invia periodicamente alla console, via radiofrequenza, dei pacchetti di dati  contenenti i dati meteo misurati dai sensori, relativi a velocità e direzione del vento, temperatura, umidità relativa dell'aria e quantità di pioggia caduta. 



 

 
Nel gruppo di sensori trova posto anche un ricevitore radio in grado di sintonizzarsi sulla frequenza della stazione di tempo tedesca DCF77 (è probabilmente in grado di ricevere e decodificare anche altre stazioni e standard di tempo). La sua funzione è quella di ricevere l'ora esatta e ritrasmetterla periodicamente (ogni 2 ore) alla console interna per tenerla perfettamente sincronizzata con il segnale di tempo proveniente dall'orologio atomico tedesco. 



La console contiene inoltre un sensore barometrico, un sensore di temperatura ed un sensore di umidità, questi ultimi atti a misurare i dati dell'ambiente all'interno del quale la console è collocata.
Tutti questi dati sono visualizzati sul display LCD della console, e sono resi disponibili anche tramite una porta USB posta nella console stessa: connettendovi un PC ed usando del software opportuno è possibile tener traccia delle condizioni meteo della propria zona.

Sfortunatamente la connessione USB si dimostra talvolta poco affidabile nel lungo periodo e tende ad andare in stallo di tanto in tanto rendendo necessario il reset della console. Inoltre avere la console connessa al PC tramite un (corto) cavo USB preclude la possibilità di averla a portata di mano, costringendo a scegliere se si desidera avere il colpo d'occhio sul pannello LCD oppure avere la possibilità di registrare i suoi dati (magari postandoli su di un sito web).

Una possibile soluzione è quella di catturare con un qualche tipo di ricevitore i segnali radio inviati dai sensori alla console, decodificandoli opportunamente ed infine salvandoli. 
Purtroppo c'è uno svantaggio: poiché il sensore barometrico è racchiuso nella console e non nel gruppo di sensori esterni, i dati relativi alla pressione NON sono inviati via radio. Perciò dovremo connettere un sensore barometrico a tale ricevitore per integrare i dati di pressione mancanti.

Il minicomputer RaspberryPi si adatta perfettamente a questo utilizzo: è economico, dispone di porte GPIO alle quali connettere i nostri sensori, la sua piccola potenza è più che sufficiente per questo compito e non appesantirà la bolletta elettrica neppure con un utilizzo continuativo (consuma meno di 5 watts). Il sensore barometrico sarà un economico BMP085 oppure BMP180 ed il collegamento al minicomputer richiede solo 4 fili. 

Perchè rtl-sdr?


Quando ho iniziato i miei test di ricezione dati dalla WH1080 utilizzavo una RaspberryPi collegata ad un modulo radio RFM01: è un piccolo radioricevitore dati  che funziona bene in condizioni normali. Qualche linea di codice trovata nel web, qualche altro collegamento di fili e l'insieme 'Rasp + RFM01 + BMP085' ha funzionato per una stagione... O quasi.

Sfortunatamente infatti con il cambio di stagione ho scoperto che la mia WH1080 tende a slittare in frequenza, probabilmente a causa della mancanza di un sistema di compensazione temperatura/frequenza a bordo del trasmettitore dati esterno: più la temperatura scendeva in inverno più il segnale slittava ed il mio 'insieme' non riusciva a far fronte al problema. Così durante la parte più interessante dell'inverno non ero in grado di registrare dati!
Un'opzione era quella di ricalibrare la frequenza di ricezione del modulo RFM01, ma con l'arrivo dell'estate ed il conseguente innalzamento di temperatura il problema ovviamente si ripresentava in verso opposto con il medesimo risultato: niente dati e necessità di nuova calibrazione...

Inoltre il programma (in linguaggio C) che utilizzavo per ricevere i dati prevedeva la scrittura degli stessi in un file temporaneo. Il file era quindi preso in carico dal mio programma di salvataggio dati in Python (datalogger) che ne estraeva i dati contenuti per la successiva elaborazione. Successivamente il file veniva sovrascritto dal programma in C all'arrivo di nuovi dati (la WH1080 li invia ogni 48 secondi) e riletto dal datalogger Python, e così via.  Ciò significa che in un anno quel file veniva sovrascritto più di 500.000 volte!
E' un po' troppo per la povera SDcard che costituisce l'hard disk della Raspberry (come è noto il numero possibile di cicli di scrittura in una SDcard non è affatto infinito, dopo di che si può buttare...).
Così dopo qualche tentativo sono riuscito ad apportare alcune modifiche al codice C, in modo che il programma passasse i suoi valori 'al volo' al datalogger Python anziché farli 'transitare' in un file di scambio. Ma questo approccio, sommato al problema dello slittamento di frequenza, introduceva nuove occasioni di instabilità al sistema...
C'era bisogno di un altro modo per ricevere i dati, un approccio differente: rtl-sdr.


Si può trovare molta documentazione a riguardo sul web a proposito di rtl-sdr e delle sue opportunità. Il progetto rtl_433 , che si basa sulle librerie rtl-sdr è una perfetta soluzione per il nostro scopo. 
 

Dopo numerosi test posso affermare che:


  • la chiavetta rtl_sdr è molto più sensibile del modulo RFM01 (già solo utilizzando la sua mini antenna);
  • è una soluzione MOLTO più stabile: se si utilizza un buon datalogger dotato di un'ottima gestione degli errori (errori di database, errori di output non json/csv a causa di interferenze...) può funzionare senza problemi per settimane e settimane;
  • è in grado di far fronte agli slittamenti in frequenza del TX: basta con la mancanza di ricezione! Non più perdite di dati!
  • non è più necessario passare i dati al datalogger utilizzando il metodo del 'file di scambio'. E' ora possibile catturare 'al volo' dati formattati in json/csv dal programma utilizzando ad esempio il piping del suo output verso il proprio script (Python?) di data logging. Come risultato la SDcard ringrazia: è posta molto meno sotto stress e la sua vita teorica -naturalmente- si allunga di parecchio.
  • il processo di lettura utilizza molta meno CPU rispetto all'utilizzo del modulo RFM01 (attualmente il mio processo si attesta a circa il 15% di CPU in una 'vecchia' Rasp modello B);
  • il ricevitore USB è quasi plug & play! Niente fili, basta inserire la chiavetta nella porta USB della Raspberry (e naturalmente collegare la mini antenna alla chiavetta :smile:


...Abbiamo ancora naturalmente il problema della mancanza dei dati relativi alla pressione, ecco perchè dovremo collegare alla Raspberry (o BananaPi) un modulo sensore BMP085 o compatibile, implementando del relativo codice per la lettura dei dati. Essendo rtl_433 un progetto generico e non orientato ad uno specifico hardware, esso non contiene codice specifico per Raspberry (o BananaPi) e/o relativi sensori.

Ecco quindi il motivo per il quale ho deciso di integrare del codice preso-in-prestito-dal-web per leggere dati dal BMP085 ad uno snapshot di rtl_433, ottenendo questa soluzione all-in-one per la WH1080.

Guardando al codice si potrebbe obiettare che è poco elegante, ma almeno per ora pur essendo poco più di un test si sta comportando benissimo. Ho verificato il suo ottimo e stabile funzionamento sia su di una RaspberryPi modello B che su di una B+ (con a bordo Raspbian Jessie vers. 2015-11-21), una chiavetta USB DVB-T RTL2832U di provenienza cinese supereconomica (8 euro) ed un sensore BMP180. Successivamente ho riscontrato l'ottimo funzionamento pure su di una BananaPi M1 (con la piccola modifica di 1 carattere, come spiego più avanti), e dovrebbe riuscire a compilare e lavorare felicemente anche su Raspberry Pi 2.

Ho rimosso tutti i moduli attraverso i quali rtl_433 riconosceva il segnale radio di vari altri dispositivi, lasciando attivo soltanto il 'Fine Offset WH1080 weather station' per mantenere l'utilizzo di risorse al minimo, ma ritengo che l'eventuale ri-aggiunta di codice relativo a dispositivi originariamente riconosciuti non sia difficoltosa.


Quindi questo software può:

  • Leggere i dati ricevuti dai sensori esterni della propria stazione WH1080 (o di quella del vicino): direzione e velocità del vento, temperatura, umidità, pioggia, e pressione (grazie al sensore BMP085/BMP180 collegato alla RaspberryPi/BananaPi);
  • Ricevere data/ora esatta (sistema DCF77 e forse altri) trasmessi dalla stazione: la WH1080 trasmette segnali di tempo all'inizio di ogni ora pari. A sua volta riceve tali segnali da un trasmettitore ad alta potenza situato in Germania (parliamo del sistema DCF77), collegato ad un orologio atomico locale che garantisce la precisione dell'ora di riferimento. Utilizzando uno script si può facilmente mantenere l'orologio interno della Raspberry sincronizzato con data ed ora  esatta senza il bisogno di NTP o RTC. Non serve nemmeno una connessione dati!
  • Fornire dati in formato json/csv per le proprie esigenze Python  (o altri linguaggi di programmazione);
  • Fornire la flessibilità di rtl_433 grazie alle sue opzioni: è possibile ottimizzare la ricezione del segnale, la frequenza, soglia di sensibilità ecc. ...

 

Istruzioni per la compilazione ed installazione (testato su Raspbian Jessie (2015-11-21) per quanto riguarda RaspberryPi, e su Bananian Linux (3.4.104-bananian) per BananaPi):


Connettere la chiavetta USB alla RaspPi/BananaPi e collegare il sensore di pressione alla porta GPIO (cercare in Google se non si sa come fare, a seconda del proprio modello di RaspberryPi / BananaPi. Ci sono da collegare solo 4 fili. Prestare solo ATTENZIONE ad utilizzare per l'alimentazione del modulo barometrico il pin Rasp/Banana a 3.3VDC , NON quello a 5VDC).

 ---

Poiché questa soluzione deriva da rtl_433, valgono le stesse operazioni di compilazione, ma a causa dell'aggiunta del sensore barometrico c'è qualche operazione extra da eseguire.
Prima di tutto SPI e I2C nella Raspberry dovranno essere abilitati. Utilizzare sudo raspi-config, portarsi su 'Advanced Options' ed abilitare entrambi. Rispondere 'Yes' alla domanda relativa al modulo kernel da caricare di default all'avvio default, per ora non eseguire il reboot.

Per quanto riguarda il BananaPi occorre installare le sue librerie GPIO_BP. Istruzioni e sorgenti si trovano qui: https://github.com/LeMaker/RPi.GPIO_BP

Dovremmo essere pronti ora per la compilazione. Si assume che la propria home sia /home/pi; naturalmente si può utilizzare qualsiasi directory purché scrivibile dal proprio utente, ma ovviamente si dovranno adattare di conseguenza i comandi che seguono.  

Nota per gli utenti BananaPi: non ricordo esattamente se fossero necessari ulteriori pacchetti da installare. Se così fosse fatemelo sapere, così da aggiornare questa guida.

Ecco come procedere:



sudo apt-get update

sudo apt-get install build-essential libusb-1.0-0-dev i2c-tools

sudo apt-get libi2c-dev cmake git

cd /home/pi

git clone git://git.osmocom.org/rtl-sdr.git

cd rtl-sdr

mkdir build

cd build

cmake ../ -DINSTALL_UDEV_RULES=ON -DDETACH_KERNEL_DRIVER=ON

make

sudo make install
 
sudo ldconfig 
 
sudo reboot 
 
 
Ora che abbiamo installato le librerie di base possiamo procedere con la compilazione ed installazione di raspberry_rtl_wh1080:


cd /home/pi

git clone https://github.com/ovrheat/raspberry_rtl_wh1080.git

cd raspberry_rtl_wh1080
 
 

Ora una parte importante: è NECESSARIO modificare questo file:


~/raspberry_wh_1080/src/devices/fineoffset_wh1080.c
 
 
identificare la linea (dovrebbe essere la n. 108) contenente:

const unsigned char station_altitude = 10;  // <----- Edit this value entering YOUR station altitude!


'10' è il valore in metri dell'altitudine della mia stazione. Dovrà essere sostituito con quello della PROPRIA stazione (in metri), altrimenti i dati relativi alla pressione potrebbero risultare non corretti.

Un'altra riga da tenere sott'occhio, soprattutto per gli utenti BananaPi, si trova poco sotto alla precedente:



char *fileName = "/dev/i2c-1"; //<------- If your Raspberry is an older model and pressure doesn't work, 
    // try changing '1' to '0'. Also change it to '2' if you are using a BananaPi! ("/dev/i2c-2";)**


Se qualcosa va storto con la lettura dei dati pressione, o peggio il programma crasha improvvisamente senza alcun messaggio quando si ricevono i primi dati, e si è sicuri del corretto collegamento del sensore BMP085, la prima cosa da fare è provare a variare quel '/dev/i2c-1' in '/dev/i2c-0', soprattutto se si dispone di una Rasp un po' vecchiotta. 

Gli utenti BananaPi DEVONO cambiare questo valore da

"/dev/i2c-1";

a

"/dev/i2c-2";


altrimenti il programma non funzionerà! 

Una volta fatto, salvare il file e tornare alla directory radice dei sorgenti:

cd /home/pi/raspberry_rtl_wh1080
 
 
Ed eseguire questa ultima batteria di comandi: 
 

 
mkdir build

cd build

cmake ../

make

sudo make install
 
 
Ignorare bellamente i vari 'Warning' che appariranno, sono causati da una non ancora completa ottimizzazione del codice ma sono ininfluenti ai fini del buon funzionamento.

L'installazione è ora terminata e pronta per il primo test. Ricordarsi di connettere la mini antenna alla chiavetta (...doh!). 



Utilizzo:

Per l'help e per visualizzare tutte le opzioni del programma:

rtl_433 -h
 
 
 
Vediamo ora qualche esempio di utilizzo pratico, tenendo in mente quanto segue: il gruppo sensori esterno invia i propri dati ogni 48 secondi, perciò non si può pretendere di vedere immediatamente i dati apparire sul nostro schermo se ci si trova durante l'intervallo di silenzio. Molto probabilmente servirà qualche decina di secondi durante i quali... Non succederà nulla. 
Tenerlo a mente soprattutto all'inizio delle ore pari, a causa dei 3-4 minuti di silenzio che precedono l'ora esatta, come spiegato più avanti.


Per prima cosa ci serve sapere su che frequenza trasmette la nostra WH1080. Di questa stazione se ne possono trovare almeno tre modelli per quanto riguarda la frequenza di trasmissione: 868 Mhz, 433 Mhz e 915 Mhz. E' possibile rinvenire la propria su di un'etichetta che tipicamente è posta sul retro della console interna.  La mia stazione trasmette i suoi dati su 868.3 Mhz, per cui la mia linea di comando sarà:

rtl_433 -f 868300000 -l 0
 
 
Notare che talvolta si potrebbero riscontrare problemi di ricezione se ci si sintonizza sulla frequenza esatta (è il sistema rtl-sdr che funziona così), converrà quindi spostarsi di poco dal centro esatto della frequenza corretta. Così per la mia stazione il cui centro frequenza è a 868.3 Mhz, farò meglio a sintonizzare (ad esempio) su 868.2 Mhz:

rtl_433 -f 868200000 -l 0
 
o su 868.4 Mhz:

rtl_433 -f 868400000 -l 0
 
Meglio tenerlo a mente, e soprattutto in caso di slittamenti di frequenza della WH1080 occorrerà trovare un valore che tenga conto anche di questo aspetto.

Se la propria stazione trasmette su 433 Mhz è possibile omettere la parte '-f' in quanto rtl_433 si avvia di default su quella frequenza. Lasciare però il parametro '-l 0' :

rtl_433 -l 0
 
 
'-l 0' è il parametro per il livello di soglia dei bit da decodificare. Lasciandolo a '0' si rende rtl_433 in grado di stabilirlo automaticamente. Talvolta però tale automatismo si rivela non perfettamente efficace, in quel caso si potrà provare ad impostarlo su '-l 4000' o '-l 8000' o ancora provarne altri (il campo ammesso è 0-32767).


Se si desidera l'output formattato in json, usare il parametro '-F json':

rtl_433 -f 868300000 -F json -l 0
 
Se si desidera l'output formattato in csv, usare il parametro '-F csv':

rtl_433 -f 868300000 -F csv -l 0
 
 
 
 
Come già detto la WH1080 invia dati contenenti l'ora esatta all'inizio di (quasi) ogni ora pari: al minuto 59 dell'ora dispari la stazione smette di trasmettere dati meteo. Dopo circa 3-4 minuti di silenzio, necessari probabilmente a fini di sincronizzazione, la stazione inizia ad inviare pacchetti di dati contenenti l'ora esatta per circa 3-4 minuti (con la consueta cadenza di 48 secondi tra uno e l'altro). Infine riprende con le misurazioni meteo come di consueto.
Per distinguere tra i due tipi di messaggio (meteo o data/ora) ai fini dell'acquisizione dati, è possibile guardare al valore del campo 'msg_type' dell'uscita json/csv:

msg_type 0 = dati meteo
msg_type 1 = data/ora


Un'ultima cosa da ricordare: spesso la stazione invia pacchetti doppi di dati nello stesso secondo (o quasi): 



2016-02-24 00:26:02 :   Fine Offset WH1080 weather station
        Msg type:        0
        StationID:       0005
        Temperature:     7.3 C
        Humidity:        93 %
        Pressure:        1009.47 hPa
        Wind string:     N
        Wind degrees:    0
        Wind avg speed:  0.00
        Wind gust:       0.00
        Total rainfall:  255.0
        Internal temp.:  18.1 C
2016-02-24 00:26:02 :   Fine Offset WH1080 weather station
        Msg type:        0
        StationID:       0005
        Temperature:     7.3 C
        Humidity:        93 %
        Pressure:        1009.50 hPa
        Wind string:     N
        Wind degrees:    0
        Wind avg speed:  0.00
        Wind gust:       0.00
        Total rainfall:  255.0
        Internal temp.:  18.1 C 


(Notare la leggera differenza di pressione misurata tra i due pacchetti, ma il resto dei dati è identico). 
Talvolta il pacchetto doppio segue il primo a distanza di un secondo.
Ciò è normale, la stazione lavora così! Sarà compito dello script/datalogger  (che dovrà quindi essere programmato adeguatamente) scartare eventuali letture doppie basandosi sul fatto che sono state ricevute nell'arco massimo di un secondo (ed eventualmente con lo stesso ID di stazione se si dispone di più di una stazione dello stesso tipo). Questo, naturalmente, nel caso la ripetizione fosse un qualcosa  di indesiderato.

Concludo con il link alla pagina di questo progetto su Github:




Per quanto riguarda le opzioni particolari di rtl_433, da cui questo progetto deriva, rimando alla pagina del progetto
...Purchè non gli si chiedano informazioni relative a Raspberry/Banane e sensori di pressione... :smile:


Al prossimo pasticcio!



Nessun commento:

Posta un commento