4.premiers pas avec du code
Tout est documenté et accessible (en anglais) depuis cette page et plus particulièrement la page réservée aux développeurs. Ils vous y expliquent comment envoyer un message, créer un callback et pointent sur des projets d'apprentissage.
J'aime bien me débrouiller donc je me lance en me disant que je vais utiliser la librairie fournie pour exporter la T° du capteur embarqué directement dans la carte en m'appuyant sur un des exemples.
Le code du WeatherMonitor se lit assez simplement, donc je le transforme pour me servir de base à ma première communication et je ponds ce petit bout de code:
#include <SigFox.h>
typedef struct __attribute__ ((packed)) sigfox_message { // see http://www.catb.org/esr/structure-packing/#_structure_alignment_and_padding
int16_t moduleTemperature;
} SigfoxMessage;
// stub for message which will be sent
SigfoxMessage msg;
// =================== UTILITIES ===================
void reboot() {
NVIC_SystemReset();
while (1);
}
// =================================================
void setup() {
Serial.begin(115200);
while (!Serial);
if (!SigFox.begin()) {
Serial.println("SigFox error, rebooting");
reboot();
}
delay(100); // Wait at least 30ms after first configuration
// Enable debug prints and LED indication
SigFox.debug();
// Read and convert the module temperature
msg.moduleTemperature = (int32_t) (SigFox.internalTemperature() * 100.0); // température 1/100th of degrees
Serial.print("Internal temp: ");
Serial.print(msg.moduleTemperature, HEX); // display what we will send in Hexadecimal
Serial.print(" (");
Serial.print(msg.moduleTemperature); // display what we will send in Decimal
Serial.println(" x100 deg C)");
// Clears all pending interrupts
SigFox.status();
delay(1);
// Send the data
SigFox.beginPacket();
SigFox.write((uint8_t*)&msg, sizeof(SigfoxMessage));
Serial.print("Status: ");
Serial.println(SigFox.endPacket());
SigFox.end();
}
void loop() {}
En gros
je déclare une structure - pour le moment avec une seule data sur 2 octets - qui sera le modèle de message émis depuis mon application. il y a une petite subtilité pour cette déclaration, l'attribut packed (__attribute__ ((packed))
) qui permet de gérer les problèmes potentiels d'alignement et de padding (si j'avais plusieurs membres dans ma structure puisqu'on peut envoyer jusqu'à 12 octets, ici ce n'est pas nécessaire dans l'absolu).
- je définis une fonction utilitaires qui reboot au cas où
- j'ouvre le port Série, je démarre le modem SIGFOX
- Si tout se passe bien j'attends un petit peu (100ms pour la première config dit la spec, ensuite 30)
- j'active le mode debug (la LED verte qui montre l'activité - enfin je crois que c'est ça )
- je vais lire la T° du module, un float, que je multiplie par 100 pour avoir 2 chiffres après la virgules et je convertis en entier sur 2 octets (ça devrait rentrer pour les T° courantes) et je mets dans cela ma structure
- J'affiche sur la console série ce que je vais envoyer
- j'effectue l'envoi et affiche le code retourné par la fin de paquet (0 = tout va bien)
- je clos la connexion au module sigfox, ma transaction est terminée
Voilà... allez on se lance. J'ouvre la console à 115200 bauds, j'upload mon code.
La console m'affiche la température, puis Status et je dois patienter un petit moment avant de voir le 0 s'afficher (ne pas oublier qu'on est en "bas débit !")
</sub> <sub>[color=blue]Internal temp: B54 (2900 x100 deg C) Status: 0 [/color]</sub> <sub>
Je me connecte donc sur le site de Sigfox, pour le moment je n'ai pas défini de Callback donc je choisis d'afficher ma liste d'appareils et je choisis mon MKRFOX1200
et je dans la nouvelle fenêtre je choisis dans le menu à Gauche d'afficher les messages reçus par Sigfox
(dans cette image j'ai lancé mon programme 3 fois, donc on voit 3 messages)
et la magique je retrouve ma valeur
B54
(correspondant à 29°)... bon ce n'est pas tout à fait B54 que l'on voit. la raison est simple 0x0B54 qui était mon nombre sur 2 octets était représenté en mémoire avec d'abord l'octet de poids faible, 0x54 puis l'octet de poids fort 0x0B. c'est ce qui a été envoyé. Comme je n'ai pas appris à Sigfox le format des données qu'il allait recevoir il m'affiche l'hexadécimal brut tel qu'il l'a reçu.
Si vous allez dans l'onglet DEVICE TYPE et éditez votre device vous pouvez fournir une "grammaire de décodage" adaptée à votre objet connecté.
Custom message type decoding grammar
The "custom format" grammar is as follows :
format = field_def [" " field_def]* ;
field_def = field_name ":" byte_index ":" type_def ;
field_name = (alpha | digit | "#" | "_")* ;
byte_index = [digit*] ;
type_def = bool_def | char_def | float_def | uint_def ;
bool_def = "bool:" ("0" | "1" | "2" | "3" | "4" | "5" | "6" | "7") ;
char_def = "char:" length ("0" | "1" | "2" | "3" | "4" | "5" | "6" | "7");
float_def = "float:" ("32" | "64") [ ":little-endian" | ":big-endian" ] ("0" | "1" | "2" | "3" | "4" | "5" | "6" | "7");
uint_def = "uint:" ["1" - "64"] [ ":little-endian" | ":big-endian" ] ("0" | "1" | "2" | "3" | "4" | "5" | "6" | "7");
int_def = "int:" ["1" - "64"] [ ":little-endian" | ":big-endian" ] ("0" | "1" | "2" | "3" | "4" | "5" | "6" | "7");
length = number* ;
digit = "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9"
A field is defined by its name, its position in the message bytes, its length and its type :
the field name is an identifier including letters, digits and the '-' and '_' characters.
the byte index is the offset in the message buffer where the field is to be read from, starting at zero. If omitted, the position used is the current byte for boolean fields, the next byte for all other types if the previous element has no bit offset and the last byte used if the previous element has a bit offset. For the first field, an omitted position means zero (start of the message buffer)
Next comes the type name and parameters, which varies depending on the type :
boolean : parameter is the bit position in the target byte
char : parameter is the number of bytes to gather in a string, and optionally the bit offset where to start the reading of the first byte, Default value is 7 for the offset
float : parameters are the length in bits of the value, which can be either 32 or 64 bits, optionally the endianness for multi-bytes floats, and optionally the bit offset where to start the reading of the first byte. Default is big endian and 7 for the offset. Decoding is done according to the IEEE 754 standard.
uint (unsigned integer) : parameters are the number of bits to include in the value, optionally the endianness for multi-bytes integers, and optionally the bit offset where to start the reading of the first byte. Default is big endian and 7 for the offset.
int (signed integer) : parameters are the number of bits to include in the value, optionally the endianness for multi-bytes integers, and optionally the bit offset where to start the reading of the first byte.
Par exemple si vous donnez comme grammaire
int1::uint:8 int2::uint:8
et que vous avez reçu
1234
alors l'affichage sera
{ int1: 0x12, int2: 0x34 }
Je m'empresse donc de faire cette modification en déclare comme grammaire
temp::int:16:little-endian
je retourne sur ma page des message et là magie, je vois bien[color=blue] temp: 2900[/color]
EDIT:
Dans un autre post sur le forum principal une question se posait sur comment aller lire précisément des valeurs dans le cadre d'une grammaire un peu compliquée.
--> j'ai apporté quelques explications supplémentaires là bas
et notez que la grammaire sur le site de SIGFOX a un bug, il faut mettre un : avant le bit offset si vous l'utilisez