issues icon indicating copy to clipboard operation
issues copied to clipboard

ESP32 HTTP Request get Data - Could not allocate memory for JSON document! Requested 0 bytes, free heap: 110580

Open zibous opened this issue 2 years ago • 4 comments

The problem

StaticJsonDocument is empty

{
  "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

## ---------------------------------------------------
##  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?

[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

zibous avatar Feb 26 '23 12:02 zibous

current workaround:

If I save the (http_request_data) .get_string () to a text_sensor, I can continue to use it.

script: 
 - id: getTelegramdata    
    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:
                  - lambda: |- 
                          auto data = id(http_request_data).get_string();
                          id(telegraminfo).publish_state(data);
                          delay(100);
                          ESP_LOGI("script", "Decode Response %s", id(telegraminfo).state.c_str() );
                          json::parse_json(id(telegraminfo).state.c_str(), [](JsonObject root) {
                              ESP_LOGI("parse", "telegram raw %s", root["telegram"]); 
                              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(telegraminfo).state.c_str()"]
                  - logger.log: 
                      level: info
                      tag: "getTelegramdata"
                      format: "End telegram decoder"

text_sensor:
  - platform: template
    name: Telegram
    id: telegraminfo

I just don't understand why json :: parse_json (id (telegraminfo) .state.c_str (), [] (JsonObject root) doesn't work.

What am I doing wrong?

Log:

[14:26:23][I][main:392]: Get Data and decoder for telegram  startet"
[14:26:23][I][main:267]: HTTP Request get Data
[14:26:24][I][script:291]: Decode Response {"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)", "!"], "timestamp": "2023-02-26T14:26:23"}
[14:26:24][I][parse:293]: telegram raw 
[14:26:24][I][parse:295]: telegram 0: 
[14:26:24][I][parse:295]: telegram 1: 
[14:26:24][I][parse:295]: telegram 2: 
[14:26:24][I][parse:295]: telegram 3: 
[14:26:24][I][parse:295]: telegram 4: 
[14:26:24][I][parse:295]: telegram 5: 
[14:26:24][I][parse:295]: telegram 6: 
[14:26:24][I][parse:295]: telegram 7: 
[14:26:24][I][parse:295]: telegram 8: 
[14:26:24][I][parse:295]: telegram 9: 
[14:26:24][I][parse:295]: telegram 10: 
[14:26:24][I][parse:295]: telegram 11: 
[14:26:24][I][getTelegramdata:300]: 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)", "!"], "timestamp": "2023-02-26T14:26:23"}
[14:26:24][I][getTelegramdata:303]: End telegram decoder

zibous avatar Feb 26 '23 13:02 zibous

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

github-actions[bot] avatar Jun 27 '23 02:06 github-actions[bot]

I think the real solution for the error message Could not allocate memory for JSON document! Requested 0 bytes is not to call id(http_request_data).get_string() without using the data. The function 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: []

or, if the empty check on response_data is omitted:

[I][RESPONSE:055]: get_string(): [{"id":"sensor-switch_state","value":1,"state":"1.0"}]
[I][RESPONSE:057]: response_data: []
[I][JSON:059]: Parse
[E][json:081]: Could not allocate memory for JSON document! Requested 0 bytes, free heap: 8257524

But if the first 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

In your first getTelegramdata there is a logger.log using id(http_request_data).get_string() before using the data (hence the empty response on the second call in the lambda). In the lambda there is no check for an empty response (hence the "Requested 0 bytes"). If you put something like the first line in my example above before your line with auto data = id(http_request_data).get_string(), you'll probably see the error again.

jov58 avatar Aug 02 '23 12:08 jov58

Currently This error is coming in my code 18:00:56 | [E] | [json:084] | Could not allocate memory for JSON document! Requested 0 bytes, free heap: 110580

` esphome: name: test

esp32: board: esp32dev framework: type: arduino

logger:

api: password: "123"

ota: platform: "esphome" password: "pakistan123"

wifi: ssid: "Digital Spyre" password: "DigitalSpyre@14321Nada"

ap: ssid: "Test Fallback Hotspot" password: "123456789"

captive_portal:

http_request: id: my_http_request verify_ssl: false

switch:

  • platform: gpio name: "Switch 1" pin: 25 id: "switch_1" on_turn_on:

    • http_request.get: url: http://192.168.100.14:3000/switch1/on
    • switch.turn_on: switch_2
      on_turn_off:
    • http_request.get: url: http://192.168.100.14:3000/switch1/off
  • platform: gpio name: "Switch 2" pin: 26 id: "switch_2" on_turn_on:

    • http_request.get: url: http://192.168.100.14:3000/switch2/on on_turn_off:
    • http_request.get: url: http://192.168.100.14:3000/switch2/off

interval:

  • interval: 30s then:
    • http_request.get: url: http://192.168.100.15/fan/living_room_fan on_response: then: - lambda: |-

            json::parse_json(body, [](JsonObject root) {
             // Extract the value field from the JSON response
              bool value = root["value"].as<bool>();
              if (value) {
                id(switch_2).turn_on();
                ESP_LOGI("HTTP_RESPONSE", "Switch 2 turned ON because value is true");
              } else {
                ESP_LOGI("HTTP_RESPONSE", "Switch 2 not triggered, value is false");
              }
              return true;
            });
      

web_server: port: 80 `

DevWhiz1 avatar Oct 14 '24 13:10 DevWhiz1

I fixed this by adding capture_response to the http_request block

     - http_request.post:
          url: http://rhome:8123/api/services/schedule/get_schedule?return_response
          headers:
            Content-Type: application/json
            Authorization: !secret ha_token
          capture_response: true
          json:
            entity_id: "schedule.lighting"

pebblebed-tech avatar Jan 27 '25 12:01 pebblebed-tech