bblanchon / ArduinoJson

📟 JSON library for Arduino and embedded C++. Simple and efficient.
https://arduinojson.org
MIT License
6.67k stars 1.11k forks source link

JsonObject has no member named key... #590

Closed zibous closed 6 years ago

zibous commented 6 years ago

JsonObject has no member named key

Is there a simpler way to go through all the elements, but I did not find a solution. I am currently loading the data with "JsonObject& data = jsonBuffer.parseObject(file);" and then calling the parseJSONdata (data [F ("data")] function.

But get the error message:

Class ArduinoJson :: JsonObject has no member named key

void parseJSONdata(JsonArray& jsonArray){
  for (auto &element : jsonArray){
      if(element["rows"].size()){
          JsonArray& items = element["rows"];
          Serial.println("Items:" + String(items.size()));
          for(int i=0;i<items.size();i++) {            
            JsonObject& elem = items[i];
            Serial.println(elem.key);
            // update value
            elem.value = getUpdateValue(elem.key);
          }
      }
  }
}

bool loadData(String filename){

    String output;

    // read template 
    File file = SPIFFS.open(filename, "r");
    DynamicJsonBuffer jsonBuffer;
    JsonObject& data = jsonBuffer.parseObject(file);

    // update template data
    parseJSONdata(data[F("data")]);

    // build the response    
    data.printTo(output);
    sendHttpHeader();
    server.send(200, F("text/json"), output);
    return true;

}

json datafile

{
    "text": {
        "tbtitle": "Home SHD-D1M001",
        "pgt": "Sensors & Services",
        "h2": "Installed Componets (Sensors, Services)",
        "html": [{
            "target": "page-head",
            "type": "h1",
            "class": "icon-home",
            "text": "Sensors & Services"
        }]
    },
    "menu": {
        "component": "navigation",
        "id": "navi",
        "rows": [{
                "href": "index.html",
                "id": "#",
                "key": "",
                "interval": 0,
                "class": "icon-home",
                "status":"enabled",
                "label": "Home"
            },
            {
                "href": "",
                "id": "device",
                "key": "",
                "interval": 0,
                "class": "icon-device",
                "status":"enabled",
                "label": "Device"
            },
            {
                "href": "",
                "id": "services",
                "interval": 0,
                "key": "",
                "class": "icon-report",
                "status":"enabled",
                "label": "Services"
            },
            {
                "href": "",
                "id": "dht22",
                "key": "dht-",
                "interval": 10000,
                "class": "icon-dht",
                "status":"disabled",
                "label": "DHT22 Sensor"
            },
            {
                "href": "",
                "id": "bme280",
                "key": "bme-",
                "interval": 10000,
                "class": "icon-dht",
                "status":"disabled",
                "label": "BME280 Sensor"
            },
            {
                "href": "",
                "id": "irdat",
                "key": "ir-",
                "interval": 10000,
                "class": "icon-irtx",
                "status":"disabled",
                "label": "IR (Infrared)"
            },
            {
                "href": "",
                "id": "rfdat",
                "key": "ir-",
                "interval": 10000,
                "class": "icon-radio",
                "status":"disabled",
                "label": "Radio 433 MHz"
            },
            {
                "href": "",
                "id": "btdat",
                "key": "bt-",
                "interval": 10000,
                "class": "icon-bluetooth",
                "status":"disabled",
                "label": "Bluetooth"
            },
            {
                "href": "",
                "id": "settings",
                "key": "",
                "interval": 0,
                "class": "icon-config",
                "status":"enabled",
                "label": "Settings"
            },
            {
                "href": "",
                "id": "update",
                "key": "",
                "interval": 0,
                "class": "icon-upload",
                "status":"enabled",
                "label": "Firmware"
            },
            {
                "href": "",
                "id": "restart",
                "key": "",
                "interval": 0,
                "class": "icon-refresh",
                "status":"enabled",
                "label": "Restart System"
            }
        ]
    },
    "data": [{
            "title": "Sensor Modules",
            "component": "datateaser",
            "id": "mv",
            "rows": [{
                    "name": "Sensor DHT22",
                    "key": "dht-",
                    "type": "DHT",
                    "text": "DHT22/AM2302 Digital Temperature and Humidity Sensor.",
                    "led": "green",
                    "status":"online",
                    "chartdata":"24.34,25.10,21.45.22.50,23.10,23.00,22.00,23.50,24.10",
                    "img": "",
                    "link": ""
                },
                {
                    "name": "Sensor BME 280",
                    "type": "BME",
                    "key": "bme-",
                    "text": "High Precision Barometric Pressure Module,Temperature and Humidity",
                    "led": "red",
                    "status":"online",
                    "values": "T:24.43 °C \n H:54.00% \n P:1024 hpa",
                    "img": "",
                    "link": ""
                },
                {
                    "name": "RF 433 Mhz Transmitter",
                    "type": "RF-TX",
                    "key": "rf-tx",
                    "text": "RF Transmitter Module 433MHz Wireless for switches",
                    "led": "green",
                    "status":"online",
                    "img": "",
                    "link": ""
                },
                {
                    "name": "RF 433 Mhz Receiver",
                    "type": "RF-RX",
                    "key": "rf-rx",
                    "text": "RF Receiver Module 433MHz Wireless for watching",
                    "led": "green",
                    "status":"online",
                    "img": "",
                    "link": ""
                },
                {
                    "name": "Infrared Transmitter",
                    "type": "IR-TX",
                    "key": "ir-tx",
                    "text": "RF Transmitter Module 433MHz Wireless for switches",
                    "led": "green",
                    "status":"online",
                    "img": "",
                    "link": ""
                },
                {
                    "name": "Infrared Receiver",
                    "type": "IR-RX",
                    "key": "ir-rx",
                    "text": "Infrared Receiver IR Receiver Module 38K",
                    "led": "red",
                    "status":"disabled",
                    "img": "",
                    "link": ""
                },
                {
                    "name": "BLE beacons Sensor",
                    "type": "BLE",
                    "key": "ble-",
                    "text": "Wireless Serial BLE Bluetooth V4.0 Transceiver Module",
                    "led": "red",
                    "status":"disabled",
                    "img": "",
                    "link": ""
                }
            ]
        },
        {
            "title": "Services",
            "component": "datateaser",
            "id": "mds",
            "rows": [{
                    "name": "NTP Support",
                    "type": "NTP",
                    "text": "",
                    "led": "green",
                    "status":"online",
                    "img": "",
                    "link": ""
                },
                {
                    "name": "MDNS Support",
                    "type": "MDNS",
                    "text": "",
                    "led": "green",
                    "status":"online",
                    "img": "",
                    "link": ""
                },
                {
                    "name": "FTP Support",
                    "type": "FTP",
                    "text": "",
                    "led": "green",
                    "status":"online",
                    "img": "",
                    "link": ""
                },
                {
                    "name": "MQTT Support",
                    "type": "MQTT",
                    "text": "",
                    "led": "green",
                    "status":"online",
                    "img": "",
                    "link": ""
                },
                {
                    "name": "TASK Support",
                    "type": "TSK",
                    "text": "",
                    "led": "green",
                    "status":"online",
                    "img": "",
                    "link": ""
                },
                {
                    "name": "SYSLOG Support",
                    "type": "SYL",
                    "text": "Syslog Settings - Syslog server connection",
                    "led": "green",
                    "status":"online",
                    "img": "",
                    "link": ""
                },
                {
                    "name": "ALEXA Support",
                    "type": "AX",
                    "text": "",
                    "led": "green",
                    "status":"online",
                    "img": "",
                    "link": ""
                },
                {
                    "name": "WEBSERVER Support",
                    "type": "WEB",
                    "text": "",
                    "led": "green",
                    "status":"online",
                    "img": "",
                    "link": ""
                },
                {
                    "name": "EMBEDIS Support",
                    "type": "EDS",
                    "text": "",
                    "led": "green",
                    "status":"online",
                    "img": "",
                    "link": ""
                }
            ]
        }
    ]
}
bblanchon commented 6 years ago

Hi @zibous,

If I understand correctly, you want to iterate through all the key-value pairs of a JsonObject. This can be done with a for loop on the JsonObject, just like you did for the JsonArray. The trick is that the auto is deduced to a JsonVariant not a JsonObject, so you need to cast.

Here, applied to the parseJSONdata() from above:

void parseJSONdata(JsonArray &components) {
  for (JsonObject &component : components) {
    JsonArray &rows = component["rows"];
    for (JsonObject &row : rows) {
      for (JsonPair &column : row) {
        Serial.println(column.key);
        column.value = getUpdateValue(column.key);
      }
    }
  }
}

See:

zibous commented 6 years ago

Hi bblanchon, Thanks for your information, works fine.

The json file is a template. After loading, I want to update the attributes with the device information. Therefore, I have to go through all nodes and check if something has changed. If so then these should be filled with the new value.

The only problem is that I can not update "column.value". Error: "operant types are ('Arduino :: JsonVariant and' String '").

String getUpdateValue(String fieldname, String defaultValue){
    String cfgval;
    // try to find the value
    if (Embedis::get(fieldname, cfgval)) {
        #ifdef DEBUG_MESSAGES
          Serial.printf("[Field Update]\t Name:%s Value:%s\n", fieldname.c_str(), cfgval.c_str());
        #endif
        return cfgval;
    }
    #ifdef DEBUG_MESSAGES
    Serial.printf("[Field Update]\t Name:%s not found !\n", fieldname.c_str());
    #endif
    return defaultValue;
}

void parseJSONdata(JsonArray &components){
  for (JsonObject &component : components) {
    JsonArray &rows = component["rows"];
    for (JsonObject &row : rows) {
      for (JsonPair &column : row) {
        String fieldname = column.key;
        if ( strcmp(column.key, "status")==0 ){
          String _prefix = row["key"];
           if(_prefix!="")
              fieldname = _prefix + column.key;
        }
        column.value = getUpdateValue(fieldname, column.value);
      }
    }
  }
}

FYI: PlatformIO Lib is 5.11.1, ArduinoJson 5.11.2 released 2 days ago is not aviable.

bblanchon commented 6 years ago

Indeed, this is a limitation of the current design of ArduinoJson. A detached JsonVariant is not able to make a copy of a String. There are two workarounds:

// 1. use the JsonBuffer directly.
column.value = jsonBuffer.strdup(getUpdateValue(fieldname, column.value));

// 2. pass through the JsonObject
row[column.key] = getUpdateValue(fieldname, column.value);

Sorry about that, this may change in 6.x.

zibous commented 6 years ago

Hi Benoît,

Thank you, works.

/**
  *  parse the json data of the template
  *  and update the values
  */
 void parseJSONdata(JsonArray &components){
   for (JsonObject &component : components) {
     JsonArray &rows = component[F("rows")];
     for (JsonObject &row : rows) {
         if (row.containsKey(F("field")) && row.containsKey(F("value"))){
           String fieldname = row[F("field")];
           String newValue  = getUpdateValue(fieldname);
           if(newValue.length()){
              #ifdef DEBUG_MESSAGES
                 Serial.printf("[Field Update]\t Update:%s=%s\n", fieldname.c_str(), newValue.c_str());
              #endif
              row[F("value")] = newValue;
           }
         }
      }
   }
 }

New problem:

 // try to open the json file
  File file = SPIFFS.open(filename, "r");
  if(file){
      // file found, so we can prepare the data
      DynamicJsonBuffer jsonBuffer;
      // parse the file
      JsonObject& data = jsonBuffer.parseObject(file);
      // We don't need the file anymore
      file.close();
      if (!data.success()) {
          #ifdef DEBUG_MESSAGES
            Serial.printf("[WEBSERVER]\tError parsing file: %s\n", filename.c_str());
          #endif
          #ifdef SYSLOG_SUPPORT
            syslog.logf(LOG_ERR, "Webserver Error open file: %s", filename.c_str());
          #endif
          sendAjaxMessage(F("error"), "System message", "Error parsing file " + filename);
          return false;
      }
      ...
  }

For a larger Json file (> 3.5KB) this can not be parsed. The file is valid.

see: https://www.freeformatter.com/json-validator.html The JSON input is valid according to RFC 4627 (JSON specfication). The JSON input is valid in JavaScript.

home.json.zip

PlatformIO: Can not upgrade to the latest version, ArduinoJson 5.11.2 is not (yet) available. PlatformIO Lib is 5.11.1, ArduinoJson 5.11.2 released 2 days ago is not aviable.

bblanchon commented 6 years ago

Hi @zibous,

It looks like a memory issue. Try to pass the buffer size to the constructor of DynamicJsonBuffer. Use ArduinoJson Assistant to compute the size.

If it still doesn't work, it probably means that there is not enough RAM in the microcontroller.

Regards, Benoit