ZippoSLO
(Marko)
February 24, 2023, 12:08pm
1
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?
ZippoSLO
(Marko)
February 25, 2023, 9:42pm
2
Nobody has this problem…?
petsie
February 27, 2023, 10:44am
3
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
ZippoSLO
(Marko)
February 27, 2023, 1:29pm
4
Thank you, now works correctly via globals.
How can I inform the ESPHome team about this bug?
ZippoSLO
(Marko)
February 27, 2023, 1:49pm
5
I think it has already opened:
opened 12:21PM - 26 Feb 23 UTC
### The problem
StaticJsonDocument is empty
```json
{
"telegram": [
… "/ISk5MT174-0001",
"0.9.1(130203)",
"0.9.2(0230223)",
"0.0.0(00339188)",
"0.2.0(1.03)",
"C.1.6(FDF5)",
"1.8.1(0011404.409*kWh)",
"1.8.2(0023813.725*kWh)",
"2.8.1(0015608.962*kWh)",
"2.8.2(0000900.569*kWh)",
"F.F.0(0000000)",
"!"
]
}
```
Could not allocate memory for JSON document! Requested 0 bytes, free heap: 110580
1st log output shows the payload
2nd Error Could not allocate memory for JSON document
3rd log output shows no payload
### Which version of ESPHome has the issue?
2023.2.4
### What type of installation are you using?
Docker
### Which version of Home Assistant has the issue?
_No response_
### What platform are you using?
ESP32
### Board
az-delivery-devkit-v4
### Component causing the issue
http_request
### Example YAML snippet
```yaml
## ---------------------------------------------------
## TEST ESPLESEKOPF TELEGRAMS
## 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-lesekopf2"
friendly_name: "Smartmeter"
device_description: "Smartmeter Device for Gridmeter ISKRA 2013 M13 1376, Drehstromzähler"
domain: !secret domain
appversion: "2.0.1"
service_url: !secret service_host
service: "mt174.gridmeter"
## ---------------------------------------------------
## device configuration
## ---------------------------------------------------
board: "az-delivery-devkit-v4"
uart_rx_pin: "GPIO17" # white
uart_tx_pin: "GPIO16" # orange
uart_baudrate: "300"
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
reboot_timeout: 0s
# ----------------------------------------------------------------
# Logger
# ----------------------------------------------------------------
logger:
id: mylogger
level: info
baud_rate: 0 #disable logging over uart
# ----------------------------------------------------------------
# HTTP
# ----------------------------------------------------------------
http_request:
id: http_request_data
useragent: esphome/mt174test
timeout: 10s
# ----------------------------------------------------------------
# Serial interface
# ----------------------------------------------------------------
uart:
id: my_uart
tx_pin: GPIO17 # white [TX] az-delivery-devkit-v4,
rx_pin: GPIO16 # orange [RX] az-delivery-devkit-v4,
baud_rate: 300
data_bits: 7
parity: EVEN
stop_bits: 1
rx_buffer_size: 512
debug:
direction: BOTH
after:
delimiter: "\r\n"
sequence:
- lambda: |-
UARTDebug::log_string(direction, bytes); //Still log the data
std::string str(bytes.begin(), bytes.end());
ESP_LOGI("UART", "DATA: %s",str.c_str());
## ---------------------------------------------------
## SCRIPTS
## ---------------------------------------------------
script:
- id: writeTelegram
parameters:
message: string
mode: queued
then:
- logger.log:
level: info
format: "Telegram message: %s"
args: ["message"]
- uart.write:
id: my_uart
data: !lambda |-
std::string str = message;
std::vector<uint8_t> vec(str.begin(), str.end());
return vec;
- uart.write:
id: my_uart
data: "\r\n"
- delay: 10ms
- logger.log: "Next Telegram message"
- id: getNetInfoData
mode: queued
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
- logger.log:
level: info
format: "Start telegramdata: %s"
args: ["id(http_request_data).get_string()"]
- id: getTelegramdata
mode: queued
then:
- logger.log:
level: info
format: "HTTP Request get Data"
- http_request.get:
url: !secret data_host
headers:
Content-Type: application/json
verify_ssl: false
on_response:
- if:
condition:
lambda: |-
return status_code == 200;
then:
- logger.log:
level: info
tag: "getTelegramdata"
format: "Response status: %d, Duration: %u ms"
args:
- status_code
- duration_ms
- logger.log:
level: info
tag: "getTelegramdata"
format: "Response telegramdata: %s"
args: ["id(http_request_data).get_string()"]
# {"telegram":
# [
# "/ISk5MT174-0001",
# "0.9.1(130203)",
# "0.9.2(0230223)",
# "0.0.0(00339188)",
# "0.2.0(1.03)", "C.1.6(FDF5)",
# "1.8.1(0011404.409*kWh)",
# "1.8.2(0023813.725*kWh)",
# "2.8.1(0015608.962*kWh)",
# "2.8.2(0000900.569*kWh)",
# "F.F.0(0000000)", "!"
# ]}
- lambda: |-
ESP_LOGI("script", "Decode Response");
json::parse_json(id(http_request_data).get_string(), [](JsonObject root) {
for (uint16_t i = 0; i < 12; i++) {
ESP_LOGI("parse", "telegram %d: %s",i,root["telegram"][i] );
}
});
- logger.log:
level: info
tag: "getTelegramdata"
format: "Response telegramdata: %s"
args: ["id(http_request_data).get_string()"]
- logger.log:
level: info
tag: "getTelegramdata"
format: "End telegram decoder"
- id: snddata
then:
- lambda: |-
uint16_t size = id(seltelegram).size();
for (uint16_t i = 0; i < size; i++) {
auto option = id(seltelegram).at(i);
auto value = option.value();
ESP_LOGI("script", "Option at %d is: %s", index, value.c_str());
id(writeTelegram).execute(value);
}
select:
- platform: template
name: "Select Telegram"
id: seltelegram
optimistic: true
options:
- "/ISk5MT174-0001"
- "0.9.1(130203)"
- "0.9.2(0230223)"
- "0.0.0(00339188)"
- "0.2.0(1.03)"
- "C.1.6(FDF5)"
- "1.8.1(0016519.075*kWh)"
- "1.8.2(0029595.323*kWh)"
- "2.8.1(0020656.624*kWh)"
- "2.8.1(0020656.624*kWh)"
- "F.F.0(0000000)"
on_value:
then:
- logger.log:
format: "Telegram Data: %s"
tag: "select"
args: ["x.c_str()"]
- lambda:
id(writeTelegram).execute(x.c_str());
## ---------------------------------------------------
## switches
## ---------------------------------------------------
switch:
- platform: restart
id: restart_device
name: ${friendly_name} restart
button:
- platform: template
name: 'Test: Get Telegram Data'
id: btnTestTelegramData
on_press:
- logger.log:
level: info
format: Get Data and decoder for telegram startet"
- script.execute: getTelegramdata
- platform: template
name: 'Test: Telegram Data'
id: btnTestTelegram
on_press:
- logger.log:
level: info
format: "Simple Testcase"
- script.execute: snddata
- platform: template
name: 'Test: IP Data'
id: btnGetNetInfoData
on_press:
- script.execute: getNetInfoData
.....
```
### Anything in the logs that might be useful for us?
```txt
[13:07:15][I][main:413]: Get Data and decoder for telegram startet"
[13:07:15][I][main:267]: HTTP Request get Data
[13:07:15][I][getTelegramdata:290]: Response status: 200, Duration: 48 ms
[13:07:15][I][getTelegramdata:293]: Response telegramdata: {"telegram": ["/ISk5MT174-0001", "0.9.1(130203)", "0.9.2(0230223)", "0.0.0(00339188)", "0.2.0(1.03)", "C.1.6(FDF5)", "1.8.1(0011404.409*kWh)", "1.8.2(0023813.725*kWh)", "2.8.1(0015608.962*kWh)", "2.8.2(0000900.569*kWh)", "F.F.0(0000000)", "!"]}
[13:07:15][I][script:314]: Decode Response
[13:07:15][E][json:081]: Could not allocate memory for JSON document! Requested 0 bytes, free heap: 110580
[13:07:15][I][getTelegramdata:322]: Response telegramdata: <-- 2nd Log output empty !
[13:07:15][I][getTelegramdata:325]: End telegram decoder
```
### Additional information
_No response_
jov
August 2, 2023, 12:15pm
6
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