Parsing JSON always empty

Hello!

What is the correct method to parse a string into a JSON and then get values from it? I tried many things, but nothind works - the value is always empty in the lambda section, but outside it is present.

                on_response:
                  then:
                    - logger.log: 
                        format: "Got REST response: %s"
                        args : ['id(http_request_data).get_string()']
                    - lambda: |-
                        ESP_LOGI("debug", "JSON get_string value:", id(http_request_data).get_string());
                        std::string data = id(http_request_data).get_string();
                        ESP_LOGI("debug", "JSON data value:", data);

Here’s the log

[12:44:15][D][wiegand:073]: received 26-bit tag: 3052795
[12:44:15][I][TAG:096]: received tag 3052795
[12:44:15][D][main:107]: Got REST response: {"USEROK":1}
[12:44:15][I][debug:114]: JSON get_string value:

I used the code provided in the EspHome article: HTTP Request — ESPHome (see the paragraph " GET values from a JSON body response").

The problem is that when logging the REST respone, the value is correct:

- logger.log: 
    format: "Got REST response: %s"            
    args : ['id(http_request_data).get_string()']

is logged as

[12:44:15][D][main:107]: Got REST response: {"USEROK":1}

but when parsing in the lambda section, I always get an empty value in log, even if calling the same variable

ESP_LOGI("debug", "JSON get_string value:", id(http_request_data).get_string());

is logged as

[12:44:15][I][debug:114]: JSON get_string value:

How to correctly pass the string value and then parse it?

Nobody has this problem…?

I also had this with a chip: ESP32 - az-delivery-devkit-v4.

It looks like this version does not work with the id (http_request_data).get_string ();.
But if I save the request in a global variable or in a text sensor, I can process it.

ESP Version: 2023.2.4

## ---------------------------------------------------
##  TEST id(http_request_data).get_string()
##  board: az-delivery-devkit-v4; framework: arduino; 
##  platform: platformio/espressif32 @ 5.2.0
## ---------------------------------------------------
##  2023.2.4|Flash: 4096kB Speed:40MHz Mode:DIO|
##  Chip: ESP32 Features:WIFI_BGN,BLE,BT, Cores:2 Revision:3|
##  ESP-IDF: v4.4.2|EFuse MAC: 78:21:84:9C:B2:AC|
##  Reset: Software Reset CPU|Wakeup: Unknown
## ---------------------------------------------------
substitutions:
  device_name_short: "esp-ipinfo"
  friendly_name: "IPInfo"
  device_description: "Testcase for ip info"
  domain: !secret domain
  appversion: "2.0.1"
  update_interval: "60s"

esp32:
  board: az-delivery-devkit-v4
  framework:
    type: arduino

esphome:
  name: "${device_name_short}"
  comment: "${device_description}"
  build_path: ./build/${device_name_short}


## ---------------------------------------------------
## WIFI Settings
## ---------------------------------------------------
wifi:
  networks:
    - ssid:  !secret ssid3_name
      password: !secret ssid3_pswd
      priority : 1
    - ssid:  !secret ssid1_name
      password: !secret ssid1_pswd
      priority : 2
    - ssid:  !secret ssid2_name
      password: !secret ssid2_pswd
      priority : 3
  domain: !secret domain

## ---------------------------------------------------
## WEBSERVER Settings
## ---------------------------------------------------
web_server:
  port: 80
  version: 2
  local: true

## ---------------------------------------------------
## OTA Settings
## ---------------------------------------------------
ota:
  password: !secret ota_pswd
  on_error:
    then:
      - logger.log:
          format: "OTA update error %d"
          args: ["x"]

## ---------------------------------------------------
## Native API Component
## ---------------------------------------------------
api:
  id: espapi
  port: 6053
  # The amount of time to wait before
  # rebooting when no client connects to the API.
  # Can be disabled by setting this to 0s
  reboot_timeout: 0s

## ---------------------------------------------------
## Global variables
## ---------------------------------------------------
globals:
  - id: ipInfodata
    type: std::string
    restore_value: no
    initial_value: '""'

## ---------------------------------------------------
## Logger
## ---------------------------------------------------
logger:
  id: mylogger
  level: info
  baud_rate: 0 #disable logging over uart

## ---------------------------------------------------
## HTTP REQUEST HANDLER
## ---------------------------------------------------
http_request:
  id: http_request_data
  useragent: esphome/iptest
  timeout: 10s


## ---------------------------------------------------
## Testcase
## http://ip-api.com/json/
## https://wasab.is/json
## ---------------------------------------------------
script:
  - id: getNetInfoData
      then:
        - http_request.get:
            url: http://ip-api.com/json/
            headers:
              Content-Type: application/json
            verify_ssl: false
            on_response:
              - if:
                  condition:
                     lambda: |-
                        return status_code == 200;
                  then:
                    - logger.log:
                        level: info
                        format: "Response status: %d, Duration: %u ms"
                        args:
                          - status_code
                          - duration_ms
                    - lambda: |-
                        id(ipInfodata) = id(http_request_data).get_string();
                    - logger.log:
                        level: info
                        format: "Start telegramdata: %s"
                        args: ["id(telegraminfo).state.c_str()"]
                    # see: https://arduinojson.org/v6/assistant/#/step1
                    - lambda: |-
                        StaticJsonDocument<2048> doc;
                        DeserializationError error = deserializeJson(doc, id(ipInfodata));
                        if (error) {
                          ESP_LOGI("parse error", "deserializeJson failed %s",error.c_str());
                        }else{
                            const char* status = doc["status"]; // "success"
                            const char* country = doc["country"];
                            const char* countryCode = doc["countryCode"];
                            const char* region = doc["region"];
                            const char* regionName = doc["regionName"];
                            const char* city = doc["city"];
                            const char* zip = doc["zip"];
                            float lat = doc["lat"];
                            float lon = doc["lon"];
                            const char* timezone = doc["timezone"];
                            const char* isp = doc["isp"];
                            const char* org = doc["org"];
                            const char* as = doc["as"];
                            const char* query = doc["query"];
                            ESP_LOGI("IPInfo", "status %s",status);
                            ESP_LOGI("IPInfo", "city %s-%s",zip, city);
                            ESP_LOGI("IPInfo", "country %s",country);
                            ESP_LOGI("IPInfo", "regionName %s",regionName);
                            ESP_LOGI("IPInfo", "Coordinates: %.1f, %.1f",lat, lon);
                            ESP_LOGI("IPInfo", "timezone %s",timezone);
                            ESP_LOGI("IPInfo", "org %s",org);
                            ESP_LOGI("IPInfo", "provider %s",as);
                            ESP_LOGI("IPInfo", "Public IP %s",query);
                        }


## ---------------------------------------------------
## BUTTONS
## ---------------------------------------------------
button:
  - platform: template
    name: 'Test: IP Data'
    id: btnGetNetInfoData
    on_press:
      - script.execute: getNetInfoData

1 Like

Thank you, now works correctly via globals.

How can I inform the ESPHome team about this bug?

I think it has already opened:

This wasn’t the solution for me and I don’t think the real solution is to use globals. It looks like id(http_request_data).get_string() returns an empty string after the first call.

This code:

ESP_LOGI(RESPONSE, get_string(): [%s], id(http_request_data).get_string());
std::string response_data = id(http_request_data).get_string();
ESP_LOGI(RESPONSE, response_data: [%s], response_data.c_str());
if (!response_data.empty()) {
	ESP_LOGI("JSON", "Parse");
	json::parse_json(response_data, [](JsonObject root) {
		id(switch_x).publish_state(root["value"]);
	});
}

produces this log:

[I][RESPONSE:055]: get_string(): [{"id":"sensor-switch_state","value":1,"state":"1.0"}]
[I][RESPONSE:057]: response_data: []

And if the first ESP_LOGI line is omitted:

[I][RESPONSE:056]: response_data: [{"id":"sensor-switch_state","value":1,"state":"1.0"}]
[I][JSON:058]: Parse
[D][sensor:094]: 'Switch': Sending state 1.00000  with 1 decimals of accuracy