2022-10-11 16:31:57 +02:00
/*
2024-02-06 22:55:06 +04:00
* SPDX - FileCopyrightText : 2022 - 2024 Espressif Systems ( Shanghai ) CO LTD
2022-10-11 16:31:57 +02:00
*
2019-06-20 15:37:40 +08:00
* SPDX - License - Identifier : Unlicense OR CC0 - 1.0
2022-10-11 16:31:57 +02:00
*/
2019-06-20 15:37:40 +08:00
/* ESP HTTP Client Example
This example code is in the Public Domain ( or CC0 licensed , at your option . )
Unless required by applicable law or agreed to in writing , this
software is distributed on an " AS IS " BASIS , WITHOUT WARRANTIES OR
CONDITIONS OF ANY KIND , either express or implied .
*/
# include <stdio.h>
# include "esp_wifi.h"
# include "esp_system.h"
# include "nvs_flash.h"
2019-07-05 16:58:04 +08:00
# include "esp_event.h"
2019-06-20 15:37:40 +08:00
# include "protocol_examples_common.h"
# include "freertos/FreeRTOS.h"
# include "freertos/task.h"
2019-11-14 18:09:38 +08:00
# include "freertos/semphr.h"
2019-06-20 15:37:40 +08:00
# include "freertos/event_groups.h"
# include "esp_log.h"
# include "esp_websocket_client.h"
# include "esp_event.h"
2022-07-11 16:05:24 +04:00
# include <cJSON.h>
2019-06-20 15:37:40 +08:00
2022-01-14 18:11:59 +01:00
# define NO_DATA_TIMEOUT_SEC 5
2019-11-14 18:09:38 +08:00
2023-02-15 15:41:46 +01:00
static const char * TAG = " websocket " ;
2019-06-20 15:37:40 +08:00
2019-11-14 18:09:38 +08:00
static TimerHandle_t shutdown_signal_timer ;
static SemaphoreHandle_t shutdown_sema ;
2022-10-04 11:01:08 +02:00
static void log_error_if_nonzero ( const char * message , int error_code )
{
if ( error_code ! = 0 ) {
ESP_LOGE ( TAG , " Last error %s: 0x%x " , message , error_code ) ;
}
}
2019-11-14 18:09:38 +08:00
static void shutdown_signaler ( TimerHandle_t xTimer )
{
ESP_LOGI ( TAG , " No data received for %d seconds, signaling shutdown " , NO_DATA_TIMEOUT_SEC ) ;
xSemaphoreGive ( shutdown_sema ) ;
}
2019-10-15 17:27:47 +08:00
# if CONFIG_WEBSOCKET_URI_FROM_STDIN
static void get_string ( char * line , size_t size )
{
int count = 0 ;
while ( count < size ) {
int c = fgetc ( stdin ) ;
if ( c = = ' \n ' ) {
line [ count ] = ' \0 ' ;
break ;
} else if ( c > 0 & & c < 127 ) {
line [ count ] = c ;
+ + count ;
}
vTaskDelay ( 10 / portTICK_PERIOD_MS ) ;
}
}
# endif /* CONFIG_WEBSOCKET_URI_FROM_STDIN */
2019-06-20 15:37:40 +08:00
static void websocket_event_handler ( void * handler_args , esp_event_base_t base , int32_t event_id , void * event_data )
{
esp_websocket_event_data_t * data = ( esp_websocket_event_data_t * ) event_data ;
switch ( event_id ) {
2019-11-14 18:09:38 +08:00
case WEBSOCKET_EVENT_CONNECTED :
ESP_LOGI ( TAG , " WEBSOCKET_EVENT_CONNECTED " ) ;
break ;
case WEBSOCKET_EVENT_DISCONNECTED :
ESP_LOGI ( TAG , " WEBSOCKET_EVENT_DISCONNECTED " ) ;
2022-10-04 11:01:08 +02:00
log_error_if_nonzero ( " HTTP status code " , data - > error_handle . esp_ws_handshake_status_code ) ;
if ( data - > error_handle . error_type = = WEBSOCKET_ERROR_TYPE_TCP_TRANSPORT ) {
log_error_if_nonzero ( " reported from esp-tls " , data - > error_handle . esp_tls_last_esp_err ) ;
log_error_if_nonzero ( " reported from tls stack " , data - > error_handle . esp_tls_stack_err ) ;
log_error_if_nonzero ( " captured as transport's socket errno " , data - > error_handle . esp_transport_sock_errno ) ;
}
2019-11-14 18:09:38 +08:00
break ;
case WEBSOCKET_EVENT_DATA :
ESP_LOGI ( TAG , " WEBSOCKET_EVENT_DATA " ) ;
ESP_LOGI ( TAG , " Received opcode=%d " , data - > op_code ) ;
2024-04-12 13:14:22 +04:00
if ( data - > op_code = = 0x2 ) { // Opcode 0x2 indicates binary data
ESP_LOG_BUFFER_HEX ( " Received binary data " , data - > data_ptr , data - > data_len ) ;
} else if ( data - > op_code = = 0x08 & & data - > data_len = = 2 ) {
2020-07-17 17:59:05 +02:00
ESP_LOGW ( TAG , " Received closed message with code=%d " , 256 * data - > data_ptr [ 0 ] + data - > data_ptr [ 1 ] ) ;
} else {
2024-02-06 22:55:06 +04:00
ESP_LOGW ( TAG , " Received=%.*s \n \n " , data - > data_len , ( char * ) data - > data_ptr ) ;
2020-07-17 17:59:05 +02:00
}
2022-10-11 16:31:57 +02:00
2022-07-11 16:05:24 +04:00
// If received data contains json structure it succeed to parse
cJSON * root = cJSON_Parse ( data - > data_ptr ) ;
if ( root ) {
for ( int i = 0 ; i < cJSON_GetArraySize ( root ) ; i + + ) {
cJSON * elem = cJSON_GetArrayItem ( root , i ) ;
cJSON * id = cJSON_GetObjectItem ( elem , " id " ) ;
cJSON * name = cJSON_GetObjectItem ( elem , " name " ) ;
ESP_LOGW ( TAG , " Json={'id': '%s', 'name': '%s'} " , id - > valuestring , name - > valuestring ) ;
}
cJSON_Delete ( root ) ;
}
2019-11-14 18:09:38 +08:00
ESP_LOGW ( TAG , " Total payload length=%d, data_len=%d, current payload offset=%d \r \n " , data - > payload_len , data - > data_len , data - > payload_offset ) ;
xTimerReset ( shutdown_signal_timer , portMAX_DELAY ) ;
break ;
case WEBSOCKET_EVENT_ERROR :
ESP_LOGI ( TAG , " WEBSOCKET_EVENT_ERROR " ) ;
2022-10-04 11:01:08 +02:00
log_error_if_nonzero ( " HTTP status code " , data - > error_handle . esp_ws_handshake_status_code ) ;
if ( data - > error_handle . error_type = = WEBSOCKET_ERROR_TYPE_TCP_TRANSPORT ) {
log_error_if_nonzero ( " reported from esp-tls " , data - > error_handle . esp_tls_last_esp_err ) ;
log_error_if_nonzero ( " reported from tls stack " , data - > error_handle . esp_tls_stack_err ) ;
log_error_if_nonzero ( " captured as transport's socket errno " , data - > error_handle . esp_transport_sock_errno ) ;
}
2019-11-14 18:09:38 +08:00
break ;
2019-06-20 15:37:40 +08:00
}
}
static void websocket_app_start ( void )
{
2019-10-15 17:27:47 +08:00
esp_websocket_client_config_t websocket_cfg = { } ;
2019-11-14 18:09:38 +08:00
shutdown_signal_timer = xTimerCreate ( " Websocket shutdown timer " , NO_DATA_TIMEOUT_SEC * 1000 / portTICK_PERIOD_MS ,
pdFALSE , NULL , shutdown_signaler ) ;
shutdown_sema = xSemaphoreCreateBinary ( ) ;
# if CONFIG_WEBSOCKET_URI_FROM_STDIN
2019-10-15 17:27:47 +08:00
char line [ 128 ] ;
ESP_LOGI ( TAG , " Please enter uri of websocket endpoint " ) ;
get_string ( line , sizeof ( line ) ) ;
websocket_cfg . uri = line ;
ESP_LOGI ( TAG , " Endpoint uri: %s \n " , line ) ;
2019-11-14 18:09:38 +08:00
# else
2019-10-15 17:27:47 +08:00
websocket_cfg . uri = CONFIG_WEBSOCKET_URI ;
2019-11-14 18:09:38 +08:00
# endif /* CONFIG_WEBSOCKET_URI_FROM_STDIN */
2019-06-20 15:37:40 +08:00
2024-02-06 22:55:06 +04:00
# if CONFIG_WS_OVER_TLS_MUTUAL_AUTH
/* Configuring client certificates for mutual authentification */
extern const char cacert_start [ ] asm ( " _binary_ca_cert_pem_start " ) ; // CA certificate
extern const char cert_start [ ] asm ( " _binary_client_cert_pem_start " ) ; // Client certificate
extern const char cert_end [ ] asm ( " _binary_client_cert_pem_end " ) ;
extern const char key_start [ ] asm ( " _binary_client_key_pem_start " ) ; // Client private key
extern const char key_end [ ] asm ( " _binary_client_key_pem_end " ) ;
websocket_cfg . cert_pem = cacert_start ;
websocket_cfg . client_cert = cert_start ;
websocket_cfg . client_cert_len = cert_end - cert_start ;
websocket_cfg . client_key = key_start ;
websocket_cfg . client_key_len = key_end - key_start ;
# elif CONFIG_WS_OVER_TLS_SERVER_AUTH
extern const char cacert_start [ ] asm ( " _binary_ca_certificate_public_domain_pem_start " ) ; // CA cert of wss://echo.websocket.event, modify it if using another server
websocket_cfg . cert_pem = cacert_start ;
# endif
# if CONFIG_WS_OVER_TLS_SKIP_COMMON_NAME_CHECK
websocket_cfg . skip_cert_common_name_check = true ;
# endif
2019-10-15 17:27:47 +08:00
ESP_LOGI ( TAG , " Connecting to %s... " , websocket_cfg . uri ) ;
2019-06-20 15:37:40 +08:00
esp_websocket_client_handle_t client = esp_websocket_client_init ( & websocket_cfg ) ;
esp_websocket_register_events ( client , WEBSOCKET_EVENT_ANY , websocket_event_handler , ( void * ) client ) ;
esp_websocket_client_start ( client ) ;
2019-11-14 18:09:38 +08:00
xTimerStart ( shutdown_signal_timer , portMAX_DELAY ) ;
2019-06-20 15:37:40 +08:00
char data [ 32 ] ;
int i = 0 ;
2022-01-14 18:11:59 +01:00
while ( i < 5 ) {
2019-06-20 15:37:40 +08:00
if ( esp_websocket_client_is_connected ( client ) ) {
int len = sprintf ( data , " hello %04d " , i + + ) ;
ESP_LOGI ( TAG , " Sending %s " , data ) ;
2020-03-05 16:26:26 +01:00
esp_websocket_client_send_text ( client , data , len , portMAX_DELAY ) ;
2019-06-20 15:37:40 +08:00
}
2022-02-08 17:39:38 +08:00
vTaskDelay ( 1000 / portTICK_PERIOD_MS ) ;
2019-06-20 15:37:40 +08:00
}
2019-11-14 18:09:38 +08:00
2023-09-26 14:46:21 +04:00
vTaskDelay ( 1000 / portTICK_PERIOD_MS ) ;
2024-04-12 13:14:22 +04:00
// Sending text data
ESP_LOGI ( TAG , " Sending fragmented text message " ) ;
2023-09-26 14:46:21 +04:00
memset ( data , ' a ' , sizeof ( data ) ) ;
esp_websocket_client_send_text_partial ( client , data , sizeof ( data ) , portMAX_DELAY ) ;
memset ( data , ' b ' , sizeof ( data ) ) ;
esp_websocket_client_send_cont_msg ( client , data , sizeof ( data ) , portMAX_DELAY ) ;
esp_websocket_client_send_fin ( client , portMAX_DELAY ) ;
2024-04-12 13:14:22 +04:00
vTaskDelay ( 1000 / portTICK_PERIOD_MS ) ;
// Sending binary data
ESP_LOGI ( TAG , " Sending fragmented binary message " ) ;
char binary_data [ 5 ] ;
memset ( binary_data , 0 , sizeof ( binary_data ) ) ;
esp_websocket_client_send_bin_partial ( client , binary_data , sizeof ( binary_data ) , portMAX_DELAY ) ;
memset ( binary_data , 1 , sizeof ( binary_data ) ) ;
esp_websocket_client_send_cont_msg ( client , binary_data , sizeof ( binary_data ) , portMAX_DELAY ) ;
esp_websocket_client_send_fin ( client , portMAX_DELAY ) ;
vTaskDelay ( 1000 / portTICK_PERIOD_MS ) ;
// Sending text data longer than ws buffer (default 1024)
ESP_LOGI ( TAG , " Sending text longer than ws buffer (default 1024) " ) ;
const int size = 2000 ;
char * long_data = malloc ( size ) ;
memset ( long_data , ' a ' , size ) ;
esp_websocket_client_send_text ( client , long_data , size , portMAX_DELAY ) ;
2023-09-26 14:46:21 +04:00
2019-11-14 18:09:38 +08:00
xSemaphoreTake ( shutdown_sema , portMAX_DELAY ) ;
2020-07-17 17:59:05 +02:00
esp_websocket_client_close ( client , portMAX_DELAY ) ;
2019-06-20 15:37:40 +08:00
ESP_LOGI ( TAG , " Websocket Stopped " ) ;
esp_websocket_client_destroy ( client ) ;
}
2019-07-16 16:33:30 +07:00
void app_main ( void )
2019-06-20 15:37:40 +08:00
{
ESP_LOGI ( TAG , " [APP] Startup.. " ) ;
2023-05-17 07:35:21 +02:00
ESP_LOGI ( TAG , " [APP] Free memory: % " PRIu32 " bytes " , esp_get_free_heap_size ( ) ) ;
2019-06-20 15:37:40 +08:00
ESP_LOGI ( TAG , " [APP] IDF version: %s " , esp_get_idf_version ( ) ) ;
esp_log_level_set ( " * " , ESP_LOG_INFO ) ;
2023-02-15 15:41:46 +01:00
esp_log_level_set ( " websocket_client " , ESP_LOG_DEBUG ) ;
esp_log_level_set ( " transport_ws " , ESP_LOG_DEBUG ) ;
esp_log_level_set ( " trans_tcp " , ESP_LOG_DEBUG ) ;
2019-06-20 15:37:40 +08:00
ESP_ERROR_CHECK ( nvs_flash_init ( ) ) ;
2019-11-29 10:54:02 +01:00
ESP_ERROR_CHECK ( esp_netif_init ( ) ) ;
2019-06-20 15:37:40 +08:00
ESP_ERROR_CHECK ( esp_event_loop_create_default ( ) ) ;
/* This helper function configures Wi-Fi or Ethernet, as selected in menuconfig.
* Read " Establishing Wi-Fi or Ethernet Connection " section in
* examples / protocols / README . md for more information about this function .
*/
ESP_ERROR_CHECK ( example_connect ( ) ) ;
websocket_app_start ( ) ;
}