[SOLVED] HTTP Server and Websockets together
Posted: Tue Dec 19, 2023 6:23 am
Hello everyone!
I use http server and websockets in my firmware. The web server is a backend for processing get post requests. One of handlers I have is:
I took the code from here as the basis for the implementation of websockets:
https://github.com/espressif/esp-idf/tr ... wss_server
4 ntc thermistors, 6 ds18b20 sensors, 2 motion sensors and 3 relays are connected to my ESP 32.
Several tasks are created with different frequency for thermistors, ds18b20, motion sensors (every 10 seconds).
Example of task:
queue_send - the method that receives data and sends notifications (now these are websockets, but later I will add mqtt support)
How I receive from queue:
ws_send_broadcast_message method:
When executed, this method sends a message with sensor readings to all active websocket clients. Frontend (vue.js) takes these readings and processes them properly.
My problem is that if ws_send_broadcast_message is running, I cannot correctly execute any POST GET request (open the main page, or switch relays). It feels like the response from the server is "shuffled" and the page is partially returned. If the ws_send_broadcast_message method is not called, then everything works correctly.
When I make a GET request and a websockets message arrives at the same time, it turns out that this is the trouble. It's clear here in the screenshot Can you tell me how this can be fixed?
How can I send and serve a websockets message at the same time with POST GET requests?
I use http server and websockets in my firmware. The web server is a backend for processing get post requests. One of handlers I have is:
Code: Select all
/* Websockets URI handler */
httpd_uri_t websocket_server_uri = {
.uri = "/ws",
.method = HTTP_GET,
.handler = websocket_server_handler,
.user_ctx = rest_context,
.is_websocket = true,
.handle_ws_control_frames = true};
httpd_register_uri_handler(server, &websocket_server_uri);
//...............
static esp_err_t websocket_server_handler(httpd_req_t *req)
{
esp_err_t ret = ws_handler_for_uri(req);
return ret;
}
https://github.com/espressif/esp-idf/tr ... wss_server
4 ntc thermistors, 6 ds18b20 sensors, 2 motion sensors and 3 relays are connected to my ESP 32.
Several tasks are created with different frequency for thermistors, ds18b20, motion sensors (every 10 seconds).
Example of task:
Code: Select all
void onewire_task(void *arg)
{
char string_address[16] = {0};
while (true)
{
for (int i = 0; i < MAX_SENSORS; i++)
{
if (addresses[i] != 0)
{
onewire_uint64_t_to_addr_str(addresses[i], string_address);
uint8_t family_id = (uint8_t)addresses[i];
switch (family_id)
{
case DS18X20_FAMILY_DS18B20: // CASE ONE-WIRE TEMP SENSOR
case DS18X20_FAMILY_DS18S20: // CASE ONE-WIRE TEMP SENSOR
case DS18X20_FAMILY_DS1822: // CASE ONE-WIRE TEMP SENSOR
case DS18X20_FAMILY_MAX31850: // CASE ONE-WIRE TEMP SENSOR
float temp;
esp_err_t res = ds18x20_read_temp(addresses[i], &temp);
if (res == ESP_OK)
{
queue_payload_ds18x20_t payload;
payload.family_id = (uint8_t)addresses[i];
payload.temp = temp;
payload.address = (uint64_t)addresses[i];
queue_message_t message;
message.type = QE_DS18X20;
message.payload = (void *)&payload;
queue_send(message);
}
break;
default:
break;
}
}
}
ESP_LOGW(ONE_WIRE_TAG, "[onewire_task] Free memory: %ld bytes", esp_get_free_heap_size());
vTaskDelay(ONEWIRE_TASK_TIMEOUT / portTICK_PERIOD_MS);
}
vTaskDelete(NULL);
}
////---------- somewhere-----//////
xTaskCreatePinnedToCore(onewire_task, "onewire_task", 4096, NULL, ONE_WIRE_TASK_PRIORITY, &onewire_task_handle, 1);
Code: Select all
void queue_send(queue_message_t message)
{
if (queue != NULL)
{
BaseType_t ret = xQueueSend(queue, &message, (1000 / portTICK_PERIOD_MS));
}
}
Code: Select all
void queue_recieve_task(void *arg)
{
QueueHandle_t queue = (QueueHandle_t)arg;
queue_message_t message;
bool has_type = false;
while (true)
{
if (xQueueReceive(queue, &message, (1000 / portTICK_PERIOD_MS)))
{
cJSON *json = cJSON_CreateObject();
cJSON_AddNumberToObject(json, "type", message.type);
cJSON *json_message = cJSON_CreateObject();
switch (message.type)
{
case QE_DS18X20:
has_type = true;
queue_payload_ds18x20_t *ds18x20_payload = (queue_payload_ds18x20_t *)message.payload;
char str[16] = {0};
uint64_t_to_string((uint64_t)ds18x20_payload->address, str);
cJSON_AddNumberToObject(json_message, "family", (uint8_t)ds18x20_payload->address);
cJSON_AddNumberToObject(json_message, "temp", ds18x20_payload->temp);
cJSON_AddStringToObject(json_message, "serial", str);
ESP_LOGI(TAG_QUEUE, "[QE_DS18X20] SN: %s, temp %.2f°C, family_id %d", str, ds18x20_payload->temp, (uint8_t)ds18x20_payload->address);
break;
/// some code
}
if (has_type)
{
cJSON_AddItemToObject(json, "message", json_message);
char *json_print = cJSON_PrintUnformatted(json);
ws_send_broadcast_message((void *)json_print);
free(json_print);
has_type = false;
}
cJSON_Delete(json);
}
}
Code: Select all
esp_err_t ws_send_broadcast_message(void *data)
{
if (p_server == NULL)
{
return ESP_FAIL;
}
httpd_ws_frame_t ws_pkt;
memset(&ws_pkt, 0, sizeof(httpd_ws_frame_t));
ws_pkt.payload = (uint8_t *)data;
ws_pkt.len = strlen(data);
ws_pkt.type = HTTPD_WS_TYPE_TEXT;
for (int i = 0; i < MAX_CLIENTS; i++)
{
if (client_fds[i] > 0)
{
httpd_ws_send_frame_async(p_server, client_fds[i], &ws_pkt);
}
}
return ESP_OK;
}
My problem is that if ws_send_broadcast_message is running, I cannot correctly execute any POST GET request (open the main page, or switch relays). It feels like the response from the server is "shuffled" and the page is partially returned. If the ws_send_broadcast_message method is not called, then everything works correctly.
When I make a GET request and a websockets message arrives at the same time, it turns out that this is the trouble. It's clear here in the screenshot Can you tell me how this can be fixed?
How can I send and serve a websockets message at the same time with POST GET requests?