xPL.Arduino, réception des messages
Bonjour, j’ai ouvert un projet sur google code récement : xPL.Arduino. C’est une librairie permettant l’émission et le decodage de message xPL. Je vais vous expliquer rapidement dans cet article comment réceptionner et parser les messages xPL.
[adsGrandRectangleHTexte]
Les sources de la librairie sont accessibles sur google code et la version 0.2 est disponible dans la section download.
Je vais vous détailler les exemples concernant le shield ENC28J60 puisque c’est celui que j’utilise pour le moment et qu’il est légèrement plus compliqué à mettre en oeuvre.
Réception des messages xPL
Je vous rappelle que j’utilise la librairie ethercard pour la gestion du shield ethernet.
La partie déclaration. On définit ici le buffer de réception des trames ethernet (au moins égale à la taille max d’un message xPL) ainsi que les paramètres de la carte réseau. Adresse IP, MAC, Passerelle et l’adresse de broadcast du réseau.
Attention, la librairie ethercard n’émet des packets en broadcast que sur l’adresse 255.255.255.255, n’indiquez donc pas ici l’adresse de broadcast du réseau (192.168.0.255 dans mon cas). Et si vous utilisez xpl-perl, indiquez au xpl-hub d’écouter sur 0.0.0.0 avec –define broadcast=0.0.0.0 sinon vous ne recevrez rien :/
#include <xPL.h> #include <EtherCard.h> byte Ethernet::buffer[XPL_MESSAGE_BUFFER_MAX]; xPL xpl; // Init du serveur HTTP uint8_t mymac[6] = { 0x54,0x55,0x58,0x10,0x00,0x11 }; uint8_t myip[4] = { 192,168,0,133 }; uint8_t gwip[4] = { 192,168,0,240}; // Ethercard seems to only send broadcast on this addr // if using xpl-perl, don't forget to add "--define broadcast=0.0.0.0" to the xpl-hub uint8_t broadcast[4] = { 255,255,255,255};
On définit ensuite deux fonctions. Une qui se chargera de l’émission des messages sur le réseau. Cette fonction est à adapter en fonction du shield ethernet et de la libraire ethernet utilisée.
void SendUdPMessage(char *buffer) { ether.sendUdp (buffer, strlen(buffer), xpl.udp_port, broadcast, xpl.udp_port); }
La deuxième fonction sera appellée par la librairie xPL à chaque fois qu’elle aura parsé un message xPL avec succès. On y fait ce que l’on veut, c’est ici que l’on va faire réagir l’arduino en fonction du type de message reçu.
Dans l’exemple, on affiche le message dans la console et si le message est explicitement destiné à l’arduino (xpl.TargeIsMe), on vérifie de quel type est ce message. Si son schéma est de type lighting.basic on affiche un message sur la console.
void AfterParseAction(xPL_Message * message) { if (xpl.TargetIsMe(message)) { if (message->IsSchema_P(PSTR("lighting"), PSTR("basic"))) { Serial.println(PSTR("is lighting.basic")); } } // show message Serial.println(message->toString()); }
Vient ensuite le setup. On passe nos deux fonctions à la librairie xPL, puis on définit la source par laquelle l’arduino sera vu sur le réseau xPL, ici : xpl-arduino.test. Il reste ensuite à définir l’interval en minutes entre chaque message heartbeat. Ces messages permettent aux autres applications xPL du réseau de connaitre votre application et de savoir si elle est toujours active.
void setup() { [...] xpl.SendExternal = &SendUdPMessage; // pointer to the send callback xpl.AfterParseAction = &AfterParseAction; // pointer to a post parsing action callback xpl.SetSource_P(PSTR("xpl"), PSTR("arduino"), PSTR("test")); // parameters for hearbeat message }
Le corp du sketch. On commence par xpl.Process(). Cette méthode gère l’émission des messages heartbeat.
On récupère ensuite les packets entrant (ether.packetReceive()) et si c’est un message xPL on le parse avec xpl.ParseInputMessage.
Si vous avez suivis, une fois le parsing terminé, la librairie appelle notre fonction AfterParseAction pour traiter le message.
void loop() { xpl.Process(); // heartbeat management word len = ether.packetReceive(); if( len > 0 ) { // Check if Xpl UDP packet if( isXpl( Ethernet::buffer ) ) { char xPLMessageBuff[XPL_MESSAGE_BUFFER_MAX]; ByteToChar(Ethernet::buffer, xPLMessageBuff, len); // parse du message xpl.ParseInputMessage(xPLMessageBuff); } } }
Et voila, c’est tout pour la réception de messages. Je vous invite à lire l’article suivant sur l’émission de message xPL.
Bonjour,
J’essai actuellement d’utiliser votre librairie, cependant lorsque je test le code d’exemple pour le shield ethernet classique, le premier message reçu est affiché entièrement mais le second ne contient pas de commande.
De plus, tout ce qui utilise le progmem ne semble pas fonctionner :
– Serial.println(PSTR( …
– IsSchema_P(PSTR(« lighting »), PSTR(« basic »))
Pourtant il détecte bien lorsqu’un message est pour lui.
Faut il ajouter quelque chose pour la gestion du Progmem ? Merci de votre aide
Goo
Bonjour,
N’ayant pas encore de shield officiel, je n’ai testé que sur enc28j60. Cependant tout le code de la librairie est commun, il n’y a que le code du sketch qui change donc ca devrait fonctionner de la meme façon.
Deux choses à vérifier :
sur quelle version de l’IDE arduino travaillez vous ? < à 1.0 ou >= à 1.0 ?
et sur quel arduino ? Il me semble que pour l’instant, niveau memoire, le UNO est un peut juste pour le parser (à vérifier).
Tout d’abord, merci de votre réponse si rapide.
Je suis sur un shield officiel, un arduino UNO et un IDE 1.0.1.
Avec les 2 corrections précisée dans le post ci dessous, tout fonctionne parfaitement lors de la reception du premier message.
En revanche, a partir du deuxième message, seules les commandes ne sont plus enregistrée.
Edit : pendant que l’écriture de ce message j’ai fait un test dont le résultat est étrange :
Envoie du premier message (contenant 3 commande) : pas de souci.
Envoie d’un autre message (1 commande) : pas de souci.
Envoie du message à 3 commande : probleme.
Envoie du message à 1 commande : pas de souci
Pour l’IDE, c’est celui que j’utilsie aussi.
Pour les commands, la memoire est alouée dynamiquement (pas top sur de l’embarqué) mais on limite (arbitrairement) les messages à 10 commandes.
Normalement c’est désaloué proprement une fois le message traité. Il faudrait peut etre vérifier de ce coté ?
En effet le problème semble être dû à un problème de taille mémoire.
Après avoir réduit la taille des valeurs à 32 (au lieu de 128) tout semble fonctionner.
Merci beaucoup
Par contre tu risque de recevoir des messages xPL incomplets :/ (je n’en ai jamais vu d’une telle taille cela dit)
128 est la taille définit dans la spec du protocol.
Je cherche justement à réduire l’empreinte mémoire du parser donc si tu as des idées n’hésite pas 🙂
Hi there,
Warning: I’m not a programmer so I might say dumb things. 😉
I’m playing with xPL and have a problem accessing the commands and values when there are multiple in the xPL message.
The xPL message is like:
xpl-stat
{
hop=1
source=blah.host
target=*
}
sensor.basic
{
device=testdevice
type=input
current=99
}
In my Arduino source I use:
void AfterParseAction(xPL_Message * message)
{
Serial.println(message->command_count);
ParseSensorUpdate(message->command->name);
ParseSensorUpdate(message->command->value);
}
The message count is 3 as expected, but my ParseSensorUpdate function only sees « device » and « testdevice » for name and value of the xPL-command.
How can I access the « current » and « 99 » part?
I tried « ParseSensorUpdate(message->command[1].name) » and various combinations, but I doesn’t compile… 🙁
Je rajoute une petite précision
Dans IsSchema, ne faudrait il pas changer :
if (memcmp(schema.class_id, _classId, 8) == 0)
par
if (memcmp(schema.class_id, _classId, strlen(schema.class_id)) == 0)
?
Si si tu as raison, il y a une coquille ici que johan m’a remonté la semaine dernière. Je n’ai pas eu le temps de corriger et vérifier le reste du code.
Si l’arduino chope des messages avec des shemas qui font justement 8 caractères cela pose problème.
Merci pour l’info, j’essai de corriger rapidement.
ou l’inverse pardon
Bonjour, j’ai retravaillé le code de la librairie parce que j’avais plusieurs problèmes de fuite de mémoire + le parser qui n’était pas totalement bullet-proof sur des messages mal formés. J’ai posté cela sur le site de google dans la partie issues:
Salut,
Merci Laurent pour ton travail. Suite aux commentaires de Goo et Johan j’avais commencé à regarder ces problèmes mais je ne suis pas aller aussi loin 🙂
Veux tu un accès en tant que commiter sur le projet google code ?
Hi,
My French writing skills are not very good, so please excuse me for writing in English.
I used the zip file from the bug report at http://code.google.com/p/xpl-arduino/issues/detail?id=1in order to get it working.
It contains an error were an IP address was hardcoded in xPL.cpp.
I assume this was for a test, because the correct line was just before it and was commented out.
I stil have 2 issues, though.
1: It seems « if (xpl.TargetIsMe(message)) » does not work.
2: How can I have access to the command and the values of a received xPL message? Is this functionality available?
The last part is quite imortant. 🙂
Is this library still maintained?
Hi,
No problem 🙂
The author of the bug report have change the heartbeat schema from hbeat.basic to hbeat.app in which you have some more informations (port, remote-ip). According to the specifications this is used by « PC based app ». For small devices, you can use hbeat.basic (the commented line above) and change XPL_HBEAT_ANSWER_TYPE_ID from « app » to « basic »
>1: It seems « if (xpl.TargetIsMe(message)) » does not work.
Can’t say, I need to make a test :/
>2: How can I have access to the command and the values of a received xPL message? Is this functionality available?
There is actually no functions to acces command tab but it’s a public properties of the xPL_Message class so you should be able to use it directly.
Would you want some search functions ?
> Is this library still maintained?
Yes, I will release a new version (based on the version from the bug report) as soon as possible, just need to find some time to test it before :/
I email you as soon a new version is available if you want.
Bonjour j’ai également le même problème que Goo après l’envoie de les messages via une première carte Arduino, je veux récuperer l’information avec cette deuxième carte arduino mais il ne m’affiche que le premier message entièrement
xpl-trig
{
hop=1
source=xpl-arduino.test
target=*
}
sensor.basic
{
device=1
type=temp
current=27.63
}
xpl-trig
{
hop=1
source=xpl-arduino.test
target=*
}
sensor.basic
{
xpl-trig
{
hop=1
source=xpl-arduino.test
target=*
}
sensor.basic
{
Voici à peut près le résultat IDE 1.0.3 avec une carte Arduino UNO et un shield Ethernet Officiel
Cordialement Quentin
Ah désolé pour le post j’ai utilisé la librairie de Laurent et ca marche maintenant 😉
Bonjour Olivier,
Je cherche à implémenter le protocol xPL sur ma carte Arduino et je suis tombé sur ton blog qui parlait d’une librairie que tu as developpé.
Je suis donc très intéressé pour utiliser cette librairie mais j’ai quelques questions avant :
1 – La librairie est-elle indépendante du connecteur réseau ? utilisation d’un module wifi ou zigbee par exemple ?
2 – Laurent a corrigé des bugs dans la librairie mais au vu de la date de création du zip de la 0.2, la librairie ne comporte pas les fix de Laurent.
Est-ce bien le cas ? si oui, serait-il possible d’avoir une nouvelle version avec ces fix ?
merci d’avance
Bonsoir,
Le code est indépendant du hardware, charge à toi d’ajouter le code nécessaire à l’envoi du paquet dans le sketch. J’ai testé, et fournis un ex, sur les deux shields Ethernet connus (l’officiel et le ENC) donc ça devrait le faire pour d’autre type de matériel.
Effectivement je n’ai pas maintenu la librairie (suite à la vente de ma maison). La version corrigée de Laurent est disponible ici si je ne me trompe pas: https://code.google.com/p/xpl-arduino/issues/detail?id=1
Je viens tout juste de racheter une maison que je compte domotiser, il est donc probable que dans les mois à venir je rafraichisse tout ça 🙂
++