ArduinoJson - Valeur devient nulle au bout d'un certain temps

Bonjour à tous,

Je teste ce petit programme pour transformer une valeur angulaire de direction du vent en une direction type Girouette? pour l’intégrer ensuite dans un programme plus complexe de balise météo.

Tout se passe bien pendant un certain temps et j’ai bien une orientation du vent qui correspond a l’angle mesuré par la girouette puis la valeur passe à “null” au bout d’environ 4 mn de fonctionnement du programme.

Ci dessous le programme :

#include <ArduinoJson.h>

char *sectors[ ] = {"N", "NNE", "NE", "ENE", "E", "ESE", "SE", "SSE", "S", "SSW", "SW", "WSW", "W", "WNW", "NW", "NNW", "N"};

int windDir = 0;
int index = 0;
String compassDir = "";

//json
StaticJsonDocument<400> doc;

// fonction de traitement getInfo
void handleInfo() {
  String Info;
  doc["D"] = compassDir;
  doc["P"] = pression;
  serializeJson(doc, Info);
  Serial.println(Info);
}
void getHeading(int direction) {
  index = windDir % 360;//modulo
  index = round(index / 22.5);
  compassDir = (sectors[index]);
}
void setup()
{
  Serial.begin(115200);
  Serial.println(*sectors);
}

void loop()
{
  windDir = random(361);
  getHeading(windDir);
  Serial.print("Index = "); Serial.print(index); Serial.print(" - ");
  Serial.println(compassDir);
  handleInfo();
  delay(2000);  
}

Le suivi partiel de la sortie serial :

20:42:13.087 -> Index = 12 - W
20:42:13.087 -> {"D":null,"P":712}
20:42:15.086 -> Index = 12 - W
20:42:15.086 -> {"D":null,"P":712}
20:42:17.088 -> Index = 12 - W
20:42:17.088 -> {"D":null,"P":712}
20:42:19.091 -> Index = 3 - ENE
20:42:19.091 -> {"D":null,"P":712}
20:42:21.089 -> Index = 10 - SW
20:42:21.089 -> {"D":null,"P":712}
20:42:23.090 -> Index = 5 - ESE
20:42:23.090 -> {"D":null,"P":712}
20:42:25.091 -> Index = 6 - SE
20:42:25.091 -> {"D":null,"P":712}

Pouvez-vous m’aider ?

Merci.

Tu définis l’espace mémoire pour les besoins de ArduinoJSON ici :

StaticJsonDocument<400> doc;

Ce choix ou ce dimensionnement sont peut-être insuffisants.

Ce qui est bien avec cette bibliothèque c’est qu’elle dispose d’un assistant qui te donne automatiquement les besoins en mémoire, pour peu que tu lui indiques la structure de ton JSON. Il te donne aussi le code nécessaire pour parser ou sérialiser les données. Il n’y a plus qu’à faire un copier / coller.

Exemple :
Données JSON de météo à Londres :

{“coord”:{“lon”:-0.13,“lat”:51.51},“weather”:[{“id”:300,“main”:“Drizzle”,“description”:“light intensity drizzle”,“icon”:“09d”}],“base”:“stations”,“main”:{“temp”:280.32,“pressure”:1012,“humidity”:81,“temp_min”:279.15,“temp_max”:281.15},“visibility”:10000,“wind”:{“speed”:4.1,“deg”:80},“clouds”:{“all”:90},“dt”:1485789600,“sys”:{“type”:1,“id”:5091,“message”:0.0103,“country”:“GB”,“sunrise”:1485762037,“sunset”:1485794875},“id”:2643743,“name”:“London”,“cod”:200}

Besoin mémoire :

Expression
JSON_ARRAY_SIZE(1) + JSON_OBJECT_SIZE(1) + 2*JSON_OBJECT_SIZE(2) + JSON_OBJECT_SIZE(4) + JSON_OBJECT_SIZE(5) + JSON_OBJECT_SIZE(6) + JSON_OBJECT_SIZE(12)

Code de lecture des données :

const size_t capacity = JSON_ARRAY_SIZE(1) + JSON_OBJECT_SIZE(1) + 2*JSON_OBJECT_SIZE(2) + JSON_OBJECT_SIZE(4) + JSON_OBJECT_SIZE(5) + JSON_OBJECT_SIZE(6) + JSON_OBJECT_SIZE(12) + 280;
DynamicJsonDocument doc(capacity);

const char* json = "{\"coord\":{\"lon\":-0.13,\"lat\":51.51},\"weather\":[{\"id\":300,\"main\":\"Drizzle\",\"description\":\"light intensity drizzle\",\"icon\":\"09d\"}],\"base\":\"stations\",\"main\":{\"temp\":280.32,\"pressure\":1012,\"humidity\":81,\"temp_min\":279.15,\"temp_max\":281.15},\"visibility\":10000,\"wind\":{\"speed\":4.1,\"deg\":80},\"clouds\":{\"all\":90},\"dt\":1485789600,\"sys\":{\"type\":1,\"id\":5091,\"message\":0.0103,\"country\":\"GB\",\"sunrise\":1485762037,\"sunset\":1485794875},\"id\":2643743,\"name\":\"London\",\"cod\":200}";

deserializeJson(doc, json);

float coord_lon = doc["coord"]["lon"]; // -0.13
float coord_lat = doc["coord"]["lat"]; // 51.51

JsonObject weather_0 = doc["weather"][0];
int weather_0_id = weather_0["id"]; // 300
const char* weather_0_main = weather_0["main"]; // "Drizzle"
const char* weather_0_description = weather_0["description"]; // "light intensity drizzle"
const char* weather_0_icon = weather_0["icon"]; // "09d"

const char* base = doc["base"]; // "stations"

JsonObject main = doc["main"];
float main_temp = main["temp"]; // 280.32
int main_pressure = main["pressure"]; // 1012
int main_humidity = main["humidity"]; // 81
float main_temp_min = main["temp_min"]; // 279.15
float main_temp_max = main["temp_max"]; // 281.15

int visibility = doc["visibility"]; // 10000

float wind_speed = doc["wind"]["speed"]; // 4.1
int wind_deg = doc["wind"]["deg"]; // 80

int clouds_all = doc["clouds"]["all"]; // 90

long dt = doc["dt"]; // 1485789600

JsonObject sys = doc["sys"];
int sys_type = sys["type"]; // 1
int sys_id = sys["id"]; // 5091
float sys_message = sys["message"]; // 0.0103
const char* sys_country = sys["country"]; // "GB"
long sys_sunrise = sys["sunrise"]; // 1485762037
long sys_sunset = sys["sunset"]; // 1485794875

long id = doc["id"]; // 2643743
const char* name = doc["name"]; // "London"
int cod = doc["cod"]; // 200

Code pour sérialiser les données :

const size_t capacity = JSON_ARRAY_SIZE(1) + JSON_OBJECT_SIZE(1) + 2*JSON_OBJECT_SIZE(2) + JSON_OBJECT_SIZE(4) + JSON_OBJECT_SIZE(5) + JSON_OBJECT_SIZE(6) + JSON_OBJECT_SIZE(12);
DynamicJsonDocument doc(capacity);

JsonObject coord = doc.createNestedObject("coord");
coord["lon"] = -0.13;
coord["lat"] = 51.51;

JsonArray weather = doc.createNestedArray("weather");

JsonObject weather_0 = weather.createNestedObject();
weather_0["id"] = 300;
weather_0["main"] = "Drizzle";
weather_0["description"] = "light intensity drizzle";
weather_0["icon"] = "09d";
doc["base"] = "stations";

JsonObject main = doc.createNestedObject("main");
main["temp"] = 280.32;
main["pressure"] = 1012;
main["humidity"] = 81;
main["temp_min"] = 279.15;
main["temp_max"] = 281.15;
doc["visibility"] = 10000;

JsonObject wind = doc.createNestedObject("wind");
wind["speed"] = 4.1;
wind["deg"] = 80;
JsonObject clouds = doc.createNestedObject("clouds");
clouds["all"] = 90;
doc["dt"] = 1485789600;

JsonObject sys = doc.createNestedObject("sys");
sys["type"] = 1;
sys["id"] = 5091;
sys["message"] = 0.0103;
sys["country"] = "GB";
sys["sunrise"] = 1485762037;
sys["sunset"] = 1485794875;
doc["id"] = 2643743;
doc["name"] = "London";
doc["cod"] = 200;

serializeJson(doc, Serial);

Dans ton cas, pour des données :

{"D":250,"P":712}

Le code pour parser :

const size_t capacity = JSON_OBJECT_SIZE(2) + 10;
DynamicJsonDocument doc(capacity);

const char* json = "{\"D\":250,\"P\":712}";

deserializeJson(doc, json);

int D = doc["D"]; // 250
int P = doc["P"]; // 712

et pour sérialiser :

const size_t capacity = JSON_OBJECT_SIZE(2);
DynamicJsonDocument doc(capacity);

doc["D"] = 250;
doc["P"] = 712;

serializeJson(doc, Serial);

Tu peux voir qu’il propose une allocation mémoire dynamique (DynamicJsonDocument) plutôt que statique (StaticJsonDocument) et si tu affiches la valeur de ‘capacity’ tu verras si ton choix de 400 est suffisant…

Bonjour Lesept,

Merci pour cette aide !

J'ai fait la manip avec l'assistant mais ça ne fonctionne pas : ci dessous le résultat :

const size_t capacity = JSON_OBJECT_SIZE(2);

13:49:29.471 -> NE
13:49:29.471 -> {"P":807,"D":null}
13:49:32.456 -> E
13:49:32.456 -> {"P":73,"D":null}
13:49:35.475 -> SW
13:49:35.475 -> {"P":930,"D":null}
13:49:38.458 -> N
13:49:38.458 -> {"P":544,"D":null}
13:49:41.481 -> SSE
13:49:41.481 -> {"P":923,"D":null}

Pour voir, j'ai changé la capacité avec 4 et voila ce que ça donne :

const size_t capacity = JSON_OBJECT_SIZE(4);

13:47:41.754 -> NE
13:47:41.754 -> {"P":807,"D":"NE"}
13:47:44.734 -> E
13:47:44.734 -> {"P":73,"D":"E"}
13:47:47.753 -> SW
13:47:47.753 -> {"P":930,"D":"SW"}
13:47:50.735 -> N
13:47:50.735 -> {"P":544,"D":"N"}
13:47:53.758 -> SSE
13:47:53.758 -> {"P":923,"D":"SSE"}
13:47:56.747 -> W
13:47:56.747 -> {"P":440,"D":"W"}
13:47:59.734 -> WNW
13:47:59.734 -> {"P":492,"D":null}
13:48:02.753 -> SSE
13:48:02.753 -> {"P":987,"D":null}
13:48:05.735 -> WSW
13:48:05.735 -> {"P":327,"D":null}
13:48:08.752 -> NNE
13:48:08.752 -> {"P":840,"D":null}

Ca semble bien être lié à l'espace mémoire mais, du coup, je ne sais pas comment le dimensionner.

Est-ce que la façon de déclarer les directions par : char * sectors[ ] est la bonne et faut il utiliser la classe String qui consomme beaucoup de mémoire ?

En gros, y a t'il une autre façon de réaliser ce programme ?

Au fait, J’utilise pour ce test une carte uno. La mémoire de la carte peut elle être en cause également?

Quand je déplace la déclaration du json dans la fonction, ça fonctionne :

// fonction de traitement getInfo
void handleInfo() {
  const size_t capacity = JSON_OBJECT_SIZE(2);
  DynamicJsonDocument doc(capacity);
  String Info;
  doc["D"] = compassDir;
  doc["P"] = 1000;
  serializeJson(doc, Info);
  Serial.println(Info);
}

N Index = 9 - SSW {"D":"SSW"} Index = 15 - NNW {"D":"NNW"} Index = 9 - SSW {"D":"SSW"} Index = 13 - WNW {"D":"WNW"} Index = 13 - WNW {"D":"WNW"} Index = 5 - ESE {"D":"ESE"} Index = 11 - WSW {"D":"WSW"} Index = 1 - NNE {"D":"NNE"} Index = 1 - NNE {"D":"NNE"} Index = 4 - E {"D":"E"} Index = 15 - NNW {"D":"NNW"} Index = 7 - SSE {"D":"SSE"} Index = 5 - ESE {"D":"ESE"} Index = 6 - SE {"D":"SE"} Index = 11 - WSW {"D":"WSW"} Index = 14 - NW {"D":"NW"} Index = 13 - WNW {"D":"WNW"} Index = 4 - E {"D":"E"} Index = 13 - WNW {"D":"WNW"} Index = 15 - NNW {"D":"NNW"} Index = 4 - E {"D":"E"} Index = 7 - SSE {"D":"SSE"} Index = 3 - ENE {"D":"ENE"} Index = 3 - ENE {"D":"ENE"} Index = 14 - NW {"D":"NW"} Index = 8 - S {"D":"S"} Index = 5 - ESE {"D":"ESE"} Index = 1 - NNE {"D":"NNE"} Index = 12 - W {"D":"W"} Index = 3 - ENE {"D":"ENE"} Index = 15 - NNW {"D":"NNW"} Index = 11 - WSW {"D":"WSW"} Index = 4 - E {"D":"E"} Index = 9 - SSW {"D":"SSW"} Index = 5 - ESE {"D":"ESE"} Index = 10 - SW {"D":"SW"} Index = 3 - ENE {"D":"ENE"} Index = 4 - E {"D":"E"} Index = 3 - ENE {"D":"ENE"} Index = 2 - NE {"D":"NE"}

Bonjour Lesept,

Effectivement, ton sketch modifié fonctionne correctement. J'avais mis :

const size_t capacity = JSON_OBJECT_SIZE(2); DynamicJsonDocument doc(capacity);

dans la zone des variables globales.

Merci encore pour ton aide.

Rebonjour Lesept,

Finalement, il reste un problème !

le sketch fonctionne mais info n'affiche pas "P" mais n'affiche que "D" :

Si je change l'ordre de doc[D) et doc[P] :

void handleInfo() {
  const size_t capacity = JSON_OBJECT_SIZE(2);
  DynamicJsonDocument doc(capacity);
  String Info;
  doc["P"] = 1000;  
  doc["D"] = compassDir;

  serializeJson(doc, Info);
  Serial.println(Info);
}

ça donne ça :

Index = 7 - SSE
{"P":1000,"D":null}
Index = 10 - SW
{"P":1000,"D":null}
Index = 5 - ESE
{"P":1000,"D":null}
Index = 8 - S
{"P":1000,"D":null}
Index = 0 - N
{"P":1000,"D":null}
Index = 10 - SW
{"P":1000,"D":null}
Index = 0 - N
{"P":1000,"D":null

Pas simple à comprendre pour moi !

Merci pour ton aide

Si ton json reste aussi simple tu peux le créer directement,sans utiliser la bibliothèque.

char jsonPayload[20];
sprintf (jsonPayload, "{\"P\":%d, \"D\":%s}", pression, compassDir) ;

A tester. Il faudra peut-être mettre des \ devant les accolades…

Bonjour Lesept,

Finalement, après avoir lu pas mal d'exemples sur le site de la bibliothèque ArduinoJson, j'ai réglé le problème qui venait bien de l'occupation mémoire par : DynamicJsonDocument doc(1024);

Voici le code de la fonction :

void handleInfo() {
  DynamicJsonDocument doc(1024);
  Serial.print("CompassDir = "); Serial.println(compassDir);
  String Info;
  doc["T"] = temperature;
  doc["H"] = humidity;
  doc["V"] = windSpeed;
  doc["D"] = compassDir;
  doc["P"] = pression;
  doc["V"] = tension;
  doc["A"] = averageSpeed;
  doc["mT"] = minTemp;
  doc["MT"] = maxTemp;
  serializeJson(doc, Info);
  Serial.println(Info);

  server.send(200, "application/json", Info);
}

Merci pour l'aide.

Impec ! Si tu as l'occasion, j'aimerais bien savoir à combien correspond ce JSON_OBJECT_SIZE(2). Peux-tu tester avec ce paramètre et afficher la valeur de la variable capacity ?

Ton 1024 est le résultat minimal issu de nombreux essais ou est-ce la première valeur qui a marché ?

Bonjour Lesept,

Voici le test avec ce code testé sur une UNO:

#include <ArduinoJson.h>

char *sectors[ ] = {"N", "NNE", "NE", "ENE", "E", "ESE", "SE", "SSE", "S", "SSW", "SW", "WSW", "W", "WNW", "NW", "NNW", "N"};
int index = 0;
int pression;
String compassDir;



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

}

void loop() {
  pression = random(1000);
  index = random(17);
  compassDir = (sectors[index]);
  Serial.println(compassDir);

  const size_t capacity = JSON_OBJECT_SIZE(2);
  Serial.print("capacity = ");Serial.println(capacity);
  DynamicJsonDocument doc(capacity);

  String info;
  doc["P"] = pression;
  doc["D"] = compassDir;

  serializeJson(doc, info);
  Serial.println(info);
  delay(3000);
}

Et le résultat :

NE
capacity = 16
{"P":807,"D":null}
E
capacity = 16
{"P":73,"D":null}
SW
capacity = 16
{"P":930,"D":null}

Pour la deuxième question, je me suis inspiré de l’exemple fourni avec la bibliothèque ArduinoJson qui traitait de String, à savoir :

https://github.com/bblanchon/ArduinoJson/blob/6.x/examples/StringExample/StringExample.ino

/ ArduinoJson - arduinojson.org
// Copyright Benoit Blanchon 2014-2020
// MIT License
//
// This example shows the different ways you can use String with ArduinoJson.
//
// Use String objects sparingly, because ArduinoJson duplicates them in the
// JsonDocument. Prefer plain old char[], as they are more efficient in term of
// code size, speed, and memory usage.
//
// https://arduinojson.org/v6/example/string/

#include <ArduinoJson.h>

void setup() {
  DynamicJsonDocument doc(1024);

  // You can use a String as your JSON input.
  // WARNING: the string in the input  will be duplicated in the JsonDocument.
  String input =
      "{\"sensor\":\"gps\",\"time\":1351824120,\"data\":[48.756080,2.302038]}";
  deserializeJson(doc, input);
  JsonObject obj = doc.as<JsonObject>();

  // You can use a String to get an element of a JsonObject
  // No duplication is done.
  long time = obj[String("time")];

  // You can use a String to set an element of a JsonObject
  // WARNING: the content of the String will be duplicated in the JsonDocument.
  obj[String("time")] = time;

  // You can get a String from a JsonObject or JsonArray:
  // No duplication is done, at least not in the JsonDocument.
  String sensor = obj["sensor"];

  // Unfortunately, the following doesn't work (issue #118):
  // sensor = obj["sensor"]; // <-  error "ambiguous overload for 'operator='"
  // As a workaround, you need to replace by:
  sensor = obj["sensor"].as<String>();

  // You can set a String to a JsonObject or JsonArray:
  // WARNING: the content of the String will be duplicated in the JsonDocument.
  obj["sensor"] = sensor;

  // It works with serialized() too:
  obj["sensor"] = serialized(sensor);

  // You can also concatenate strings
  // WARNING: the content of the String will be duplicated in the JsonDocument.
  obj[String("sen") + "sor"] = String("gp") + "s";

  // You can compare the content of a JsonObject with a String
  if (obj["sensor"] == sensor) {
    // ...
  }

  // Lastly, you can print the resulting JSON to a String
  String output;
  serializeJson(doc, output);
}

void loop() {
  // not used in this example
}

Je n’aime pas utiliser String et d’après ce que dit le concepteur de la bibliothèque c’est très gourmand en mémoire mais, dans mon cas, comment faire Autrement ?

“Use String objects sparingly, because ArduinoJson duplicates them in the
// JsonDocument. Prefer plain old char, as they are more efficient in term of
// code size, speed, and memory usage.”

A bientôt.

Bon c'est clair que 16 était trop peu, mais 1024 doit être surestimé.

Si tu ne veux pas utiliser les String je t'ai donné un exemple dans le message 6 pour t'en passer.