Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

esp_http_client_perform(client) slow and is_async causing non connect (IDFGH-11442) #12578

Closed
3 tasks done
ThatBigPrint opened this issue Nov 13, 2023 · 21 comments
Closed
3 tasks done
Assignees
Labels
Awaiting Response awaiting a response from the author Resolution: NA Issue resolution is unavailable Status: Done Issue is done internally Type: Bug bugs in IDF

Comments

@ThatBigPrint
Copy link

ThatBigPrint commented Nov 13, 2023

Answers checklist.

  • I have read the documentation ESP-IDF Programming Guide and the issue is not addressed there.
  • I have updated my IDF branch (master or release) to the latest version and checked that the issue is present there.
  • I have searched the issue tracker for a similar issue and not found a similar issue.

IDF version.

5.1 release

Espressif SoC revision.

Esp32-devkit

Operating System used.

macOS

How did you build your project?

VS Code IDE

If you are using Windows, please specify command line type.

None

Development Kit.

Esp32-devkit

Power Supply used.

USB

What is the expected behavior?

I want the stream of data to be responsive its only responding to changes every 5 seconds... So I tried to use is_async but the client can't connect... I added certificates for https which was supposed to be a prerequisite

What is the actual behavior?

It's just looping through every 5 seconds ~ then giving me the new data if there is any... Or the keep alive

If I use the is_async I get the can't connect error

Steps to reproduce.

`// Include necessary headers
#include <string.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_wifi.h"
#include "nvs_flash.h"
#include "esp_event.h"
#include "esp_log.h"
#include "esp_system.h"
#include "esp_http_client.h"
#include "lwip/err.h"
#include "lwip/sys.h"
#include "cJSON.h"

#include "esp_crt_bundle.h"

#include <sys/param.h>
#include <stdlib.h>
#include <ctype.h>
#include "esp_netif.h"
#include "esp_tls.h"

#include "freertos/event_groups.h"

#define WIFI_CONNECTED_BIT BIT0
#define WIFI_FAIL_BIT BIT1

#define MAX_HTTP_RECV_BUFFER 16384
#define MAX_HTTP_OUTPUT_BUFFER 2048

extern const uint8_t server_cert_pem_start[] asm("_binary_ca_cert_pem_start");
extern const uint8_t server_cert_pem_end[] asm("_binary_ca_cert_pem_end");

static EventGroupHandle_t s_wifi_event_group;
static const char *TAG = "wifi_station";

static void wifi_event_handler(void *arg, esp_event_base_t event_base,
int32_t event_id, void *event_data)
{
if (event_id == WIFI_EVENT_STA_START)
{
esp_wifi_connect();
}
else if (event_id == WIFI_EVENT_STA_DISCONNECTED)
{
esp_wifi_connect();
ESP_LOGI(TAG, "retry to connect to the AP");
xEventGroupClearBits(s_wifi_event_group, WIFI_CONNECTED_BIT);
}
else if (event_id == IP_EVENT_STA_GOT_IP)
{
ip_event_got_ip_t *event = (ip_event_got_ip_t *)event_data;
ESP_LOGI(TAG, "got ip:" IPSTR, IP2STR(&event->ip_info.ip));
xEventGroupSetBits(s_wifi_event_group, WIFI_CONNECTED_BIT);
}
}

esp_err_t _http_event_handler(esp_http_client_event_t *evt)
{
static char output_buffer; // Buffer to store response of http request from event handler
static int output_len; // Stores number of bytes read
switch (evt->event_id)
{
case HTTP_EVENT_ERROR:
ESP_LOGD(TAG, "HTTP_EVENT_ERROR");
break;
case HTTP_EVENT_ON_CONNECTED:
ESP_LOGD(TAG, "HTTP_EVENT_ON_CONNECTED");
break;
case HTTP_EVENT_HEADER_SENT:
ESP_LOGD(TAG, "HTTP_EVENT_HEADER_SENT");
break;
case HTTP_EVENT_ON_HEADER:
ESP_LOGD(TAG, "HTTP_EVENT_ON_HEADER, key=%s, value=%s", evt->header_key, evt->header_value);
break;
case HTTP_EVENT_ON_DATA:
ESP_LOGD(TAG, "HTTP_EVENT_ON_DATA, len=%d", evt->data_len);
// Clean the buffer in case of a new request
if (output_len == 0 && evt->user_data)
{
// we are just starting to copy the output data into the use
memset(evt->user_data, 0, MAX_HTTP_OUTPUT_BUFFER);
}
/

* Check for chunked encoding is added as the URL for chunked encoding used in this example returns binary data.
* However, event handler can also be used in case chunked encoding is used.
*/
if (!esp_http_client_is_chunked_response(evt->client))
{
// If user_data buffer is configured, copy the response into the buffer
int copy_len = 0;
if (evt->user_data)
{
// The last byte in evt->user_data is kept for the NULL character in case of out-of-bound access.
copy_len = MIN(evt->data_len, (MAX_HTTP_OUTPUT_BUFFER - output_len));
if (copy_len)
{
memcpy(evt->user_data + output_len, evt->data, copy_len);
}
}
else
{
int content_len = esp_http_client_get_content_length(evt->client);
if (output_buffer == NULL)
{
// We initialize output_buffer with 0 because it is used by strlen() and similar functions therefore should be null terminated.
output_buffer = (char *)calloc(content_len + 1, sizeof(char));
output_len = 0;
if (output_buffer == NULL)
{
ESP_LOGE(TAG, "Failed to allocate memory for output buffer");
return ESP_FAIL;
}
}
copy_len = MIN(evt->data_len, (content_len - output_len));
if (copy_len)
{
memcpy(output_buffer + output_len, evt->data, copy_len);
}
}
output_len += copy_len;
}

    break;
case HTTP_EVENT_ON_FINISH:
    ESP_LOGD(TAG, "HTTP_EVENT_ON_FINISH");
    if (output_buffer != NULL)
    {
        // Response is accumulated in output_buffer. Uncomment the below line to print the accumulated response
        // ESP_LOG_BUFFER_HEX(TAG, output_buffer, output_len);
        free(output_buffer);
        output_buffer = NULL;
    }
    output_len = 0;
    break;
case HTTP_EVENT_DISCONNECTED:
    ESP_LOGI(TAG, "HTTP_EVENT_DISCONNECTED");
    int mbedtls_err = 0;
    esp_err_t err = esp_tls_get_and_clear_last_error((esp_tls_error_handle_t)evt->data, &mbedtls_err, NULL);
    if (err != 0)
    {
        ESP_LOGI(TAG, "Last esp error code: 0x%x", err);
        ESP_LOGI(TAG, "Last mbedtls failure: 0x%x", mbedtls_err);
    }
    if (output_buffer != NULL)
    {
        free(output_buffer);
        output_buffer = NULL;
    }
    output_len = 0;
    break;
case HTTP_EVENT_REDIRECT:
    ESP_LOGD(TAG, "HTTP_EVENT_REDIRECT");
    esp_http_client_set_header(evt->client, "From", "[email protected]");
    esp_http_client_set_header(evt->client, "Accept", "text/html");
    esp_http_client_set_redirection(evt->client);
    break;
}
return ESP_OK;

}

void wifi_init_sta()
{
s_wifi_event_group = xEventGroupCreate();

ESP_ERROR_CHECK(nvs_flash_init());
ESP_ERROR_CHECK(esp_netif_init());
ESP_ERROR_CHECK(esp_event_loop_create_default());

esp_netif_create_default_wifi_sta();

wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
ESP_ERROR_CHECK(esp_wifi_init(&cfg));

esp_event_handler_instance_t instance_any_id;
esp_event_handler_instance_t instance_got_ip;
ESP_ERROR_CHECK(esp_event_handler_instance_register(WIFI_EVENT,
                                                    ESP_EVENT_ANY_ID,
                                                    &wifi_event_handler,
                                                    NULL,
                                                    &instance_any_id));
ESP_ERROR_CHECK(esp_event_handler_instance_register(IP_EVENT,
                                                    IP_EVENT_STA_GOT_IP,
                                                    &wifi_event_handler,
                                                    NULL,
                                                    &instance_got_ip));

wifi_config_t wifi_config = {
    .sta = {
        .ssid = WIFI_SSID,
        .password = WIFI_PASS},
};
ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA));
ESP_ERROR_CHECK(esp_wifi_set_config(ESP_IF_WIFI_STA, &wifi_config));
ESP_ERROR_CHECK(esp_wifi_start());

// Wait for WiFi connection
EventBits_t bits = xEventGroupWaitBits(s_wifi_event_group,
                                       WIFI_CONNECTED_BIT | WIFI_FAIL_BIT,
                                       pdFALSE,
                                       pdFALSE,
                                       portMAX_DELAY);

if (bits & WIFI_CONNECTED_BIT)
{
    ESP_LOGI(TAG, "connected to ap SSID:%s", WIFI_SSID);
}
else if (bits & WIFI_FAIL_BIT)
{
    ESP_LOGI(TAG, "Failed to connect to SSID:%s", WIFI_SSID);
}
else
{
    ESP_LOGE(TAG, "UNEXPECTED EVENT");
}

// Clean up event handler
ESP_ERROR_CHECK(esp_event_handler_instance_unregister(IP_EVENT, IP_EVENT_STA_GOT_IP, instance_got_ip));
ESP_ERROR_CHECK(esp_event_handler_instance_unregister(WIFI_EVENT, ESP_EVENT_ANY_ID, instance_any_id));
vEventGroupDelete(s_wifi_event_group);

}

void sse_stream_task(void *pvParameters)
{
char *buffer = malloc(MAX_HTTP_RECV_BUFFER + 1);
if (buffer == NULL)
{
ESP_LOGE(TAG, "Cannot malloc http receive buffer");
return;
}

char full_url[256];

snprintf(full_url, sizeof(full_url), "%s%s?auth=%s", FIREBASE_HOST, FIREBASE_PATH, FIREBASE_AUTH);

ESP_LOGI(TAG, "Connecting to Firebase URL: %s", full_url);

esp_http_client_config_t config = {
    .url = full_url,
    .transport_type = HTTP_TRANSPORT_OVER_SSL,
    .cert_pem = (char *)server_cert_pem_start,
    .event_handler = _http_event_handler,
    .is_async = false,
};
esp_http_client_handle_t client = esp_http_client_init(&config);
esp_http_client_set_header(client, "Accept", "text/event-stream");
esp_http_client_set_header(client, "Cache-Control", "no-cache");
esp_err_t err;
if ((err = esp_http_client_open(client, 0)) != ESP_OK)
{
    ESP_LOGE(TAG, "Failed to open HTTP connection: %s", esp_err_to_name(err));
    free(buffer);
    // return;
}
int content_length = esp_http_client_fetch_headers(client);
int total_read_len = 0, read_len;
if (total_read_len < content_length && content_length <= MAX_HTTP_RECV_BUFFER)
{
    read_len = esp_http_client_read(client, buffer, content_length);
    if (read_len <= 0)
    {
        ESP_LOGE(TAG, "Error read data");
    }
    buffer[read_len] = 0;
    ESP_LOGI(TAG, "read_len = %d", read_len);
}

while (1)
{
    read_len = esp_http_client_read(client, buffer, MAX_HTTP_RECV_BUFFER);
    if (read_len < 0)
    {
        ESP_LOGE(TAG, "Error reading data");
        // continue; // Break the loop on error
    }
    else if (read_len == 0)
    {
        // ESP_LOGI(TAG, "No new data received");
        //  You may implement a mechanism to exit if no data is received for a long time
    }
    else
    {
        buffer[read_len] = 0; // Null-terminate the buffer
        ESP_LOGI(TAG, "Received data: %s", buffer);

        cJSON *root = cJSON_Parse(buffer);
        if (root == NULL)
        {
            ESP_LOGE(TAG, "Failed to parse JSON");
        }
        else
        {
            // Process the JSON as needed
            char *jsonString = cJSON_Print(root);
            if (jsonString)
            {
                ESP_LOGI(TAG, "Parsed JSON: %s", jsonString);
                free(jsonString);
            }
            cJSON_Delete(root);
        }
    }

    // vTaskDelay(10 / portTICK_PERIOD_MS); // Small delay to yield to other tasks
}

// Clean up outside the loop
esp_http_client_close(client);
esp_http_client_cleanup(client);
free(buffer);
vTaskDelete(NULL);

}

void app_main()
{
ESP_LOGI(TAG, "ESP_WIFI_MODE_STA");
wifi_init_sta(); // Initialize WiFi
xTaskCreate(&sse_stream_task, "sse_stream_task", 4096, NULL, 5, NULL);
}
`

Debug Logs.

No response

More Information.

No response

@ThatBigPrint ThatBigPrint added the Type: Bug bugs in IDF label Nov 13, 2023
@espressif-bot espressif-bot added the Status: Opened Issue is new label Nov 13, 2023
@github-actions github-actions bot changed the title esp_http_client_perform(client) slow and is_async causing non connect esp_http_client_perform(client) slow and is_async causing non connect (IDFGH-11442) Nov 13, 2023
@ThatBigPrint
Copy link
Author

Updates ?

@suryasid09
Copy link

hello, did you find what was causing the issue?
I too am facing the same issue when I try to do http stream using http_client_open(). When I use http_client_perform(), it works fine, but speed is around 400KB/sec which I want to improve using http streamer as mentioned in the esp documentation.

Funny thing! when I use http_client_open(), it throws me the same error what you got. And after that if I modify my program to use http_client_perform(), it gives the same error and stops working all together!

@hmalpani
Copy link
Contributor

hmalpani commented Nov 27, 2023

Hello @ThatBigPrint @suryasid09

Can you try the patch shared in this issue and check if that fixes your issue

@suryasid09
Copy link

@hmalpani I tried with the patch you provided, it didn't fix the issue. A more context in what I am doing.

I am reading from the USB 4KB of data until end of the file. After each 4KB read operation, I am uploading it to the locally created XAMP server using HTTP post. I was already getting good speed of around 400KB/sec but I want to improve it. So, I decided to use HTTP in streamer mode as mentioned in the documentation. However, I always get the error as above pointed.

This is the screenshot from Wireshark and esp32. I would appreciate any help in this regard.
esp
wireshark

@espressif-bot espressif-bot added Status: In Progress Work is in progress and removed Status: Opened Issue is new labels Dec 1, 2023
@hmalpani
Copy link
Contributor

hmalpani commented Dec 6, 2023

Hello @ThatBigPrint
Can you share the debug logs when you get this error. Please also share the sdkconfig file.

Thanks!

@espressif-bot espressif-bot added the Awaiting Response awaiting a response from the author label Dec 7, 2023
@ThatBigPrint
Copy link
Author

ThatBigPrint commented Dec 9, 2023

@hmalpani the patch worked but why isn't it in the main repo ?

Also have we got an example of how i would for instance start the async and stream etc which currently works how do i do i put for instance on the same client to the same endppoint. ?

@hmalpani
Copy link
Contributor

Hello @ThatBigPrint
The fix has been merged into master 61d4775

I didn't quite understand the second question. Can you please elaborate?

Thanks!

@ThatBigPrint
Copy link
Author

so this is the part of my code the sse stream is fine but when i call the post on a separate client and handler it kicks the stream off am i missing something? i want to be able to post to the database whilst the main sse client is running i have tried the perform on the same client etc but this is the closest I've had it to working. do i need to interrupt the perform in the sse stream task whilst the post is happening?

idealy i want to post using te same client and handler but im not sure how i can call the post within the inbound connection client ?
`static void post_rest_function()
{
char full_url[256];
char mac_str[20];
uint8_t mac[6] = {0};
esp_wifi_get_mac(ESP_IF_WIFI_STA, mac);
snprintf(mac_str, sizeof(mac_str), "%02x%02x%02x%02x%02x%02x", MAC2STR(mac));
ESP_LOGI(TAG, "MAC: %s", mac_str);

// snprintf(full_url, sizeof(full_url), "%s%s?auth=%s", FIREBASE_HOST, FIREBASE_PATH, FIREBASE_AUTH);
snprintf(full_url, sizeof(full_url), "%s/%s%s.json?auth=%s", FIREBASE_HOST, rvd_data_str, FIREBASE_PATH, FIREBASE_AUTH);
//snprintf(full_url, sizeof(full_url), "%s/%s%s%s.json?auth=%s", FIREBASE_HOST, rvd_data_str, FIREBASE_PATH, mac_str, FIREBASE_AUTH);

esp_http_client_config_t config_outbound = {
    .url = full_url,
    .method = HTTP_METHOD_PUT,
    .crt_bundle_attach = esp_crt_bundle_attach,
    .event_handler = outbound_http_event_handler,
    };

outbound_client = esp_http_client_init(&config_outbound);

char* outbound_data = "{}";
ESP_LOGI(TAG, "Outbound data: %s", outbound_data);

esp_http_client_set_header(outbound_client, "Content-Type", "application/json");
esp_http_client_set_header(outbound_client, "Accept", "application/json");
esp_http_client_set_post_field(outbound_client, outbound_data, strlen(outbound_data));

esp_err_t err = esp_http_client_perform(outbound_client);
if (err == ESP_OK)
{
    ESP_LOGI(TAG, "HTTPS Status = %d, content_length = %" PRId64,
             esp_http_client_get_status_code(outbound_client),
             esp_http_client_get_content_length(outbound_client));
}
else
{
    ESP_LOGE(TAG, "Error perform http request %s", esp_err_to_name(err));
}
esp_http_client_cleanup(outbound_client);

}

void sse_stream_task(void *pvParameters)
{
start_config = true;
char *buffer = malloc(MAX_HTTP_RECV_BUFFER + 1);
if (buffer == NULL)
{
ESP_LOGE(TAG, "Cannot malloc http receive buffer");
return;
}

char full_url[256];

// snprintf(full_url, sizeof(full_url), "%s%s?auth=%s", FIREBASE_HOST, FIREBASE_PATH, FIREBASE_AUTH);
snprintf(full_url, sizeof(full_url), "%s/%s%s.json?auth=%s", FIREBASE_HOST, rvd_data_str, FIREBASE_PATH, FIREBASE_AUTH);

ESP_LOGI(TAG, "Connecting to Firebase URL: %s", full_url);

esp_http_client_config_t config_inbound = {
    .url = full_url,
    .crt_bundle_attach = esp_crt_bundle_attach,
    .event_handler = inbound_http_event_handler,
    .is_async = true,
    .user_data = buffer,
};
inbound_client = esp_http_client_init(&config_inbound);
esp_http_client_set_header(inbound_client, "Accept", "text/event-stream");
esp_err_t err;
while (1)
{
    err = esp_http_client_perform(inbound_client);
    if (err != ESP_ERR_HTTP_EAGAIN)
    {
        //break;
    }
}
if (err == ESP_OK)
{
    ESP_LOGI(TAG, "HTTPS Status = %d, content_length = %" PRId64,
             esp_http_client_get_status_code(inbound_client),
             esp_http_client_get_content_length(inbound_client));
}
else
{
    ESP_LOGE(TAG, "Error perform http request %s", esp_err_to_name(err));
}
esp_http_client_cleanup(inbound_client);

}`

just to clarify the functions work indipendantly its just the posting whilst the sse is running blocks the sse as per the docs ive set up a second client and handler because the sse is in async mode ?

@hmalpani
Copy link
Contributor

@ThatBigPrint
I think you should start the stream task using the workflow described here

I hope this helps. If not can you share a sample application with which I can reproduce this issue?

Thanks!

@ThatBigPrint
Copy link
Author

ThatBigPrint commented Dec 11, 2023

ive also tried this but i dont think its not putting...

{
    start_config = true;
    char *buffer = malloc(MAX_HTTP_RECV_BUFFER + 1);
    if (buffer == NULL)
    {
        ESP_LOGE(TAG, "Cannot malloc http receive buffer");
        return;
    }

    char full_url[256];

    // snprintf(full_url, sizeof(full_url), "%s%s?auth=%s", FIREBASE_HOST, FIREBASE_PATH, FIREBASE_AUTH);
    snprintf(full_url, sizeof(full_url), "%s/%s%s.json?auth=%s", FIREBASE_HOST, rvd_data_str, FIREBASE_PATH, FIREBASE_AUTH);

    ESP_LOGI(TAG, "Connecting to Firebase URL: %s", full_url);

    esp_http_client_config_t config = {
        .url = full_url,
        .method = HTTP_METHOD_PUT,
        .crt_bundle_attach = esp_crt_bundle_attach,
        .event_handler = _http_event_handler,
        .is_async = true,
        .user_data = buffer,
    };
    client = esp_http_client_init(&config);

    esp_http_client_set_header(client, "Accept", "text/event-stream");

    esp_err_t err;
    while (1)
    {
        if (data_to_send)
        {
            char outbound_data[256];
            snprintf(outbound_data, sizeof(outbound_data), "{\"brightness\": \"%s\", \"keep_alive\": %d}", global_brightness, keep_alive);
            ESP_LOGI(TAG, "Outbound data: %s", outbound_data);

            esp_http_client_set_post_field(client, outbound_data, strlen(outbound_data));

            err = esp_http_client_perform(client);
            if (err == ESP_OK)
            {
                ESP_LOGI(TAG, "HTTPS Status = %d, content_length = %" PRId64,
                         esp_http_client_get_status_code(client),
                         esp_http_client_get_content_length(client));
            }
            else
            {
                ESP_LOGE(TAG, "Error perform http request %s", esp_err_to_name(err));
            }

            data_to_send = false;
        }
        else
        {

            err = esp_http_client_perform(client);
            if (err != ESP_ERR_HTTP_EAGAIN)
            {
                break;
            }
        }
    }

    if (err == ESP_OK)
    {
        ESP_LOGI(TAG, "HTTPS Status = %d, content_length = %" PRId64,
                 esp_http_client_get_status_code(client),
                 esp_http_client_get_content_length(client));
    }
    else
    {
        ESP_LOGE(TAG, "Error perform http request %s", esp_err_to_name(err));
    }
    esp_http_client_cleanup(client);
}```

this is the log 

I (12169) esp-x509-crt-bundle: Certificate validated
I (12964) Mesh/Firebase: DATA=event: put
data: {"path":"/","data":null}

I (21536) Mesh/Firebase: System information, channel: 1, layer: 1, self mac: 68:b6:b3:44:ee:fc, parent bssid: c4:e5:32:85:a7:e9, parent rssi: -60, free heap: 202400
I (21541) Mesh/Firebase: child node number: 0
I (31536) Mesh/Firebase: System information, channel: 1, layer: 1, self mac: 68:b6:b3:44:ee:fc, parent bssid: c4:e5:32:85:a7:e9, parent rssi: -58, free heap: 202400
I (31541) Mesh/Firebase: child node number: 0
I (41536) Mesh/Firebase: System information, channel: 1, layer: 1, self mac: 68:b6:b3:44:ee:fc, parent bssid: c4:e5:32:85:a7:e9, parent rssi: -57, free heap: 202400
I (41541) Mesh/Firebase: child node number: 0
I (43065) Mesh/Firebase: DATA=event: keep-alive
data: null

I (48068) Mesh/Firebase: Outbound data: {"brightness": "", "keep_alive": 1}
I (51536) Mesh/Firebase: System information, channel: 1, layer: 1, self mac: 68:b6:b3:44:ee:fc, parent bssid: c4:e5:32:85:a7:e9, parent rssi: -58, free heap: 202312
I (51541) Mesh/Firebase: child node number: 0
E (53070) Mesh/Firebase: Error perform http request ESP_ERR_HTTP_EAGAIN
I (61536) Mesh/Firebase: System information, channel: 1, layer: 1, self mac: 68:b6:b3:44:ee:fc, parent bssid: c4:e5:32:85:a7:e9, parent rssi: -57, free heap: 202312
I (61541) Mesh/Firebase: child node number: 0
I (71536) Mesh/Firebase: System information, channel: 1, layer: 1, self mac: 68:b6:b3:44:ee:fc, parent bssid: c4:e5:32:85:a7:e9, parent rssi: -58, free heap: 202312
I (71541) Mesh/Firebase: child node number: 0
I (72864) Mesh/Firebase: DATA=event: keep-alive
data: null

I (77867) Mesh/Firebase: Outbound data: {"brightness": "", "keep_alive": 2}
I (81536) Mesh/Firebase: System information, channel: 1, layer: 1, self mac: 68:b6:b3:44:ee:fc, parent bssid: c4:e5:32:85:a7:e9, parent rssi: -57, free heap: 202308
I (81541) Mesh/Firebase: child node number: 0
E (82869) Mesh/Firebase: Error perform http request ESP_ERR_HTTP_EAGAIN
I (91536) Mesh/Firebase: System information, channel: 1, layer: 1, self mac: 68:b6:b3:44:ee:fc, parent bssid: c4:e5:32:85:a7:e9, parent rssi: -59, free heap: 202308
I (91541) Mesh/Firebase: child node number: 0


this is not a stream reader? 

@hmalpani
Copy link
Contributor

Hello @ThatBigPrint
It would be helpful if you could share whole code which can be used to reproduce this.

@ThatBigPrint
Copy link
Author

ThatBigPrint commented Dec 11, 2023

#include <inttypes.h>
#include <string.h>
#include <stdlib.h>
#include <sys/param.h>
#include <sys/socket.h>
#include <ctype.h>

#include "lwip/err.h"
#include "lwip/sys.h"

#include "nvs_flash.h"

#include "cJSON.h"

#include "esp_log.h"
#include "esp_wifi.h"
#include "esp_event.h"
#include "esp_system.h"
#include "esp_netif.h"
#include "esp_smartconfig.h"
#include "esp_bridge.h"
#include "esp_mesh_lite.h"
#include "esp_netif_types.h"
#include "esp_event_base.h"
#include "esp_mac.h"
#include "esp_http_client.h"
#include "esp_crt_bundle.h"
#include "esp_tls.h"
#include "esp_bridge_wifi.h"

#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/timers.h"
#include "freertos/event_groups.h"


#define MAX_HTTP_RECV_BUFFER 16384
#define MAX_HTTP_OUTPUT_BUFFER 16384
static esp_http_client_handle_t client;
static esp_http_client_handle_t outbound_client;

#define FIREBASE_HOST ""
#define FIREBASE_PATH ""
#define FIREBASE_AUTH ""

#define SMARTCONFIG_START_CONFIG() {   \
    .enable_log = false,               \
    .esp_touch_v2_enable_crypt = true, \
    .esp_touch_v2_key = ""};

static EventGroupHandle_t s_wifi_event_group;
const int WIFI_CONNECTED_BIT = BIT0;
const int BRIDGE_EVENT_STA_CONNECTED = BIT0;
static const int ESPTOUCH_DONE_BIT = BIT1;
static const char *TAG = "Mesh/Firebase";

static char *output_buffer;
static int output_len;

uint8_t ssid[33] = {0};
uint8_t password[65] = {0};
uint8_t rvd_data[65] = {0};

char ssid_str[34] = {0};
char password_str[66] = {0};
char rvd_data_str[66] = {0};

char global_brightness[100] = {0}; // Adjust the size as needed
int global_yoo = 0;

// char *ssid_str = NULL;
// char *password_str = NULL;

bool wifi_connected = false;
bool http_connected = false;
bool start_config = false;
bool mesh_connected_to_router = false;
bool wifi_config_done = false;
bool data_to_send = false;

int keep_alive = 0;

static void smartconfig_example_task(void *parm);
static void post_rest_function();

static void check_status()
{
    EventBits_t uxBits;
    uxBits = xEventGroupGetBits(s_wifi_event_group);
    if (WIFI_CONNECTED_BIT)
    {
        wifi_connected = true;
        // printf("wifi connected\n");
    }

    if (BRIDGE_EVENT_STA_CONNECTED)
    {
        wifi_connected = true;
        // printf("mesh connected\n");
    }

    if (uxBits)
    {
        // printf("got bits\n");
    }
}

esp_err_t _http_event_handler(esp_http_client_event_t *evt)
{
    switch (evt->event_id)
    {
    case HTTP_EVENT_ERROR:
        http_connected = false;
        ESP_LOGD(TAG, "HTTP_EVENT_ERROR");
        break;
    case HTTP_EVENT_ON_CONNECTED:
        http_connected = true;
        ESP_LOGD(TAG, "HTTP_EVENT_ON_CONNECTED");
        break;
    case HTTP_EVENT_HEADER_SENT:
        ESP_LOGD(TAG, "HTTP_EVENT_HEADER_SENT");
        break;
    case HTTP_EVENT_ON_HEADER:
        ESP_LOGD(TAG, "HTTP_EVENT_ON_HEADER, key=%s, value=%s", evt->header_key, evt->header_value);
        break;
    case HTTP_EVENT_ON_DATA:
        // Log data for debugging
        ESP_LOGI(TAG, "DATA=%.*s", evt->data_len, (char *)evt->data);

        // Check for keep-alive message
        if (strstr((char *)evt->data, "event: keep-alive") != NULL && strstr((char *)evt->data, "data: null") != NULL)
        {
            // ESP_LOGI(TAG, "Keep-alive message received, no action required.");
            keep_alive++;
            // post_rest_function();
            data_to_send = true;
            break;
        }

        // Extract JSON part from data
        char *json_start = strstr((char *)evt->data, "{");
        if (json_start == NULL)
        {
            ESP_LOGE(TAG, "No JSON data found");
            return ESP_FAIL;
        }

        // Parse JSON
        cJSON *json = cJSON_Parse(json_start);
        if (json == NULL)
        {
            const char *error_ptr = cJSON_GetErrorPtr();
            if (error_ptr != NULL)
            {
                ESP_LOGE(TAG, "Error in parsing JSON: %s", error_ptr);
            }
            cJSON_Delete(json);
            return ESP_FAIL;
        }

        cJSON *path = cJSON_GetObjectItemCaseSensitive(json, "path");
        cJSON *data = cJSON_GetObjectItemCaseSensitive(json, "data");
        if (cJSON_IsString(path) && (path->valuestring != NULL))
        {
            // ESP_LOGI(TAG, "Path: %s", path->valuestring);

            if (strcmp(path->valuestring, "/") == 0 && cJSON_IsObject(data))
            {
                cJSON *brightness = cJSON_GetObjectItemCaseSensitive(data, "brightness");
                cJSON *yoo = cJSON_GetObjectItemCaseSensitive(data, "yoo");

                if (cJSON_IsString(brightness) && (brightness->valuestring != NULL))
                {
                    strncpy(global_brightness, brightness->valuestring, sizeof(global_brightness) - 1);
                    // ESP_LOGI(TAG, "brightness: %s", global_brightness);
                }

                if (cJSON_IsNumber(yoo))
                {
                    global_yoo = yoo->valueint;
                    // ESP_LOGI(TAG, "yoo: %d", global_yoo);
                }
            }
            else if (strstr(path->valuestring, "/brightness") != NULL && cJSON_IsString(data))
            {
                strncpy(global_brightness, data->valuestring, sizeof(global_brightness) - 1);
                // ESP_LOGI(TAG, "brightness: %s", global_brightness);
            }
            else if (strstr(path->valuestring, "/yoo") != NULL && cJSON_IsNumber(data))
            {
                global_yoo = data->valueint;
                // ESP_LOGI(TAG, "yoo: %d", global_yoo);
            }
            // handle other paths if needed
        }

        cJSON_Delete(json);
        break;

    case HTTP_EVENT_ON_FINISH:
        ESP_LOGD(TAG, "HTTP_EVENT_ON_FINISH");
        if (output_buffer != NULL)
        {
            // Response is accumulated in output_buffer. Uncomment the below line to print the accumulated response
            // ESP_LOG_BUFFER_HEX(TAG, output_buffer, output_len);
            free(output_buffer);
            output_buffer = NULL;
        }
        output_len = 0;
        break;
    case HTTP_EVENT_DISCONNECTED:
        http_connected = false;
        ESP_LOGI(TAG, "HTTP_EVENT_DISCONNECTED");
        int mbedtls_err = 0;
        esp_err_t err = esp_tls_get_and_clear_last_error((esp_tls_error_handle_t)evt->data, &mbedtls_err, NULL);
        if (err != 0)
        {
            ESP_LOGI(TAG, "Last esp error code: 0x%x", err);
            ESP_LOGI(TAG, "Last mbedtls failure: 0x%x", mbedtls_err);
        }
        if (output_buffer != NULL)
        {
            free(output_buffer);
            output_buffer = NULL;
        }
        output_len = 0;
        break;
    case HTTP_EVENT_REDIRECT:
        ESP_LOGD(TAG, "HTTP_EVENT_REDIRECT");
        esp_http_client_set_header(evt->client, "From", "[email protected]");
        esp_http_client_set_header(evt->client, "Accept", "text/html");
        esp_http_client_set_redirection(evt->client);
        break;
    }
    return ESP_OK;
}

esp_err_t outbound_http_event_handler(esp_http_client_event_t *evt)
{
    switch (evt->event_id)
    {
    case HTTP_EVENT_ERROR:
        ESP_LOGD(TAG, "Outbound HTTP_EVENT_ERROR");
        break;
    case HTTP_EVENT_ON_CONNECTED:
        ESP_LOGD(TAG, "Outbound HTTP_EVENT_ON_CONNECTED");
        break;
    // ... other cases as per your requirement
    default:
        break;
    }
    return ESP_OK;
}

static void event_handler(void *arg, esp_event_base_t event_base,
                          int32_t event_id, void *event_data)
{
    if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_START)
    {
        xTaskCreate(smartconfig_example_task, "smartconfig_example_task", 4096, NULL, 3, NULL);
    }
    else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_DISCONNECTED)
    {
        esp_wifi_connect();
        xEventGroupClearBits(s_wifi_event_group, WIFI_CONNECTED_BIT);
    }
    else if (event_base == IP_EVENT && event_id == IP_EVENT_STA_GOT_IP)
    {
        xEventGroupSetBits(s_wifi_event_group, WIFI_CONNECTED_BIT);
    }
    else if (event_base == SC_EVENT && event_id == SC_EVENT_SCAN_DONE)
    {
        ESP_LOGI(TAG, "Scan done");
    }
    else if (event_base == SC_EVENT && event_id == SC_EVENT_FOUND_CHANNEL)
    {
        ESP_LOGI(TAG, "Found channel");
    }
    else if (event_base == SC_EVENT && event_id == SC_EVENT_GOT_SSID_PSWD)
    {
        ESP_LOGI(TAG, "Got SSID and password");

        smartconfig_event_got_ssid_pswd_t *evt = (smartconfig_event_got_ssid_pswd_t *)event_data;
        wifi_config_t wifi_config;

        bzero(&wifi_config, sizeof(wifi_config_t));
        memcpy(wifi_config.sta.ssid, evt->ssid, sizeof(wifi_config.sta.ssid));
        memcpy(wifi_config.sta.password, evt->password, sizeof(wifi_config.sta.password));
        wifi_config.sta.bssid_set = evt->bssid_set;
        if (wifi_config.sta.bssid_set == true)
        {
            memcpy(wifi_config.sta.bssid, evt->bssid, sizeof(wifi_config.sta.bssid));
        }

        memcpy(ssid, evt->ssid, sizeof(evt->ssid));
        memcpy(password, evt->password, sizeof(evt->password));
        ESP_LOGI(TAG, "SSID:%s", ssid);
        ESP_LOGI(TAG, "PASSWORD:%s", password);
        ESP_ERROR_CHECK(esp_smartconfig_get_rvd_data(rvd_data, sizeof(rvd_data)));
        ESP_LOGI(TAG, "RVD_DATA:%s", rvd_data);

        ESP_ERROR_CHECK(esp_wifi_disconnect());
        ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_STA, &wifi_config));
        esp_wifi_connect();
    }
    else if (event_base == SC_EVENT && event_id == SC_EVENT_SEND_ACK_DONE)
    {
        char ssid_str[33] = {0};
        char password_str[65] = {0};
        char rvd_data_str[65] = {0};

        strncpy(ssid_str, (char *)ssid, sizeof(ssid));
        strncpy(password_str, (char *)password, sizeof(password));
        strncpy(rvd_data_str, (char *)rvd_data, sizeof(rvd_data));

        esp_err_t save_ssid_status = info_save_string("ssid", ssid_str);
        esp_err_t save_password_status = info_save_string("password", password_str);
        esp_err_t save_rvd_status = info_save_string("rvd_data", rvd_data_str);

        if (save_ssid_status == ESP_OK)
        {
            ESP_LOGI(TAG, "SSID saved: %s", ssid_str);
        }
        else
        {
            ESP_LOGE(TAG, "Failed to save SSID");
        }

        if (save_password_status == ESP_OK)
        {
            ESP_LOGI(TAG, "Password saved: %s", password_str);
        }
        else
        {
            ESP_LOGE(TAG, "Failed to save Password");
        }

        if (save_rvd_status == ESP_OK)
        {
            ESP_LOGI(TAG, "RVD Data saved: %s", rvd_data_str);
        }
        else
        {
            ESP_LOGE(TAG, "Failed to save RVD Data");
        }

        // If all data saved successfully, set the bit and restart
        if (save_ssid_status == ESP_OK && save_password_status == ESP_OK && save_rvd_status == ESP_OK)
        {
            ESP_LOGI(TAG, "All credentials saved, restarting...");
            xEventGroupSetBits(s_wifi_event_group, ESPTOUCH_DONE_BIT);
            esp_restart();
        }
        else
        {
            ESP_LOGE(TAG, "Not all credentials were saved successfully. Not restarting.");
        }
    }
}

static esp_err_t esp_storage_init(void)
{
    esp_err_t ret = nvs_flash_init();

    if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND)
    {
        ESP_ERROR_CHECK(nvs_flash_erase());
        ret = nvs_flash_init();
    }

    return ret;
}

static void post_rest_function()
{
    char full_url[256];
    char mac_str[20];
    uint8_t mac[6] = {0};
    esp_wifi_get_mac(ESP_IF_WIFI_STA, mac);
    snprintf(mac_str, sizeof(mac_str), "%02x%02x%02x%02x%02x%02x", MAC2STR(mac));
    ESP_LOGI(TAG, "MAC: %s", mac_str);

    // snprintf(full_url, sizeof(full_url), "%s%s?auth=%s", FIREBASE_HOST, FIREBASE_PATH, FIREBASE_AUTH);
    snprintf(full_url, sizeof(full_url), "%s/%s%s.json?auth=%s", FIREBASE_HOST, rvd_data_str, FIREBASE_PATH, FIREBASE_AUTH);
    // snprintf(full_url, sizeof(full_url), "%s/%s%s%s.json?auth=%s", FIREBASE_HOST, rvd_data_str, FIREBASE_PATH, mac_str, FIREBASE_AUTH);

    esp_http_client_config_t config_outbound = {
        .url = full_url,
        .method = HTTP_METHOD_PUT,
        .crt_bundle_attach = esp_crt_bundle_attach,
        .event_handler = outbound_http_event_handler,
    };

    outbound_client = esp_http_client_init(&config_outbound);

    char *outbound_data = "{\"brightness\": \"100\", \"yoo\": \"1\"}";
    ESP_LOGI(TAG, "Outbound data: %s", outbound_data);

    esp_http_client_set_header(outbound_client, "Content-Type", "application/json");
    esp_http_client_set_header(outbound_client, "Accept", "application/json");
    esp_http_client_set_post_field(outbound_client, outbound_data, strlen(outbound_data));

    esp_err_t err = esp_http_client_perform(outbound_client);
    if (err == ESP_OK)
    {
        ESP_LOGI(TAG, "HTTPS Status = %d, content_length = %" PRId64,
                 esp_http_client_get_status_code(outbound_client),
                 esp_http_client_get_content_length(outbound_client));
    }
    else
    {
        ESP_LOGE(TAG, "Error perform http request %s", esp_err_to_name(err));
    }
    esp_http_client_cleanup(outbound_client);
}

void sse_stream_task(void *pvParameters)
{
    start_config = true;
    char *buffer = malloc(MAX_HTTP_RECV_BUFFER + 1);
    if (buffer == NULL)
    {
        ESP_LOGE(TAG, "Cannot malloc http receive buffer");
        return;
    }

    char full_url[256];

    // snprintf(full_url, sizeof(full_url), "%s%s?auth=%s", FIREBASE_HOST, FIREBASE_PATH, FIREBASE_AUTH);
    snprintf(full_url, sizeof(full_url), "%s/%s%s.json?auth=%s", FIREBASE_HOST, rvd_data_str, FIREBASE_PATH, FIREBASE_AUTH);

    ESP_LOGI(TAG, "Connecting to Firebase URL: %s", full_url);

    esp_http_client_config_t config = {
        .url = full_url,
        .method = HTTP_METHOD_PUT,
        .crt_bundle_attach = esp_crt_bundle_attach,
        .event_handler = _http_event_handler,
        .is_async = true,
        .user_data = buffer,
    };
    client = esp_http_client_init(&config);

    esp_http_client_set_header(client, "Accept", "text/event-stream");

    esp_err_t err;
    while (1)
    {
        if (data_to_send)
        {
            char outbound_data[256]; // Increase the size of the buffer to accommodate the formatted string
            snprintf(outbound_data, sizeof(outbound_data), "{\"brightness\": \"%s\", \"keep_alive\": %d}", global_brightness, keep_alive);
            ESP_LOGI(TAG, "Outbound data: %s", outbound_data);

            esp_http_client_set_header(client, "Content-Type", "application/json");
            esp_http_client_set_header(client, "Accept", "application/json");

            esp_http_client_set_post_field(client, outbound_data, strlen(outbound_data));

            err = esp_http_client_perform(client);
            if (err == ESP_OK)
            {
                ESP_LOGI(TAG, "HTTPS Status = %d, content_length = %" PRId64,
                         esp_http_client_get_status_code(client),
                         esp_http_client_get_content_length(client));
            }
            else
            {
                ESP_LOGE(TAG, "Error perform http request %s", esp_err_to_name(err));
            }

            data_to_send = false;
        }
        else
        {

            err = esp_http_client_perform(client);
            if (err != ESP_ERR_HTTP_EAGAIN)
            {
                break;
            }
        }
    }

    if (err == ESP_OK)
    {
        ESP_LOGI(TAG, "HTTPS Status = %d, content_length = %" PRId64,
                 esp_http_client_get_status_code(client),
                 esp_http_client_get_content_length(client));
    }
    else
    {
        ESP_LOGE(TAG, "Error perform http request %s", esp_err_to_name(err));
    }
    esp_http_client_cleanup(client);
}

void initialise_wifi(void)
{
    // char ssid_str[34] = {0};
    // char password_str[66] = {0};
    // char rvd_data_str[66] = {0};

    // Load SSID and password using the info_load_string function
    esp_err_t load_ssid_status = info_load_string("ssid", ssid_str, sizeof(ssid_str));
    esp_err_t load_password_status = info_load_string("password", password_str, sizeof(password_str));
    esp_err_t load_rvd_data_status = info_load_string("rvd_data", rvd_data_str, sizeof(rvd_data_str));

    if (load_ssid_status == ESP_OK && load_password_status == ESP_OK && strlen(ssid_str) > 0 && strlen(password_str) > 0)
    {
        ESP_LOGI(TAG, "Found NVS WiFi credentials. Starting connecting to wifi...");

        ESP_ERROR_CHECK(esp_netif_init());
        s_wifi_event_group = xEventGroupCreate();
        ESP_ERROR_CHECK(esp_event_loop_create_default());

        esp_bridge_create_all_netif();

        wifi_config_t wifi_config;
        memset(&wifi_config, 0, sizeof(wifi_config_t));
        strncpy((char *)wifi_config.sta.ssid, ssid_str, sizeof(wifi_config.sta.ssid));
        strncpy((char *)wifi_config.sta.password, password_str, sizeof(wifi_config.sta.password));

        esp_bridge_wifi_set(WIFI_MODE_STA, (char *)wifi_config.sta.ssid, (char *)wifi_config.sta.password, NULL);

        memset(&wifi_config, 0x0, sizeof(wifi_config_t));
        size_t softap_ssid_len = sizeof(wifi_config.ap.ssid);
        if (esp_mesh_lite_get_softap_ssid_from_nvs((char *)wifi_config.ap.ssid, &softap_ssid_len) != ESP_OK)
        {
            snprintf((char *)wifi_config.ap.ssid, sizeof(wifi_config.ap.ssid), "%s", CONFIG_BRIDGE_SOFTAP_SSID);
        }
        size_t softap_psw_len = sizeof(wifi_config.ap.password);
        if (esp_mesh_lite_get_softap_psw_from_nvs((char *)wifi_config.ap.password, &softap_psw_len) != ESP_OK)
        {
            strlcpy((char *)wifi_config.ap.password, CONFIG_BRIDGE_SOFTAP_PASSWORD, sizeof(wifi_config.ap.password));
        }
        esp_bridge_wifi_set(WIFI_MODE_AP, (char *)wifi_config.ap.ssid, (char *)wifi_config.ap.password, NULL);

        wifi_config_done = true;
    }
    else
    {
        ESP_ERROR_CHECK(esp_netif_init());
        s_wifi_event_group = xEventGroupCreate();
        ESP_ERROR_CHECK(esp_event_loop_create_default());
        esp_netif_t *sta_netif = esp_netif_create_default_wifi_sta();
        assert(sta_netif);

        wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
        ESP_ERROR_CHECK(esp_wifi_init(&cfg));

        ESP_ERROR_CHECK(esp_event_handler_register(WIFI_EVENT, ESP_EVENT_ANY_ID, &event_handler, NULL));
        ESP_ERROR_CHECK(esp_event_handler_register(IP_EVENT, IP_EVENT_STA_GOT_IP, &event_handler, NULL));
        ESP_ERROR_CHECK(esp_event_handler_register(SC_EVENT, ESP_EVENT_ANY_ID, &event_handler, NULL));

        ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA));
        ESP_ERROR_CHECK(esp_wifi_start());
        ESP_LOGI(TAG, "Could not open NVS to read WiFi credentials. Starting SmartConfig...");
    }
}

static void smartconfig_example_task(void *parm)
{
    EventBits_t uxBits;
    ESP_ERROR_CHECK(esp_smartconfig_set_type(SC_TYPE_ESPTOUCH_V2));
    smartconfig_start_config_t cfg = SMARTCONFIG_START_CONFIG();
    ESP_ERROR_CHECK(esp_smartconfig_start(&cfg));
    while (1)
    {
        uxBits = xEventGroupWaitBits(s_wifi_event_group, WIFI_CONNECTED_BIT | ESPTOUCH_DONE_BIT, true, false, portMAX_DELAY);
        if (uxBits & WIFI_CONNECTED_BIT)
        {
            ESP_LOGI(TAG, "WiFi Connected to ap");
        }
        if (uxBits & ESPTOUCH_DONE_BIT)
        {
            ESP_LOGI(TAG, "smartconfig over");
            esp_smartconfig_stop();
            // esp_restart();
            vTaskDelete(NULL);
        }
    }
}

static void print_system_info_timercb(TimerHandle_t timer)
{
    uint8_t primary = 0;
    uint8_t sta_mac[6] = {0};
    wifi_ap_record_t ap_info = {0};
    wifi_second_chan_t second = 0;
    wifi_sta_list_t wifi_sta_list = {0x0};
    check_status();
    esp_wifi_sta_get_ap_info(&ap_info);
    esp_wifi_get_mac(ESP_IF_WIFI_STA, sta_mac);
    esp_wifi_ap_get_sta_list(&wifi_sta_list);
    esp_wifi_get_channel(&primary, &second);
    ESP_LOGI(TAG, "System information, channel: %d, layer: %d, self mac: " MACSTR ", parent bssid: " MACSTR ", parent rssi: %d, free heap: %" PRIu32 "", primary,
             esp_mesh_lite_get_level(), MAC2STR(sta_mac), MAC2STR(ap_info.bssid),
             (ap_info.rssi != 0 ? ap_info.rssi : -120), esp_get_free_heap_size());
    ESP_LOGI(TAG, "child node number: %d", esp_mesh_lite_get_child_node_number());
    for (int i = 0; i < wifi_sta_list.num; i++)
    {
        ESP_LOGI(TAG, "Child mac: " MACSTR, MAC2STR(wifi_sta_list.sta[i].mac));
    }
    // ESP_LOGI(TAG, "yoo: %d", global_yoo);
    // ESP_LOGI(TAG, "yoo: %s", global_brightness);
    if (start_config)
    {
    }
    if (wifi_connected && !start_config)
    {
        xTaskCreate(&sse_stream_task, "sse_stream_task", 4096 * 2, NULL, 5, NULL);
        // post_rest_function();
        start_config = true;
    }
}

void app_main()
{
    esp_log_level_set("*", ESP_LOG_INFO);

    esp_storage_init();

    initialise_wifi();


    if (wifi_config_done)
    {
        // wifi_config_t wifi_cfg;
        // esp_wifi_get_config(WIFI_IF_AP, &wifi_cfg);

        // wifi_cfg.ap.ssid_hidden = true;
        // wifi_cfg.ap.beacon_interval = 100;
        // esp_wifi_set_config(WIFI_IF_AP, &wifi_cfg);
        esp_mesh_lite_config_t mesh_lite_config = ESP_MESH_LITE_DEFAULT_INIT();
        esp_mesh_lite_init(&mesh_lite_config);
        esp_mesh_lite_start();
        TimerHandle_t timer = xTimerCreate("print_system_info", 10000 / portTICK_PERIOD_MS,
                                           true, NULL, print_system_info_timercb);
        xTimerStart(timer, 0);
    }
}

@ThatBigPrint
Copy link
Author

Guys i still need help on this basicaly i want to have the incoming stream hapen and to be able to post out with the seperate function to the same endpoint do i need to interupt the client perform ? is this an issue with .is_async ?

@KaeLL
Copy link
Contributor

KaeLL commented Dec 13, 2023

Would you please wrap this mess like this

```c
#include <stdio.h>

void app_main( void )
{
   printf( "Hello, World!" );
}
```

so it becomes

#include <stdio.h>

void app_main( void )
{
   printf( "Hello, World!" );
}

?

@ThatBigPrint
Copy link
Author

@KaeLL mess resoved... would be pretty good if github could do that when you click the <>.... any help?

@ThatBigPrint
Copy link
Author

ThatBigPrint commented Dec 18, 2023

ok i have made some progress but at the cost of massive heap use, i just don't clean up the post function.... the issue im having is and yes i have attempted to use the same client... if i separate the clients and handlers performing cleanup on the post client kill the incoming client... if i use the same client and prepare the post data and perform nothing gets sent it just sits there... no heap change at all... so the only way i have it working is i do as below

static void https_async()
{
    start_config = true;
    char *buffer = malloc(MAX_HTTP_RECV_BUFFER + 1);
    if (buffer == NULL)
    {
        ESP_LOGE(TAG, "Cannot malloc http receive buffer");
        return;
    }


    esp_http_client_config_t config_outbound = {
        .url = full_url,
        .method = HTTP_METHOD_PATCH,
        .crt_bundle_attach = esp_crt_bundle_attach,
        .event_handler = _http_event_handler,
        .user_data = buffer,
    };

    outbound_client = esp_http_client_init(&config_outbound);

    esp_http_client_set_header(outbound_client, "Content-Type", "application/json");
    esp_http_client_set_header(outbound_client, "Accept", "application/json");

    char *outbound_data = "";
    esp_http_client_set_post_field(outbound_client, outbound_data, strlen(outbound_data));
    ESP_LOGI(TAG, "Outbound data: %s", outbound_data);

    esp_http_client_perform(outbound_client);

    esp_http_client_config_t config = {
        .url = full_url,
        .crt_bundle_attach = esp_crt_bundle_attach,
        .event_handler = _http_event_handler,
        .is_async = true,
        .user_data = buffer,
    };

    client = esp_http_client_init(&config);
    esp_http_client_set_header(client, "Accept", "text/event-stream");

    esp_err_t err;

    do
    {
        if (data_to_send == true)
        {
            char outbound_data[300];

            esp_http_client_set_post_field(outbound_client, outbound_data, strlen(outbound_data));
            ESP_LOGI(TAG, "Outbound data: %s", outbound_data);
            err = esp_http_client_perform(outbound_client);
            
            data_to_send = false;
        }
        else
        {
            err = esp_http_client_perform(client);
        }
    }

    while (1);

    if (err == ESP_OK)
    {
        ESP_LOGI(TAG, "HTTP POST Status = %d, content_length = %lld",
                 esp_http_client_get_status_code(client),
                 esp_http_client_get_content_length(client));
    }
    else
    {
        ESP_LOGE(TAG, "Error perform http request %s", esp_err_to_name(err));
    }



    esp_http_client_cleanup(outbound_client);
    esp_http_client_cleanup(client);
    free(buffer);
}

This is far from ideal i really need help with this mainly waning to perform cleanup once the patch has been done as this is not need to be done frequently just every now and then but if the cleanup is called it kills everything according to the vague is_async docs its preferred if you re-use client but it just never submits the prepared data as previously said

worse case is there a way to determine the stack size allocated to the patch task as it is very simple?

@ThatBigPrint
Copy link
Author

@hmalpani ?

@hmalpani
Copy link
Contributor

Hello @ThatBigPrint

This is my understanding of the problem you are facing. You want to use the same client handle for two purposes: first post data to the server and second read data from the server. I suppose these two are using POST and GET methods respectively. So I think, before calling esp_http_client_perform(), you need to set the method again. You can refer to the esp_http_client_example

@ThatBigPrint
Copy link
Author

No, i want the is_async to remain running for incoming get (that remains running continuously) and the random patch to be able to run every now and then with a cleanup to free resources but as soon as you call cleanup for the patch it disconnects the continuous incoming client as well

@hmalpani
Copy link
Contributor

If you are using the same client handle for both the requests, while cleaning up, you might have cleaned up the resources required for the GET request (that remains running continuously).
If you use two different handles for both the requests, does it works?

@hmalpani
Copy link
Contributor

Closing this issue. Please feel free to reopen if you have more updates. Thanks!

@espressif-bot espressif-bot added the Status: Done Issue is done internally label Feb 13, 2024
@espressif-bot espressif-bot added Resolution: NA Issue resolution is unavailable and removed Status: In Progress Work is in progress labels Feb 13, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Awaiting Response awaiting a response from the author Resolution: NA Issue resolution is unavailable Status: Done Issue is done internally Type: Bug bugs in IDF
Projects
None yet
Development

No branches or pull requests

5 participants