envoi d'un message vers SIGFOX Max 12 octets

Bonjour,
Je dois envoyer des données de capteurs dans un message sigfox. Peut'on optimiser mon code pour que j'envoi une donnée complémentaire et que ca reste dans du 12 octects ?

Les données envoyées :

typedef struct __attribute__ ((packed)) sigfox_message { 
 
 int16_t temp2;
 int16_t dhtTemperature;
 uint16_t dhtHumidity;
 float poids;
 uint16_t tension;
 uint16_t essaimage;
}

essaimage = 1 ou 0
tension de la batterie de 00 à 100
poids : avec 3 chiffres après la virgules
dhtHumidity : entier sur 2 chiffre
temp2 et dhtTempearature : entier sur 2 chiffre

Merci
partie SIFGOX Portail :
temp2::int:16:little-endian dhtTemperature::int:16:little-endian dhtHumidity::uint:16:little-endian poids::float:32:little-endian tension::uint:16:little-endian essaimage::uint:16:little-endian

mais cela depasse les 12 octets !
Merci.

Bonjour

optimisation possible en réduisant le nombre de bits de chaque élément du message

première étape , sans compliquer le traitement :
dhtTemperature, temp2, dhthumidité, tension : 8 bits au lieu de 16 (int8)
essaimage : 1 bit (uint:1, côté portail Sigfox)

En compliquant un peu , au vu de la plage des données, il est possible de tasser encore plus en n'allouant que 7 bits à tension et les deux dht (7 bits suffisent pour coder un entier de 0 à 127)

voir par exemple cette page du site Framboise 314 (bas de page "Dans 12 octets qu'est-ce que tu veux mettre ?"

avec les contraintes que vous donnez vous pouvez avoir 9 octets sur MKRFOX

struct __attribute__ ((packed)) sigfox_messageBig {
  uint8_t   tension;          // 0 à 255
  uint8_t   essaimage;        // 0 à 255
  int8_t    dhtTemperature;   // -128° à 127°
  int8_t    temp2;            // -128° à 127°
  uint8_t   dhtHumidity;      // 0 à 100%
  float     poids;
} ;

mais vous pouvez faire mieux avec vos contraintes, sans pour autant modifier la façon dont on accède aux champs de la structure: Vous pouvez d'utiliser des champs de bit (bit field pour les anglophones) - ça donne ce que l'on attend d'un point de vue représentation mémoire

struct __attribute__ ((packed)) sigfox_messageSmall {
  uint8_t   tension : 7;      // 7 bits (0 à 127)
  uint8_t   essaimage: 1;     // 1 bit (0 ou 1)
  int8_t    dhtTemperature;   // -128° à 127°
  int8_t    temp2;            // -128° à 127°
  uint8_t   dhtHumidity;      // 0 à 100%
  float     poids;
} ;

Voici un petit programme d'essai

/*
  tension de la batterie de 00 à 100
  essaimage = 1 ou 0
  poids : avec 3 chiffres après la virgules
  dhtHumidity : entier sur 2 chiffre
  temp2 et dhtTempearature : entier sur 2 chiffre

*/

struct __attribute__ ((packed)) sigfox_messageBig {
  uint8_t   tension;          // 0 à 255
  uint8_t   essaimage;        // 0 à 255
  int8_t    dhtTemperature;   // -128° à 127°
  int8_t    temp2;            // -128° à 127°
  uint8_t   dhtHumidity;      // 0 à 100%
  float     poids;
} ;

struct __attribute__ ((packed)) sigfox_messageSmall {
  uint8_t   tension : 7;      // 7 bits (0 à 127)
  uint8_t   essaimage: 1;     // 1 bit (0 ou 1)
  int8_t    dhtTemperature;   // -128° à 127°
  int8_t    temp2;            // -128° à 127°
  uint8_t   dhtHumidity;      // 0 à 100%
  float     poids;
} ;

sigfox_messageBig enregistrement1;
sigfox_messageSmall enregistrement2;

void printBinary(uint8_t * ptr, byte n)
{
  for (int i = n - 1 ; i >= 0; --i) {
    for (int b = 7; b >= 0; --b) {
      if (bitRead(*(ptr + i), b)) Serial.print("1");
      else Serial.print("0");
    }
    Serial.print(" ");
  }
}


void setup() {
  uint8_t * ptr;

  Serial.begin(115200);
  while (!Serial);


  Serial.println("****** structure de base ******");
  Serial.print("Taille d'un enregistrement Big = ");
  Serial.println(sizeof(enregistrement1));

  ptr  = (uint8_t *) &enregistrement1;
  enregistrement1.tension = 64 + 16 + 4 + 1; // on devrait voir B01010101
  enregistrement1.essaimage = true;       // le bit de poids faible à 1

  printBinary(ptr, 1); Serial.println("\ttension");
  printBinary(ptr + 1, 1); Serial.println("\tEssaimage");

  Serial.println("\n****** avec champs de bit ******");
  Serial.print("Taille d'un enregistrement Small = ");
  Serial.println(sizeof(enregistrement2));

  ptr  = (uint8_t *) &enregistrement2;
  enregistrement2.tension = 64 + 16 + 4 + 1; // on devrait voir B01010101
  enregistrement2.essaimage = false;       // le bit de poids fort à 0
  printBinary(ptr, 1); Serial.println("\tEssaimage et Tension");

  enregistrement2.essaimage = true;       // le bit de poids fort à 1
  printBinary(ptr, 1); Serial.println("\tEssaimage et Tension");

  enregistrement2.tension = 8 + 4 + 2 + 1; // les 4 bits de poids faibles à 1
  printBinary(ptr, 1); Serial.println("\tEssaimage et Tension");
}


void loop() {}

si vous l'exécutez vous verrez dans la console série:

[sub][color=blue]****** structure de base ******
Taille d'un enregistrement Big = 9
01010101 	tension
[color=red]00000001[/color] 	[color=red]Essaimage[/color]

****** avec champs de bit ******
Taille d'un enregistrement Small = 8
[color=red]0[/color]1010101 	[color=red]Essaimage[/color] et Tension
[color=red]1[/color]1010101 	[color=red]Essaimage[/color] et Tension
[color=red]1[/color]0001111 	[color=red]Essaimage[/color] et Tension
[/color][/sub]

al1fch:
Bonjour

optimisation possible en réduisant le nombre de bits de chaque élément du message

première étape , sans compliquer le traitement :
dhtTemperature, temp2, dhthumidité, tension : 8 bits au lieu de 16 (int8)
essaimage : 1 bit (uint:1, côté portail Sigfox)

En compliquant un peu , au vu de la plage des données, il est possible de tasser encore plus en n'allouant que 7 bits à tension et les deux dht (7 bits suffisent pour coder un entier de 0 à 127)

voir par exemple cette page du site Framboise 314 (bas de page "Dans 12 octets qu'est-ce que tu veux mettre ?"

Bonsoir al1
Ton lien est intéressant à parcourir
on arrive sur celui ci
https://yadom.fr/reseaux-iot/sigfox/carte-breakout-sfm10r1.html
(module sigfox + abo 1/an 140 msg/jour)
qui semble simple d'interfaçage

Juste pour jouer ,je vais en commander un lundi ;D

moins complète que la MKRFOX mais moins chère

Bonjour Artouste, Bonjour JML

Ce petit 'modem' ou 'transceiver' Sigfox est pratique et 'passe partout'.( je m'en sers avec une carte Micro Pro, un WeeMos D1 mini, un Weemos Lolin 32, Raspberry...)

Côté prix il faut souligner qu'il n'inclut qu'un abonnement Sigfox d'une année contre deux pour le MKR Fox 1200. (Un an Sigfox coute chez yadom 14 € HT) Un µC ou µP externe est bien entendu à ajouter.
L'écart de prix est réduit d'autant. (l'antenne demi-onde parait par contre de meilleure facture)

SNOC (Yadom) fabrique ce break-out pour un module du coréen Wisol, lequel module reproduit le schéma d'application de la puce radio AX-SFEU de On Semi. Puce bien documentée. On voit sur le pdf que certains GPIO ainsi que RX sont '5V tolérant' (pas vu l'info ailleurs) On peut donc le connecter à 9600 bauds en soft-serial à une carte Uno. (j'ai eu l'info du site Wisol avec une photo de l'intérieur du module pour constater l'absence de composant actif autre que l'AX-SFEU et donc la conservation du '5V tolerant' pour une partie des GPIO)

Interfaçage et commandes ultra simples .... je me contente en tout et pour tout de 3 commandes AT dont une pour mettre le module en sommeil profond. Pour la mise en route pas besoin de manipulation pour récupérer les données d'identification (ID et PAC) elles sont imprimées sur une carte.

Le dialogue avec Yadom, Wisol et Sigfox a été facile . J'ai eu rapidement les compléments d'information souhaités.
Le S.A.V Yadom à l'écoute et réactif (pb sur le pigtail d'un des 2 modules commandés)

Côté consommation c'est excellent : 100nA en deep sleep (réveil par GPIO 9 qui tolère le 5V)
Commandé par un Arduino Micro modifié qui consomme 4µA en sommeil ça laisse entrevoir une belle autonomie ! L'auto décharge des piles ou de la batterie devient sans doute le facteur limitant principal !!

Merci pour le détail - effectivement semble super intéressant

Le bémol Sifgox est l'incertitude sur la couverture : pas évident avant essai de savoir si le coin de campagne ( où on aimerait remplacer le module GSM énergivore) sera couvert ou pas.
La carte de couverture du site Sifgox est figée à une grande échelle.
Je n'ai pas trouvé pour le réseau Sigfox de page renseignant sur la qualité de couverture pour un code postal donné.

pour info voici l'intérieur du module WSSFM10R1AT (source Wisol) implanté sur le breakout de SNOC/Yadom


pour info également voici , vu en SDR, l'envoi en 7 secondes d'un message Sigfox avec la répétition sur 3 fréquences

Côté MKR si le MKR WAN 1300 (lora et lorawan) à 35 € HT inclut en France un abonnement au réseau LoRaWAN Orange ou Bouygues (Objenious) je fonce !!

Je crois qu’il n’y a pas d’abonnement associé, c’est dommage car ça semble galère pour un particulier bidouilleur de souscrire une offre Orange ou Bouygues (Orange a un starter kit avec 6 mois compris qui permettra ensuite un abonnement entre 1€ ou 2€ par mois par objet suivant la durée d’engagement). Si c’est pour jouer autour de chez vous il y a aussi la solution d’acheter une pico gateway LoRa (par exemple la Pico-Gateway Lora MG003-L-EU) et faire votre propre réseau privé)

Un petit espoir : qu'Orange valide le kit MKR WAN1300 et fasse une offre autour. Peu d'espoir, c'est pas dans l'ADN d'Orange qui préfère sans doute encore se limiter aux 'partenaires' ayant pignon sur rue...
Sur le site Orange LiveObjects on peut lire ceci qui évoque des contraintes légales (???) non citées qui réserveraient le réseau aux entreprises !!! (un bon point pour Sigfox !!)
kbis.jpg

J'ai regardé les solutions 'gateway perso privée' ainsi que les possibilités de 'gateway sur réseau collaboratif The Thing Network.'

Dans mon cas le gateway perso privé ou le gateway TTN n'ont pas d'intérêt, je cherche à remplacer le GSM en un lieu ou il n'y a pas de WiFi. Il me semble qu'avec la disparition programmée de la 2G la question se pose.

Pour les premiers pas , sans couverture/abonnement LoRaWAN il ya la posibilité de monter une gateway 'simple client' avec l'un des modules LoRa du marché

J'ai 'compilé' peu à peu les infos sur les diverses solutions LoRaWAN dans un récent fil ouvert avec "LoRaWAN" en titre, avec la problématique : où est la pile réseau LoRaWAN ?

Merci pour le fil de duscussion (avec la bonne url)

Pour en revenir au sujet initial, j'ai modifié dans le Back-end SIGFOX la partie grammaire ainsi (dans le Custom payload config) :

temp2::int:8:big-endian dhtTemperature::int:8:big-endian dhtHumidity::uint:8:big-endian poids::float:32:little-endian tension::uint:8:big-endian essaimage::uint:8:big-endian

et tout fonctionne correctement.
Merci.

@fabricecarrique
Avec cette nouvelle définition du format des données envoyées il te reste, si mes calculs sont bons, 24 bits disponibles dans le message Sigfox

al1fch:
Bonjour Artouste, Bonjour JML

Ce petit 'modem' ou 'transceiver' Sigfox est pratique et 'passe partout'.( je m'en sers avec une carte Micro Pro, un WeeMos D1 mini, un Weemos Lolin 32, Raspberry...)

Côté prix il faut souligner qu'il n'inclut qu'un abonnement Sigfox d'une année contre deux pour le MKR Fox 1200. (Un an Sigfox coute chez yadom 14 € HT) Un µC ou µP externe est bien entendu à ajouter.
L'écart de prix est réduit d'autant. (l'antenne demi-onde parait par contre de meilleure facture)

SNOC (Yadom) fabrique ce break-out pour un module du coréen Wisol, lequel module reproduit le schéma d'application de la puce radio AX-SFEU de On Semi. Puce bien documentée. On voit sur le pdf que certains GPIO ainsi que RX sont '5V tolérant' (pas vu l'info ailleurs) On peut donc le connecter à 9600 bauds en soft-serial à une carte Uno. (j'ai eu l'info du site Wisol avec une photo de l'intérieur du module pour constater l'absence de composant actif autre que l'AX-SFEU et donc la conservation du '5V tolerant' pour une partie des GPIO)

Interfaçage et commandes ultra simples .... je me contente en tout et pour tout de 3 commandes AT dont une pour mettre le module en sommeil profond. Pour la mise en route pas besoin de manipulation pour récupérer les données d'identification (ID et PAC) elles sont imprimées sur une carte.

Le dialogue avec Yadom, Wisol et Sigfox a été facile . J'ai eu rapidement les compléments d'information souhaités.
Le S.A.V Yadom à l'écoute et réactif (pb sur le pigtail d'un des 2 modules commandés)

Côté consommation c'est excellent : 100nA en deep sleep (réveil par GPIO 9 qui tolère le 5V)
Commandé par un Arduino Micro modifié qui consomme 4µA en sommeil ça laisse entrevoir une belle autonomie ! L'auto décharge des piles ou de la batterie devient sans doute le facteur limitant principal !!

Bonjour Al1
effectivement la durée de l'abo Vs MKr1200 est à prendre en compte
mais "pour" jouer avec # MCU je trouve ce module plus versatile .
De toutes façons , l'un comme l'autre passeront dans mon "budget pro" "veille techno" 8)

fabricecarrique:
Pour en revenir au sujet initial, j'ai modifié dans le Back-end SIGFOX la partie grammaire ainsi (dans le Custom payload config) :

temp2::int:8:big-endian dhtTemperature::int:8:big-endian dhtHumidity::uint:8:big-endian poids::float:32:little-endian tension::uint:8:big-endian essaimage::uint:8:big-endian

et tout fonctionne correctement.
Merci.

pour être intellectuellement "correct" — même si ça ne change absolument rien et pour un octet ça ne veut de toute façon rien dire — au lieu de dire big-endian pour vos int:8, mettez little-endian partout. Les données Arduino avec le compilateur actuel sont little-endian.

ça évitera de se demander pourquoi certaines données sont big-endian et d'autres little-endian

@ al1fch et J-m-l
?
sur l'environnement "iHM" sigfox "qu'à ce jour " je ne connais pas 8)
avec un "crédit/jours" de x "trames/MSG"

Comment (où) est vérifié/vérifiable , le "crédit restant ?

pas de système de crédit, on n'a pas à faire à un opérateur téléphonique !
A ce jour le 'dépassement de forfait' n'est pas au centre de leur modèle économique .....

Le réseau Sigfox doit , dans chaque pays, respecter la régulation concernant la bande de fréquence utilisée. En France c'est 6 messages par heure. Chaque message émis dure 6 secondes. Donc 36 secondes maxi d'émission par heure = 1% du temps maxi comme le définit l'ARCEP
(Je ne sais pas pourquoi Sigfox a choisi dans les 868MHz une bande plutôt restrictive en taux d'occupation et en débit .... LoRaWAn utilise , lui, une bande plus 'généreuse' dans les 868 MHz)

L'utilisateur s'engage à respecter le quota .

Sigfox ne garantit pas l'acheminement des messages excédentaires (sans doute communique-t-il avec les utilisateurs qui dépassent le quota de manière répétitive avant de les blacklister)

Vois cette réponse sur ask.Sigfox.com

Idem pour les 4 messages que l'objet peut recevoir tous les 24h. Sigfox doit gèrer le cumul des messages 'retours' !!

Voiçi une copie d'écran des mes statistiques d'émission telles qu'elles apparaissent dans mon 'compte', présentées içi en nb de messages par jour, graduation verticale 50 messages par jour.
J'ai dépassé ponctuellement les 124 messages /jour lors des premiers essais, une journée à 216 messages par jour. (Problème initial de brown out du Mega 328 et de resets intempestifs vu l'alimentation utilisée)
stats.jpg

ok Al1
merci de ta réponse commentée.
j'apprécierais surement mieux lorsque j'aurais effectivement de quoi jouer "globalement" 8)

Je ferais un test de qq parametres "dans ma campagne"

Artouste:
ok Al1
merci de ta réponse commentée.
j'apprécierais surement mieux lorsque j'aurais effectivement de quoi jouer "globalement" 8)

Je ferais un test de qq parametres "dans ma campagne"

Bonsoir Al1

rapide retour sigfox" , aprés un long week-end du 11 novembre assez dispersé géographiquement "en Normandie" 8)

Mon Constat "Sigfox" à cet instant = "ça promet beaucoup" , mais ça ne se concrétise pas pas bien sur le terrain

Pour l'instant : je remballe 8)

J-M-L:
avec les contraintes que vous donnez vous pouvez avoir 9 octets sur MKRFOX

struct __attribute__ ((packed)) sigfox_messageBig {

uint8_t  tension;          // 0 à 255
  uint8_t  essaimage;        // 0 à 255
  int8_t    dhtTemperature;  // -128° à 127°
  int8_t    temp2;            // -128° à 127°
  uint8_t  dhtHumidity;      // 0 à 100%
  float    poids;
} ;




mais vous pouvez faire mieux avec vos contraintes, sans pour autant modifier la façon dont on accède aux champs de la structure: Vous pouvez d'utiliser [des champs de bit](http://en.cppreference.com/w/cpp/language/bit_field) (bit field pour les anglophones) - ça donne ce que l'on attend d'un point de vue représentation mémoire



struct attribute ((packed)) sigfox_messageSmall {
  uint8_t  tension : 7;      // 7 bits (0 à 127)
  uint8_t  essaimage: 1;    // 1 bit (0 ou 1)
  int8_t    dhtTemperature;  // -128° à 127°
  int8_t    temp2;            // -128° à 127°
  uint8_t  dhtHumidity;      // 0 à 100%
  float    poids;
} ;





Voici un petit programme d'essai


/*
  tension de la batterie de 00 à 100
  essaimage = 1 ou 0
  poids : avec 3 chiffres après la virgules
  dhtHumidity : entier sur 2 chiffre
  temp2 et dhtTempearature : entier sur 2 chiffre

*/

struct attribute ((packed)) sigfox_messageBig {
  uint8_t  tension;          // 0 à 255
  uint8_t  essaimage;        // 0 à 255
  int8_t    dhtTemperature;  // -128° à 127°
  int8_t    temp2;            // -128° à 127°
  uint8_t  dhtHumidity;      // 0 à 100%
  float    poids;
} ;

struct attribute ((packed)) sigfox_messageSmall {
  uint8_t  tension : 7;      // 7 bits (0 à 127)
  uint8_t  essaimage: 1;    // 1 bit (0 ou 1)
  int8_t    dhtTemperature;  // -128° à 127°
  int8_t    temp2;            // -128° à 127°
  uint8_t  dhtHumidity;      // 0 à 100%
  float    poids;
} ;

sigfox_messageBig enregistrement1;
sigfox_messageSmall enregistrement2;

void printBinary(uint8_t * ptr, byte n)
{
  for (int i = n - 1 ; i >= 0; --i) {
    for (int b = 7; b >= 0; --b) {
      if (bitRead(*(ptr + i), b)) Serial.print("1");
      else Serial.print("0");
    }
    Serial.print(" ");
  }
}

void setup() {
  uint8_t * ptr;

Serial.begin(115200);
  while (!Serial);

Serial.println("****** structure de base ******");
  Serial.print("Taille d'un enregistrement Big = ");
  Serial.println(sizeof(enregistrement1));

ptr  = (uint8_t *) &enregistrement1;
  enregistrement1.tension = 64 + 16 + 4 + 1; // on devrait voir B01010101
  enregistrement1.essaimage = true;      // le bit de poids faible à 1

printBinary(ptr, 1); Serial.println("\ttension");
  printBinary(ptr + 1, 1); Serial.println("\tEssaimage");

Serial.println("\n****** avec champs de bit ******");
  Serial.print("Taille d'un enregistrement Small = ");
  Serial.println(sizeof(enregistrement2));

ptr  = (uint8_t *) &enregistrement2;
  enregistrement2.tension = 64 + 16 + 4 + 1; // on devrait voir B01010101
  enregistrement2.essaimage = false;      // le bit de poids fort à 0
  printBinary(ptr, 1); Serial.println("\tEssaimage et Tension");

enregistrement2.essaimage = true;      // le bit de poids fort à 1
  printBinary(ptr, 1); Serial.println("\tEssaimage et Tension");

enregistrement2.tension = 8 + 4 + 2 + 1; // les 4 bits de poids faibles à 1
  printBinary(ptr, 1); Serial.println("\tEssaimage et Tension");
}

void loop() {}




si vous l'exécutez vous verrez dans la console série:



[sub][color=blue]****** structure de base ******
Taille d'un enregistrement Big = 9
01010101 tension
00000001 Essaimage

****** avec champs de bit ******
Taille d'un enregistrement Small = 8
01010101 Essaimage et Tension
11010101 Essaimage et Tension
10001111 Essaimage et Tension
[/color][/sub]

al1fch:
Bonjour

optimisation possible en réduisant le nombre de bits de chaque élément du message

première étape , sans compliquer le traitement :
dhtTemperature, temp2, dhthumidité, tension : 8 bits au lieu de 16 (int8)
essaimage : 1 bit (uint:1, côté portail Sigfox)

En compliquant un peu , au vu de la plage des données, il est possible de tasser encore plus en n'allouant que 7 bits à tension et les deux dht (7 bits suffisent pour coder un entier de 0 à 127)

voir par exemple cette page du site Framboise 314 (bas de page "Dans 12 octets qu'est-ce que tu veux mettre ?"

ok merci votre optiomisation a fonctionné avec mon code, mais si je veux rajouter 3 autres load cell ? ca passe plus en taille, je ne sais pas quoi mettre.