Sensore di temperatura con Big Data e l'IOT

Da lumacawiki.

Sensore di temperature con Big Data e l'IOT

Ecco allora, sempre per la serie di articoli relativia allo spippolamento, due argomenti che van di moda oggidì: l'IOT (l'internet delle cose, che poi non è altro che un sensore che sputa da qualche parte un dato, usando Internet) e i Big Data (che di preciso non saprei spiegare, ma è tipo una mole mostruosa di dati facilmente e rapidamente interrogabili per estrarre qualche informazione tramite l'ausilio di software che vanno oltre il classico database relazionale).

Riassunto

Senstempelk.jpg

Un sensore di temperatura manda la temperatura rilevata a un servizio. Il servizio salva questo dato. È poi possibile creare dei grafici.

Nulla di fantascientifico, tutto questo si può ottenere usando un database MySQL e una pagina PHP con un modulo o un altro oggetto utile per creare grafici (sia che l'immagine del grafico venga generata sul server oppure sul browser via javascript).

Ma qui si vuol fare i ganzi e si utilizzeranno delle teNNologie moderne, roba da modaioli.

Componenti

Hardware

  • Arduino mini (in questo caso un clone perché siamo poveri, i fautori del Made in Italy ci perdoneranno)
  • una resistenza da 4k7
  • One Wire Digital Temperature Sensor DS18B20
  • breadboard
  • qualche cavetto

Software

E qui si spippola. Non descriveremo tutti i passaggi per installare i componenti, ecc. Inoltre le descrizioni degli oggetti saranno sommarie, perché è difficile spiegare le cose agli altri quando si è i primi a non capirci nulla.

  • NodeJS (per leggere la temperatura dal sensore e inviarla via UDP al servente Logstash)
  • Logstash (che, in ascolto sulla porta UDP 4002 riceve il messaggio, lo interpreta e lo manda a Elasticsearch)
  • Elasticsearch (un motore per il salvataggio di dati in formato chiave-valore, e per l'analisi di tali dati)
  • Kibana (interfaccia web per la visualizzazione ed elaborazione dei dati salvati su Elasticsearch, orientato ai messaggi di logging, dove è possibile creare grafici che si aggiornano in real time)

Elastic Stack (ELK)

La tripletta Logstash Elasticsearch Kibana viene spesso utilizzata per l'analisi massiccia in scala temporale dei log provenienti da più fonti. I dati in ingresso a Logstash possono essere molteplici e di vari tipi e formati, così come quelli in uscita.

Per quanto riguarda Elasticsearch, Wikipedia ci dice: "Elasticsearch è un server di ricerca basato su Lucene, con capacità Full Text, con supporto ad architetture distribuite. Tutte le funzionalità sono nativamente esposte tramite interfaccia RESTful, mentre le informazioni sono gestite come documenti JSON. Elasticsearch nel gennaio 2016 risulta essere il motore di ricerca più utilizzato."\\ TUTTO CHIARO VERO?!

SchemaELK.jpg

Il sensore e lo Sketch

La costruzione del sensore è presto fatta. Andate su questo sito e vedete di arrangiare i vostri componenti come meglio vi riesce.

Importare le librerie OneWire e DallasTemperature nell'IDE Arduino (potete trovarle in Sketch -> Include Library -> Manage Library).

Lo sketch

Lo sketch sarà il seguente:

#include <OneWire.h>
#include <DallasTemperature.h>
#define ONE_WIRE_BUS 4
OneWire oneWire(ONE_WIRE_BUS);
DallasTemperature sensors(&oneWire);
int incomingByte = 0;
void setup(void)
{
  Serial.begin(57600);
  sensors.begin();
}
 
 
void loop(void)
{
  if (Serial.available() > 0) {
        incomingByte = Serial.read();
        sensors.requestTemperatures();
        Serial.print(sensors.getTempCByIndex(0));
    }
}

Il funzionamento è molto semplice: quando sulla seriale arriverà qualcosa, verrà interrogato il sensore e stampato, sempre sulla seriale, il valore in gradi Celsius.

È importante specificare incomingByte = Serial.read();, altrimenti lo sketch inizierà a sputare a raffica i risultati anche se non richiesto.

Il sensore una volta interrogato impiega quasi un secondo per rispondere, questo va tenuto di conto nel programma NodeJS che andrà a succhiare il valore della temperatura da Arduino.

Il programma in NodeJS

Il sensore fatto con Arduino verrà mantenuto attaccato a un PC, a un server, via USB.

È certamente superfluo utilizzare NodeJS, potremmo usare quel che ci garba di più. Pitone, la bash, qualche tool di Linux.
Ma usiamo NodeJS. È ganzo.

Si suppone qui che NodeJS sia già installato sulla vostra distribuzione. Per comodità sarebbe bene avere anche NPM (il package manager per installare i moduli). Debian 7 non ha npm nel repository ufficiale, mentre Arch e altre distribuzioni sì. Fate riferimento alla pagina web Installing Node.js via package manager.

Create una directory dove metterete il programma e entrateci dentro (ovviamente dalla linea di comando).
Date il comando npm install serialport --save
Create un file con il seguente contenuto, circa.

var SerialPort = require('serialport');

const dgram = require('dgram');

var UDPPORT = "4002";
var HOST = "logstash.tuodominio.net";

SerialPort.list(function(err, ports) {
    ports.forEach(function(port) {
        console.log(port.comName);
    });
});

var portName = "/dev/ttyUSB0"

var myPort = new SerialPort(portName, {
    baudRate: 57600,
});

myPort.on('open', showPortOpen);
myPort.on('data', sendSerialData);
myPort.on('close', showPortClose);
myPort.on('error', showError);

function showPortOpen() {
    console.log('port open. Data rate: ' + myPort.options.baudRate);
}

function sendSerialData(temp) {
    var message = Buffer.from(temp + ";sensore57");
    const client = dgram.createSocket('udp4');
    try {
        client.send(message, 0, message.length, UDPPORT, HOST, function(err, bytes) {
            if (err) throw err;
            //console.log('Sending UDP message to ' + HOST + ':' + UDPPORT);
            client.close();
        });
    } catch (e) {
        console.log("udp send throw: " + e)
    }
}

function showPortClose() {
    console.log('port closed.');
}

function showError(error) {
    console.log('Serial port error: ' + error);
}

var invio = 0;

setInterval(function() {
    console.log('.');
    myPort.write(invio.toString());
}, 2000);

Cambiate ovviamente la porta seriale con quella dove è attaccato Arduino, l'IP o il nome dell'host dove gira Logstash e la porta UDP che avrete configurato in ascolto sempre su Logstash.

Il programma si spiega abbastanza bene da solo: via seriale viene mandato un valore qualsiasi; come da sketch, Arduino risponde con un valore; quando il programma riceve un dato via seriale lo manda via UDP alla macchina dove gira Logstash.

Perché UDP? Perché leggete wikipedia. UDP non mantiene la sessione. Manda il pacchetto e ciao. Se arriva arriva, se non arriva non arriva. Tanto se si perdono i dati della temperatura di qualche rilevazione, ai fini del Big Data non è importante. L'UDP quindi è più leggero e in teoria occupa meno la rete e le risorse del computer. Antanizzazioni del genere.

Per ulteriori informazioni circa NodeJS e la comunicazione seriale consultate questa pagina web.

È bene non far girare il programma come root. L'utente che userete però dovrà avere diritti di lettura e scrittura sulla porta USB. Generalmente si mette l'utente nel gruppo dialout. Oppure si può fare qualcosa di più raffinato con UDEV: udevttypersistente TTY persistente con udev.

Elastic Stack

Come già detto, di descrizioni e spiegazioni di questi oggetti ne è pieno il web. L'installazione è piuttosto semplice. Basta scaricare il tar.gz decomprimerlo e se avete Java (anche OpenJDK va bene) installato, il gioco è fatto. Per Kibana esistono i pacchetti RPM e DEB, oppure anche in questo caso basta decomprimere il file tar.gz

Nota: essendo questi software scritti in Java, succhiano un sacco di risorse. È capace che se installate tutto su una macchina sola, schianti tutto. Infatti, come detto all'inizio, questa architettura è un po' una forzatura se realmente non si ha a che fare con i Big Data. Ma siamo qui a spippolare, quindi vedete di risolvervi i problemi da soli.

Configurazione

Elasticsearch

Se non si vuole approfondire troppo, Elasticsearch non ha bisogno di configurazioni, se non specificare su quale IP e quali porte stare in ascolto.

Una volta lanciato, dobbiamo creare un template dove andiamo a specificare il mapping degli indici, ossia quello relativo al campo temperatura è un valore numerico: se non facciamo preventivamente questa operazione, lui di default creerebbe un mapping dove tutti i campi sono stringhe. E non ci garba perché vogliamo fare dei grafici in base a dei valori numerici.

Quindi in perfetto stile RESTful, gli si manda a dire di creare un template.

curl -XPOST http://elasticsearch.tuodominio.net:9200/_template/temperature -d '{"template" : "temperature-*", "mappings":{"logs":{"properties":{"@timestamp":{"type":"date","format":"dateOptionalTime"},"@version":{"type":"string"},"sensor":{"type":"string", "index" : "not_analyzed"},"tags":{"type":"string"},"gradi":{"type":"float"}}}}}'

Kibana

Kibana uguale: gli va solo detto qual è l'IP e la porta del server Elasticsearch.

Logstash

L'unico che ha bisogno di un file di configurazione è Logstash. Logstash potrebbe avere più input e più output, con protocolli e tipi di messaggio diversi; e vari filtri.
I filtri sono la sezione dove si fa il parsing del messaggio e lo si scompone in campi (chiavi?) con i relativi valori da mandare a Elasticsearch (o dove ci pare).

Ecco il file di configurazione:

input {
   udp {
      port => 4002
      add_field => {
         Environment => "temperature"
      }
   }
}

filter {
   if ( [Environment] == "temperature" ) {
        grok {
         match => {
            "message" => '%{NUMBER:gradi};%{GREEDYDATA:sensor}'
        }
      }
   }
}

output {
  if ( [Environment] == "temperature" ) {
      elasticsearch {
         hosts => ["elasticsearch.tuodominio.net"]
         index => "temperature-%{+YYYY.MM.dd}"
      }
     stdout { codec => rubydebug }
   }
}

Anche questo file si spiega da solo: input -> filtro -> output

La sezione grok "message" => '%{NUMBER:gradi};%{GREEDYDATA:sensor}' è tipo le espressioni regolari. Il messaggio (che proviene dal programma NodeJS) è separato da ";", la parte prima se è un numero assegnalo alla chiave gradi, la parte dopo è una stringa qualsiasi e assegnala alla chiave sensor (così potremo avere più sensori, ognuno con il suo identificativo, e creare grafici distinti).

Avviamo Logstash. Anche lui non va avviato come root (altrimenti non parte nemmeno).

/opt/logstash-2.3.4/bin/logstash --verbose -f /opt/logstash-2.3.4/temperature.conf --auto-reload

Se usiamo netstat sulla macchina dove gira Logstash vedremo che è aperta la porta 4002/UDP

Avvio della baracca

Avviamo ora il programma in NodeJS

node nodetemp.js

Vedremo arrivare su Logstash i messaggi.

Colleghiamoci con un browser alla macchina con Kibana, sulla porta 5601.
Per prima cosa andiamo in Settings e nella colonna di sinistra Index Patterns, Add New +. Qui specifichiamo temperature-* in Index name or pattern.

Ora potete tornare nella scheda Discover: il grafico che vedete qui corrisponde al numero di messaggi ricevuti nell'unità di tempo, non ai valori della temperatura.

Andate sulla scheda Visualize.
Qui dovete spippolare un po'. Anche perché se di statistica ecc. non ci si capisce nulla, si può arrivare fino a un certo punto. Però l'informatica è una materia democratica, e anche l'ignorante può arrivare a ottenere qualcosa di decente, simpatico e forse utile. Non è solo roba da puzzettoni elitari e aristocratici.