Réseaux et télécommunications
Fermer ×

Présentation de l'IOT

Définitions et modèle

Définitions

L'internet des Objets ou bien Internet of Things (IOT) est défini comme une infrastructure qui permet d'interconnecter des objets physiques ou virtuels en utilisant les technologies de l'information et de la communication.

Dans cette infrastructure, on définit :

Cette technologie fait l'objet de recommandations définis pat l'ITU-T Y.2060 (06/2012)

Modèle IOT

  • Prise en charge des services et des applications
    • Traitement et stockage
  • Réseau
    • Connexion réseau, contrôle d'accès, authentification
  • Dispositif
    • Interaction avec le réseau, mise en veille
    • Gestion des interfaces de communication et protocoles
  • Capacités de gestion
    • Gestion du fonctionnement, du trafic et des flux de données
    • Activation et désactivation à distance
    • Mise à jour du dispositif
  • Capacités de sécurité
    • Authentification
    • Protection des données

Architectures

Interconnexions

Objets

IOT Longue distance

Les objets sont connectés en utilisant les technologies Sigfox ou LoraWan. Ces réseaux sont disponibles sur tout le territoire et nécessitent un abonnement auprès d'un opérateur. Toutefois la technologie LoraWan peut être déployée indépendamment d'un opérateur car il existe une version libre.

Les antennes sont associées à une station qui assure la gestion des connexions radios et l'interfaçage avec le réseau local (LoraWan) ou internet (Sigfox ou LoraWan).

Les données sont transmises, via un protocole réseau standard, à un serveur associé à une base de données pour le stockage des données des objets connectés.

Les données sont ainsi accessibles par l'intermédiaire d'un serveur web.

IOT local

Les données des capteurs sont envoyées au "broker", via une connexion TCP/IP, en utilisant le protocole MQTT. On parle de publication, ces données sont accessibles au serveur pour le stockage en utilisant une méthode d'abonnement.

Le broker ne stocke généralement pas les données reçues, ce qui signifie que le serveur doit être abonné avant que les données ne soient transmises.

Dans cette configuration, le broker, le serveur ainsi que la base de données peuvent être implémentés sur le même système.

Les données sont également accessibles par l'intermédiaire d'un serveur web.

Utilisation du protocole HTTP

Méthodes utilisées

Les capteurs envoient leurs données à l'aide des méthodes GET ou POST du web. Ces données sont traitées à l'aide d'un script CGI ou fastCGI.

Méthode POST et JSON

Dans le cas de la méthode "POST", les données peuvent être transmises en utilisant le format JSON qui est très utilisé dans les échanges de données sur le web.

Ce format est une suite de paires clé : valeur séparées par des virgules l'ensemble encadré par des accolades :

{ "cle" : valeur, "liste" : [ "cle1" : valeur1 , "cle2" : valeur2 , ... ]  }
		

Les types de données des valeurs peuvent être des nombres, chaînes de caractères, booléens ou encore des listes encadrées par des crochets, pour ce dernier cas, les éléments de la liste sont des paires cle : valeur.

Exemple pour les données d'un capteur de température et humidité :

{ "temperature" : 22.2 , "humidite" : 60 }
		

Utilisation du protocole MQTT

Ce protocole fonctionne par système de publication (publish) et abonnement (suscribe) géré par un serveur : le courtier (broker). Chaque objet, ordinateur, serveur peut s'abonner à un ou plusieurs messages, ces messages peuvent être envoyés par ces mêmes appareils.

Les messages sont hiérarchisés sous la forme d'un arborescence où chaque niveau est séparé du suivant par le caractère "/", comme par exemple :

/maison/piece1/lumiere1

Cela correspond à une source lumineuse lumiere1 de la pièce piece1 de la maison.

Il est possible d'utiliser le caractère joker "+" pour accéder à tous les éléments d'une partie de l'arborescence.

/maison/+/lumiere1

Cela permet d'accéder aux lumiere1 de toutes les pièces.

Base de donnée et langage SQL

Définitions et structure

Une base de données relationnelle est un système de stockage de données organisé en tables. Chaque table est composée de rangées avec chaque rangée composée de colonnes. Chaque colonne est identifiée par un nom (champ). Une rangée est une liste de données.

Dans ce type d'architecture, il est possible d'effectuer des accès par rangée et/ou par colonne à l'aide de filtres. Ces derniers sont définis à partir de règles.

Une structure de donnée complète est structurée en tables reliées à l'aide des valeurs qu'elles contiennent que sont les clés primaires et étrangères. Les clés primaires sont uniques, c'est à dire que deux rangées ne peuvent avoir la même clé. Cette unicité permet d'accéder à une rangée sans ambiguïté.

Il existe plusieurs bases de données, nous citerons, ici, les logiciels libres les plus utilisés

Exemple de base

On propose de créer une base obletsconnectes qui permet de stocker les mesures horodatées de données de capteurs de température, humidité, pression, ...

Ce diagramme a été créé avec MySQL Workbench.

La base est composée de plusieurs tables :

Les tables constructeurs et fournisseurs sont utiles pour la maintenance du système afin de pouvoir accéder aux documents du capteur en cas de panne ou de modification du système.

Cet exemple est basique et ne contient sans doute pas toutes les informations nécessaires et utiles, mais il permet de montrer ce que peut être une base de donnée pour l'internet des objets.

Le langage SQL

Présentation

Le langage SQL (Structured_Query_Language) est le langage qui permet d'accéder aux données de cette base. Il permet de gérer les bases ainsi que les tables de chaque base, les données de chaque table (ajout, suppression, modification), ... On peut également visiter la partie SQL du site w3schools ou encore la documentation SQLite

Le langage sql n'est pas sensible à la casse (majuscule ou minuscule).

Les types de données

Les types de données disponibles peuvent varier en fonction de la base de donnée utilisée. on présente ici un échantillon de ces types :

Les valeurs par défaut des paramètres dépendent des bases de données.

Gestion des bases

Cela n'est pas utilisé avec SQLite, car dans ce cas on utilise un fichier par base.

Gestion des tables

Exemples de code SQL pour la création de la table mesures

CREATE TABLE mesures ( 
	idmesure INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
	date datetime NOT NULL,
	valeur FLOAT NOT NULL, 
	idobjet INT(11) NOT NULL ,
	FOREIGN KEY (idobjet) REFERENCES objets (idobjet)
);
		

La table mesure comprend une clé primaire idmesure qui est incrementée à chaque ajout de rangée

valeur correspond à la valeur fournie par le capteur représenté par idobjet à la date enregistrée dans date

idobjet est une clé étrangère vers la clé primaire de la table objets

Utilisation de SQLite en C

On utilise la librairie sqlite, il faut inclure le fichier de définitions sqlite3.h et ajouter sqlite3 à l'édition de lien.

L'accès à la base en appliquant les étapes suivantes :

  1. Ouverture avec sqlite3_open(fichierbase,fd_sql) avec fichierbase qui est le fichier représentant la base de données, et fd_sql qui est l'adresse d'un pointeur vers une variable de type sqlite3, la valeur de retour est un code d'erreur qui vaut SQLITE_OK si tout s'est bien passé
  2. Requête SQL avec sqlite3_exec(sql_fd, requete_sql, traitementresultat, 0, &erreursMSG) avec sql_fd qui est un pointeur vers la structure sqlite3, requete_sql qui est une chaîne de caractères qui contient la requête sql, traitementresultat qui pointe vers une fonction qui traite les résultats de la requête si cela est nécessaire, et erreurMSG qui contient le message d'erreur si celui-ci existe; la valeur de retour est un code d'erreur qui vaut SQLITE_OK si tout s'est bien passé
  3. Fermeture avec sqlite3_close(sql_fd) avec sql_fd qui est un pointeur vers la structure sqlite3

Exemple d'utilisation de la base

Le programme permet uniquement d'ajouter des mesures à la table mesures et de lire son contenu.

Voir le code des fonctions de gestions de la table mesures

Fichier basecapteurs.h

#ifndef __BASECAPTEURS_H
#define __BASECAPTEURS_H

#include <sqlite3.h>


typedef struct sMesure {
	char dateheure[30] ;
	float valeur;
	int idobjet;
} t_mesure;

typedef t_mesure * ptr_mesure;

char *datemaintenant(char *);
int ajouteDonnees(sqlite3 *,t_mesure );
int lireDonnees(sqlite3 *,int (*)(void*,int,char**,char**));

#endif
					

La fonction datemaintenant retourne la date courante sous la forme d'une chaîne de caractères compatible avec le format datetime de la base de données.

La fonction ajouteDonnees ajoute une mesure à la table mesures en utilisant la requête sql insert.

La fonction LireDonnees effectue la lecture complète de la table mesure, le traitement du résultat est confié à la fonction transmise en paramètres.

Fichier basecapteurs.c

#include <time.h>
#include <stdlib.h>
#include <stdio.h>
#include "basecapteurs.h"

char *datemaintenant(char *dateheure) {
	time_t temps ;
	struct tm *sdateheure;
	temps= time(NULL);
	sdateheure = localtime(&temps);
	strftime(dateheure,30,"%Y-%m-%d %H:%M:%S",sdateheure);	
	return dateheure;
} 

int ajouteDonnees(sqlite3 *sql_fd,t_mesure mesure) {
	char sql[1024];
	char *erreursMSG;
	sprintf(sql,"insert into mesures (date,valeur,idobjet) values  ( \"%s\" , %.2f , %d );",mesure.dateheure,mesure.valeur,mesure.idobjet);
	int erreur = sqlite3_exec(sql_fd, sql, NULL, 0, &erreursMSG);
	if (erreur != SQLITE_OK) {
		fprintf(stderr,"Erreur %d %s\n",erreur,erreursMSG);
		sqlite3_free(erreursMSG);
	}
	return erreur;
}

int lireDonnees(sqlite3 *sql_fd,int (*traiteresultat)(void*,int,char**,char**)) {
	char *erreursMSG;
	int erreur = sqlite3_exec(sql_fd, "select * from mesures", traiteresultat, 0, &erreursMSG);	
	if (erreur != SQLITE_OK) {
		fprintf(stderr,"Erreur %d %s\n",erreur,erreursMSG);
		sqlite3_free(erreursMSG);
	}
	return erreur;
}
					
Voir le programme de test de ces fonctions de traitement

Fichier testcapteurs.c

#include <stdlib.h>
#include <stdio.h>
#include <sqlite3.h>
#include "basecapteurs.h"

static int  traitement(void *NonUtilise, int nbcols, char **colonne, char **NomCol) {
   for(int i = 0; i<nbcols; i++) {
      printf("%s = %s\n", NomCol[i], colonne[i] ? colonne[i] : "NULL");
   }
   printf("\n");
   return 0;
}

int main(int argc, char **argv) {
	sqlite3 *sql_fd;
	t_mesure mesure;
	int erreur ;
	erreur = sqlite3_open("objetsconnectes.db",&sql_fd);
	if( erreur ) {
		fprintf(stderr,"Erreur %d\n",erreur);
		return EXIT_FAILURE;
	}
	if (argc != 6) {
		erreur = lireDonnees(sql_fd,traitement);
		if (erreur != SQLITE_OK) {
			return EXIT_FAILURE;
		}
	}
	else {
		printf("ajout de mesures\n");
		datemaintenant(mesure.dateheure);
		for(int i=0;i<5;i+=1) {
			mesure.valeur = strtof(argv[i+1],NULL);
			mesure.idobjet = i+1;
			printf("ajoute mesure %f pour l'objet %d\n",mesure.valeur,mesure.idobjet);
			erreur = ajouteDonnees(sql_fd,mesure);
			if (erreur != SQLITE_OK) {
				return EXIT_FAILURE;
			}
		}
	}
	sqlite3_close(sql_fd);
	return EXIT_SUCCESS;
}
					

Le programme de test affiche le contenu de la table mesures ou bien ajoute les valeurs des 5 valeurs des capteurs qui sont : la température,l'humidité, la pression, la luminosité,la valeur des UVs.

Ces 5 valeurs correspondent aux 5 objets de la table objets.

Utilisation de SQLite en python

On utilise la librairie sqlite3

L'accès à la base en appliquant les étapes suivantes :

  1. Connexion à la base avec sqlite3.connect(fichierbase) qui retourne un objet objetconnexion qui sera utilisé par les autres fonctions
  2. objetconnexion.cursor() qui retourne un objet cursor qui permet d'effectuer les requêtes sql
  3. objetcurseur.execute(sql) qui exécute la requête sql, et retourne un objet dont le type dépend du résultat attendu.
  4. objetcurseur.close() libère l'objet cursor
  5. objetconnexion.commit() qui termine les requêtes en attente, il n'est pas nécessaire si l'option autocommit est activée.
  6. objetconnexion.close() libère l'objet connection

Exemple d'utilisation de la base

Le programme permet uniquement d'ajouter des mesures à la table mesures et de lire son contenu.

Voir le code des fonctions de gestions de la table mesures

Fichier basecapteurs.py

import sqlite3
from datetime import datetime

def afficheresultats(resultats):
	for rangee in resultats:
		ligne = ""
		for colonne in rangee:
			ligne = ligne + "\t" + str(colonne)
		print(ligne)

def main(args):
	connexiondb = sqlite3.connect("objetsconnectes.db")
	curseur = connexiondb.cursor()
	nbargs = len(args)
	if nbargs != 6 :
		res=curseur.execute("select * from mesures")
		resultats = res.fetchall()
		afficheresultats(resultats)
	else:
		date = datetime.now()
		chdate = date.strftime("%Y-%m-%d %H:%M:%S")
		for i in range(5):
			valeur=args[i+1]
			idobjet = i + 1
			sql = f"insert into mesures ( date, valeur , idobjet ) values ( \"{chdate}\" , {valeur} , {idobjet} )"
			curseur.execute(sql)
	curseur.close()
	connexiondb.commit()
	connexiondb.close()
	return 0

if __name__ == '__main__':
    import sys
    sys.exit(main(sys.argv))
					

Comme pour le programme C si on transmets 5 paramètres on ajoute ces valeurs dans la table mesures, sinon on lite le contenu de la table mesures.

Lors de la lecture l'objet retourné est une liste de liste. On construit une chaîne de caractères par ligne, que l'on affiche ensuite.

Utilisation d'un serveur dédié : Domoticz

Description

Dédié à la domotique, Domoticz est un serveur HTTP, une base de données, un client MQTT, le tout administré à distance à l'aide d'une interface web.Il est multiplate-forme (linux,windows, raspberry pi).

La connexion distante se fait avec l'URL http://ip:port/, où l'ip est l'adresse IP de la machine sur laquelle est installée la machine et le numéro de port est 8080 pour le protocole http. Il est également possible d'utiliser le protocole HTTPS avec le numéro de port 443 à condition qu'il n'y ait pas d'autre serveur web sur la machine qui utilise déjà ce port. De plus le port 443 n'est utilisable qu'en mode root. Il est également possible de modifier le numéro de port HTTPS.

On peut modifier ces paramètres au lancement de domoticz :
${ROOTDOMOTICZ}/domoticz -sslwww nouveauport -sslcert ${ROOTDOMOTICZ}/server_cert.pem
avec ROOTDOMOTICZ qui contient le chemin de l'installation de domoticz.

Le premier accès se fait en mode administrateur avec le login et mot de passe par défaut, fournis sur le site de domoticz.

La première étape consiste à choisir la langue et saisir les coordonnées GPS. Ensuite il faut créer un utilisateur qui sera utilisé par les objets distants pour transmettre les données, mais également pour accéder aux données des capteurs.

Ensuite il faut ajouter un utilisateur qui sera utilisé par les objets qui transmettent les données, et pour accéder aux données sans utiliser le mode administrateur. Cela se fait avec le menu configuration->users : saisir un nom, un mot de passe, les droits utilisateurs puis ajouter.

Maintenant le système est prêt pour l'enregistrement des capteurs et actionneurs. On peut, par exemple, choisir une interface matérielle de type Dummy puis lui ajouter des capteurs virtuels (température, humidité, ...).

Transmission des données

La transmission des données se fait avec une URL HTTP qui, pour un capteur, est de la forme :

https://ip:port/json.htm?type=command&param=udevice&idx=numero&nvalue=nombre&svalue=chaine
avec

La réponse se fait au format JSON (présenté en début de cette page), quand tout s'est bien passe elle est

{
	"status": "OK",
	"title": "Update Device"
}
		

Utilisation de MQTT

Ce logiciel permet d'utiliser MQTT en souscrivant, par exemple, un abonnement auprès du serveur MQTT. Pour cela il faut ajouter un matériel MQTT Client Gateway with LAN interface, l'arborescence par défaut est domoticz/in pour les données entrantes (capteurs). Il faut également préciser l'adresse disante qui peut être localhost si les serveurs MQTT et Domoticz sont situés sur la même machine.