Reputation: 1
I'm trying to make ESP32 behave as web-server, and collect data from web-client to control the speed of the motor. My IDE is VS code and I'm using ESP-IDF as my extension. I'm not using Platform-IO. The ESP32 stops receiving data from the client after 6 iterations. I'm pasting the code below. I have referred the examples, did a lot of google search, but could not find the solution. Can anyone please suggest what could be the error and please suggest if there is an alternate way of implementing the use case.
#include <stdio.h>
#include <string.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/event_groups.h"
#include "esp_system.h"
#include "esp_wifi.h"
#include "esp_event.h"
#include "esp_log.h"
#include "esp_netif.h"
#include "nvs_flash.h"
#include "driver/gpio.h"
#include "driver/uart.h"
#include "lwip/err.h"
#include "lwip/sys.h"
#include <lwip/sockets.h>
#include <lwip/sys.h>
#include <lwip/api.h>
#include <lwip/netdb.h>
#include "spi_flash_mmap.h"
#include <esp_http_server.h>
typedef struct
{
char str_value[4];
long long_value;
} URL_t;
char web_homepage_string[] = "<!DOCTYPE html><html><head><meta name=\"viewport\" content=\"width=device-width, initial-scale=1\"><style>html {font-family: Arial; display: inline-block; text-align: center;}h1 {font-size: 2.2rem;color:green;}h2 {font-size: 2.1rem;}p {font-size: 1.9rem;} body {max-width: 500px; margin:0px auto; padding-bottom: 30px;} .slider { -webkit-appearance: none; margin: 14px; width: 400px; height: 15px; border-radius: 5px; background: #39a6de; outline: none; -webkit-transition: .2s; transition: opacity .2s;} .slider::-webkit-slider-thumb {-webkit-appearance: none; appearance: none; width: 25px; height: 25px; border-radius: 12px; background: #f74d4d; cursor: pointer;} .slider::-moz-range-thumb { width: 25px; height: 25px; border-radius: 12px; background: #F74D4D; cursor: pointer; } </style> </head> <body> <h1>Rhino Motor Speed Control</h1><h2>Speed Value</h2> <p><span id=\"textSliderValue\">0</span></p> <p><input type=\"range\" onchange=\"updateSliderVal(this)\" id=\"speedSlider\" min=\"-255\" max=\"255\" value=\"0\" step=\"5\" class=\"slider\"></p> <script> function updateSliderVal(element) { var motorSliderValue = document.getElementById(\"speedSlider\").value; document.getElementById(\"textSliderValue\").innerHTML = motorSliderValue; console.log(motorSliderValue); var httpRequest = new XMLHttpRequest(); httpRequest.open(\"GET\", \"/webclient_speed?value=\" + motorSliderValue, true); httpRequest.send();}</script> </body> </html>";
/*Macros define GPIO pin values for UART-Peripheral. */
#define UART_1_TX_PIN (10)
#define UART_1_RX_PIN (9)
static const int UART_RX_BUF_SIZE = 1024;
/* Host WiFi Details. */
#define ESP_HOST_WIFI_SSID CONFIG_ESP_WIFI_SSID
#define ESP_HOST_WIFI_PASS CONFIG_ESP_WIFI_PASSWORD
#define ESP_HOST_MAXIMUM_RETRY CONFIG_ESP_MAXIMUM_RETRY
/* FreeRTOS event group to signal when we are connected*/
static EventGroupHandle_t s_wifi_event_group;
/* The event group allows multiple bits for each event, but we only care about two events:
* - we are connected to the AP with an IP
* - we failed to connect after the maximum amount of retries */
#define WIFI_CONNECTED_BIT BIT0
#define WIFI_FAIL_BIT BIT1
static const char *TAG = "ESP Web-Server";
static int s_retry_num = 0;
/* FreeRTOS event-handler to handle Wi-Fi and TCP/IP events.*/
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)
{
esp_wifi_connect();
}
else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_DISCONNECTED)
{
if (s_retry_num < ESP_HOST_MAXIMUM_RETRY)
{
esp_wifi_connect();
s_retry_num++;
ESP_LOGI(TAG, "retry to connect to the AP");
}
else
{
xEventGroupSetBits(s_wifi_event_group, WIFI_FAIL_BIT);
}
ESP_LOGI(TAG,"connect to the AP fail");
}
else if (event_base == IP_EVENT && 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));
s_retry_num = 0;
xEventGroupSetBits(s_wifi_event_group, WIFI_CONNECTED_BIT);
}
else
{
/* No Action.*/
}
}
/* Function to configure ESP32 Wi-Fi.*/
void WiFi_InitIn_StationMode(void)
{
s_wifi_event_group = xEventGroupCreate();
/* lwIP is a widely used open-source TCP/IP stack designed for embedded systems.
*ESP-NETIF is another library that encapsulates lwIP and provide another set of APIs.
*The below function performs lwIP initialisation and create lwIP task. */
ESP_ERROR_CHECK(esp_netif_init());
/* There is something called as default event loop whose understanding isn't much.
*This is required for handling WiFi events.*/
ESP_ERROR_CHECK(esp_event_loop_create_default());
/* Creating a network interface instance binding WiFi driver and
*TCP/IP stack (esp-netif or lwIP). This is done by calling the below function.*/
esp_netif_create_default_wifi_sta();
/* Initializing the WiFi-Driver with the default configuration.*/
wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
ESP_ERROR_CHECK(esp_wifi_init(&cfg));
/* Registering for callbacks that listens for WiFi and TCP/IP events.*/
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,
&event_handler,
NULL,
&instance_any_id));
ESP_ERROR_CHECK(esp_event_handler_instance_register(IP_EVENT,
IP_EVENT_STA_GOT_IP,
&event_handler,
NULL,
&instance_got_ip));
/* Configuring the WiFi driver.*/
wifi_config_t wifi_config =
{
.sta =
{
.ssid = ESP_HOST_WIFI_SSID,
.password = ESP_HOST_WIFI_PASS,
/* Authmode threshold resets to WPA2 as default if password matches WPA2 standards (pasword len => 8).
* If you want to connect the device to deprecated WEP/WPA networks, Please set the threshold value
* to WIFI_AUTH_WEP/WIFI_AUTH_WPA_PSK and set the password with length and format matching to
* WIFI_AUTH_WEP/WIFI_AUTH_WPA_PSK standards.
*/
.threshold.authmode = WIFI_AUTH_WPA2_PSK,
.sae_pwe_h2e = WPA3_SAE_PWE_BOTH,
.sae_h2e_identifier = "",
},
};
ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA) );
ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_STA, &wifi_config) );
/* Start the WiFi and connect to the Access Point.*/
ESP_ERROR_CHECK(esp_wifi_start() );
ESP_LOGI(TAG, "wifi_init_sta finished.");
/* Waiting until either the connection is established (WIFI_CONNECTED_BIT) or connection failed for the maximum
* number of re-tries (WIFI_FAIL_BIT). The bits are set by event_handler() (see above) */
EventBits_t bits = xEventGroupWaitBits(s_wifi_event_group,
WIFI_CONNECTED_BIT | WIFI_FAIL_BIT,
pdFALSE,
pdFALSE,
portMAX_DELAY);
/* xEventGroupWaitBits() returns the bits before the call returned, hence we can test which event actually
* happened. */
if (bits & WIFI_CONNECTED_BIT)
{
ESP_LOGI(TAG, "connected to ap SSID:%s password:%s",
ESP_HOST_WIFI_SSID, ESP_HOST_WIFI_PASS);
}
else if (bits & WIFI_FAIL_BIT)
{
ESP_LOGI(TAG, "Failed to connect to SSID:%s, password:%s",
ESP_HOST_WIFI_SSID, ESP_HOST_WIFI_PASS);
}
else
{
ESP_LOGE(TAG, "UNEXPECTED EVENT");
}
}
/* Function to perform the required UART initialization.
Currently we are using UART-1 instance which is on GPIO9 and GPIO10.*/
void UART_Init(void)
{
const uart_config_t uart_config =
{
.baud_rate = 9600,
.data_bits = UART_DATA_8_BITS,
.parity = UART_PARITY_DISABLE,
.stop_bits = UART_STOP_BITS_1,
.flow_ctrl = UART_HW_FLOWCTRL_DISABLE,
.source_clk = UART_SCLK_DEFAULT,
};
uart_driver_install(UART_NUM_1, UART_RX_BUF_SIZE * 2, 0, 0, NULL, 0);
uart_param_config(UART_NUM_1, &uart_config);
uart_set_pin(UART_NUM_1, UART_1_TX_PIN, UART_1_RX_PIN, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE);
}
esp_err_t send_web_page(httpd_req_t *req)
{
int response;
response = httpd_resp_send(req, web_homepage_string, HTTPD_RESP_USE_STRLEN);
return response;
}
esp_err_t HomePage_req_handler(httpd_req_t *req)
{
return send_web_page(req);
}
esp_err_t ReceiveSpeedFrom_Webclient_handler(httpd_req_t *req)
{
ESP_LOGI(TAG,"client-data[%s]",req->uri);
//char Uart_Buff[5] = {'S',};
//memcpy(&Uart_Buff[1], &req->uri[23], (strlen(req->uri) - 23));
//uart_write_bytes(UART_NUM_1, (const char*)Uart_Buff, strlen(Uart_Buff));
//ESP_LOGI(TAG, "motor speed %s", Uart_Buff);
return ESP_OK;
}
/* Handler which has to get called when web-client makes requests.*/
httpd_uri_t uri_get_homepage =
{
.uri = "/",
.method = HTTP_GET,
.handler = HomePage_req_handler,
.user_ctx = NULL
};
httpd_uri_t GetSpeedValue_FromWebClient =
{
.uri = "/webclient_speed",
.method = HTTP_GET,
.handler = ReceiveSpeedFrom_Webclient_handler,
.user_ctx = NULL
};
httpd_handle_t Setup_HTTP_server(void)
{
httpd_config_t HTTP_ServerConfig = HTTPD_DEFAULT_CONFIG();
httpd_handle_t HTTP_ServerDetails = NULL;
if (httpd_start(&HTTP_ServerDetails, &HTTP_ServerConfig) == ESP_OK)
{
httpd_register_uri_handler(HTTP_ServerDetails, &uri_get_homepage);
httpd_register_uri_handler(HTTP_ServerDetails, &GetSpeedValue_FromWebClient);
}
else
{
/* No Action.*/
}
return HTTP_ServerDetails;
}
void app_main(void)
{
/* NVS(Non-Volatile Storage) is a partition in flash memory which stores key-value pairs.
We can use NVS to store WiFi configuration.*/
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();
}
ESP_ERROR_CHECK(ret);
/* Initialize the UART interface.*/
UART_Init();
ESP_LOGI(TAG, "ESP_WIFI_MODE_STA");
WiFi_InitIn_StationMode();
ESP_LOGI(TAG, "Rhino Motor Control Web Server is running ... ...\n");
Setup_HTTP_server();
}
I have tried internet search, referred example codes. But I have not found any solution. Every 2nd search points me to Arduino IDE solution, but I want a ESP-IDF solution.
Upvotes: 0
Views: 1036
Reputation: 11
The reason you are not able to receive any responses after 6 is because you are not sending a "200 OK" response from the ESP web server. You can see this if you do cntrl+I on the web server and then move the slider, you will notice that your requests stay in (pending) state. Here is a revised version of your ReceiveSpeedFrom_Webclient_handler function:
esp_err_t ReceiveSpeedFrom_Webclient_handler(httpd_req_t *req) {
ESP_LOGI(TAG,"client-data[%s]",req->uri);
// Send the HTTP response with the appropriate status code
httpd_resp_send(req, NULL, 0);
return ESP_OK;
}
Upvotes: 1