• Non ci sono risultati.

2.7 Formati e protocolli di trasmissione

2.7.1 JSON

JSON, acronimo di JavaScript Object Notation, è un semplice formato open- standard di interscambio di dati in applicazioni client-server. JSON è basato sul linguaggio JavaScript Standard ECMA-262 3° edizione del dicembre 1999.

Scritto in linguaggio testuale e indipendente dal linguaggio di programmazione, JSON struttura i dati in oggetti (nel senso informatico del termine) composti da un insieme di coppie nome-valore, o un elenco ordinato di valori per mezzo di un vettore o array. Queste caratteristiche rendono JSON ideale per la comunicazione tra i vari elementi programmati in linguaggi differenti presenti in questo progetto di tesi.

2.7.2 MQTT

Il Message Queuing Telemetry Transport (MQTT) è un protocollo ISO (International Standard Organization) a livello applicativo posizionato sopra il protocollo di trasporto TCP/IP.

58

Sviluppato nel 1999 dal Dr. Andy Stanford-Clark alla IBM e Arlen Nipper di Arcom (adesso Eurotech), MQTT è un protocollo aperto nato per essere “leggero” minimizzando il traffico di rete e le risorse del dispositivo, garantendo comunque elevata affidabilità di consegna.

MQTT viene usato in contesti di comunicazione fra i nodi su di una rete con bassa larghezza di banda, bassa affidabilità, alta latenza e tra dispositivi con limitate capacità hardware. Sono recentemente nate molte librerie open-source per supportare l’implementazione di MQTT su una serie di architetture embedded con linguaggi in C, C++ Java, Lua, Python, Javascript e molti altri.

Questo protocollo è usato in compagnie del calibro di Amazon o Facebook, è infatti impiegato nell’applicazione Messenger per far fronte a problemi di latenza e battery- drain.

Citando il post di Lucy Zhang, Software Engineer presso Facebook visitabile al link https://www.facebook.com/notes/facebook-engineering/building-facebook-

messenger/10150259350998920/ da cui un estratto:

«One of the problems we experienced was long latency when sending a message. The method we were using to send was reliable but slow, and there were limitations on how much we could improve it. With just a few weeks until launch, we ended up building a new mechanism that maintains a persistent connection to our servers. To do this without killing battery life, we used a protocol called MQTT that we had experimented with in Beluga. MQTT is specifically designed for applications like sending telemetry data to and from space probes, so it is designed to use bandwidth and batteries sparingly. By maintaining an MQTT connection and routing messages through our chat pipeline, we were able to often achieve phone- to-phone delivery in the hundreds of milliseconds, rather than multiple seconds»

Il punto centrale della comunicazione tra dispositivi è il broker MQTT, che può essere considerate come il “server MQTT” (nel progetto il broker è integrato nel codice di Node.js sul server Raspberry Pi).

Ogni client MQTT pubblica un messaggio con un argomento chiamato topic, necessario al broker per filtrare e instradare tutti i messaggi tra i publisher e i subscriber

59 che sono sottoscritti a quel medesimo argomento.

L’argomento è una stringa di caratteri Unicode UTF-8, il quale può essere suddiviso a sua volta in più livelli separandoli con la barra obliqua “/” definendo così:

dominio/categoria/oggetto

Il dominio è un identificatore univoco legato a un ambiente specifico, categoria è un nome all’interno di un dominio che può identificare un insieme di dispositivi, mentre l’oggetto rappresenta il singolo dispositivo.

Non è necessario che un client crei l’argomento desiderato prima di pubblicarlo o abbonarlo, poiché un broker accetta ogni argomento valido senza alcuna inizializzazione precedente.

Ogni client è in grado sia di pubblicare che ricevere messaggi sottoscrivendosi ad un determinato argomento, i quali saranno recapitati dal broker.

A differenza dell’HTTP dove il client deve conoscere l’indirizzo del dispositivo a cui si sta per connettere, in MQTT i client non devono conoscersi, ma comunicano solo l’argomento senza dover essere consapevoli di chi è registrato.

Figura 2.10: Modello di comunicazione publish/subscribe

Questo tipo di architettura implementata in MQTT si chiama publish/subscribe (ISO/IEC PRF 20922), consente di realizzare soluzioni altamente scalabili e OASIS (Organization for the Advancement of Structured information) ha dichiarato che è il protocollo di riferimento per l’IoT.

MQTT si contraddistingue dal più diffuso protocollo HTTP che è invece strutturato sul paradigma richiesta/risposta, come visualizzabile in questa breve tabella comparativa tra i due:

60

MQTT HTTP

Pattern Publish/Subscribe Request/Response

Orientamento Incentrato sul dato:

i dati sono trasferiti come un array di byte

Incentrato sul documento: supporta lo standard MIME che definisce il tipo di contenuto Dimensione

messaggi

Piccola, con un header di 2 byte codificati in binario

Grande, i dettagli sullo status sono text-based

Livelli di servizio

3 QoS Tutti i messaggi hanno lo stesso

livello di servizio Distribuzione

dei dati

Utenti supportati: 1 a 0, 1 a 1, 1 a N

Supporta solo la comunicazione 1 a 1 (point-to-point)

Tabella 2.1: Comparazione protocolli MQTT / HTTP

In questa logica, MQTT, a differenza di HTTP, non deve richiedere le informazioni di cui si ha bisogno (pull), ma sono le informazioni che vengono inviate quando necessario (push) nella logica data-events. Pertanto ogni client MQTT ha una connessione TCP a stati permanentemente aperta al broker, permettendo comunque una comunicazione quasi real-time. Se il collegamento con un client fosse interrotto, il broker MQTT conserva i messaggi destinati a quel client per inviarglieli quando è nuovamente online.

Il protocollo MQTT lavora scambiando una serie di Control Packets in modo predefinito nel modo illustrato:

Header fisso Presente in tutti Control Packets MQTT

Header variabile Presente in alcuni Control Packets MQTT

Payload Presente in alcuni Control Packets MQTT

Ogni messaggio previsto con un formato MQTT ha bisogno di un Control Packet di header fisso composto da due byte strutturati come di seguito:

Bit 7 6 5 4 3 2 1 0

Byte 1 Tipo di messaggio DUP Livello QoS RETAIN

Byte 2 Lunghezza rimanente

61

precisamente occupano le posizioni dal settimo al quarto bit. I 4 bit rappresentano sedici valori, ognuno dei quali associato ad un determinato tipo come nella seguente tabella:

Valore Tipo Flow Descrizione

0 Riservato Riservato

1 CONNECT Client-to-broker Connessione richiesta al broker

2 CONNACK Broker-to-client Acknowledgment di una

connessione

3 PUBLISH Entrambi Pubblicazione di un messaggio

4 PUBACK Entrambi Acknowledgement di una Publish

5 PUBREC Publish ricevuta

6 PUBREL Publish rilasciata

7 PUBCOMP Publish completata

8 SUBSCRIBE Client-to-broker Richiesta subscription

9 SUBACK Broker-to-client Acknowledgement di una

subscription

10 UNSUBSCRIBE Client-to-broker Richiesta unsubscription

11 UNSUBACK Broker-to-client Acknowledgement di una

unsubscription

12 PINGREQ Richiesta di Ping

13 PINGRESP Risposta di Ping

14 DISCONNECT Client-to-broker Client disconnesso

15 Riservato Riservato

Tabella 2.2: MQTT message type

Il DUP flag posizionato al terzo bit è usato nei Control Packets PUBLISH e SUBSCRIBE per avvisare quando il broker prova a consegnare un messaggio duplicato. In particolare il flag di Dup viene settato 1 quando il client o il server cercano di re-inviare un publish, pubrel, subscribe o un unsubscribe andato perso o non confermato dal relativo ACK. Questo flag può essere settato esclusivamente per i messaggi che hanno un QoS maggiore di 0, ed è richiesto un acknoledgment. Quando il dup è settato l’header comprende un messaggio ID.

I due bit in prima e seconda posizione nel primo byte dell’header sono utilizzati per indicare il livello di QoS (Quality of Service) tra i tre livelli disponibili nel protocollo MQTT. QoS con livello più alto hanno una maggiore affidabilità nella consegna dei

62

messaggi ma anche un consumo maggiore in termini di banda. I tre livelli di QoS disponibili sono:

0. at most once delivery: offre la stessa affidabilità le livello sottostante TCP e il messaggio può andare perso o essere duplicato, questo si adatta particolarmente bene nei contesti in cui la perdita di un messaggio non è cruciale;

1. at least once delivery: assicura che ogni messaggio sia sempre consegnato, ad ogni modo potrebbe avvenire una doppia consegna del messaggio; 2. exactly once delivery: assicura che ogni messaggio sia sempre consegnato

senza duplicazioni, ideale nei casi in cui niente possa essere perduto o che una doppia consegna dello stesso contenuto sia causa di errori nell’elaborazione delle informazioni.

Il RETAIN flag, posizionato in cima al byte, può essere utilizzato solo nei messaggi PUBLISH inviati dal client al server, e serve per indicare un retained message, ossia un messaggio trattenuto. Se impostato ad 1 su uno specifico topic, il RETAIN flag indica che il messaggio, dopo essere stato inviato ai correnti iscritti, viene trattenuto sul server per poi essere inviato a ogni futuro subscriber di quel topic. Se non ci sono retained message non viene inviato niente. Questo permette ai nuovi sottoscritti al topic di ricevere l’ultimo dato trattenuto dal broker.

Il campo REMAINING LENGTH è un dato memorizzato nel secondo byte che rappresenta il numero di byte rimanenti del messaggio corrente, includendo il payload. I messaggi possono assumere qualsiasi formato, il protocollo MQTT è data-agnostic e la codifica avviene usando un singolo byte per messaggi fino a 127 byte. I messaggi di dimensioni maggiori vengono gestiti con i primi 7 bit di ogni byte che tengono il dato, e l’ottavo bit altri byte seguenti nella rappresentazione, con un limite di 4 byte. MQTT può inoltre disporre di un header variabile, il quale, quando presente, è compreso fra l’header fisso e il payload.

La struttura dell’header variabile è la seguente:

• Protocol name: specifica il nome del protocollo con la codifica UTF, nei messaggi CONNECT;

• Protocol version: specifica la versione del protocollo utilizzato nei messaggi MQTT CONNECT;

• Flag nei messaggi CONNECT: una serie di 8 bit che consentono di specificare la presenza di alcuni parametri di connessione all’interno del messaggio, come

63 di seguito: Bit 7 6 5 4 3 2 1 0 User name flag Password flag Will retain

Will Qos Will

flag

Clean session

Reserved

1. Clean session flag: il broker conserverà le sottoscrizioni dei client dopo la loro disconnessione se è impostato a 0, potendo così ristabilire tutte le sottoscrizioni precedenti alla disconnessione in modo automatico. Oltre alle sottoscrizioni il broker memorizzerà anche i messaggi ricevuti su quel topic dopo la disconnessione per poi recapitarli quando il client sarà nuovamente online;

2. Will flag: quando impostato 1 indica la presenza del messaggio Last Will, dovranno perciò essere presenti anche i flag Will QoS e Will Retain, inoltre il payload deve contenere il Will Topic e il Will Message; Il messaggio “testamento”, attuabile quando un client si connette ad un server informandolo di possedere una specifica Wills, un messaggio da pubblicare su uno o più specifici topic nel caso di disconnessione improvvisa.

3. Will QoS: specifica il livello QoS del Will message;

4. Will retain flag: se questo bit è impostato 1 il broker deve mantenere i messaggi inviati;

5. Username e Password: indica che nel messaggio sono presenti nome utente e password necessari client per autenticarsi;

• Keep alive timer: definisce un intervallo, fino ad un massimo di 18 ore, dopo il quale la connessione del client è considerata persa.

• Connect return code: valore di ritorno di CONNECT in cui con il valore 0 indica una connessione rifiutata per protocollo non compatibile, 1 connessione rifiutata a causa dell’identificatore rifiutato, 2 broker non accessibile, 3 nome utente errato, 4 password errata, 5 autorizzazione negata. Non son attualmente implementati dal 6 al 255;

• Topic name: codificato in UTF e obbligatorio per i messaggi PUBLISH in quanto necessario per identificare il canale dove verrà pubblicato il payload. Il payload è l’effettivo contenuto del messaggio e può arrivare anche ad occupare fino ad un massimo di 256MB. Anche questa porzione di messaggio, come l’header variabile, non è disponibile per tutte le tipologie di messaggi, ma solo per le seguenti:

64

• Publish: contiene informazioni application specific.

• Connect: stringa UTF-8 obbligatoria che identifica il client, ed eventualmente, se presente, Will Topic, Will Message, nome utente e password.

• Subscribe: lista di topic a cui il cliente intende sottoscriversi, specificando per ognuno di essi il livello di QoS.

• Suback: contiene una lista di livelli QoS che il broker consentono di utilizzare.

2.8 Server

Il server è un componente che fornisce funzionalità per i dispositivi clients che ne fanno richiesta attraverso una rete.

Questo componente è composto dall’insieme fisico e logico, realizzato in questo progetto su di un hardware Raspberry PI e su software in grado di svolgere i compiti necessari in modo automatizzato, realizzato con codice scritto ad hoc per il framework Node.js, il quale fa uso della libreria Mosca per gestire il protocollo MQTT e del database MongoDB per archiviare le informazioni raccolte dai singoli dispositivi IoT per la cattura del movimento.

2.8.1 Raspberry Pi

Raspberry Pi è un single-board computer dalle dimensioni ridotte, sviluppato dalla Raspberry Pi Foundation nel Regno Unito. Concepito per l’insegnamento dell’informatica e della programmazione nelle scuole, il primo modello di Raspberry Pi è stato commercializzato all’inizio del 2012 con le versioni A e B al prezzo di $35.

65

Raspberry Pi, nella attuale versione 3, monta un processore quad-core da 1.2GHz a 64-bit con architettura ARMv8 (Advanced RISC Machine) per la quale non è possibile utilizzare i tradizionali sistemi operativi closed-source, come Microsoft Windows o Apple Mac Os, in quanto non compatibili.

Per questo motivo il sistema operativo di Raspberry Pi è basato sull’open-source di GNU/Linux, modificato per adattarlo alle caratteristiche specifiche di questo oggetto. Il sistema operativo che viene consigliato di usare è una versione di Debian ottimizzata per l’hardware del Raspberry Pi: Raspbian (Raspberry Pi + Debian), che offre, insieme al sistema operativo anche un insieme di 35.000 pacchetti precompilati di software da installare. Raspian è stato creato da un insieme di sviluppatori indipendenti dalla Raspberry Pi Foundation ma condividendo degli obiettivi comuni, per migliorare sempre di più le prestazioni di questo dispositivo.

2.8.2 Node.js

Node.js è un’efficiente framework runtime costruito sul motore d’esecuzione JavaScript V8 di Google (impiegato in Chrome) operante nella logica event-driven (programmazione ad eventi). Adatto per la realizzazione di applicazioni di rete scalabili, Node.js utilizza il linguaggio JavaScript fuori dal suo usuale ambiente d’esecuzione; ossia per lo sviluppo di applicazioni web server-side invece del suo tipico utilizzato come scripting client-side.

Node.js ha raggiunto la popolarità in tempi molto brevi, la prima release di Node.js risale al 2009 ed è stata sponsorizzata dalla società californiana Joyent. Attualmente Node.js è disponibile per le principali piattaforme, anche se maggiormente performante su sistemi operativi UNIX-like per i quali è stato sviluppato inizialmente. Il codice scritto per Node.js, essendo quindi interpretato, è portabile e cross-platform sui dispositivi in cui il software è installato. L’elevata portabilità di questo sistema ha inoltre garantito la possibilità di utilizzarlo nel progetto in Raspberry-pi 3.

Node.js gestisce i propri task con un approccio asincrono, accedendo alle risorse del sistema operativo con un modello I/O non-blocking, come lettura e scrittura di file e gestione di connessioni di rete, in modalità event-driven, quindi non sfruttando il classico modello basato su processi o thread concorrenti. Il modello event-driven, gestito a basso livello dal runtime grazie ad un sistema di callback, si basa su una richiesta al sistema operativo di ricevere notifiche al verificarsi di determinati eventi i

66

quali avviano un’azione. Ogni azione svolta risulta quindi asincrona, in cui durante le attese, principalmente dovuta alla latenza del networking, il runtime può gestire qualche altro evento, differenziandosi così dai pattern di programmazione più comuni a thread in cui una azione succede ad un’altra solo dopo che quest’ultima è stata completata.

Figura 2.12: Comparazione tra modello sincrono e asincrono

2.8.3 Mosca

Mosca è una libreria in grado di gestire agevolmente l’uso del protocollo MQTT, che, come descritto in precedenza, è un modello di messaggistica publish/subscribe il quale richiede un broker.

Mosca può essere configurato come servizio broker standalone, oppure per il suo utilizzo embedded in un’applicazione Node.js per il quale funge anche da broker sul server stesso.

Utilizzando Mosca nel secondo modo indicato, gli eventi tipici del data-event del protocollo di MQTT vengono gestiti avviando eventi di programmazione event-driven in Node.js che sono eseguiti nel seguente modo:

// eseguito quando un client si connette

server.on("clientConnected", function(client) {

//...

});

Richiesta dati

da remoto Alert (dato) Altre azioni

Attesa Sincrono:

Richiesta dati

da remoto Alert (dato)

Altre azioni Attesa

67

// eseguito quando un client si disconnette

server.on("clientDisconnected", function(client) {

//...

});

// eseguito quando un messaggio è ricevuto

server.on("published", function(packet, client) {

//...

});

// eseguito quando un client si sottoscrive a un topic

server.on("subscribed", function(topic, client) {

//...

});

// eseguito quando un client si disiscrive da un topic

server.on("unsubscribed", function(topic, client) {

//...

});

Documenti correlati