Envoi de données sous format Json avec LoRaWAN

Bonjour,

#include <lmic.h>
#include <hal/hal.h>
#include <SPI.h>

#define LMIC_DEBUG_LEVEL 2
const int trigPin = 3;
const int echoPin = 4;
float duration, distance;

static const u1_t PROGMEM DEVEUI[8] = {0xfb, 0x78, 0x37, 0xc7, 0x83, 0x24, 0x81, 0x5f};
void os_getDevEui (u1_t* buf) {
  memcpy_P(buf, DEVEUI, 8);
}

// Change this!
static const u1_t PROGMEM APPKEY[16] = {0x15, 0x50, 0x52, 0xf0, 0xe2, 0x7d, 0x72, 0xee, 0x74, 0xa8, 0x37, 0x13, 0x36, 0x71, 0xac, 0x91};
void os_getDevKey (u1_t* buf) {
  memcpy_P(buf, APPKEY, 16);
}

static osjob_t sendjob;

// Schedule TX every this many seconds
const unsigned TX_INTERVAL = 20;

// Pin mapping
const lmic_pinmap lmic_pins = {
  .nss = 10,
  .rxtx = LMIC_UNUSED_PIN,
  .rst = 9,
  .dio = {2, 6, 7},
};

void onEvent (ev_t ev) {
  Serial.print(os_getTime());
  Serial.print(": ");
  switch (ev) {
    case EV_SCAN_TIMEOUT:
      Serial.println(F("EV_SCAN_TIMEOUT"));
      break;
    case EV_BEACON_FOUND:
      Serial.println(F("EV_BEACON_FOUND"));
      break;
    case EV_BEACON_MISSED:
      Serial.println(F("EV_BEACON_MISSED"));
      break;
    case EV_BEACON_TRACKED:
      Serial.println(F("EV_BEACON_TRACKED"));
      break;
    case EV_JOINING:
      Serial.println(F("EV_JOINING"));
      break;
    case EV_JOINED:
      Serial.println(F("EV_JOINED"));
      break;
    case EV_RFU1:
      Serial.println(F("EV_RFU1"));
      break;
    case EV_JOIN_FAILED:
      Serial.println(F("EV_JOIN_FAILED"));
      break;
    case EV_REJOIN_FAILED:
      Serial.println(F("EV_REJOIN_FAILED"));
      break;
      break;
    case EV_TXCOMPLETE:
      Serial.println(F("EV_TXCOMPLETE (includes waiting for RX windows)"));
      if (LMIC.dataLen) {
        // data received in rx slot after tx
        Serial.print(F("Data Received: "));
        Serial.write(LMIC.frame + LMIC.dataBeg, LMIC.dataLen);
        Serial.println();
      }
      // Schedule next transmission
      os_setTimedCallback(&sendjob, os_getTime() + sec2osticks(TX_INTERVAL), do_send);
      break;
    case EV_LOST_TSYNC:
      Serial.println(F("EV_LOST_TSYNC"));
      break;
    case EV_RESET:
      Serial.println(F("EV_RESET"));
      break;
    case EV_RXCOMPLETE:
      // data received in ping slot
      Serial.println(F("EV_RXCOMPLETE"));
      break;
    case EV_LINK_DEAD:
      Serial.println(F("EV_LINK_DEAD"));
      break;
    case EV_LINK_ALIVE:
      Serial.println(F("EV_LINK_ALIVE"));
      break;
    default:
      Serial.println(F("Unknown event"));
      break;
  }
}

byte buffer[52];

void do_send(osjob_t* j , int distance ) {
   digitalWrite(trigPin, LOW);
  delayMicroseconds(2);
  digitalWrite(trigPin, HIGH);
  delayMicroseconds(10);
  digitalWrite(trigPin, LOW);

  duration = pulseIn(echoPin, HIGH);
  distance = (duration * 0.0343) / 2;
  Serial.print("Distance: ");
  Serial.println(distance);
  if (LMIC.opmode & OP_TXRXPEND) {
    Serial.println(F("OP_TXRXPEND, not sending"));
  } else {
    String message;
    if (distance < 6) {
      message = "Occupied";
    } else {
      message = "Not Occupied";
    }
    message.getBytes(buffer, message.length() + 1);
    Serial.println("Sending: " + message);
    LMIC_setTxData2(1, buffer, message.length(), 0);
    Serial.println(F("Packet queued"));
  }
  // Next TX is scheduled after TX_COMPLETE event.
}

// Leave this empty
static const u1_t PROGMEM APPEUI[8] = {};
void os_getArtEui (u1_t* buf) {
  memcpy_P(buf, APPEUI, 8);
}

void setup() {
  pinMode(trigPin, OUTPUT);
  pinMode(echoPin, INPUT);
  
  Serial.begin(115200);
  Serial.println(F("Starting"));
  pinMode(LED_BUILTIN, OUTPUT);
  pinMode(trigPin, OUTPUT);
  pinMode(echoPin, INPUT);

#ifdef VCC_ENABLE
  // For Pinoccio Scout boards
  pinMode(VCC_ENABLE, OUTPUT);
  digitalWrite(VCC_ENABLE, HIGH);
  delay(1000);
#endif

  // LMIC init
  os_init();
  // Reset the MAC state. Session and pending data transfers will be discarded.
  LMIC_reset();
  LMIC_setClockError(MAX_CLOCK_ERROR * 1 / 100);

  LMIC_setupChannel(0, 868100000, DR_RANGE_MAP(DR_SF12, DR_SF7),  BAND_CENTI);      // g-band
  LMIC_setupChannel(1, 868300000, DR_RANGE_MAP(DR_SF12, DR_SF7), BAND_CENTI);      // g-band
  LMIC_setupChannel(2, 868500000, DR_RANGE_MAP(DR_SF12, DR_SF7B),  BAND_CENTI);      // g-band
  LMIC_setupChannel(3, 867100000, DR_RANGE_MAP(DR_SF12, DR_SF7),  BAND_CENTI);      // g-band
  LMIC_setupChannel(4, 867300000, DR_RANGE_MAP(DR_SF12, DR_SF7),  BAND_CENTI);      // g-band
  LMIC_setupChannel(5, 867500000, DR_RANGE_MAP(DR_SF12, DR_SF7),  BAND_CENTI);      // g-band
  LMIC_setupChannel(6, 867700000, DR_RANGE_MAP(DR_SF12, DR_SF7),  BAND_CENTI);      // g-band
  LMIC_setupChannel(7, 867900000, DR_RANGE_MAP(DR_SF12, DR_SF7),  BAND_CENTI);      // g-band
  LMIC_setupChannel(8, 868800000, DR_RANGE_MAP(DR_FSK,  DR_FSK),  BAND_MILLI);      // g2-band

  // Disable link check validation
  LMIC_setLinkCheckMode(0);
//  LMIC_setDrTxpow(DR_SF7, 23);
//  LMIC_setDrTxpow(DR_SF8, 23);
//  LMIC_setDrTxpow(DR_SF9, 23);
//  LMIC_setDrTxpow(DR_SF10, 23);
//  LMIC_setDrTxpow(DR_SF11, 23);
//  LMIC_setDrTxpow(DR_SF12, 23);

  // Start job
  do_send(&sendjob, distance );
}

void loop() { 
  

  os_runloop_once();
  
}

Si vous pouvez le constater,

    String message;
    if (distance < 6) {
      message = "Occupied";
    } else {
      message = "Not Occupied";
    }

dans cette partie du code, le message a envoyé est sous format de chaines de caracteres.
J'aimerais les envoyer sous format json, comment faire ?

vous mettez le JSON dans le message

Mais comment ?

à quoi ressemble votre JSON

#include <ArduinoJson.h>
#include <lmic.h>
#include <hal/hal.h>
#include <SPI.h>

#define LMIC_DEBUG_LEVEL 2
const int trigPin = 3;
const int echoPin = 4;
float duration, distance;

static const u1_t PROGMEM DEVEUI[8] = {0xfb, 0x78, 0x37, 0xc7, 0x83, 0x24, 0x81, 0x5f};
void os_getDevEui (u1_t* buf) {
  memcpy_P(buf, DEVEUI, 8);
}

// Change this!
static const u1_t PROGMEM APPKEY[16] = {0x15, 0x50, 0x52, 0xf0, 0xe2, 0x7d, 0x72, 0xee, 0x74, 0xa8, 0x37, 0x13, 0x36, 0x71, 0xac, 0x91};
void os_getDevKey (u1_t* buf) {
  memcpy_P(buf, APPKEY, 16);
}

static osjob_t sendjob;

// Schedule TX every this many seconds
const unsigned TX_INTERVAL = 20;

// Pin mapping
const lmic_pinmap lmic_pins = {
  .nss = 10,
  .rxtx = LMIC_UNUSED_PIN,
  .rst = 9,
  .dio = {2, 6, 7},
};

void onEvent (ev_t ev) {
  Serial.print(os_getTime());
  Serial.print(": ");
  switch (ev) {
    case EV_SCAN_TIMEOUT:
      Serial.println(F("EV_SCAN_TIMEOUT"));
      break;
    case EV_BEACON_FOUND:
      Serial.println(F("EV_BEACON_FOUND"));
      break;
    case EV_BEACON_MISSED:
      Serial.println(F("EV_BEACON_MISSED"));
      break;
    case EV_BEACON_TRACKED:
      Serial.println(F("EV_BEACON_TRACKED"));
      break;
    case EV_JOINING:
      Serial.println(F("EV_JOINING"));
      break;
    case EV_JOINED:
      Serial.println(F("EV_JOINED"));
      break;
    case EV_RFU1:
      Serial.println(F("EV_RFU1"));
      break;
    case EV_JOIN_FAILED:
      Serial.println(F("EV_JOIN_FAILED"));
      break;
    case EV_REJOIN_FAILED:
      Serial.println(F("EV_REJOIN_FAILED"));
      break;
      break;
    case EV_TXCOMPLETE:
      Serial.println(F("EV_TXCOMPLETE (includes waiting for RX windows)"));
      if (LMIC.dataLen) {
        // data received in rx slot after tx
        Serial.print(F("Data Received: "));
        Serial.write(LMIC.frame + LMIC.dataBeg, LMIC.dataLen);
        Serial.println();
      }
      // Schedule next transmission
      os_setTimedCallback(&sendjob, os_getTime() + sec2osticks(TX_INTERVAL), do_send);
      break;
    case EV_LOST_TSYNC:
      Serial.println(F("EV_LOST_TSYNC"));
      break;
    case EV_RESET:
      Serial.println(F("EV_RESET"));
      break;
    case EV_RXCOMPLETE:
      // data received in ping slot
      Serial.println(F("EV_RXCOMPLETE"));
      break;
    case EV_LINK_DEAD:
      Serial.println(F("EV_LINK_DEAD"));
      break;
    case EV_LINK_ALIVE:
      Serial.println(F("EV_LINK_ALIVE"));
      break;
    default:
      Serial.println(F("Unknown event"));
      break;
  }
}

byte buffer[52];

void do_send(osjob_t* j , int distance ) {
  digitalWrite(trigPin, LOW);
  delayMicroseconds(2);
  digitalWrite(trigPin, HIGH);
  delayMicroseconds(10);
  digitalWrite(trigPin, LOW);

  duration = pulseIn(echoPin, HIGH);
  distance = (duration * 0.0343) / 2;
  Serial.print("Distance: ");
  Serial.println(distance);
  if (LMIC.opmode & OP_TXRXPEND) {
    Serial.println(F("OP_TXRXPEND, not sending"));
  } else {
    StaticJsonDocument<128> doc;
    doc["Place"] = 23;
    doc["status"] = (distance < 6) ? "Occupied" : "Not Occupied";
    doc["Parking"]="Waves";
    String jsonString;
    serializeJson(doc, jsonString);
    LMIC_setTxData2(1, (uint8_t*)jsonString.c_str(), jsonString.length(), 0);
   
    Serial.println("Sending: " + jsonString);
    Serial.println(F("Packet queued"));
  }
  // Next TX is scheduled after TX_COMPLETE event.
}

// Leave this empty
static const u1_t PROGMEM APPEUI[8] = {};
void os_getArtEui (u1_t* buf) {
  memcpy_P(buf, APPEUI, 8);
}

void setup() {
  pinMode(trigPin, OUTPUT);
  pinMode(echoPin, INPUT);
 
  Serial.begin(115200);
  Serial.println(F("Starting"));
  pinMode(LED_BUILTIN, OUTPUT);
  pinMode(trigPin, OUTPUT);
  pinMode(echoPin, INPUT);

#ifdef VCC_ENABLE
  // For Pinoccio Scout boards
  pinMode(VCC_ENABLE, OUTPUT);
  digitalWrite(VCC_ENABLE, HIGH);
  delay(1000);
#endif

  // LMIC init
  os_init();
  // Reset the MAC state. Session and pending data transfers will be discarded.
  LMIC_reset();
  LMIC_setClockError(MAX_CLOCK_ERROR * 1 / 100);

  LMIC_setupChannel(0, 868100000, DR_RANGE_MAP(DR_SF12, DR_SF7),  BAND_CENTI);      // g-band
  LMIC_setupChannel(1, 868300000, DR_RANGE_MAP(DR_SF12, DR_SF7), BAND_CENTI);      // g-band
  LMIC_setupChannel(2, 868500000, DR_RANGE_MAP(DR_SF12, DR_SF7B),  BAND_CENTI);      // g-band
  LMIC_setupChannel(3, 867100000, DR_RANGE_MAP(DR_SF12, DR_SF7),  BAND_CENTI);      // g-band
  LMIC_setupChannel(4, 867300000, DR_RANGE_MAP(DR_SF12, DR_SF7),  BAND_CENTI);      // g-band
  LMIC_setupChannel(5, 867500000, DR_RANGE_MAP(DR_SF12, DR_SF7),  BAND_CENTI);      // g-band
  LMIC_setupChannel(6, 867700000, DR_RANGE_MAP(DR_SF12, DR_SF7),  BAND_CENTI);      // g-band
  LMIC_setupChannel(7, 867900000, DR_RANGE_MAP(DR_SF12, DR_SF7),  BAND_CENTI);      // g-band
  LMIC_setupChannel(8, 868800000, DR_RANGE_MAP(DR_FSK,  DR_FSK),  BAND_MILLI);      // g2-band

  // Disable link check validation
  LMIC_setLinkCheckMode(0);
//  LMIC_setDrTxpow(DR_SF7, 23);
//  LMIC_setDrTxpow(DR_SF8, 23);
//  LMIC_setDrTxpow(DR_SF9, 23);
//  LMIC_setDrTxpow(DR_SF10, 23);
//  LMIC_setDrTxpow(DR_SF11, 23);
//  LMIC_setDrTxpow(DR_SF12, 23);

  // Start job
  do_send(&sendjob, distance );
}

void loop() {
 

  os_runloop_once();
 

J'ai un peu modifié mon code pour que le message soit envoyé sous format JSON.

voici la partie modifié:

 if (LMIC.opmode & OP_TXRXPEND) {
    Serial.println(F("OP_TXRXPEND, not sending"));
  } else {
    StaticJsonDocument<128> doc;
    doc["Place"] = 23;
    doc["status"] = (distance < 6) ? "Occupied" : "Not Occupied";
    doc["Parking"]="Waves";
    String jsonString;
    serializeJson(doc, jsonString);
    LMIC_setTxData2(1, (uint8_t*)jsonString.c_str(), jsonString.length(), 0);
   
    Serial.println("Sending: " + jsonString);
    Serial.println(F("Packet queued"));
  }
  // Next TX is scheduled after TX_COMPLETE event.
}
    doc["Place"] = 23;
    doc["status"] = (distance < 6) ? "Occupied" : "Not Occupied";
    doc["Parking"]="Waves";

vous voulez utiliser ArduinoJSON ou fabriquer le texte directement ?

quand vous faites cela

et que vous serialisez le contenu vous obtenez

{"Place": 23,"status": "Not Occupied","Parking": "Waves"}

avec un buffer de type chaîne de caractère et un snprintf() vous pouvez faire la même chose sans ArduinoJSON

char buffer[100];
snprintf(buffer, 100, "{\"Place\":%d,\"status\":\"%s\",\"Parking\":\"Waves\"}"
                       , 23, (distance < 6) ? "Occupied" : "Not Occupied");

si je veux utiliser ArduinoJSON, que dois-je faire exactement ?

quand vous faites cela

la String jsonString contient

{"Place": 23,"status": "Not Occupied","Parking": "Waves"}

donc il ne vous reste qu'à envoyer le buffer sous jacent

    Serial.println("Sending: " + jsonString);
    LMIC_setTxData2(1, jsonString.c_str(), jsonString.length(), 0);
    Serial.println(F("Packet queued"));
Serial.println("Sending: " + jsonString);
LMIC_setTxData2(1, jsonString.c_str(), jsonString.length(), 0);
Serial.println(F("Packet queued"));

Cette partie est deja incluse dans mon code

la différence avec leur code c'est que leur buffer est une variable globale et que vous utilisez une variable locale pour construire le buffer. je ne sais pas comment fonctionne LMIC_setTxData2()

essayez pour voir de mettre

    StaticJsonDocument<128> doc;

en variable globale

là où dans le code de démo ils avaient

Bonjour @toniboudi

Pourquoi ce choix d'envoyer les données en JSON sur un réseau LoRAWAN ?

Une remarque : envoyer avec LoRaWAN des données fortmatées JSON va allonger inutilement les 'payloads' , avec LORAWAN comme Sigfox on tend au contraire à compacter les données, de n'envoyer que le strict nécessaire comme informations .

Pour info voici un calculateur qui permet de déduire le nombre de messages qu'il est possible d'envoyer/ heures en fonction de la taille de la payload et des paramètres de la modulation LoRa

https://avbentem.github.io/airtime-calculator/ttn/eu868/50

Exemple avec une 'payload' de 25 octets , si le réseau fait passes tes sondes en SF11 (par exemple pour compenser un faible RSSI détécter par la passerelle) ton réseau ne t'autorisera que 1,2 messages par heure en moyenne

Bonjour,
Pouvez-vous deduire d'apres mon code quel est la meilleure solution a adopter ?
y a t il par exemple un moyen de transformer un message qui est ss forme d'une chaine de caracteres en un message ss format json ?

le format JSON (JavaScript Object Notation) est un format de données facile à lire, utilisé pour échanger des données structurées entre un serveur et un client. C'est par définition un chaîne de caractères.

si vous voulez envoyer un entier genre 23, un truc qui dit occupé ou pas et Waves (je ne sais pas ce que c'est) il y a moyen de compacter tout cela, à commencer par ne pas envoyer "Occupied" ou "Not Occupied" qui prend bcp de place

ou voulez vous dire que vous avez un texte et vous savez que c'est un format JSON et vous voulez fabriquer un document JSON par la bibliothèque ?

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.