Developing the ESP32 program

We start by creating an ESP32 project called smartmobile and name the main program file smartmobile.c. Our program will build a simple web server to serve the HTTP requests that are described in Figure 9.1.

Let's start working on our smartmobile.c file:

  1. Declare all the required header files in our program. In the following code, we include the files needed to create this project:
#include <esp_wifi.h>
#include <esp_event_loop.h>
#include <esp_log.h>
#include <esp_system.h>
#include <nvs_flash.h>
#include <sys/param.h>

#include "tcpip_adapter.h"
#include "lwip/err.h"
#include "lwip/sockets.h"
#include "lwip/sys.h"
#include "lwip/netdb.h"
#include "lwip/dns.h"
#include "freertos/event_groups.h"

#include <esp_http_server.h>
  1. Define some variables with regards to the log, state, and ESP32 I/O pins. All lamps are defined as IO12, IO14, and IO26; and all lamp states are declared as the lamp1_state, lamp2_state, and lamp3_state variables:
static const char *TAG="SMARTMOBILE";
static EventGroupHandle_t wifi_event_group;
static const int CONNECTED_BIT = BIT0;
static const int WIFI_INIT_DONE_BIT = BIT1;

#define LAMP1 12
#define LAMP2 14
#define LAMP3 26

int lamp1_state, lamp2_state, lamp3_state;

  1. Start by creating an ESP32 project called smartmobile, and name the main program file smartmobile.c.
  2. In the app_main() entry, initialize the non-volatile storage (NVS) flash by calling the nvs_flash_init() function. NVS is a light memory database that we can use to store key values on the ESP32 board. You can learn more about NVS in the official ESP32 documentation at https://docs.espressif.com/projects/esp-idf/en/latest/api-reference/storage/nvs_flash.html.
  3. Initialize the ESP32 I/O by calling the initialize_gpio() function.
  4. Run the Wi-Fi service on ESP32 with the initialize_wifi() function. The HTTP server handle is declared as a server variable; this variable is passed into the initialize_wifi() function:
void app_main()
{
static httpd_handle_t server = NULL;
ESP_ERROR_CHECK(nvs_flash_init());
initialize_gpio();
initialize_wifi(&server);

}

The initialize_gpio() function is used to initialize the ESP32 I/O.

  1. Set the I/O pins as GPIO_MODE_OUTPUT, then set all the LEDs off by calling the gpio_set_level() function by passing a value of 0. This is demonstrated in the following code:
static void initialize_gpio(){

ESP_LOGI(TAG, "initialize GPIO");
// set gpio and its direction
gpio_pad_select_gpio(LAMP1);
gpio_set_direction(LAMP1, GPIO_MODE_OUTPUT);

gpio_pad_select_gpio(LAMP2);
gpio_set_direction(LAMP2, GPIO_MODE_OUTPUT);

gpio_pad_select_gpio(LAMP3);
gpio_set_direction(LAMP3, GPIO_MODE_OUTPUT);

// turn off lamps
gpio_set_level(LAMP1, 0);
gpio_set_level(LAMP2, 0);
gpio_set_level(LAMP3, 0);

lamp1_state = 0;
lamp2_state = 0;
lamp3_state = 0;
}
  1. Initialize a Wi-Fi service on ESP32 with the initialize_wifi() function. Furthermore, create the Wi-Fi AP with the SSID name, SMART-MOBILE, and SSID key, 123456789. Call the esp_wifi_set_mode() function with the WIFI_MODE_AP parameter.
  2. Set the Wi-Fi authentication mode as WIFI_AUTH_WPA_PSK. To handle the Wi-Fi events, pass the event_handler() function to the esp_event_loop_init() function.
  3. The following code shows the initialize_wifi() function implementation:
void initialize_wifi(void *arg)
{
ESP_LOGI(TAG, "initialize Wi-Fi ");

tcpip_adapter_ip_info_t ip_info;
//ESP_ERROR_CHECK(nvs_flash_init());
// set TCP range
tcpip_adapter_init();
tcpip_adapter_dhcps_stop(TCPIP_ADAPTER_IF_AP);
tcpip_adapter_get_ip_info(TCPIP_ADAPTER_IF_AP, &ip_info);
ip_info.ip.addr = inet_addr("192.168.0.1");
ip_info.gw.addr = inet_addr("192.168.0.0");
tcpip_adapter_set_ip_info(TCPIP_ADAPTER_IF_AP, &ip_info);
tcpip_adapter_dhcps_start(TCPIP_ADAPTER_IF_AP);
// wifi init
wifi_event_group = xEventGroupCreate();
ESP_ERROR_CHECK( esp_event_loop_init(event_handler, arg));
wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
ESP_ERROR_CHECK( esp_wifi_init(&cfg) );
ESP_ERROR_CHECK( esp_wifi_set_mode(WIFI_MODE_AP) );

In the wifi_config structure, we will store the Wi-Fi SSID of the AP that will be created and run by ESP8266:

 wifi_config_t wifi_config;
memcpy(wifi_config.ap.ssid, "SMART-MOBILE", sizeof("SMART-MOBILE"));
memcpy(wifi_config.ap.password, "123456789", sizeof("123456789"));
wifi_config.ap.ssid_len = strlen("SMART-MOBILE");
wifi_config.ap.max_connection = 1;
wifi_config.ap.authmode = WIFI_AUTH_WPA_PSK;
ESP_ERROR_CHECK(esp_wifi_set_config(ESP_IF_WIFI_AP, &wifi_config));
esp_wifi_start();
}

Now that the wifi_config structure is populated with all the information, it's time to start the Wi-Fi service by calling the esp_wifi_start function.

The event_handler() function is used to listen to all events from the Wi-Fi service on the ESP32 board. We listen to the following four events:

    • SYSTEM_EVENT_AP_STACONNECTED
    • SYSTEM_EVENT_STA_START
    • SYSTEM_EVENT_STA_GOT_IP 
    • SYSTEM_EVENT_STA_DISCONNECTED
  1. Start our web server by calling the start_webserver() function when we get an SYSTEM_EVENT_AP_STACONNECTED event from the Wi-Fi service:
static esp_err_t event_handler(void *ctx, system_event_t *event)
{
httpd_handle_t *server = (httpd_handle_t *) ctx;

switch (event->event_id) {
....
case SYSTEM_EVENT_AP_STACONNECTED:
xEventGroupSetBits(wifi_event_group, CONNECTED_BIT);
ESP_LOGI(TAG, "sta connect");

/* Start the web server */
if (*server == NULL) {
*server = start_webserver();
}
break;
  1. Then, stop the web server using the stop_webserver() function when we call the SYSTEM_EVENT_STA_DISCONNECTED event from the Wi-Fi service:
    switch (event->event_id) {
...
case SYSTEM_EVENT_STA_DISCONNECTED:
esp_wifi_connect();
/* Stop the web server */
if (*server) {
stop_webserver(*server);
*server = NULL;
}
break;
default:
break;
}
  1. Use the start_webserver() and stop_webserver() functions to start and stop our web server. We can use the httpd_start() function to start the HTTP server, and the httpd_stop() function to stop the HTTP server. We should register all HTTP requests on the ESP32 board. When we start our web server, we register all HTTP requests for /ping, /state, and /lamp using the httpd_register_uri_handler() function.

We register all HTTP requests on the ESP32 board by starting our web server, as shown in the following code:

httpd_handle_t start_webserver(void)
{
httpd_handle_t server = NULL;
httpd_config_t config = HTTPD_DEFAULT_CONFIG();

// Start the httpd server
ESP_LOGI(TAG, "Starting server on port: '%d'", config.server_port);
if (httpd_start(&server, &config) == ESP_OK) {
// Set URI handlers
ESP_LOGI(TAG, "Registering URI handlers");
httpd_register_uri_handler(server, &state);
httpd_register_uri_handler(server, &lamp_post);
httpd_register_uri_handler(server, &ping);

return server;
}

ESP_LOGI(TAG, "Error starting server!");
return NULL;
}

void stop_webserver(httpd_handle_t server)
{
// Stop the httpd server
httpd_stop(server);
}
  1. The /ping request is declared as a ping variable with httpd_uri_t.
  2. We implement the /ping request on the ping_get_handler() function. We then send a "pong!" message to the requester.

We can implement the ping_get_handler() function, as follows:

esp_err_t ping_get_handler(httpd_req_t *req)
{
const char* resp_str = (const char*) req->user_ctx;
httpd_resp_send(req, resp_str, strlen(resp_str));

return ESP_OK;
}

httpd_uri_t ping = {
.uri = "/ping",
.method = HTTP_GET,
.handler = ping_get_handler,
.user_ctx = "pong!"
};
  1. The /state request is declared as a state variable with httpd_uri_t.
  2. We then implement the /state request on the state_get_handler() function. We send all lamp states from the lamp1_state, lamp2_stateand lamp3_state variables, as follows:
esp_err_t state_get_handler(httpd_req_t *req)
{
char buf[15];

sprintf(buf,"1:%d,2:%d,3:%d",lamp1_state,lamp2_state,lamp3_state);
httpd_resp_send(req, buf, strlen(buf));
return ESP_OK;
}

httpd_uri_t state = {
.uri = "/state",
.method = HTTP_GET,
.handler = state_get_handler,
.user_ctx = NULL
};
  1. The /lamp request is declared as a lamp variable with httpd_uri_t. We implement the /lamp request on the state_get_handler() function. We then parse the request content and perform a task based on its content input:
/* An HTTP POST handler */
esp_err_t lamp_post_handler(httpd_req_t *req)
{
char buf[100];
int ret, remaining = req->content_len;
while (remaining > 0) {
buf[0] = '';
if ((ret = httpd_req_recv(req, &buf, 1)) <= 0) {
if (ret == HTTPD_SOCK_ERR_TIMEOUT) {
httpd_resp_send_408(req);
}
return ESP_FAIL;
}
buf[ret] = '';
ESP_LOGI(TAG, "Recv HTTP => %s", buf);
switch(buf[0]){
....
}
....
}

The input content is from steps 1 to 6: 

  • 1: turn on lamp1
  • 2: turn off lamp1 
  • 3: turn on lamp2
  • 4: turn off lamp2
  • 5: turn on lamp3
  • 6: turn off lamp3

The following code performs these tasks to check the status of the lamps, in our case let's take step 1:

        switch(buf[0]){
case '1':
ESP_LOGI(TAG, ">>> Turn on LAMP 1");
gpio_set_level(LAMP1, 1);
sprintf(buf,"Turn on LAMP 1");
httpd_resp_send_chunk(req, buf, strlen(buf));
lamp1_state = 1;
break;
...
// End response
httpd_resp_send_chunk(req, NULL, 0);
return ESP_OK;
}

Then, we call the pass lamp_post_handler() function into the httpd_uri_t object:

httpd_uri_t lamp_post = {
.uri = "/lamp",
.method = HTTP_POST,
.handler = lamp_post_handler,
.user_ctx = NULL
};

Finally, save this program.

We have now seen how to to build an ESP32 program, and have checked the status of the lamps to study their states.

Next, we will develop Android application.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.217.6.114