Smart Sensor WiFi

De Wiki de Projets IMA
Révision datée du 12 avril 2014 à 10:00 par Tmaurice (discussion | contributions) (Prise en main de la carte avec minicom et pyserialcom)

Informations générales

Page de wiki du projet Smart Sensor WiFi

Étudiants Thomas Maurice et Benoit Maliar

Tuteurs Alexandre Boé et Thomas Vantroys

Les fichiers sources du projet sont disponibles via Git.

Liste du matériel nécessaire

Liste non exhaustive, pourra être modifiée !

Désignation Quantité Référence Prix Disponible en salle de projet
Shield WiFi TEL 0047 1 GoTronic 83€ Nope nope nope Alexandre : il doit y avoir un équivalent, voir Thomas T.M: Yep mais c'est celui là qu'il faut
Module WiFi WizFi210 1 Lextronic 30€ Nope
Quartz 32.768kHz 2 Lextronic 1.15€ Nope
Capteur de présence infrarouge 1 Lextronic 7.92€ Nope
Photorésistance ~2-3 - quelques € Nope - je verrai au magasin de l'école
ATMega328p 1 pour le proto Magasin de l'école quelques € Nope - je verrai au magasin de l'école
Cristal 16MHz 1 pour le proto Lextronic 1.40€ Nope
Capa 22pF pour le quartz 2 Magasin de l'école quelques € Nope - je verrai au magasin de l'école
Des résistances  ? Magasin de l'école quelques m€ Yep

Énoncé initial du projet

L'objectif du projet consiste en la conception et la réalisation de capteurs autonomes communiquant en WiFi afin de pouvoir remonter régulièrement des informations sur l'état des salles de cours. Les capteurs seront par exemple des détecteurs de lumières, de pression, de qualité de l'air, ...

La communication sera obligatoirement réalisée en WiFi sur le réseau de l'université en respectant les contraintes de sécurité (WPA2, ...).

Deux options sont possibles :

  • Refaire complètement une carte avec un microcontroleur et une puce wifi (comme par exemple les spark)
  • Réaliser un shield pour raspberry pi contenant les différents capteurs.

Analyse du sujet

On a ici affaire à un réseau de capteurs reliés à une base de donnée centrale accessible depuis un navigateur Internet qui est chargée de recevoir les données des différents capteurs de manière à pouvoir présenter à un utilisateur un état des différentes pièces dans lesquelles on aura disposé les capteurs. Cela peut notamment impliquer :

  • Un accès à ces données via une interface web
  • Un accès à ces données via une application mobile

On identifie donc deux parties au projet :

  • La partie capteur
  • La partie serveur

Cahier des charges

Spécifications des capteurs

Les caractéristiques souhaitées pour les capteurs sont :

  • Être capable de mesurer l'environnement dans lequel évolue le capteur (Pression, température, lumière, présence, ouverture de porte...)
  • Contacter le serveur via le WiFi pour actualiser la base. Alexandre : ce qui implique la prise en compte de la sécurité type WPA2
  • Éventuellement, être reconfigurable à distance (via un serveur web embarqué dans le microcontrôleur)
  • Être capable de gérer sa consommation d'énergie.
  • Agir en temps que datalogger si le réseau n'est pas accessible.

Spécifications du serveur

Les caractéristiques souhaitées pour le serveur sont :

  • Être capable de contacter ou d'être contacté par les capteurs via le réseau.
  • Respecter les contraintes de sécurité (WPA2)
  • Être capable d'authentifier les clients
  • Stocker les données reçues dans une base de données et éventuellement faire des calculs et des statistiques sur ces données.
  • Présenter sous format compréhensibles les données au client (web ou appli)
  • Vérifier l'état des capteurs et notifier un responsable en cas d'anomalie (déconnexion du réseau, valeur anormale d'un capteur...)

Propositions de solutions technologiques

Les capteurs

Nous proposons de réaliser une carte basée sur un ATmega328 dans lequel on pourra flasher du code Arduino. Pour gérer le WiFi, nous proposons une solution utilisant le shield TEL 0047 de Wiznet utilisant la puce WiFi WizFi210.

Cette puce gère le WPA2-PEAP mais malheureusement pas dans son firmware natif. Il va donc falloir s'arranger avec Wiznet pour obtenir le firmware qui nous permettra de faire de l'EAP.

Dans un premier temps, on se concentrera sur la mise en place d'un prototype fonctionnel a base d'un simple capteur de température. On étendra ensuite les capacités de la chose à des capteurs peut être plus complexes style I2C ou SPI.

Pour la reconfiguration du capteur, on le fera via un serveur web embarqué dans le microcontrôleur.

Le serveur

On propose une solution à base d'une machine sous Linux hébergeant un serveur MySQL et PHP.

Le SGBD utilisé sera MySQL.

La partie web du serveur destinée à présenter à l'utilisateur une vue des données serait développée en PHP/HTML5/CSS3. Les capteurs enverront les données sous forme JSON au serveur web qui se chargera du traitement.

Travail à effectuer dans un premier temps

Pour la partie BDD/Web

  • Structurer les tables dans un diagramme UML qui va bien
  • Déterminer une architecture de site (MVC)
  • Traiter les données envoyées par les capteurs au format JSON
  • Incorporer une interface admin
  • Faire un design swag

Pour les capteurs

Avant la réception du matos WiFi:

  • Réaliser la lecture d'une température et la formater en JSON Quasiment fait, on peut lire sur les ADC, le formattage n'est qu'une formalité
  • L'envoyer sur un port série à interval régulier Pareil mes routines d'envoi de strings sont écrites
  • Parser et répondre à des requêtes HTTP sur le port série Fait, mais en série, pas encore adapté au wifi
  • Faire fonctionner une RTC pour agir en tant que datalogger En cours mais il manque l'interface avec la carte SD

Après réception du matos WiFi:

  • Envoyer les requêtes JSON directement en POST au serveur Web
  • Traiter les requêtes client
  • Adapter une nouvelle carte avec juste la puce WiFi

Partie capteurs

Principe

Le principe est de réaliser des capteurs qui s'interfaceront avec l'application web de Benoit. Pour celà deux solutions ont été explorées durant le projet

  • Une solution a base d'Arduino
  • Une solution à base de RaspberryPi

Finalement la solution la plus avancée a été celle à base d'Arduino. Notons que je ne me suis pas penchés sur tout ce qui est considération d'intégration et de contraintes énérgétiques. Le but premier que je me sommes fixé était de fournir un prototype qui marche et qui peut facilement être alélioré par quiconque en aurait envie.

Organisation pratique et documentation

Tout le travail que nous avons fourni est disponible dans le dépôt git que nous avons mis en place dès les premières semaines du projet et dont le lien est le suivant : celui là, là. Pour effectuer un clone :

   git clone git://svartbergtroll.fr/smartsensor.git

La documentation a été un travail très important pour moi dans la mesure ou TOUT le code de la partie Arduino du projet a été richement documentée via Doxygen. Ainsi il est très facile de comprendre comment le capteur interragit avec ses ADC/ports série/spi ou autre simplement en lisant la doc mise à disposition.

Les documentations suivantes sont disponibles :

Point sur la partie capteurs au 28 février 2014

Shield Arduino avec la RTC et photo-résistance

Ce qui a été fait

  • L'appareil peut lire l'ADC câblé sur une photodiode et un capteur de température et convertir ça en chaine pour l'envoyer.
  • Stocker des infos de config en EEPROM et y accéder sur demande.
  • Il peut envoyer des choses au monde extérieur sur le port série et en lire.
  • Il gère quasiment parfaitement l'horloge temps réelle DS1302 (aux burst-modes près, mais c'est pas indispensable pour le moment).
  • L'intégralité du code est documenté, fonction par fonction et une doc au format Doxygen est générable.
  • Le PCB est en cours de création sous Eagle.

Ce qui ne sera pas fait

  • L'interface avec une carte SD, puisque on a opté pour une mémoire Flash.

Ce qui est en train d'être repensé mais qui doit être discuté avec les enseignants

  • Implanter un serveur Web dans l'atmega328p. Je doute que ça soit pertinent d'un point de vue énergétique, dans la mesure ou l'appareil devra être up H24 si on veut faire ça. Je pense qu'il est plus malin d'enregister les changements de config à faire dans la BDD et de les comitter au senseur dans la page de réponse qui suivra sa mise à jour des données de température/lumière. L'avantage est double, on a des écolomies d'énergies, et un cout de traitement moindre dans la mesure ou on peut déterminer le format de la chaine de màj et de le faire simple, au lieu de parser l'intégralité d'une requête HTTP.
  • Je pense qu'il est intéressant d'implanter un mode de "config initiale" par le port série pour qu'on puisse mettre manuellement les infos du capteur avant le permier déploiement (de toutes façons il faut bien entrer une conf initiale) quitte à le vérouiller logiciellement (via un bit en EEPROM par exemple) lorsqu'on en a fini avec lui. De cette manière il ne sera plus reprogrammable que par le serveur de BDD ou par un re-flashage de l'EEPROM.

Point sur la partie capteur à la mi mars

Schematic Réalisé pour la Raspberry Pi
PCB Réalisé pour la Raspberry Pi

Développement d'une solution alternative à base de RaspberryPi

Comme la carte WizFi tardait à arriver, j'ai pensé opter pour une solution alternative pour réaliser le capteur, à base d'une RaspberryPi. Certes la solution était un peu overkill pour ce que l'on voulait en faire, mais comme cela on aurait eu quelque chose de fonctionnel à montrer lors de la soutenance. L'idée était d'utiliser les GPIO de la Raspberry pour l'interfacer avec le monde exterieur.

Malheureusement la RaspberryPi est un appareil qui ne dispose pas d'entrées analogique, ce qui est assez peu pratique pour lire une température ou une luminosité de la même manière que sur un ATmega. Nous avons donc du recourir à un ADC externe fonctionnant suivant le protocole SPI, ce qui tombait plutôt bien puisque la Raspberry est équipée d'une inetrface SPI lui permettant de contrôler jusqu'à deux esclaves. Pour notre problème nous avons opté pour l'ADC MCP3208 de MicroChip. Pourquoi celui là ? Tout simplement parce qu'il dispose de huit canaux analogiques ce qui permet une grande variété de capteurs, mais également parce qu'il peut fonctionner en 3v3, tension à laquelle fonctionne également la Raspberry, comme ça on évite de la griller.

J'ai donc réalisé une carte et un PCB pour réaliser cette alternative, mais également la couche logicielle qui va avec. J'ai en effet développé une classe en C++ qui encapsule tout les appels systèmes permettant d'écrire et de lire sur le port SPI de la raspberry, en full duplex. J'ai en réalité réalisé deux classes, une classe SPI qui est la classe mère, comprenant seulement les routines d'initialisation et d'écriture du port SPI, et une SPI_MCP3208 qui comprend les commandes spécifiées dans la datasheet du composant.

Pour info, cette classe et le programme d'exemple sont disponibles sur GitHub et la documentation est disponible

Le problème parce qu'évidemment il y en a eu un, était que les données renvoyées par l'ADC étaient totalement hors sujet. Le fait est qu'à luminosité égale, si je lançais 10 acquisitions je pouvais obtenir des écarts de plus de 3000 (sur 4095 d'amplitude) entre deux valeurs, quand bien même la luminosité ne variait pas. Le plus déroutant dans tout ça c'est que le problème n'avait pas l'air de venir de mon logiciel, dans la mesure ou j'étais parfaitement capable, avec la même couche logicielle, de piloter d'autre appareils SPI fonctionnant en esclave (comme un afficheur 4x7 segments de chez SparkFun par exemple). La seconde chose la plus dérourante était que les données étaient cohérentes du point de vue du fonctionnement du composant tel que décris dans la datasheet. Je m'explique, une trame classique de communication avec l'ADC se compose comme il suit (schématiquement) :

   4 bits de commande | deux bits de sample | 12 bits de résultat MSB first

Le fait est que d'après la datasheet en continuant à envoyer des coups d'horloge au composant après le dernier bit de donnée, le composant va nous renvoyer le resultat de la conversion mais LSB first. On récupère donc le symétrique des données par rapport au LSB. Après avoir analysé plusieurs séquences j'ai pu constater que l'erreur ne venait pas de comment je récupérais mes données puisqu'elles étaient correctes du point de vue de la datasheet mais totalement abérantes d'un point de vue physique.

L'erreur ne venait pas non plus du hardware puisqu'un rapide coup d'oeuil à l'oscilloscope m'a permis de constater que ma tension sur la patte de l'ADC évoluait bien comme elle le devait. Le mystère est resté entier puisqu'après nous avons reçus la carte WizFi et nous avons pu commencer à travailler dessus, cette solution a donc été abandonnée. Cela dit, j'avais déjà commencé à réfléchir aux technologies aue j'aurais pu mettre en place pour réaliser la solution, qui auraient été :

  • Un programme de lecture des données appelé par cron à intervalle régulier (un bête script bash qui lit le port SPI et conditionne les données en POST par exemple pour les envoyer au site de Benoît)
  • Une application Web similaire à celle de Benoît mais ne concernant que les données locales de l'appareil, qui aurait permis de modifier les paramètres de mises à jour/sécurité tout simplement depuis un navigateur. J'avais penser à la réaliser en Python avec CherryPy un excellent framework python très léger, et évidemment Ink pour le design.

Partie Arduino

La partie Arduino n'a pas beaucoup évolué entre temps, dans la mesure ou le gros du travail avait déjà été fait en amont. Le driver de la RTC a cependant été enrichi de quelques fonctions supplémentaires de manière à pouvoir lire/écrire l'heure plus facilement dans la puce.

Un choix important a également été fait, il a été choisi d'abandonner l'envoi des données en JSON à l'appli web de benoit au profit de données POST, bien plus faciles à envoyer et à mettre en forme.


Découverte de la carte WizFi210

Prise en main de la carte avec minicom et pyserialcom

Dialogue avec Pyserialcom - Lecture de la même chaine avec deux modes d'affichage différents

Les premiers contacts avec la carte WizFi210 n'ont pas été faciles, en effet elle nous avait été décrite comme une carte SPI et UART. Du coup j'ai pensé tout d'abord l'interfacer avec le port SPI, comme ça je gardais mon port série pour tout ce qui était débug et autres mais malheureusement en parcourant la datasheet je me suis apperçu que différents firmwares existaient, un SPI, un UART et d'autres "Entreprises" qui contenaient par exemple le support de SSL, sans que rien n'indique quel firmware était présent dans la puce.

Cette erreur m'a bien fait perdre quatre heures de développement pendant lesquelles je me suis acharné sur un port SPI muet. Après celà, il a fallu comprendre comment fonctionnait la carte. Armé de mon fidèle minicom et de la datasheet j'ai donc commencé à essayer de configurer "à la main" la carte dans le but de réaliser une authentification sur un réseau (en l'occurrence le réseau WEP de chez moi (oui je sais le WEP caymal)) et de lancer des pings. Pinger google a été une grande victoire.

J'ai fini par comprendre comment fonctionnait la carte, j'ai donc pu commencer à implémenter la pile qui allait bien dans le microcontrôleur, les routines étaient très faciles à écrire une fois qu'on avait compris quelle commande correspondait à quel mode d'authentification, ce qui n'était pas toujours très bien documenté dans la datasheet.

Les choses se sont complexifiées quand j'ai voulu faire en sorte que le microcontrôleur sache si oui ou non la commande s'est bien déroulée, comme la carte envoyait beaucoup de caractères "invisibles" pour minicom il n'était pas toujours facile de savoir ce qu'envoyer la carte. Pour cela il a donc fallu que je reprenne et améliore un des anciens outils que j'avais développé pour un projet personnel : pyserialcom qui est en fait un logiciel de dialogue avec le port série, qui permet d'afficher la valeur hexa de chaque caractère reçu, de cette manière je pouvais voir précisément ce que m'envoyait la carte, ceci s'est révélé très pratique quand elle passait sans aucune raison apparente en "Data mode" et que je ne voyais purement et simplement plus ce qu'elle envoyait.

Envoi des données au serveur

Une fois la carte configurée et connectée aux internetz, il a fallu envoyer des données de mise à jour au site de Benoit. Nous avions au départ pensé à faire ça via post en JSON, simplement ça aurait été trop long et gourmand à mettre en place niveau mémoire (les données post doivent avoir une longueur définie et il faut encoder les caractères "{:," qui sont très utilisées dans une chaine JSON ce qui aurait rendu l'envoi des données affreuse). Du coup nous avons opté pour un format d'envoi en post tout simple. Voici par exemple la requete POST que le capteur "cap1" doté du mot de passe "coucoutuveuxvoirmadata" aurait envoyé :

   POST /recup.php HTTP/1.0
   Host: smartsensorwifi.plil.net
   Content-type: application/x-www-form-urlencoded
   Content-length: 100
   
   temp=140&lum=17&mid=cap1&mpass=coucoutuveuxvoirmadata

Malheureusement, a cause du fait que le firmware gratuit ne fournisse pas la possibilité d'utiliser SSL les données circulent en clair entre le serveur et le capteur. Elle ne seront chiffées qu'au niveau de la couche Wifi de la communication.

Bilan à la fin du projet & améliorations possibles

Voilà ce à quoi ressemble le capteur final

Le hardware

A la fin du projet, nous avons réalisé un prototype fonctionnel de ce que pourrait être le capteur. Il est important de noter que nous n'avons pas cherché à intégrer la solution mais plutôt à la développer en terme de fonctionnalités. De ce fait le prototype est assez volumineux mais sa taille peut aisément être réduite en utilisant des solutions à base de composants CMS notemment ce qui permettrait de réduire de manière significative l'encombrement de l'appareil.

Le prototype final se compose donc de trois éléments principaux. Le coeur du système est réalisé avec un Arduino Uno. Une platine de développement sur microcontrôleur basée sur un ATmega328P de chez Atmel. C'est dans cet Arduino qu'est flashé le programme du capteur. Vient en suite la partie qui prend en charge le WiFi, il s'agit d'un shield WiFi de chez GoTronic basée sur la puce WizFi210 de WizNet, cette dernière est interfacée avec l'Arduino via le port série. Enfin la dernière partie est un protoshield sur lequel est placé une breadboard sur laquelle sont enfichés les composants avec lesquels l'Arduino peut intéragir, à savoir :

  • Une photorésistance pour capter la luminosité
  • Un capteur TMP36 de température
  • Une RTC (Real Time Clock) DS1302

Notons que nous avons choisi ces capteurs pour leur facilité d'utilisation, mais dans l'absolu rien n'empêche d'utiliser n'importe quel autre capteur analogique ou TOR, ni même d'interfacer le système avec des choses plus complexes à base de SPI ou d'I2C, étant donné que l'ATmega328P en a la possibilité.

Le principe de fonctionnement du capteur est très simple. Une fois configuré à l'aide de configurator il vous suffit de déployer le capteur là où vous souhaitez qu'il opère et le laisser envoyer des mesures à interval d'une minute. On dispose ainsi d'un suivi efficace de l'environnement. Aussitôt que l'appareil est mis sous tension il va essayer de se connecter au réseau qui lui a été spécifié en configuration et une fois que cela s'est fait proprement il va passer en mode interruptif et enverra ses mises à jour toutes les minutes. Il faut aussi noter que pendant ce temps là, le capteur écoutera les connexions entrantes sur le port 80 et pourra ainsi être reconfiguré par ce biais à l'aide d'un set de commandes AT.

Le software

La partie logicielle du projet est découpée en deux parties. La première consiste en le firmware que nous avons chargé dans l'Arduino, et qui est chargé de gérer la carte WiFi et les différents capteurs.

La seconde partie consiste en un logiciel de configuration écrit spécialement pour ce projet, il s'agit de configurator. C'est un script en python qui permet via une interface graphique plutôt intuitive de configurer un capteur, et ce que ça soit par le port série d'un capteur directement relié au PC en USB ou via le réseau en utilisant une socket TCP.

Partie Web/BDD

Langages et méthodes utilisées

  • HTML 5, CSS3, PHP 5, Javascript
  • PDO (interface d'accès aux bases de données) [1]
  • INK (CSS framework)
  • Chart.js (script javascript de création de graphique)

Point sur la partie BDD/Web au 28 février 2014

  • Prise en main d'INK (framework css : [2] ). Justification d'utilisation :
    • Design visuellement beau (subjectif)
    • Simple d'utilisation une fois assimilé
  • La base de données est constituée de 2 tables : une pour gérer les utilisateurs qui se connecteront à la plateforme de monitoring et l'autre pour stocker les données des capteurs.
  • Le site se compose à cette date de 2 onglets : l'un est l'index où l'on peut voir les dernières mises à jour des capteurs et l'autre permet de chercher un capteur en particulier et d'en afficher les informations.

Point sur la partie BDD/Web mi-mars

  • La base de données contient désormais 3 tables :
    • L'une contient toujours les utilisateurs de la plateforme
    • La seconde contient désormais la liste des capteurs déclarés
    • La dernières contient les données des capteurs.
  • Le site a été amélioré :
    • Au niveau de la recherche, on affiche toujours les informations du capteur sélectionné mais on projette d'implanter un graphique des données (Utilisation de Chart.js)
    • On peut désormais déclarer et supprimer un capteur de la base. Seul les capteurs déclarés peuvent stocker leurs données dans la BDD.
    • Panel d'administration : Ajout et suppression d'utilisateur de la plateforme. Vidage de la table des données possible.
  • Modification des mises à jour dans la base de données : précédemment, on récupérait les données envoyées par l'Arduino sous format JSON. On a décidé finalement d'envoyer les données en POST (simple optimisation mémoire de l'arduino, le JSON prenait un tout petit peu plus de place)

Point sur la partie BDD/Web début avril

  • La base de données n'a pas changé depuis la dernière fois.
  • La plateforme Web a été améliorée :
    • Deux graphiques ont été incorporés suite à la recherche d'information sur un capteur. On peut désormais voir l'évolution des 10 dernières mesures de température et de luminosité du capteur sélectionné.
    • La partie d'administration permet désormais d'obtenir un suivi des mises à jour des capteurs. On y voit désormais un résumé des capteurs (ratio et liste) n'ayant pas communiqué leurs informations à H+1 (ou plus).

Requêtes sur la base

  • Requêtes de création :
    • Table 'captors' :
 CREATE TABLE IF NOT EXISTS `captors` (
   `id` int(255) NOT NULL,
   `temp` float NOT NULL,
   `lum` int(255) NOT NULL,
   `timestamp` timestamp NOT NULL default CURRENT_TIMESTAMP on update CURRENT_TIMESTAMP
 ) ENGINE=MyISAM DEFAULT CHARSET=latin1;
    • Table 'data' :
 CREATE TABLE IF NOT EXISTS `data` (
   `id` int(255) NOT NULL auto_increment,
   `password` text character set utf8 NOT NULL,
   `name` varchar(255) character set utf8 NOT NULL,
   `timestamp` timestamp NOT NULL default CURRENT_TIMESTAMP on update CURRENT_TIMESTAMP,
   PRIMARY KEY  (`id`)
 ) ENGINE=InnoDB  DEFAULT CHARSET=utf8 COLLATE=utf8_bin AUTO_INCREMENT=0;
    • Table 'users' :
 CREATE TABLE IF NOT EXISTS `users` (
   `login` varchar(255) character set utf8 NOT NULL,
   `password` varchar(255) character set utf8 NOT NULL,
   UNIQUE KEY `name` (`login`)
 ) ENGINE=MyISAM DEFAULT CHARSET=latin1;
  • Requêtes d'insertion (préparées avec PDO)

Exemple

  INSERT INTO captors(temp,lum,timestamp,id) VALUES(?,?,?,?)

Les '?' sont à remplacer par les variables PHP contenant les valeurs à mettre à jour

  • Requêtes d'update (préparées avec PDO)

Exemple

 UPDATE data SET timestamp=? WHERE id=?
  • Requêtes de suppression (préparées avec PDO)

Exemple

 DELETE  captors FROM captors WHERE timestamp  <  ?


Visuel de la plateforme