Go Down

Topic: [Résolu]Comment bien comprendre/utiliser les bytes, les doubles et les char (Read 1 time) previous topic - next topic

pierrot10

Bonjour à tous,

Je dois envoyer des données avec LoRa.
Les données à envoyer doivent etre des bytes
Code: [Select]
To send data back and forth over The Things Network you'll need to use bytes

J'utilise une librairie qui m'aide à faire ceci.

Ceci dit, il y a un truc que je n'arrive pas comprendre conecrnant le byte et la conversion des char et des double en byte.

Dans mon cas, j'ai une varaible qui est déclarée ainsi

Code: [Select]
uint8_t mydata[64];
C'est le contenu de cette varaiable qui sera envoyer

Plus bas, on du code comme ceci:
Code: [Select]
strcpy((char *) mydata,"{\"Hello\":\"Word\"");

Hello Word est bien reçu.


Je n'arrive pas à expliquer comment est compiler les texte dans mydata.

Si je remprend ce code
Code: [Select]
strcpy((char *) mydata,"{\"Hello\":\"Word\"");

Que contiendra exectement mydata?
Est-ce qu'elle contiendra "Hello Word" ou Hello Word est converti en bytes?
Est-ce que le fait myddata est un uint8_t, le texte, comme Hello Word, est converti en bytes dans mydata?
Et que fait exactement (char *) avant mydata

Ce que j'aimerais arriver à comprendre et à expliquer à un autre, est comment convertir donc du texte en bytes, et comment vérifier la taille et le contenu de la variable qui le contiendra, comme dans mon cas, mydata.

Comment puis imprimer mydata pour vérifier que le contenu correspond bien au double ou au char que je veux envoyer

Merci pour vos lumières
Il ne suffit pas de tout savoir, la persévérance, c'est déjà presque tout!
You can not know everything, perseverance, it is almost everything!

J-M-L

bonjour

je suppose que c'est la suite de la discussion des structure :)

Quote
Si je remprend ce code strcpy((char *) mydata,"{\"Hello\":\"Word\"");

Que contiendra exectement mydata?
myData comprendra la suite de représentation ASCII des caractères {"Hello":"World" avec les guillemets et un caractère nul à la fin

uint8_t ou un char c'est une zone mémoire de 8 bit, un octet. l'interprétation de ce qui est dans ces 8 bits dépend du type de données. uint8_t ça veut dire que vous indiquez votre intention d'avoir un un entier non signé sur un octet, donc un chiffre en 0 et 255 et si vous faites print par exemple vous verrez ce chiffre alors que si vous l'avez déclaré en char vous dites que c'est plutôt un caractère, généralement ASCII. le type des variable devient important quand vous appelez des fonctions parce que suivant le type passé ce n'est pas la même fonction qui est appelée. un Serial.print( <int>) n'est pas la même chose que Serial.print (<char>) (dans le premier cas la fonction va penser que vous voulez la valeur de l'entier en base 10, dans le second cas que c'est un caractère ASCII à imprimer)

Quote
comment convertir donc du texte en bytes
le compilateur le fait pour vous suivant le type de données
Code: [Select]
char x = 'a'; // l'octet associée à x est initialisé à la valeur numérique ASCII qui représente la lettre a (97)
char x = 97; // fait la même chose


Code: [Select]
char message[] = "bonjour";
crée un tableau de char qui vont successivement être initialisés avec les valeurs ASCII des lettres du mot bonjour, suivi d'un caractère de fin de chaine nul '\0'

Si vous exécutez ce code
Code: [Select]
char message[] = "Bonjour";
byte tailleMessage = sizeof(message); // taille du tableau, donc va comprendre le 0 à la fin

void setup() {
  Serial.begin(115200);

  for (byte i = 0; i < tailleMessage; i++) {
    Serial.print("message["); Serial.print(i); Serial.print("] contient la valeur ");
    Serial.print((uint8_t) message[i]); // on cast en type entier pour que la bonne fonction print soit appelée
    Serial.print(" caractere ["); Serial.print(message[i]); // ici le type est char, donc la fonction print imprime le caractere ASCII
    Serial.println("]");
  }
}

void loop() {}

vous verrez cela dans la console:
message[0] contient la valeur 66 caractere [B]
message[1] contient la valeur 111 caractere [o]
message[2] contient la valeur 110 caractere [n]
message[3] contient la valeur 106 caractere [j]
message[4] contient la valeur 111 caractere [o]
message[5] contient la valeur 117 caractere [u]
message[6] contient la valeur 114 caractere [r]
message[7] contient la valeur 0 caractere []




un double sur un UNO c'est 4 octets. Si vous faites
Code: [Select]
double x = 123.45;
alors les 4 cases mémoires pointées associées à la variable x vont stocker une représentation binaire du nombre 123.45 suivant une norme internationale (IEEE 754)

par exemple pour voir ce qui est en mémoire vous pouvez faire ce petit programme
Code: [Select]
double x = 123.45;

void setup() {
  Serial.begin(115200);

  Serial.print("x="); Serial.println(x); // imprimé sous forme de nombre à virgule car le compilateur a vu qu'on passait un double et donc appelle la bonne fonction print
 
  uint8_t *ptr = (uint8_t *) &x;  // on prend maintenant un pointeur sur la zone de stockage de la variable x et on lui dit que dedans ce sont des uint8_t
  Serial.print("les 4 octets en memoire sont 0x");
  Serial.print(*(ptr), HEX); // ici on dit qu'on veut la fonction print qui imprime en hexadécimal
  Serial.print(" 0x");
  Serial.print(*(ptr + 1), HEX);
  Serial.print(" 0x");
  Serial.print(*(ptr + 2), HEX);
  Serial.print(" 0x");
  Serial.print(*(ptr + 3), HEX);
}

void loop() {}

qui va afficher sur la console
x=123.45
les 4 octets en memoire sont 0x66 0xE6 0xF6 0x42


Votre arduino étant "little endian" les octets de poids faibles sont rangés en premier dans la représentation IEEE donc la représentation sur 4 octets associée dans l'ordre est 0x42F6E666 (on lit depuis la fin de l'impression)

si vous allez sur un site web de conversion en ligne et tapez la valeur 0x42F6E666, magique on trouve la valeur d'origine


le site vous montre en plus comment le signe, la mantisse et l'exposant sont représentés en binaire, c'est une partie des bits qui est affectée à chacun des morceaux

au final vous avez toujours des octets et des bits, le reste est juste affaire d'interprétation pour y associer une signification.
Hello - Please do not PM me for help,  others will benefit as well if you post your question publicly on the forums.
Bonjour Pas de messages privés SVP, postez dans le forum directement pour que ça profite à tous

pierrot10

Milles mercis pour ces grandes exlications
Oui c'est la suite des structures  :) . J'ai réussi à faire ce que je voulais, merci!!!!!

Je dois avouer que je nage en ce qui concerne les bits et les caracteres  >:(


Le problème que j'ai, c'est si j'active trop de capteur, les données ne sont pas envoyées. Si j'en active que 3, ca va....

Je me demande donc si je ne surchage pas mydata, qui va contenir ma chaine à envoyer.

Selon l'excercice précédent  :) , je construis ma chaine ainsi

Note: le sprintln(val,2) est une fonction qui va soit affiché dans le terminal (Serial.pritnln) ou/et das la carte SD. (Pour le moment, il n'y a pas de carte SD.....)
J'ai modifié votre exemple, pour avoir ceci à l'afficahe
Quote
Valeurs à envoyer: ba:4.31,te:2068,pr:-12896,al:42400,hu:3260,lu:1570
Code: [Select]

sprint(F("Valeurs à envoyer:\t"),2);
for (byte i = 0; i < nbMaxCapteurs; i++) {
      if (mesCapteur[i].actif) { // si le capteur n'est pas actif on n'imprime pas
        
        if(i==0)
        {
          strcpy((char *) mydata,mesCapteur[i].nomDuCapteur);
          strcat((char *) mydata,":");
          strcat((char *) mydata,mesMesures[i][mesCapteur[i].idDuCapteur].valeur);
        }
        else
        {
          strcat((char *) mydata,mesCapteur[i].nomDuCapteur);
          strcat((char *) mydata,":");
          strcat((char *) mydata,mesMesures[i][mesCapteur[i].idDuCapteur].valeur);
        }
        
        if (i < nbCapteurActif)
        {
          strcat((char *) mydata,",");
        }

// AFFICHE DANS LE TERMINAL LA CHAINE A ENVOYER
        sprint(mesCapteur[i].nomDuCapteur,2);
        sprint(F(":"),2);
        sprint(mesMesures[i][mesCapteur[i].idDuCapteur].valeur,2);
        if (i < nbCapteurActif) sprint(F(","),2);
      }
    }
    sprintln(F("\n"),2);


Si vais sur un site pour convertir ceci
Quote
ba:4.31,te:2068,pr:-12896,al:42400,hu:3260,lu:1570
Ma variable mydata doit avoir cette valeur
Quote
62613a342e33312c74653a323036382c70723a2d31323839362c616c3a34323430302c68753a333236302c6c753a31353730
Je suppose donc que (entre autre)
Code: [Select]

strcpy((char *) mydata,mesCapteur[i].nomDuCapteur);

Va donc copier le nom du capteur dans mydata et que ceci ne sera plus du texte (ou des caracteres) mes des bytes.

C'est cette conversion que je n'arrive pas à expliquer.

Si je reprends vos explications.
Quote
le compilateur le fait pour vous suivant le type de données
Mais que signifie alors (char *)? Ca indique le type de la variable source?

Aussi, est-ce que strlen(mydata) va m'indiquer la taille des bitsde mydata sur les 64
Code: [Select]
uint8_t mydata[64];

Ce que j'aimerais faire,  c'est d'afficher la progression de l'empilage du contenu de madata dans la boucle
Code: [Select]

for (byte i = 0; i < nbMaxCapteurs; i++) {...

Ainsi, je pourrai voir si, en activant des capteurs,  mydata vient à être surchargée
Il ne suffit pas de tout savoir, la persévérance, c'est déjà presque tout!
You can not know everything, perseverance, it is almost everything!

J-M-L

Votre bug il est là:
Code: [Select]
          strcpy((char *) mydata,mesCapteur[i].nomDuCapteur);
          strcat((char *) mydata,":");
          strcat((char *) mydata,mesMesures[i][mesCapteur[i].idDuCapteur].valeur);
vous  ne pouvez pas utiliser strcat() pour mettre en binaire la valeur de vos octets au milieu du buffer, ça ne fonctionne qu'avec des chaînes de caractères terminées par un '\0'...

pour ça il faut gruger un peu "à la main"... je vous ponds un petit exemple
Hello - Please do not PM me for help,  others will benefit as well if you post your question publicly on the forums.
Bonjour Pas de messages privés SVP, postez dans le forum directement pour que ça profite à tous

J-M-L

Bon alors voilà un bout de code qui remplit un buffer avec une chaîne et ensuite rajoute une valeur de 4 octets derrière.

Code: [Select]

uint32_t valeur = 0xDEADBEEF; // une valeur sur 4 octets

const uint8_t tailleMax = 20;
uint8_t data[tailleMax]; // un buffer assez grand

void printData()
{
  Serial.print("data = { ");
  for (byte i = 0; i < tailleMax; i++) {
    Serial.print("0x");
    if (data[i] <= 0xF) Serial.print("0");
    Serial.print(data[i], HEX);
    Serial.print(" ");
  }
  Serial.println("}");
}

void setup() {
  Serial.begin(115200);

  memset(data, 0xFF, tailleMax); // on met le buffer à 0xFF partout (pas nécessaire juste pour montrer, une variable globale sera à 0 la première fois)
  printData();

  strcpy((char *) data, "valeur="); // ici le buffer contient {'v','a','l','e','u','r','=','\0', ....}
  printData();

  uint32_t * ptr = (uint32_t*) (data + strlen((const char*) data)); // on caclule la où mettre les données
  *ptr = valeur; // on met les 4 octets au bon endroit.
  printData();

  uint8_t * ptr1 = ((uint8_t *) ptr) + sizeof(valeur) ; // on cherche la fin
  *ptr1 = 0; // on remet un zéro à la fin
  printData();
}

void loop() {}



ça affiche cela
data = { 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF }
data = { 0x76 0x61 0x6C 0x65 0x75 0x72 0x3D 0x00 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF }
data = { 0x76 0x61 0x6C 0x65 0x75 0x72 0x3D 0xEF 0xBE 0xAD 0xDE 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF }
data = { 0x76 0x61 0x6C 0x65 0x75 0x72 0x3D 0xEF 0xBE 0xAD 0xDE 0x00 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF }


et en image ça donne ça








mais cela dit il faudrait savoir exactement ce que vous devez envoyer... (attention j'ai écrasé le '\0' de fin de chaîne dans mon exemple, peut-être il faut le conserver pour décoder correctement de l'autre côté)





Hello - Please do not PM me for help,  others will benefit as well if you post your question publicly on the forums.
Bonjour Pas de messages privés SVP, postez dans le forum directement pour que ça profite à tous

pierrot10

Ouhaaa!!!! Je suis impressionnée par  votre réponse!!!!
Quote
mais cela dit il faudrait savoir exactement ce que vous devez envoyer
Je dois envoyer des bytes

Ce qui me pertube, et rien à voir avec votre exemple, c'est pourquoi l'exemple sur lequel je me base, ne fait pas comme ca.

Dans arduino, j'ai téléchargé la librairie pour envoyer les paquets, et je suis parti sur un exemple de la librairie,
Pourquoi il fait ainsi

Code: [Select]

strcpy((char *) mydata,"hello");
strcat((char *) mydata,":");
...

Mais qu'importe, je vais suivre votre exemple pour encapsuler mes valeurs des capteurs à envoyer en bytes.

Merci beaucoup pour ce travail, je vais faire ceci plus tard ou demain dans le train...
Il ne suffit pas de tout savoir, la persévérance, c'est déjà presque tout!
You can not know everything, perseverance, it is almost everything!

J-M-L

Votre librairie envoie peut être les données sous forme de chaîne ASCII

Comme dit plus haut, ce sont toujours des octets (ou des bits même) qui circulent. tout dépend donc du protocole de communication... qu'attendez-vous côté serveur ?
Hello - Please do not PM me for help,  others will benefit as well if you post your question publicly on the forums.
Bonjour Pas de messages privés SVP, postez dans le forum directement pour que ça profite à tous

pierrot10

Bonjour J-M-L,
(Je répond à votre dernier message avant même d'avoir étudier les dernieres propositions. Je fais ca de suite après)

Selon la documentation de The Thing Network, les données doivent être envoyées en bytes
Quote
To send data back and forth over The Things Network you'll need to use bytes.
Du côté serveeur, les données envoyées sont visible depuis la console. Mais c'est inlisible:
Code: [Select]
62613A342E33312C74653A323035382C70723A2D31323830312C616C3A34323430302C68753A333430302C6C753A20373836
Pour rendre ceci lisible, et surtout pour pouvoir m'assurer que les données sont corectement envoyé, dans la console, on peut ajouter du cote qui va traiter les données reçues. J'ai donc ajouté ce code qui ca me permettre d'avoir (et de voir) des noms de variables et des valeurs.
Code: [Select]

function Decoder(bytes, port) {

  // if (port === 1) decoded.led = bytes[0];

  var str=String.fromCharCode.apply(null,bytes);
  var a = JSON.parse(str);
  var name;
  var value;
  for (var attribute in a)
  {
    name  = attribute;
    value = a[attribute];
  }
 
  return{
    sensor:name,
    val:value
  };
 
  //var val1=(bytes[0] << 8) | bytes[1];
  //var val2=(bytes[2] << 8) | bytes[3];
 
  //return{
  //  val1:val1 / 100,
  //  val2:val2 / 100
  //}
 
}

Le truc, c'est que j'envoie mes données sous le format json, qui en soit n'est pas une bonne idée, car les { et les " prennent de bits. Vu qu'il faut que le paquet à envoyer, je vais envoyer mes données sous ce format
Quote
ba:4.30,te:2075,pr:-12958,al:42400,hu:3380,lu:1009
Je modifierai mon code, dans la console, plus tard, pour qu'il traite les donnée reçues. Mais pour le moment, ceci n'est pas un souci....


Le challenge, ce que je souhaiterais faire comme il le faut, et surtout comprendre, c'est d'empiler les valeurs de mes capteurs, comme indiqué plus haut, dans la variable
Code: [Select]
uint8_t mydata[64];
C'est le contenu de cette variable qui va être envoyé, si je suis mon exemple
LMIC_setTxData2
Dans l'exemple, lui il se content juste d'envoyer Hello Word:
Code: [Select]
//Serial.print("ready to send: ");
  strcpy((char *) mydata,"{\"Hello\":\"World\"}");
LMIC_setTxData2(1, mydata, strlen((char *)mydata), 0);


Moi je dois envoyer des valeurs....

Alors pour cela, j'ai cette boucle (et merci J-M-L) qui vient de l'exercice sur des structures


Je peux très très bien afficher (Serial.println) les résultat sous cette forme
Quote
ba:4.30,te:2075,pr:-12958,al:42400,hu:3380,lu:1009
Je modifie

Mon challenge, et mes lacunes me font défaut, je dois empiler des char dans 'mydata' et tout doit être des bytes.

J'ai fait ceci, mais je vais modifier ceci en fonction de votre dernières proposition. J'attaque ca maintenant...

Code: [Select]

sprintln(F("\nValeurs des capteurs actifs"),2);
    sprintln(F("---------------------------------------"),2);
    sprint(F("Nombre de capteurs: "),2);
    sprintln(nbMaxCapteurs,2);
    sprint(F("Nombre de capteurs actifs: "),2);
    sprintln(nbCapteurActif,2);
   
    sprint(F("Valeurs:\t"),2);
    //Serial.print(F("{"));

// EMPILE LES VALEURS MESUREES DE MES CAPTEURS DANS mydata

    for (byte i = 0; i < nbMaxCapteurs; i++) {
      if (mesCapteur[i].actif) { // si le capteur n'est pas actif on n'imprime pas
       
        if(i==0)
        {
          strcpy((char *) mydata,mesCapteur[i].nomDuCapteur);
          strcat((char *) mydata,":");
          strcat((char *) mydata,mesMesures[i][mesCapteur[i].idDuCapteur].valeur);
        }
        else
        {
          strcat((char *) mydata,mesCapteur[i].nomDuCapteur);
          strcat((char *) mydata,":");
          strcat((char *) mydata,mesMesures[i][mesCapteur[i].idDuCapteur].valeur);
        }
       
        if (i < nbCapteurActif)
        {
          strcat((char *) mydata,",");
        }

        Serial.print(F("Taille de mydata: ")); Serial.println(sizeof(mydata));

// AFFICHE ICI LES VALEURS DES CAPTEURS SEPARE PAR DES VIRGULES SAUF POUR LE DERNIER
        sprint(mesCapteur[i].nomDuCapteur,2);
        sprint(F(":"),2);
        sprint(mesMesures[i][mesCapteur[i].idDuCapteur].valeur,2);
        if (i < nbCapteurActif) sprint(F(","),2);
      }
    }
    sprintln(F("\n"),2);



Voilà, j'espère avoir bien répondu à la question  :)
Il ne suffit pas de tout savoir, la persévérance, c'est déjà presque tout!
You can not know everything, perseverance, it is almost everything!

J-M-L

Quote
To send data back and forth over The Things Network you'll need to use bytes.
Oui on échange toujours des octets... un char, une String, un entier, tout au final est représenté sous forme de bits et d'octets en mémoire

-> ça ne dit rien de l'organisation de ces octets, quel est le protocole ? qui écoute côté serveur et quel format (organisation des octets) est attendu ?
Hello - Please do not PM me for help,  others will benefit as well if you post your question publicly on the forums.
Bonjour Pas de messages privés SVP, postez dans le forum directement pour que ça profite à tous

pierrot10

My gateway utilise le proprocole LoRaWAN pour envoyer les donnée
Quote
We use a long range and low power radio frequency protocol called LoRaWAN.
(J'ai commencé à travailler sur l'exemple, mais pas encore terminé  :) )
Il ne suffit pas de tout savoir, la persévérance, c'est déjà presque tout!
You can not know everything, perseverance, it is almost everything!

pierrot10

Bonjour J-M-L
J'ai essayé de reproduire votre, mais malheureusement, je vole pas très haut  :(
Je ne sais pas si vous auriez encore un petit moment pour me metter dans la bonne voie.

Voici ce que j'ai fait...
Code: [Select]


const uint8_t tailleMax = 64;
uint8_t mydata[tailleMax];

// On met le buffer à zero partout
    // (pas nécessaire juste pour montrer, une variable globale sera à 0 la première fois)
    memset(mydata, 0xFF, tailleMax);
    // DEBUG
    printData();

/*
Ceci imrpime
mydata = { FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF }
*/

    // Loop la strcture des capteurs
    for (byte i = 0; i < nbMaxCapteurs; i++) {

      if (mesCapteur[i].actif) { // si le capteur n'est pas actif on n'imprime pas
      /*
        // PRINT LES MESURES MESUREES
        sprint(mesCapteur[i].nomDuCapteur,2);
        sprint(F(":"),2);
        sprint(mesMesures[i][mesCapteur[i].idDuCapteur].valeur,2);
        if (i < nbCapteurActif) sprint(F(","),2);
        */

        // --------------------------------------------------------
        // EMPILE LES VALERUS MESUREE DANS mydata POUR
        // LES ENVOYER A TTN
        
        // Empile le nom du capteur
        // const uint8_t tailleMax = 64;
        // uint8_t mydata[tailleMax];

        strcpy((char *) mydata, mesCapteur[i].nomDuCapteur); // Ici de toute manière, ca coincera, car au deuxième passe du second capteur, il écrasera la premiere valeur...
        // DEBUG
        printData();
/* Ceci impirme
mydata = { 62 61 00 FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF }
*/
 
     /* ICi i y a une erreu, mais je ne maitrise pas trop les pointeurs...
   // on caclule la où mettre les données suivantes
        uint32_t * ptr = (uint32_t*) (mydata+ strlen((const char*) mydata));
        // on met les octets au bon endroit en fonction du contenu de nomDuCapteur.
        *ptr = 0x3A; // Ajoute une les deux point (:)
        // DEBUG
        printData();
/*
Ceci n'imprime rien. Mon code n'imprime plus comme s'il était bloqué...
*/

        // On positionne le point et ajoute les valeur
        uint8_t * ptr1 = ((uint8_t *) ptr) + sizeof(mydata) ; // on cherche la fin
        //*ptr1 = (char *)mesMesures[i][mesCapteur[i].idDuCapteur].valeur; // Ceci ne fnctionne pas et c'est bien ceci quue je dois ajouté, pas 0x40..
        *ptr1 = 0x40; // J'ajoute un @ en bits pour comparer le résultat
        // DEBUG
        printData();

        ptr2 = (uint32_t*) (mydata + strlen((const char*) mydata));
        
        if (i < nbCapteurActif)
        {
          *ptr2 = 0x2C; // On ajoute une virgule
        }
        else
        {
          *ptr2 = 0; // On ajoute un 0 pour terminer la chaine
        }
        
        // DEBUG
        printData();
        
      
      }
    }
    sprintln(F("\n"),2);


Pourriez-vous encore me mettre sur la bonne voie?

Merci beaucoup!
Il ne suffit pas de tout savoir, la persévérance, c'est déjà presque tout!
You can not know everything, perseverance, it is almost everything!

J-M-L

Bonsoir vous n'avez pas répondu à ma question:

Comment doivent être structurées les données du côté serveur? Qui va les lire et quel format est attendu?

Lorawan c'est un protocole de communication, ça transporte des octets, mais suivant qui est au bout de la communication et ce qu'il attend, la façon d'agencer les octets sera différente

Dans votre lien ils parlent d'un "Uplink Message - a message from a Device to an Application", ce qui vous faut c'est décrire le message.
Hello - Please do not PM me for help,  others will benefit as well if you post your question publicly on the forums.
Bonjour Pas de messages privés SVP, postez dans le forum directement pour que ça profite à tous

pierrot10

#12
Sep 18, 2017, 11:17 pm Last Edit: Sep 18, 2017, 11:24 pm by pierrot10 Reason: Correction orthographe
Bonsoir,

Ben sincèrement, je ne sais pas trop quoi répondre.
Aussi, je ne me suis pas concentré la dessus à100% (hélas)

Ce que je peux vous dire, c'est que les données sont envoyée et je peux les consultées comme ceci


Aussi, je peux modifier le fomat pour que je puisse rendre la vu plus lisible.

Selon cette vue


Si j'ajoute ce code (ou remplace...)
Code: [Select]

function Decoder(bytes, port) {

  // if (port === 1) decoded.led = bytes[0];

  var str=String.fromCharCode.apply(null,bytes);
  var a = JSON.parse(str);
  var name;
  var value;
  for (var attribute in a)
  {
    name  = attribute;
    value = a[attribute];
  }
 
  return{
    sensor:name,
    val:value
  };
 
  //var val1=(bytes[0] << 8) | bytes[1];
  //var val2=(bytes[2] << 8) | bytes[3];
 
  //return{
  //  val1:val1 / 100,
  //  val2:val2 / 100
  //}
 
}

je peux visualiser le nom des variables et les valeurs. Je n'ai malheureusement pas de photo-exemple, mais ca fonctionne bien et je peux vérifier ce qui a été envoyé et reçu

Ceci dit, ce code n'est en réalité plus valable, car à ce moment là, j'envoyais les valeurs des capteurs une par une. C'est pourquoi il n'est plus.

Maitenant j'aimerais envoyer tout d'un coup
Quote
ba:4.30,te:2075,pr:-12958,al:42400,hu:3380,lu:1009
mais ne bytes  :)

TTN me permet aussi de stocker pendant une semaine, les valeurs dans une base de donnée, et j'utilise curl pour "rapatrier" ces données sur mon propre serveur/base de donnée/fichier json.

Pour le moment je ne me suis pas encore concentré la dessus. Je me concentre sur comment les envoyer et de vérifier que les données sont bien arrivées dans ma console, comme je l'ai décris plus haut. Dès que j'arriverai à bien les envoyer, j'utiliserai l'option de la base de donnée et curl.

J'espère que malgré tout, j'ai pu répondre à votre question?   :)
Il ne suffit pas de tout savoir, la persévérance, c'est déjà presque tout!
You can not know everything, perseverance, it is almost everything!

J-M-L

OK donc votre back-end est adaptatif - vous pouvez décrire comment relire les octets envoyés, il vous suffit donc de définir ce que vous voulez envoyer et comment.

si vous avez un tableau statique avec toutes les mesures (avec ces cellules vides pour les capteurs inactifs) vous pouvez ne pas vous ennuyer et envoyer d'un seul coup tout le tableau et côté serveur relire tout cela.

Mais ce n'est pas très efficace si de nombreux capteurs ne sont pas utilisés.

On pourrait essayer de définir une mesure à envoyer et dire qu'un payload c'est une suite de mesures

vous avez peu de capteurs, chaque capteur pourrait être décrit avec une lettre 'P' pour pression, 'T' pour température etc...

vous avez ensuite une valeur à envoyer, il faut définir si vous envoyez une valeur convertie dans l'unité associée (°Celsius, Pascal, etc) ou si vous envoyez la lecture digitale échantillonnée et vous faites les maths côté serveur.

Comme votre serveur est plus performant faire le calcul côté serveur et envoyer uniquement 2 octets pour les data (échantillonnage jusqu'à 16 bits), 4 octets pour l'heure de la mesure ça devrait déjà être pas mal et ça simplifie la communication.

un payload aurait alors cette tête (octet par octet)

LETTRE DATA1 DATA2 TIME1 TIME2 TIME3 TIME4
LETTRE DATA1 DATA2 TIME1 TIME2 TIME3 TIME4
LETTRE DATA1 DATA2 TIME1 TIME2 TIME3 TIME4
LETTRE DATA1 DATA2 TIME1 TIME2 TIME3 TIME4


et côté serveur en fonction de la lettre reçue, avec un switch/case vous appliquez la bonne formule de calcul.

Voici un exemple de code

Code: [Select]
struct  sample {
  uint16_t mesure;
  uint32_t chrono;
};

struct sensor {
  char identifier;
  boolean isActive;
};

sensor sensorList[] = {
  {'T', true}, // temperature
  {'P', false}, // Pression, capteur inactif
  {'B', true}, // Battery
};

enum : byte {temperature, pression, batterie}; // on définit des mots clés pour la lisibilité

const byte maxNbSensors = sizeof(sensorList) / sizeof(sensorList[0]);
const byte nbMaxMesures = 5;

sample allMesures[maxNbSensors][nbMaxMesures];

void printHex(uint8_t v)
{
  if (v < 0xF) Serial.print("0");
  Serial.print(v, HEX);
}

void setup() {
  Serial.begin(115200);

  // on en remplit quelques une avec des valeurs reconnaissables

  allMesures[temperature][0].mesure = 0xAA11;
  allMesures[temperature][0].chrono = 0x1122AABBul;
  allMesures[temperature][1].mesure = 0xBB11;
  allMesures[temperature][1].chrono = 0x2233AABBul;
  allMesures[temperature][4].mesure = 0xCC11;
  allMesures[temperature][4].chrono = 0x3344AABBul;

  allMesures[batterie][0].mesure = 0xDD33;
  allMesures[batterie][0].chrono = 0x4455AABBul;
  allMesures[batterie][1].mesure = 0xEE33;
  allMesures[batterie][1].chrono = 0x5566AABBul;
  allMesures[batterie][4].mesure = 0xFF33;
  allMesures[batterie][4].chrono = 0x6677AABBul;


  // si vous êtes "lazy" vous pouvez directement envoyer allMesures comme payload.

  // sinon on bâtit un message avec les infos pertinentes des capteurs actifs
  // on va calculer la taille du buffer data à envoyer (le payload)
  byte nbActiveSensors = 0;
  for (byte i = 0; i < maxNbSensors; i++)
    if (sensorList[i].isActive) nbActiveSensors++;

  // un buffer assez grand pour toutes nos données
  uint8_t payload[nbActiveSensors * nbMaxMesures * (sizeof(char) + sizeof(sample))];

  uint8_t * ptr = payload;
  for (byte s = 0; s < maxNbSensors; s++) {

    if (sensorList[s].isActive) {
      for (byte m = 0; m < nbMaxMesures; m++) {
        *ptr = sensorList[s].identifier; // on écrit le char
        ptr += sizeof(char); // on passe à l'octet suivant

        * ((uint16_t *) ptr) = allMesures[s][m].mesure; // on est obligé de faire un cast pour bien copier tous les octets
        ptr += sizeof(uint16_t); // on avance du bon nombre d'octets

        * ((uint32_t *) ptr) = allMesures[s][m].chrono; // on est obligé de faire un cast pour bien copier tous les octets
        ptr += sizeof(uint32_t); // on avance du bon nombre d'octets
      }
    }
  }

  // ici notre buffer est complet, on l'affiche
  Serial.println("---- le payload ----");
  // en mémoire ce serait cette suite d'octets
  for (uint16_t index = 0; index < sizeof(payload); index ++) {
    Serial.print("0x");
    printHex(payload[index]);
    Serial.println("");
  }

  Serial.println("----- le payload avec structure ----");
  for (uint16_t index = 0; index < sizeof(payload); index += sizeof(char) + sizeof(uint16_t) + sizeof(uint32_t)) {
    Serial.print("{ 0x");
    printHex(payload[index]);
    Serial.print(" (lettre '");
    Serial.print((char) payload[index]);
    Serial.print("'), 0x");
    printHex(payload[index + 1]);
    printHex(payload[index + 2]);
    Serial.print(", 0x");
    printHex(payload[index + 3]);
    printHex(payload[index + 4]);
    printHex(payload[index + 5]);
    printHex(payload[index + 6]);
    Serial.println("}");
  }
}

void loop() {}


si vous l'exécutez vous verrez ça sur la sortie

---- le payload ----
0x54
0x11
0xAA
0xBB
0xAA
0x22
0x11
0x54
0x11
0xBB
0xBB
0xAA
0x33
0x22
0x54
0x00
0x00
0x00
0x00
0x00
0x00
0x54
0x00
0x00
0x00
0x00
0x00
0x00
0x54
0x11
0xCC
0xBB
0xAA
0x44
0x33
0x42
0x33
0xDD
0xBB
0xAA
0x55
0x44
0x42
0x33
0xEE
0xBB
0xAA
0x66
0x55
0x42
0x00
0x00
0x00
0x00
0x00
0x00
0x42
0x00
0x00
0x00
0x00
0x00
0x00
0x42
0x33
0xFF
0xBB
0xAA
0x77
0x66
----- le payload avec structure ----
{ 0x54 (lettre 'T'), 0x11AA, 0xBBAA2211}
{ 0x54 (lettre 'T'), 0x11BB, 0xBBAA3322}
{ 0x54 (lettre 'T'), 0x0000, 0x00000000}
{ 0x54 (lettre 'T'), 0x0000, 0x00000000}
{ 0x54 (lettre 'T'), 0x11CC, 0xBBAA4433}
{ 0x42 (lettre 'B'), 0x33DD, 0xBBAA5544}
{ 0x42 (lettre 'B'), 0x33EE, 0xBBAA6655}
{ 0x42 (lettre 'B'), 0x0000, 0x00000000}
{ 0x42 (lettre 'B'), 0x0000, 0x00000000}
{ 0x42 (lettre 'B'), 0x33FF, 0xBBAA7766}


on voit dans l'impression que l'architecture est little endian, les octets de poids faible sont écrits en premier en mémoire. Il faudra en tenir compte du côté de la lecture côté serveur.

ça vous aide?
Hello - Please do not PM me for help,  others will benefit as well if you post your question publicly on the forums.
Bonjour Pas de messages privés SVP, postez dans le forum directement pour que ça profite à tous

pierrot10

Bonjour,

Vous êtes extra! Je ne pourrai pas rearder ceci cet après-midi, mais je le ferai aussi tot rentré ce soir.
Dans l'alternative j'ai trouvé une solution mais je n'ai pas pu encore la tester et la publier.
Mais j'aimerais "honorer" vos propositions et les appliquer.

Je regarderai ceci ce soir.

Milles mercis et toute bonne journée
Il ne suffit pas de tout savoir, la persévérance, c'est déjà presque tout!
You can not know everything, perseverance, it is almost everything!

Go Up