DigitalSpirit / Blog

Les entrailles d'OpenAlarm : Une première interface PC en Python

Je vous ai présenté dans le précédent article le principe de fonctionnement d'un OpenAlarm Node, c'est parfaitement fonctionnel et utilisable mais nous pouvons simplifier grandement tout ça et c'est là qu'intervient l'interface que je vais vous présenter dans cet article.

Un programme en Python nommé simplement base.py permet les interactions avec les OpenAlarm Node, il s'utilise en ligne de commande :

$ python3 base.py --help
OpenAlarm Base
Usage:
base.py [options] nodeid <nodeid>
base.py [options] config write <config>
base.py [options] config set <key> <value>
base.py [options] profile write <profile_name> [<profile_id>]
base.py [options] profile set <profile_id>
base.py [options] node write <node_name>
base.py [options] node read
base.py [options] listen [--csv <csv_file>]
base.py [options] remote <node_name> --set <commands>...
base.py --version
Options:
-p            Serial port
-f            Force node write even when different nodeid
-h --help     Show this screen
-d --debug    Debug mode
-v --verbose  Verbose mode
$ 

Je vais passer en revue toutes les possibilités offertes par ce programme.

nodeid

python3 base.py -p /dev/usbserial0 nodeid 2

Cette commande va donner au Node dont le périphérique série est /dev/usbserial0 l'identifiant de node 2

config write

python3 base.py -p /dev/usbserial0 config write default

Cette commande va écrire la configuration nommée default dans le node lié au périphérique /dev/usbserial0

Mais d'oû sort la configuration default ?

Toute la configuration d'OpenAlarm tient dans un fichier au format Yaml et default correspond dans l'exemple ci-dessus à la configuration du même nom du nœud config.

Ce n'est pas clair ? Regardons de plus près une partie du fichier de configuration oa.yaml :

[...]
configs:
    default: &default
        group: 210
        freq: 433
        ack: yes
        cmdtimeout: 15
        usbtimeout: 15
        autostart: yes
        power: 0
        remote:
            active: yes
            wait_error_cycle: 7
[...]

Nous y trouvons une suite de clefs / valeurs (les mêmes clefs que nous avons aperçu dans l'article précédent sur les entrailles du firmware) qui vont permettre de configurer comme nous le souhaitons notre Node.

Ainsi, dans l'exemple ci-dessus, nous donnons au Node le groupe 210, nous les spécifions une fréquence de 433Mhz, avec accusé de réception (ack = true), bref, je suppose que vous avez compris le principe de fonctionnement...

La commande config write va donc lire la configuration et l'envoyer au Node directement.

config set

python3 base.py -p /dev/usbserial0 config set group 220

Cette commande permet de modifier directement des variables de configuration, utile si on ne veut changer qu'un seule des paramètres.

profile write

python3 base.py -p /dev/usbserial0 profile write pir0

C'est assez explicite, avec cette commande, nous écrivons le profile nommé pir0 dans le périphérique /dev/usbserial0 (pour en savoir plus sur les profiles, voir le dernier article)

pir0 correspond au nœud du même nom du fichier oa.yaml :

[...]
    pir0: &profilepir
        description: Module avec capteur infrarouge 0
        feedback: yes
        period: 3
        eintwait: 3
        external_interrupts:
            io0: rising
        ios:
            io0: [ input, nopullup ]
        frame:
id: 2
content:
- counter
- waketype
- wakearg
- [ input0, input1, input2 ]
- voltage
- temperature
[...]

profile set

python3 base.py -p /dev/usbserial0 profile set 0

Change le profile courant du Node.

node write

python3 base.py -p /dev/usbserial0 node write xxx

Nous avons vu au dessus le fichier Yaml avec les nœuds configs et profiles, il existe un autre type de nœud, il s'agit de 'nodes' qui contient tous les paramètres pour un Node nommé.

Voici le contenu du nœud nodes du fichier oa.yaml :

[...]
nodes:
    pir0:
        id: 2
        config: *default
        key: abcdefghijklmnop
        profile:
            0: *profilepir
    temp:
        id: 1
        config: *default
        key: AKdlIqdjMKAQwJKz
        profile:
            0: *profiletemp
[...]

node read

python3 base.py -p /dev/usbserial0 node read

Lit le Node et affiche des informations sur sa configuration.

listen

python3 base.py -p /dev/usbserial0 node listen

Se connecte au Node via la liaison série et passe en mode promiscuous, une sorte de mode sniffer ou toutes les frames valident envoyées par les OpenAlarm Node sont retournées via l'interface série.

Si nous nous connections au node directement via l'interface série et que nous entrons la commande série, voici le format du contenu retourné :

$ ino serial
listen
OKX 010206000103047A0B16
OKX 010207000103007A0B16
OKX 010208000202007A0B16
OKX 010209000103007A0B16

À chaque réception d'une frame valide, elle est retournée sous la forme OKX 010206000103047A0B16, ou OK indique un paquet valide, X indique que le format de la frame est hexa, puis, suivi d'un espace, nous avons la frame brute.

Ce contenu n'est pas franchement lisible et c'est pour cela que nous utilisons le programme en Python qui nous simplifie grandement la vie, voici la même fonction listen mais utilisée via l'interface en Python :

$ python3 base.py -p /dev/usbserial0 node listen
Use device /dev/usbserial0
Start listen mode !
Nodeid: 1, frame type: 2 (0 second(s))
    Input       : bit0:0, bit1:0, bit2:0
    Voltage     : 2.94
    Temperature : 21.00
Nodeid: 1, frame type: 2 (5 second(s))
    Input       : bit0:0, bit1:0, bit2:0
    Voltage     : 2.94
    Temperature : 21.00
Nodeid: 1, frame type: 2 (5 second(s))
    Input       : bit0:0, bit1:0, bit2:0
    Voltage     : 2.94
    Temperature : 21.00
Nodeid: 1, frame type: 2 (5 second(s))
    Input       : bit0:0, bit1:0, bit2:0
    Voltage     : 2.94
    Temperature : 21.00

C'est tout de même beaucoup plus clair ainsi ! Non ?

Par curiosité, rendons cela un peu plus verbeux...

$ python3 base.py -p /dev/usbserial0 --verbose node listen
Verbose mode !
Use device /dev/usbserial0
Start listen mode !
verbose get
-> 0
verbose set 0
-> OK
listen raw
Nodeid: 1, frame type: 2, payload: 64000202007A0B15 (2 second(s))
    Counter     : 100
    Waketype    : 2
    Wakearg     : 2
    Input       : bit0:0, bit1:0, bit2:0
    Voltage     : 2.94
    Temperature : 21.00
Nodeid: 1, frame type: 2, payload: 65000202007A0B15 (5 second(s))
    Counter     : 101
    Waketype    : 2
    Wakearg     : 2
    Input       : bit0:0, bit1:0, bit2:0
    Voltage     : 2.94
    Temperature : 21.00
Nodeid: 1, frame type: 2, payload: 66000202007A0B15 (5 second(s))
    Counter     : 103
    Waketype    : 2
    Wakearg     : 2
    Input       : bit0:0, bit1:0, bit2:0
    Voltage     : 2.94
    Temperature : 21.00

Une fois ces données reçue, c'est à vous d'en faire ce que vous voulez...
Un paramètre csv vous permet de spécifier un fichier afin de stocker toutes ces informations dans un fichier.

node remote

python3 base.py -p /dev/usbserial0 remote pir --set period=1

Cette commande va se connecter à l'OpenAlarm Node connecté sur l'USB puis tenter une liaison distante avec le Node nommé pir (voir fichier format Yaml) afin de changer le paramètre period.


Voilà, vous savez tout sur l'interface actuelle en Python, si vous voulez en savoir, vous pouvez consulter le code et au sujet du fichier oa.yaml, je vous invite également à le consulter !

Ouvrir l'article

Les entrailles d'OpenAlarm : Le firmware

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 :

  1. Installer Ino, ça peut être utile ;)
  2. Placez-vous dans le dossier src/node
  3. 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
  • 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...

Ouvrir l'article

Mise à jour des OpenAlarm Node : Version 1.5.0

OpenAlarm Node 1.5.0

Format de la carte

Comme je l'évoquais dans un article précédent, Seeedstudio qui produit les pcb, m'a demandé un surplus de 17$ à cause des demi-trous en bordure de la carte, vu le cout total de production des PCB (9$ pour 10), ça fait une belle surprise et de toute façon, je n'étais pas convaincu de l'utilité / praticité de ces demi-trous, j'ai donc résolu le problème en augmentant quelque peu la largeur de la carte qui passe de 16mm à 19mm, rien de bien méchant et surtout un gain appréciable en terme de place disponible sur le PCB.

Améliorations par rapport à la version 1.0.0 :

  • L'ouverture du port USB à été agrandie car ça coinçait un peu sur la première version.
  • Certains composants ont été déplacés pour faciliter le montage
  • Les broches de programmation ont été agrandis (voir plus bas)

Comparatif visuel et à l'échelle entre un Funky v3, un OpenAlarm Node 1.0.0 et un OpenAlarm Node 1.5.0 :
Comparatif Funky v3, OpenAlarm Node 1.0.0 et OpenAlarm Node 1.5.0

Comme vous le voyez, nous sommes un poil plus gros que la version 1.0.0 mais ça reste très petit comme le prouve cette photo :
Un OpenAlarm Node 1.5.0 dans la main

Vue de derrière :
Vue de derrière

Entrées / sorties

Avec la taille gagnée, j'en ai profité pour revoir le mappage des entrées / sorties, maintenant, elles sont placées dans l'ordre de chaque côté de la carte, toutes groupées par fonction.

On trouve dorénavant sur le côté gauche les 3 broches d'alimentations VIN (entrée de 3.3V à 7V), GND, VCC (entrée de 3V à 5V), 4 entrées / sorties génériques ayant chacune une interruption matérielle D0, D1, D2, D3.
Sur le côté droit, on trouve 2 entrées analogiques A0 et A1 et d'autres entrées / sorties génériques D6, D7, D8, D9 et D12 (D8 et D9 ayant également des interruptions matérielles).

Les entrées / sorties d'un OpenAlarm Node 1.5.0

Sur l'ancienne version des OpenAlarm Node et sur les Funky, il n'est pas possible d'utiliser le port physique I2C car la broche PD0 (SCL) est utilisé comme broche d'interruption pour dialoguer avec le module radio.
À cause d'un bug dans la librairie JeeNode de pilotage du module radio, il n'était pas possible d'utiliser une autre broche, le problème étant résolu, j'ai libéré PD0 afin de pouvoir utiliser le port I2C directement, et c'est PB7 (D11) qui est maintenant utilisé pour le dialogue avec le module radio.

Le PCB

Un des principes des OpenAlarm Node est de pouvoir utiliser des cartes filles que l'on vient superposer les unes sur les autres avec le même principe que les shields d'Arduino ou la spécification Hats pour les Raspberry.
Nous avons donc un PCB pour la carte mère et des PCB pour chaque carte fille mais comme évoqué précédemment, un critère important est le cout et faire fabriquer plusieurs PCB, c'est onéreux. La plus petite taille de PCB disponible chez Seeedstudio étant de 5cm x 5cm, il y a de la place perdue (le PCB de la carte mère fait 19mm x 21mm), j'ai donc ajouté 3 cartes filles directement sur le PCB original, il ne reste plus qu'à découper (un coup de cutter et on casse proprement l'époxy).

Pour le prix d'un PCB, on se retrouve avec 4 PCB dont 2 utilisables comme des platines d'essais et une autre intégrant un chargeur de batterie LiPo.
Le PCB de la version 1.5.0 d'OpenAlarm Node

Les cartes filles

Pour ce premier batch d'OpenAlarm Node 1.5.0, j'ai donc inclut directement 2 cartes filles d'essai et 1 autre carte fille d'essai avec un chargeur LiPo à base de Max1555 qui chargera automatiquement la batterie lorsque le Node sera branché sur USB, un voyant permettant de voir si la charge à bien lieu.

Un OpenAlarm Node avec une carte fille proto sur laquelle on aperçoit un capteur infrarouge :
Carte fille Lipo pour OpenAlarm Node

Un OpenAlarm Node avec une carte fille LiPo :
Carte fille proto pour OpenAlarm Node

Programmation

Programmation du bootloader

Comme évoqué plus haut, les contacts de programmation du bootloader étant un peu trop petit sur la première version, ils ont été agrandi afin d'en faciliter l'utilisation.

Pad de programmation d'un OpenAlarm Node 1.5.0

Sur la première version des OpenAlarm Node, je soudais directement des fils sur le port de programmation afin d'envoyer le bootloader, c'était long, source de problèmes mais surtout, franchement pas pratique, j'ai donc fabriqué un outils parfait pour cette tâche :

Que peut-on faire avec une pince à linge en Inox et des pogopins (des pointes de contacts) ?
pince-a-linge-inox.png pogopin.png

On fait une pince de programmation très pratique !
Pince de programmation DIY Pince de programmation DIY

Programmation par USB

Le bootloader n'a besoin d'être programmé qu'une seule fois, par la suite, le programme est chargé directement par USB, comme pour l'ancienne version du PCB, j'utilise un port USB un peu particulier puisque ce dernier est directement sur le PCB, je ne suis pas rentré en détail dessus dans mes derniers articles, voici quelques informations à ce sujet.

Pour commencer, pourquoi ne pas mettre un port physique microUSB ?

  • Ça prend de la place, c'est épais
  • Ce n'est pas forcément plus solide
  • C'est toujours ça de moins à souder
  • Ça coute moins cher
  • Parce qu'on peut le faire !

Pour cela, il faut que votre PCB fasse 0.8mm d'épaisseur au maximum, vous aurez également à limer chaque côté du bord d'insertion sinon, vous aurez de mauvaises surprises...
Limage du connecteur USB avant insertion OpenAlarm Node en cours de programmation usb_1.jpg

Je n'ai pas eu de souci avec ce genre de connecteur, sauf un limage un peu trop léger du PCB, qui, lors de l'insertion à plié les contacts internes du connecteurs de la prise USB et l'a donc rendu inutilisable mais le connecteur PCB n'a absolument rien eu : PCB=1 / USB=0 ;).
Je maltraite pas mal les connecteurs et aucun n'a rompu (alors que sur les Funky v3, j'ai un connecteur standard USB qui s'est arraché) et ne montre de signe de faiblesse donc je pense que c'est une solution parfaitement utilisable...

La suite

Au niveau logiciel, beaucoup énormément d'évolutions aussi bien au niveau code embarqué que Python qui seront l'occasion d'un prochain article qui devrait sortir très prochainement...

Si vous êtes intéressé par OpenAlarm, si vous avez des conseils, si vous voulez participer, venez en discuter sur IRC, canal #madeinfr sur irc.freenode.net, vous pouvez également suivre les évolutions sur Twitter @hugokernel, un forum OpenAlarm est également disponible chez Madeinfr et enfin, tout ceci est sur GitHub / hugokernel / OpenAlarm.

Ouvrir l'article

OpenAlarm : Le premier OpenAlarm Node est fonctionnel !

Voici des nouvelles de OpenAlarm, un projet d'alarme libre, si vous avez râté les épisodes précédents, voici de quoi combler ce manque :


J'ai reçu les PCB de Seeedstudio et est enfin pu réaliser le premier OpenAlarm Node dont voici une photo :

Vue de côté d'un OpenAlarm Node

Une vue qui détaille les différents éléments d'un OpenAlarm Node :

Explication OpenAlarm Node

De haut en bas :

  • Le bouton Reset utilisé lors de la programmation via le port USB
  • Un port micro USB utilisé pour la programmation et la configuration
  • 2 led (rouge et verte) utile pour donner des informations diverses
  • On trouve ensuite des points de connexion (voir tableau plus bas)
  • Des points d'accroche sécable permettant d'accrocher le module (si non utilisé, il est possible de les retirer)

À propos des points de connexion

connexion.png

Tous les points de connexion sont au pas de 2.54mm, facilitant leur utilisation sur une plaquette breadboard par exemple.

Chaque point met à disposition une surface sur laquelle il est possible de souder directement un capteur, un fil ET, il est également possible de souder des contacts latéralement.

Vous remarquerez que les points de connexion sont divisés en 2, mais pourquoi avoir fait ça me direz-vous ? Pour une raison simple, gagner de la place, en faisant ainsi, j'ai réduit au maximum la largeur du module.

Mapping

Nom Atmega32u4 Description
VBUS VBUS, UVCC Alimentation USB, utile si vous souhaitez alimenter le montage via une tension supérieure à 3.3V
D7 PE6 Entrée / Sortie 7, INT6, AIN0
D11 PB7 Entrée / Sortie 11, PCINT7, 0C0A, OC1C, #RTS
VCC VCC, AVCC Alimentation 3.3V
D2 PD1 Entrée / Sortie 2 INT1, SDA
RX PD2 Entrée / Sortie 0, RX, INT2
TX
PD3 Entrée / Sortie 1, TX, INT3
GND GND, UGND La masse
A4 PF1 ADC1
A3 PF4 ADC4
D9 PB5 Entrée / Sortie 9, PWM16, PCINT5, ADC12, OC1A, #OC4B
D8 PB4 Entrée / Sortie 8, PCINT4, ADC11
D6 PD7 Entrée / Sortie 6, T0 PWM, ADC10, #OC4D
D12 PD6 Entrée / Sortie 12, T1, ADC9 , #OC4D

Évolutions

Pour la prochaine version du PCB de OpenAlarm Node, j'ai effectué / prévu les modifications suivantes :

  • RX renommé en D0 et TX en D1 (plus logique pour la notation Arduino)
  • L'ouverture du port microUSB à été agrandie
  • Des composants ont été déplacés afin de simplifier leur pose (meilleure occupation de l'espace)
  • Agrandissement des pads de programmation de l'AVR
  • Rerouter SCL afin qu'il soit accessible depuis l'un des ports extérieurs de OpenAlarm (actuellement utilisé pour le RFM12) mais cela pose actuellement des soucis logiciels
  • Grouper les pads par fonction (alimentation : grouper VCC / VBUS et GND)
  • J'ai passé une nouvelle commande chez Seeedstudio de PCB pour un shield OpenAlarm (que je présenterai dans un prochain article) et Seeedstudio m'a gentiment annoncé que dorénavant les trous coupés en 2 seront facturés 17$ de plus (alors que pour le premier batch, je n'ai rien payé de plus), ça fait mal pour une commande de 9$... Du coup, je vais devoir trouver une solution qui serait d'avoir des trous entier et donc d'augmenter légèrement la largeur...

2 vues recto / verso :

OpenAlarm Node recto OpenAlarm Node verso

Participer ?

Et pour ceux qui voudrait participer à l'aventure, je peux soit vous envoyer un PCB brut ou soit vous faire une carte complète, contactez moi directement (comme c'est encore en dèv, je ne monte pas encore de boutique).

Ouvrir l'article

Présentation des OpenAlarm Node

Voilà enfin des nouvelles de OpenAlarm, mais le projet n'est pas mort, loin de là mais ce n'est pas mon seul projet et ça ne permet pas vraiment de payer mes factures, soyez donc patient, ou mieux, participez !

Funky v3

Pour le développement des modules capteurs que j’appellerai maintenant OpenAlarm Node ou pour faire plus court, « Node », je me suis basé sur l'excellent travail de Martin au sujet de module autonome basé sur des RFM12 : les Funky (en version 3), ces derniers sont très petits (un des premiers critères de choix) et consomme très peu (autre critère important) et pour finir, ils sont architecturés autour de microcontrôleurs ATMega, on peut donc bénéficier de la simplicité de développement de l'environnement Arduino...

funky_v3.jpg
Source de la photo

Caractéristiques (source) :

  • Poids de 3gr
  • Compatible avec Arduino
  • Microcontrôleur ATMega32U4, le même que celui utilisé sur l'Arduino Leonardo
  • Pas besoin de programmateur externe, programmation directe via USB
  • Utilisation des modules radios 433/868Mhz RFM12B
  • Peu être utilisé avec le nouveau module RFM69CW
  • Fonctionne à 8Mhz, et peut être alimenté via 2.7V - 3.3V, dont les piles boutons
  • Mode faible consommation
  • La version "step-up" inclu la version 3.3V du LTC3525 boost regulator.

Les Funky v3 étant libre, j'ai donc fabriqué mes propres modules afin de les tester et faire quelques mesures avec.

2015-06-15_10.53.06.jpg
Un de mes modules Funky v3 fait maison

J'ai effectué de multiples tests logiciel, notamment, afin d'obtenir au moins les même résultats annoncé de Martin concernant la faible consommation de ces modules.

La course à la consommation moindre

À quoi bon avoir un module autonome capable de détecter l'ouverture d'une porte si ce dernier demande à être rechargé toutes les semaines et donc retiré momentanément de son service ?

Il est donc essentiel que les modules capteurs de OpenAlarm soit très peu gourmand en énergie.

Le microcontrôleur central des OpenAlarm Node dispose d'un BOD (Brown-out Detection permettant de détecter une tension d'alimentation faible, très utile pour éviter les erreurs d'exécution du micrologiciel embarqué), sans BOD activé, il est possible de descendre la consommation à 5µA, en l'activant, on perd 20 µA mais avec une sécurité supplémentaire, si la tension descend en dessous du seuil configuré, l'AVR entre en veille, garantissant le bon fonctionnement général du programme.

Une solution intéressante aurait été de pouvoir désactiver le BOD durant les périodes de veille via un appel de fonction (sleep_bod_disable()), malheureusement, c'est uniquement possible sur les AVR suffixés d'un P comme Picopower et aucun AVR Mega intégrant un contrôleur USB ne fait parti de cette famille...

Une vue de la consommation pendant une phase d'émission, on remarque un pic de consommation à gauche au moment de la sortie de veille et les pics de conso lors de l'émission du module radio à droite :
TEK00000.PNG

LDO

Un régulateur LDO (Low DropOut) permet de travailler avec une tension d'entrée proche de celle en sortie, il permet dans la node OpenAlarm l'alimentation du montage en convertissant le 5V du port USB en 3.3V.

Dans le design de Martin, au choix, il est possible d'intégrer un MCP170X ou un XC2606 (même brochage) mais dans les 2 cas, j'ai eu quelques soucis...

Le MCP1700 / MCP1703 induit un courant de fuite et la consommation monte en flèche (voir les articles de Martin à ce sujet : High sleep current issue with Funky v2 sorted out, Funky v2’s LDO to blame for high sleep current. Now fixed et Every μA counts).

Le XC6206 est le plus intéressant car il induit une perte de seulement 10µA, ainsi, à 4V, sans LDO, l'AVR en veille, la carte ne consomme que 5.5µA, avec le LDO, on passe à 15µA...

Afin d'éviter un courant de fuite s'échappant via le LDO lors de l'utilisation sur batterie, une idée serait de mettre une diode Schottky (diode à faible chute de tension) en sortie du régulateur, mais il faut qu'elle est des caractéristiques qui nous conviennent bien, c'est à dire une tension directe la plus faible possible et un courant de fuite le plus faible possible (un article à ce sujet Reverse diode current), une diode ayant des caractéristiques intéressantes est la RB751S40 avec vf ~ 300mV et un courant de fuite de 300nA.

Les tests avec cette diode se sont montrés concluants, elle est donc embauchée pour cette tâche !

Mosfet

Le Mosfet est uniquement utilisé pour réduire le courant au démarrage en désactivant le RFM, il est activé une fois l'AVR démarré via logiciel.

Article de Martin à ce sujet : Funky v2 rev 1

Ma version

Basé sur mes tests, j'ai décidé de faire une version légèrement différente pour les OpenAlarm Node :

  • Réduire au maximum la taille
  • Intégrer le port USB dans le PCB afin de gagner en taille / épaisseur / cout (on verra ce que ça donne au niveau solidité mais ayant déjà cassé un port physique sur un Funky, je doute que cela soit pire)
  • Dissocier la partie alimentation du Node en lui même, selon moi, le type d'alimentation dépend avant tout de l'utilisation finale qui va en être fait, exemple :
    • Un Node situé à proximité immédiate d'une source de courant n'a pas besoin d'emmener avec lui des régulateurs ("step-up" comme dans le Funky).
    • Je souhaite alimenter mon module avec une batterie au plomb de 12V, idem, pas besoin de composant en plus
    Au final, les OpenAlarm Node sont conçu afin de pouvoir supporter des cartes filles qui pourront intégrer une partie pour la gestion de l'alimentation.
  • Ajouter une LED afin d'en avoir 2 (rouge et verte), pratique pour indiquer des états sur nos capteurs
  • Des points d'accroches sécables
  • Les broches des ports accessibles facilement en périphérie de la carte au pas de 2.54mm

Voici le schéma de principe qui diffère assez peu de celui des Funky v3 (ajout d'une diode après le régulateur LDO et d'une LED) :
schema.png

Et le PCB, recto / verso :
pcb.png

Une vue 3D à l'échelle avec une pièce de 1 euro :
gerber.png

On remarque le port microUSB réalisé directement dans le PCB, ce dernier faisant 0.8mm d'épaisseur.

Le circuit est légèrement plus petit que le Funky v3 et il est simple d'accéder au broches des ports qui sont matérialisés par les 14 pads à droite et à gauche de la carte.

Le bouton de reset est placé sur la gauche, les leds sont à droite du connecteur USB.

Et la base ?

Oui, c'est bien beau d'avoir des modules autonomes de détection mais où est la base recevant les informations des Nodes ? Et bien, pour le moment, il n'y en a pas ! Il suffit d'utiliser un Node branché directement sur le port USB d'un PC (RaspberryPi par exemple) et voilà, nous avons notre base...

Cette solution à beaucoup d'avantages (cout, facilité, etc...) et n'empêche en rien de créer une base par la suite, elle permet surtout d'avoir quelque chose de fonctionnel malgré le temps dont je ne dispose pas toujours pour avancer sur le projet.

Où en est-on ?

Les PCB sont en cours de fabrication, puis, viendra la phase d'assemblage des cartes, de tests et enfin, un nouvel article...

En attendant, tout est disponible sur GitHub !

Compléments d'informations

Ouvrir l'article

OpenAlarm : Un système d'alarme libre

Après de multiples recherches sur Internet, je m'avoue vaincu : pas moyen de trouver un système d'alarme libre suffisamment avancé et les systèmes propriétaires sont beaucoup trop chères, même d'occasion...

Bien sûr, il reste les systèmes d'alarmes bas de gamme mais que valent t'ils vraiment face à des pros du vol qui connaissent bien les parades...

J'ai donc décidé de développer mon propre système libre, les toutes premières briques ont été posées sur le wiki SystèmeDAlarmeLibre et dans cet article, je vais détailler mes choix.

Cahier des charges

  • Multi-zones sans fil, hors de question de tirer des cables partout, il faudra donc prévoir des capteurs autonomes en énergie et capable de communiquer avec la base par radio
  • Système d'avertissement local sonore et lumineux ainsi qu'un envoi de SMS avec détail sur l'incident (zone, type d’évènement, horodatage)
  • Type de capteurs : Infra rouge (PIR), ouverture (reed switch), vibration, sonore, lumière, fumée, fuite d'eau et pourquoi pas la température et l'humidité
  • Communications sécurisées : Multi-bandes et il ne doit pas être possible de brouiller la bande de fréquences utilisée sans déclencher d'alerte, on ne doit pas pouvoir forger de faux messages de « tout va bien »
  • Alarmes techniques en cas de batterie faible des capteurs autonomes ou perte du signal d'un capteur
  • Watchdog : La centrale doit être capable de se sortir elle même d'un plantage inopiné
  • Autonomie électrique de la centrale : en cas de coupure d'alimentation, elle doit tenir suffisamment longtemps pour avoir le temps de lancer ces alertes
  • Les boitiers des capteurs et de la centrale devront être autant que possible réalisables grâce aux outils d'un fablab (impression 3d, découpe laser, etc...)

Choix techniques

Centrale

La centrale devra donc gérer la communication avec les capteurs, être capable de déclencher des alertes en rapport avec l'incident reporté (effraction supposée : signal sonore et lumineux, envoi de SMS), gérer l'interface utilisateur par le biais d'un serveur web embarqué et d'un clavier déporté.

Le coeur

Le coeur du système sera un RaspberryPi, tout simplement car je connais bien cette carte, elle est peu onéreuse et ces capacités seront largement suffisantes pour ce qu'on va lui demander de faire... La faible consommation du RaspberryPi facilitera son alimentation en cas de perte de la tension du secteur.

Raspberry_Pi_-_Model_A.jpg

En terme de logiciel, Python sera employé et le système sera donc adaptable à toute carte ou PC...

python.png

La communication

La communication avec les capteurs sera effectuée à l'aide d'un nRF905 (http://www.nordicsemi.com/eng/Products/Sub-1-GHz-RF/nRF905), un circuit intégré spécialisé ayant la particularité de pouvoir émettre au choix sur 3 bandes (433, 868 et 915MHz), d'avoir une très faible consommation et d'être très simple à mettre en oeuvre.

Le module GSM pour l'envoi de SMS sera un SIM900.

nrf905.jpg sim900.jpg

Module capteurs

Une des partie les plus critiques du système est la capture des événements par le biais de capteurs (infra-rouge, etc...), ces modules doivent être totalement autonome, alimenté par batterie, voici les parties communes :

  • La partie radio basé sur un nRF905
  • Le coeur : Un Avr (tinyAvr) d'Atmel se chargera de lire l'état du capteur, de communiquer avec la base, de vérifier l'état de la batterie
  • Des entrées / sorties pour y brancher le ou les capteurs
  • Une batterie

L'autonomie étant critique, l'AVR pourra se mettre en veille et en sortir soit au bout d'un temps déterminé pour vérifier l'état du capteur et avertir la base que tout va bien (ou que tout va mal), ou il pourra également sortir de veille par le biais d'un changement d'état du capteur.

Je pense faire une carte électronique générique pour tous les capteurs afin de gagner en coût et en facilité.

La suite

Dans un premier temps, je veux m'assurer de la bonne portée pratique des modules radios ainsi que de leur consommation car il s'agit DES parties critiques du système.

Ayant d'autres projets sur le feu (dont certain qui trainent depuis bien trop longtemps), j'essaierai d'avancer sur OpenAlarm au mieux...En attendant, j'attends vos retours / avis / conseils / idées, etc...

Un dépôt GitHub OpenAlarm à été ouvert oû je mettrai toutes les informations utiles au développement, le wiki sur GitHub sera aussi tenu à jour.

Ouvrir l'article