Smart Sensor WiFi : Différence entre versions
(→Analyse du sujet) |
|||
(66 révisions intermédiaires par 4 utilisateurs non affichées) | |||
Ligne 1 : | Ligne 1 : | ||
+ | <include nopre noesc src="/home/pedago/pimasc/include/video-SmartSensorWiFi-iframe.html" /> | ||
+ | __TOC__ | ||
+ | <br style="clear: both;"> | ||
== Informations générales == | == Informations générales == | ||
Ligne 7 : | Ligne 10 : | ||
Tuteurs ''Alexandre Boé et Thomas Vantroys'' | Tuteurs ''Alexandre Boé et Thomas Vantroys'' | ||
− | Les fichiers sources du projet sont disponibles [http://git.svartbergtroll.fr/smartsensor.git via Git]. ''Alexandre : | + | Les fichiers sources du projet sont disponibles [http://git.svartbergtroll.fr/smartsensor.git via Git]. |
+ | |||
+ | == Liste du matériel nécessaire == | ||
+ | |||
+ | '''Liste non exhaustive, pourra être modifiée !''' | ||
+ | |||
+ | <table border="1"> | ||
+ | <th>Désignation</th> | ||
+ | <th>Quantité</th> | ||
+ | <th>Référence</th> | ||
+ | <th>Prix</th> | ||
+ | <th>Disponible en salle de projet</th> | ||
+ | |||
+ | <tr> | ||
+ | <td>Shield WiFi TEL 0047</td> | ||
+ | <td>1</td> | ||
+ | <td>[http://www.gotronic.fr/art-module-wifi-shield-tel0047-19392.htm GoTronic]</td> | ||
+ | <td>83€</td> | ||
+ | <td>Nope nope nope ''Alexandre : il doit y avoir un équivalent, voir Thomas'' ''T.M: Yep mais c'est celui là qu'il faut''</td> | ||
+ | </tr> | ||
+ | <tr> | ||
+ | <td>Module WiFi WizFi210</td> | ||
+ | <td>1</td> | ||
+ | <td>[http://www.lextronic.fr/P26882-module-wlan-wizfi210-ca.html Lextronic]</td> | ||
+ | <td>30€</td> | ||
+ | <td>Nope</td> | ||
+ | </tr> | ||
+ | <tr> | ||
+ | <td>Quartz 32.768kHz</td> | ||
+ | <td>2</td> | ||
+ | <td>[http://www.lextronic.fr/P6488-quartz-32768-khz.html Lextronic]</td> | ||
+ | <td>1.15€</td> | ||
+ | <td>Nope</td> | ||
+ | </tr> | ||
+ | <tr> | ||
+ | <td>Capteur de présence infrarouge</td> | ||
+ | <td>1</td> | ||
+ | <td>[http://www.lextronic.fr/P26228-capteur-infrarouge.html Lextronic]</td> | ||
+ | <td>7.92€</td> | ||
+ | <td>Nope</td> | ||
+ | </tr> | ||
+ | <tr> | ||
+ | <td>Photorésistance</td> | ||
+ | <td>~2-3</td> | ||
+ | <td> - </td> | ||
+ | <td>quelques €</td> | ||
+ | <td>Nope - je verrai au magasin de l'école</td> | ||
+ | </tr> | ||
+ | <tr> | ||
+ | <td>ATMega328p</td> | ||
+ | <td>1 pour le proto</td> | ||
+ | <td>Magasin de l'école</td> | ||
+ | <td>quelques €</td> | ||
+ | <td>Nope - je verrai au magasin de l'école</td> | ||
+ | </tr> | ||
+ | <tr> | ||
+ | <td>Cristal 16MHz</td> | ||
+ | <td>1 pour le proto</td> | ||
+ | <td>[http://www.lextronic.fr/P6501-quartz-16-mhz.html Lextronic]</td> | ||
+ | <td>1.40€</td> | ||
+ | <td>Nope</td> | ||
+ | </tr> | ||
+ | <tr> | ||
+ | <td>Capa 22pF pour le quartz</td> | ||
+ | <td>2</td> | ||
+ | <td>Magasin de l'école</td> | ||
+ | <td>quelques €</td> | ||
+ | <td>Nope - je verrai au magasin de l'école</td> | ||
+ | </tr> | ||
+ | <tr> | ||
+ | <td>Des résistances</td> | ||
+ | <td> ? </td> | ||
+ | <td>Magasin de l'école</td> | ||
+ | <td>quelques m€</td> | ||
+ | <td>Yep</td> | ||
+ | </tr> | ||
+ | </table> | ||
== Énoncé initial du projet == | == Énoncé initial du projet == | ||
Ligne 25 : | Ligne 104 : | ||
== Analyse du sujet == | == Analyse du sujet == | ||
− | On a ici affaire à un réseau de capteurs reliés à une base de donnée centrale | + | 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 | + | 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 | à pouvoir présenter à un utilisateur un état des différentes pièces dans | ||
lesquelles on aura disposé les capteurs. Cela peut notamment impliquer : | lesquelles on aura disposé les capteurs. Cela peut notamment impliquer : | ||
Ligne 32 : | Ligne 111 : | ||
* Un accès à ces données via une interface web | * Un accès à ces données via une interface web | ||
* Un accès à ces données via une application mobile | * Un accès à ces données via une application mobile | ||
− | |||
On identifie donc deux parties au projet : | On identifie donc deux parties au projet : | ||
Ligne 44 : | Ligne 122 : | ||
* Être capable de mesurer l'environnement dans lequel évolue le capteur (Pression, température, lumière, présence, ouverture de porte...) | * Ê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. | + | * 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 ( | + | * Éventuellement, être reconfigurable à distance (via un serveur web embarqué dans le microcontrôleur) |
* Être capable de gérer sa consommation d'énergie. | * Être capable de gérer sa consommation d'énergie. | ||
* Agir en temps que datalogger si le réseau n'est pas accessible. | * Agir en temps que datalogger si le réseau n'est pas accessible. | ||
Ligne 62 : | Ligne 140 : | ||
==== Les capteurs ==== | ==== Les capteurs ==== | ||
Nous proposons de réaliser une carte basée sur un ATmega328 dans lequel on pourra flasher du code Arduino. | 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 | + | 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 | |
− | l' | + | 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 | 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. | é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 ==== | ==== Le serveur ==== | ||
− | On propose une solution à base d'une machine sous Linux | + | On propose une solution à base d'une machine sous Linux hébergeant un serveur MySQL et PHP. |
− | |||
− | Le SGBD utilisé | + | 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. | La partie web du serveur destinée à présenter à l'utilisateur une vue des données serait développée en PHP/HTML5/CSS3. | ||
− | La partie serveur qui | + | 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 #swagg | ||
+ | |||
+ | === 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 : [http://git.svartbergtroll.fr/smartsensor.git/ 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 [http://doxygen.org 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 : | ||
+ | * Documentation de la partie Arduino : [http://doc.svartbergtroll.fr/sswarduino/ ici] | ||
+ | * Documentation de la classe SPI : [http://doc.svartbergtroll.fr/raspberryspi là] | ||
+ | * Documentation de [http://git.svartbergtroll.fr/smartsensor.git/blob/master/doc/useConfigurator.md configurator.py] | ||
+ | * Documentation des [http://git.svartbergtroll.fr/smartsensor.git/blob/master/doc/SensorATCommands.md commandes AT de configuration à distance] | ||
+ | * Tout les schématics sont dans le dossier PCB/ | ||
+ | |||
+ | === Point sur la partie capteurs au 28 février 2014 === | ||
+ | [[Image:SmartSensorWifi28FevShield.jpg|right|thumb|300px|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 === | ||
+ | |||
+ | [[Image:SSWRPISch.png|right|thumb|300px|Schematic Réalisé pour la Raspberry Pi]] | ||
+ | [[Image:SSWRPIPCB.png|right|thumb|300px|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 [https://github.com/svartbergtroll/RaspberrySPI/ GitHub] et la documentation est disponible [http://doc.svartbergtroll.fr/raspberryspi/ là] | ||
+ | |||
+ | ''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 [http://cherrypy.org CherryPy] un excellent framework python très léger, et évidemment [http://int.sapo.pt 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. | ||
+ | |||
+ | Le dernier choix a été le partitionnement de l'EEPROM afin d'y stocker des données de configuration. L'EEPROM est divisée en secteur de maximum 256 octets. Chaque secteur comprend un octet qui indique la taille des données présente dans le secteur puis les données elles même. Ce système bien que primitif est fonctionnel et est simple à mettre en place. Tout est documenté dans le fichier eep.h du dépôt. | ||
+ | |||
+ | === Découverte de la carte WizFi210 === | ||
+ | ==== Prise en main de la carte avec minicom et pyserialcom ==== | ||
+ | [[Image:SSWpyserialcom.png|right|thumb|300px|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 : [https://github.com/svartbergtroll/pyserialcom 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. | ||
+ | |||
+ | === (Re)configuration à distance === | ||
+ | |||
+ | [[Image:SSWconfigurator.png|right|thumb|400px|L'interface du logiciel configurator]] | ||
+ | |||
+ | Une fois que le projet est capable de communiquer avec l'appli web, de soumettre des données, de se connecter à un réseau et ce genre de chose il ne manque pas beaucoup de fonctionnalités. Ceci dit une fonctionnalité indispensable s'est vite faite ressentir : le besoin de pouvoir reconfigurer le capteur à distance. En effet, à ce jour le seul moyen de reconfigurer le capteur était en modifiant en dur les identifiants et de reflasher le programme ensuite, ce qui n'est quand même pas très pratique... | ||
+ | |||
+ | Pour palier à ce problème j'ai donc créé un set relativement complet de commandes AT, documenté [http://git.svartbergtroll.fr/smartsensor.git/blob/master/doc/SensorATCommands.md ici]. L'idée est que le capteur écoute ce qu'il se passe sur son port série et dès qu'une commande AT est reconnue elle est exécutée pour peu que l'on soit authentifié sur le capteur. Pour se faire j'ai établi deux modes de configuration, une configuration "locale" via le port série, et une reconfiguration à distance via le réseau. | ||
+ | |||
+ | ==== Configuration via le port série ==== | ||
+ | La configuration via le port série est très simple, il suffit de relier le senseur à un ordinateur via un câble USB et de lancer Minicom. Notez que pour entrer en mode configuration le bouton à gauche du capteur doit être enfoncé au moment du reboot. Attendez deux/trois seconde histoire d'être certain que le capteur soit en mode configuration puis entrez les commandes AT que vous voulez. Par exemple pour changer l'ID et le mot de passe d'un capteur, la session minicom ressemblera à : | ||
+ | |||
+ | AT+ID=foobar | ||
+ | [OK] | ||
+ | AT+PW=heartbleed | ||
+ | [OK] | ||
+ | |||
+ | Simple n'est-il pas ? On sort simplement du mode de configuration avec | ||
+ | |||
+ | AT+EXIT | ||
+ | |||
+ | Et le capteur reprendra son mode de fonctionnement normal. | ||
+ | |||
+ | ''ACHTUNG'' il est aussi indispensable que le shield arduino soit en mode "PROG" et non en "RUN" durant la configuration, autrement cela ne fonctionnera pas. Les modifications que vous avez envoyé à l'arduino seront prises en compte immédiatement. | ||
+ | |||
+ | ==== Configuration via le réseau ==== | ||
+ | Le capteur peut également être reconfiguré par le réseau, la procédure est légèrement différente puisqu'il faut s'identifier avant de lancer des commandes. Cette identification se fait avec ce qu'il la ''master key'' qui un peu le mot de passe admin du capteur. On peut le reconfigurer très facilement en utilisant netcat par exemple. Par défaut le capteur écoute sur le port 80. | ||
+ | |||
+ | $ nc addresseducapteur 80 | ||
+ | AT+IDENT=masterkey | ||
+ | [OK] -- At this point we shall enter commands | ||
+ | AT+ID=foobar | ||
+ | [OK] | ||
+ | AT+PW=heartbleed | ||
+ | [OK] | ||
+ | AT+EXIT | ||
+ | [OK] EXITING CONFIG MODE | ||
+ | |||
+ | Et voilà ! | ||
+ | |||
+ | ==== Configurator.py ==== | ||
+ | Pour simplifier le processus j'ai développé un petit logiciel en python répondant au doux nom de ''configurator.py''. Il a été réalisé en utilisant pygtk et pyserial pour communiquer avec le capteur. Son fonctionnement est décrit dans la section [http://git.svartbergtroll.fr/smartsensor.git/blob/master/doc/useConfigurator.md doc du dépôt git]. De cette manière, nul besoin de devoir apprendre par coeur les commandes AT. De plus comme il est écrit en python, le logiciel estportable et peut aussi fonctionner sous une machine Windows. | ||
+ | |||
+ | === Bilan à la fin du projet === | ||
+ | [[Image:SSWfinalhardware.jpg|right|thumb|400px|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) [http://www.php.net/manual/fr/intro.pdo.php] | ||
+ | * 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 : [http://ink.sapo.pt/] ). 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 === | ||
+ | |||
+ | <gallery> | ||
+ | File:Indexssw.jpg|Page de connexion de la plateforme | ||
+ | File:Connectessw.jpg|une fois connecté,... | ||
+ | File:Searchssw.jpg|Recherche d'un capteur | ||
+ | File:Search_graphssw.jpg|Capteur trouvé mon capitaine! | ||
+ | File:Addssw.jpg|une fois connecté,... | ||
+ | File:Adminssw.jpg|Panel d'administration | ||
+ | </gallery> | ||
+ | |||
+ | == Rapport == | ||
+ | Le rapport de projet est disponible ici : [[Fichier:SSWRapport.pdf]] | ||
+ | |||
+ | = Matériel récupéré = | ||
+ | |||
+ | * 1 Raspberry | ||
+ | * 1 shield "maison" pour raspberry | ||
+ | * 1 arduino | ||
+ | * 1 shield WiFi | ||
+ | * 1 carte WiFi | ||
+ | * 1 dongle USB WiFi |
Version actuelle datée du 4 juin 2014 à 11:18
Sommaire
- 1 Informations générales
- 2 Liste du matériel nécessaire
- 3 Énoncé initial du projet
- 4 Analyse du sujet
- 5 Travail à effectuer dans un premier temps
- 6 Partie capteurs
- 7 Partie Web/BDD
- 8 Rapport
- 9 Matériel récupéré
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 #swagg
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 :
- Documentation de la partie Arduino : ici
- Documentation de la classe SPI : là
- Documentation de configurator.py
- Documentation des commandes AT de configuration à distance
- Tout les schématics sont dans le dossier PCB/
Point sur la partie capteurs au 28 février 2014
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
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 là
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.
Le dernier choix a été le partitionnement de l'EEPROM afin d'y stocker des données de configuration. L'EEPROM est divisée en secteur de maximum 256 octets. Chaque secteur comprend un octet qui indique la taille des données présente dans le secteur puis les données elles même. Ce système bien que primitif est fonctionnel et est simple à mettre en place. Tout est documenté dans le fichier eep.h du dépôt.
Découverte de la carte WizFi210
Prise en main de la carte avec minicom et pyserialcom
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.
(Re)configuration à distance
Une fois que le projet est capable de communiquer avec l'appli web, de soumettre des données, de se connecter à un réseau et ce genre de chose il ne manque pas beaucoup de fonctionnalités. Ceci dit une fonctionnalité indispensable s'est vite faite ressentir : le besoin de pouvoir reconfigurer le capteur à distance. En effet, à ce jour le seul moyen de reconfigurer le capteur était en modifiant en dur les identifiants et de reflasher le programme ensuite, ce qui n'est quand même pas très pratique...
Pour palier à ce problème j'ai donc créé un set relativement complet de commandes AT, documenté ici. L'idée est que le capteur écoute ce qu'il se passe sur son port série et dès qu'une commande AT est reconnue elle est exécutée pour peu que l'on soit authentifié sur le capteur. Pour se faire j'ai établi deux modes de configuration, une configuration "locale" via le port série, et une reconfiguration à distance via le réseau.
Configuration via le port série
La configuration via le port série est très simple, il suffit de relier le senseur à un ordinateur via un câble USB et de lancer Minicom. Notez que pour entrer en mode configuration le bouton à gauche du capteur doit être enfoncé au moment du reboot. Attendez deux/trois seconde histoire d'être certain que le capteur soit en mode configuration puis entrez les commandes AT que vous voulez. Par exemple pour changer l'ID et le mot de passe d'un capteur, la session minicom ressemblera à :
AT+ID=foobar [OK] AT+PW=heartbleed [OK]
Simple n'est-il pas ? On sort simplement du mode de configuration avec
AT+EXIT
Et le capteur reprendra son mode de fonctionnement normal.
ACHTUNG il est aussi indispensable que le shield arduino soit en mode "PROG" et non en "RUN" durant la configuration, autrement cela ne fonctionnera pas. Les modifications que vous avez envoyé à l'arduino seront prises en compte immédiatement.
Configuration via le réseau
Le capteur peut également être reconfiguré par le réseau, la procédure est légèrement différente puisqu'il faut s'identifier avant de lancer des commandes. Cette identification se fait avec ce qu'il la master key qui un peu le mot de passe admin du capteur. On peut le reconfigurer très facilement en utilisant netcat par exemple. Par défaut le capteur écoute sur le port 80.
$ nc addresseducapteur 80 AT+IDENT=masterkey [OK] -- At this point we shall enter commands AT+ID=foobar [OK] AT+PW=heartbleed [OK] AT+EXIT [OK] EXITING CONFIG MODE
Et voilà !
Configurator.py
Pour simplifier le processus j'ai développé un petit logiciel en python répondant au doux nom de configurator.py. Il a été réalisé en utilisant pygtk et pyserial pour communiquer avec le capteur. Son fonctionnement est décrit dans la section doc du dépôt git. De cette manière, nul besoin de devoir apprendre par coeur les commandes AT. De plus comme il est écrit en python, le logiciel estportable et peut aussi fonctionner sous une machine Windows.
Bilan à la fin du projet
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
Rapport
Le rapport de projet est disponible ici : Fichier:SSWRapport.pdf
Matériel récupéré
- 1 Raspberry
- 1 shield "maison" pour raspberry
- 1 arduino
- 1 shield WiFi
- 1 carte WiFi
- 1 dongle USB WiFi