Il est temps de vous parler un peu de la partie logiciel du projet OpenAlarm qui est en 2 parties : le logiciel interne (firmware) aux OpenAlarm Node et la partie qui tourne sur l'ordinateur, dans cette première partie, je vais vous présenter uniquement le fonctionnement des OpenAlarm Node.
Cet article est volontairement technique et rentre dans des détails que l'utilisateur final n'aura pas à connaître mais si vous souhaitez participer au projet, vous aurez besoin de ces informations.
Principe de fonctionnement
Le fonctionnement des OpenAlarm Node est plutôt simple, le système est conçu pour être utilisable sans base, c'est à faire qu'avec juste 2 Node (et un ordinateur), vous avez un système pleinement utilisable, en effet, chaque Node embarque le code nécessaire pour la surveillance de grandeur issue de capteur (mouvement, température, luminosité, courrier dans la boite aux lettres, etc...) mais également celui pour servir de base réceptionnant les messages des autres capteurs.
Un Node à donc plusieurs modes de fonctionnement :
- Le mode « écoute » (lancé par la commande listen) qui permet de recevoir tous les messages des autres nodes, ce mode sera celui utilisé par la base pour réceptionner les messages de tous les Nodes
- Le mode « surveillance » (lancé par la commande guard) permettant de rentrer en surveillance et d'envoyer à intervalle régulier les informations contenues dans les frames (voir plus bas)
- Le mode « remote » (lancé par la commande remote) afin de se connecter à un Node distant (par radio) afin d'en modifier les paramètres
À la mise sous tension, un Node démarrera automatiquement en mode surveillance si ce dernier n'est pas branché à un ordinateur et ne reçoit pas de commande le lançant dans un autre mode.
Difficile de faire plus simple, non ?
Les sources
Tous les fichiers sources sont disponibles dans le dossier /src dont voici l'arborescence :
- base : Contient le code source Python utilisé sur l'ordinateur
- lib : Les librairies utilisées par le projet voir plus bas
- node : Le code source embarqué dans les node
Le firmware
Les sources et librairies
Le firmware de chaque node est écrit en C et compilé avec les outils Arduino, j'ai utilisé Ino (une interface en ligne de commande pour Arduino) pour compiler / programmer les OpenAlarm Node mais vous pouvez bien entendu utiliser l'environnement par défaut d'Arduino.
Les librairies utilisées :
- Jeelib
: la plus importante, elle est l'interface entre le cœur du montage, le
microcontrôleur, et la partie radio, elle gère également des fonctions
très utile de mise en sommeil, etc... Je vous invite à parcourir la
documentation très complète sur cette librairie qui simplifie grandement
le développement.
Il existe d'autres librairies permettant l'interfaçage avec les modules radios utilisés dans OpenAlarm comme celle de LowPowerLab ou encore RadioHead que j'ai découvert il y a peu de temps. L'idée serait de les tester en profondeur afin de voir si il serait intéressant de basculer sur une autre ou pourquoi pas, prendre le meilleur des 3 pour en faire une dédiée à OpenAlarm qui permettrait notamment de prendre moins de place en mémoire (le principale problème de Jeelib)... - SerialCommand : Une librairie utilitaire permettant de piloter les OpenAlarm Node via des lignes de commande, elle prend peu de place et permet de gérer des commandes suivi de leur arguments simplement (ex: set power 1 envoyé via la liaison série va modifier la valeur de la puissance d'émission à 1)
- DallasTemperature et OneWireNoResistor sont utilisées si vous souhaitez communiquer avec des modules OneWire
- OpenAlarm qui contient les fonctions principales du projet
Afin de compiler les sources avec Ino, voici les étapes à suivre :
- Installer Ino, ça peut être utile ;)
- Placez-vous dans le dossier src/node
- Lancez la commande ino build et voilà, vous pouvez maintenant envoyer le firmware sur le node (après avoir appuyé sur le bouton reset de ce dernier) via la commande ino upload
Voilà, vous avez un OpenAlarm Node fonctionnel...
Les commandes
Lorsque vous branchez un OpenAlarm Node sur le port USB de votre ordinateur, un périphérique série est créé et vous permet de dialoguer directement avec ce dernier via des commandes.
Pour lire la configuration du Node connecté :
$ ino serial config OpenAlarm node, version oa10 - nodeid : 1 - freq : 433Mhz - group : 210 - ack : yes - power : 0 (highest) - autostart : yes - cmd timeout : 15 second(s) - usb timeout : 15 second(s) - remote : yes (wait error cycle: 7) - key : AKdlIqdjMKAQwJKz Profile 0: - period : 3 second(s) - feedback : yes - eint wait : 3
En rouge, nous avons la commande saisie sur l'ordinateur pour démarrer la liaison serie via USB et en vert la commande saisie via la liaison série sur le Node, le reste étant la réponse faite par la Node.
Liste des commandes disponibles :
Liées à la configuration :
- config : Affiche la configuration courante
- verbose : Spécifie le niveau de verbosité
- debug : Active ou non la débug
- get : Retourne la valeur d'une variable de configuration (ex: get power pour lire la puissance d'émission)
- set : Modifie la valeur d'une variable de configuration (ex: set key ABCDEF pour modifier la clef)
- frame : Permet de lire / modifier les frames radio (voir plus bas)
- int : Permet de lire / modifier les interruptions matérielles (ce qui va sortir le node du mode veille)
- io : Permet de lire / modifier / configurer les entrées / sorties
Commandes permettant de faire rentrer la node dans des modes spécifiques :
- guard : Entre dans le mode de surveillance
- listen : Entre dans le mode réception
- remote : Connexion à un node distant
- exit : Sort du mode courant
Liées à la partie radio :
- send : Envoie les arguments par radio
- rfinit : Initialise la partie radio
Liées aux tests :
- blink : Fait clignoter les leds
- test : Commandes fourre-tout permettant de lancer divers tests (usb, io, sleep, ...)
- read : Lit une frame
- volt : Lit la tension
- temp : Lecture / calibration de la température (capteur intégré à l'µC)
Toutes les commandes ne sont pas toujours directement accessibles à des fins d'économies de mémoire et sont activables ou non via des #define.
Les paquets
J'ai voulu faire un système totalement configurable, ainsi, le format des paquets envoyés par la liaison radio n'est pas fixe et modifiable à souhait.
Utilisons la commande frame afin d'afficher le format courant :
frame
Frame (type: 2, size: 9) :
-> [type] [counter] [waketype] [wakearg] [input0,input1,input2] [voltage] [temperature]
La commande frame affiche alors le contenu d'une frame telle qu'elle sera envoyée à la base, voici une explication sur les différents éléments :
- [type] : Le type de frame sur un octet permettant à la base de décoder les informations reçues (type: 2 dans l'exemple)
- [counter] : Le compteur de frame usr 2 octets, à chaque envoi de frame, ce compteur est incrémenté (utile à la base pour savoir si cette dernière a manqué des paquets)
- [waketype] : Une information sur ce qui a sorti la node de la veille (ex: interruption externe, timer, etc...) sur un octet
- [wakearg] : Informations complémentaire sur la sortie de vieille (ex: l'entrée pour une interruption externe, la période pour le timer, etc...) sur un octet
- [input0,input1,input2] : Un octet contenant la valeur des entrées 0, 1 et 2
- [voltage] : La tension de la batterie (sur 2 octets)
- [temperature] : La température lue via le capteur de l'µC (sur un octet)
En rouge, il s'agit de l'entête fixe (le préambule), en vert, nous avons ce qui reste totalement configurable par l'utilisateur
Si dans votre application, vous n'avez besoin que de la température, il vous suffit de le spécifier à l'aide de la commande frame :
frame set 4 65
Frame set !
Explication des arguments envoyés :
- frame : La commande voulue
- set : Un argument de la commande frame : on souhaite écrire le format d'une frame
- 4 : Le type de frame (ce sera utilisé par la base pour reconnaitre le format)
- 65 : 65 correspond à la température (voir explication plus bas)
Si nous retapons la commande frame, nous voyons que le format à bien changé :
frame
Frame (type: 4, size: 5) :
-> [type] [counter] [waketype] [wakearg] [temperature]
Au sujet du contenu des frames, dans la précédente commande, nous voulions une frame constituée uniquement de la température et nous avons utilisé 65 pour le spécifier, voici une liste de ce qu'il est possible d'utiliser pour constituer une frame :
- input0 à input9 (8 à 17) : Les entrées numérique du microcontrôleur sur un bit
- analog0 à analog5 (32 à 37) : Les entrées analogiques sur 2 octets
- voltage (64) : La tension de la batterie
- temperature (65) : La température issue du capteur interne du microcontrôleur
- Bien entendu, vous pouvez ajouter n'importe quel type de chose à ajouter dans une frame
Les interruptions
Nous venons de le voir, au travers des frames, nous pouvons envoyer les informations que nous voulons à la base, ces informations seront envoyées à intervalle régulier défini au préalable (par exemple, avec un intervalle d'une minute), le reste du temps, l'OpenAlarm Node reste en veille afin de consommer le moins possible.
Mais comment faire si un événement se produit exactement durant cette veille ? C'est là qu'intervienne les interruptions qui vont sortir de veille notre Node afin d'envoyer immédiatement une frame dans le but d'alerter la base.
Le microcontrôleur possède des interruptions matérielles sur certaines de ses entrées / sorties et afin de spécifier lesquelles vont nous servir pour sortir le Node du sommeil, nous utilisons la commande int comme ceci :
La commande int sans argument nous liste les interruptions actuelles :
int
Not int !
Ajoutons 2 interruptions, la 2 correspondant à l'entrée / sortie 0 afin de surveiller un front descendant (falling) et la 0 pour un front montant (rising) :
int add 2 falling Int added ! int add 0 rising Int added !
Listons de nouveau les interruptions :
int
Ints (size: 2) :
- 2 (input 0) falling
- 0 (input 3) rising
Voilà, lorsque l'OpenAlarm Node rentrera en mode guard, il configurera les interruptions ci-dessus afin qu'il sorte du mode veille en cas d’événement pour envoyer une frame d'alerte.
Les entrées / sorties
Voilà une dernière commande qui va nous être bien utile, elle permet de configurer les entrées / sorties dans un état prédéfinie au moment de l'entrée en veille.
io
Inputs :
- io0 : input pullup
- io1 : input nopullup
- io2 : input nopullup
- io3 : input nopullup
- io4 : input nopullup
- io5 : input nopullup
- io6 : input nopullup
- io7 : input nopullup
- io8 : input nopullup
- io9 : input nopullup
Les profiles
Nous venons de voir les paquets, les interruptions et les entrées / sorties, OpenAlarm permet de créer des profiles qui regroupent tous ces paramètres afin de changer rapidement de configuration sans avoir à renvoyer tous les réglagles.
On peut ainsi imaginer être sur un profile simple lorsque vous êtes chez vous ou l'OpenAlarm Node envoie à une période de 5 minutes les paquets contenant le contenu des mesures de ces capteurs, et, lorsque vous partez de chez vous, vous basculez à distance sur un autre profile ou la période d'envoi est de 15 secondes.
En procédant ainsi, on gagne en autonomie.
Un profile peut contenir les informations suivantes :
- period : La période d'envoi des informations à la base
- feedback : Faire clignoter les leds du Node selon l'action courant
- eintwait : Lorsqu'un évènement est détecté, nombre de cycle d'attente durant laquelle l'évènement si il est reproduit doit être ignoré (si eintwait = 2 et period = 5 secondes alors, le temps durant lequel un nouvel évènement sera ignoré sera de 10 secondes)
- external_interrupts : Il s'agit de la configuration des interruptions externes (Les interruptions)
- ios : La configuration des entrées / sorties (Les entrées / sorties)
- frame : Le format des paquets (Les paquets)
Chaque OpenAlarm Node peut avoir un maximum de 3 profiles différents.
Pour basculer d'un profile à un autre, il suffit d'utiliser la commande set ainsi :
set profile set 1
Done
Un exemple concret
Voici un exemple concret d'utilisation de ce que nous venons de voir.
Imaginez que vous vouliez surveiller une pièce isolée avec un détecteur de mouvement, vous souhaitez également détecter des chocs (dans le cas ou votre Node est placé sur une des portes par exemple) et tant qu'à faire, vous aimeriez connaître la température de cette pièce.
Nous avons 3 capteurs utilisées :
- Le détecteur de mouvement (PIR) que nous allons brancher arbitrairement sur l'entrée 0, ce capteur place sa sortie à l'état haut lorsqu'une détection est faite, sa sortie est de type push / pull et ne nécessite donc pas de résistance de tirage
- Un capteur de vibration qui peut être vue comme un simple interrupteur se fermant lorsqu'une vibration est détecté, nous aurons besoin pour lui d'une résistance de tirage et nous brancherons ce capteur sur l’entrée 1
- Le capteur de température interne
Nous nous connectons alors sur l'OpenAlarm Node :
$ ino serial frame set 2 8 9 64 Frame set ! io set 0 input nopullup Io set ! io set 1 input pullup Io set ! int add 2 falling int set ! int add 3 rising int set !
Explications pour chaque commande :
- ino serial On ouvre dans un terminal une liaison série avec le Node
-
frame set 2 8 9 64
- 2 : On indique que la frame sera de type 2
- 8 : Il s'agit de l’entrée 0 (voir explications sur les paquets)
- 9 : L’entrée 1 (voir explications sur les paquets)
- 64 : La température (voir explications sur les paquets)
- io set 0 input nopullup On indique que l’entrée / sortie 0 devra être configurée en entrée sans résistance de rappel
- io set 1 input pullup On indique que l’entrée / sortie 1 devra être configurée en entrée avec résistance de rappel
- int add 2 falling On configure une interruption matérielle 2 (correspondant a l’entrée 0) sur un front montant
- int add 3 rising On configure une interruption matérielle 3 (correspondant a l’entrée 1) sur un front descendant
Pour voir le paquet qui sera envoyé, utilisez la commande frame :
frame
Frame (type: 2, size: 7) :
-> [type] [counter] [waketype] [wakearg] [input0,input1] [temperature]
Une fois ceci réalisé, on peut configurer la période à laquelle le Node va nous donner des nouvelles de lui (1 minute et 30 secondes ici) puis on le lance en mode surveillance :
set period 90 Done guard Starting guard mode !
Maintenant, l'OpenAlarm Node nous enverra toutes les 1 minute et 30 secondes la frame que nous avons configuré et si un évènement survient via le capteur de mouvement ou le capteur de vibration, une frame est immédiatement envoyée.
Notre Node est pleinement fonctionnel en surveillance de sa zone mais imaginons que nous voulions changer la période d'envoi des frames, comme nous sommes feignants, nous n'allons pas aller chercher le Node mais tout simplement nous connecter à distance dessus afin de changer le paramètre voulu :
remote 1 AKdlIqdjMKAQwJKz Connecting... Success! period 60 power 3 exit Disconnected!
Dans cet exemple, l'utilisateur se connecte au Node 1 avec la clef AKdlIqdjMKAQwJKz, puis saisie 3 commandes (en orange) afin de changer la période d'envoi des informations à 60 secondes et modifie la puissance d'émission avant de se déconnecter avec la commande exit.
Voilà pour le tour de présentation du fonctionnement logiciel des OpenAlarm Node, dans un prochain article, je présenterai l'interface Python permettant de réaliser les mêmes opérations mais de façon automatisées...