Circuit Diagram
Assemble this circuit first. An LED has been connected to GPIO13 through a common collector transistor. The red indicator LED on the board is used as an indicator that the ESP32 device is ready to accept a connection from the mobile phone, so we do not have to use a separate LED for this purpose.
Video Explanation (see it happen!)
Please watch the following youtube video to see how the project works.
Test Android App
We created an android app that you can use for testing the above circuit.
Or, use this link:
https://play.google.com/store/apps/details?id=in.hoven.electrator
Source Code
This is the code for main.c file. This file has to be uploaded to the ESP32 device. Steps for uploading have been given next.
Enter your own wifi ssid and passwords before you upload to ESP32!Copy this code and paste it in the "main.c" file. Then compile with Visual Studio Code Platform IO.
#define HIDE_LOG #define LOG_LOCAL_LEVEL ESP_LOG_DEBUG #include <string.h> #include "freertos/FreeRTOS.h" #include "freertos/task.h" #include "esp_wifi.h" #include "esp_log.h" #include "nvs_flash.h" #include "driver/gptimer.h" #include "esp_http_client.h" #include "esp_mac.h" #include "esp_http_server.h" #include "cJSON.h" #include "driver/gpio.h" #include "driver/ledc.h" // auth mode WPA2 for home wifi #define ESP_WIFI_SSID "--your-ssid--" #define ESP_WIFI_PASS "--your-password--" // WIFI MAC for ASP.NET Core Server, example 32a33489e4f61100, max 8 xx hex numbers char MAC_ADDRESS_WIFI[8 * 2 + 1] = { 0 }; //---------------- Event Messages -------------// static const int MAX_QUE_SIZE = 100; static const uint16_t MSG_WIFI_CONNECTED = 0x00; static const uint16_t MSG_WIFI_DISCONNECTED = 0x01; static const uint16_t MSG_WIFI_FAILED = 0x02; static const uint16_t MSG_TIMER_TICK = 0x03; static const uint16_t MSG_SAVE_LASTVAL = 0x04; static const uint16_t MSG_SET_VALUE = 0x05; //----------------log tags ---------------// static const char* TAGWIFI = "tag:Wifi station"; static const char* TAGTCP = "tag:Tcp"; static const char* TAGAPP = "tag:App"; static const char* TAGBLINK = "tag:Blink"; // -------------- storage ----------------// static const char* NS_STORAGE = "storage"; static const char* KEY_LAST_VAL = "last_value"; static uint8_t g_value = 0; //-------------------client commands from phone ----------// static const uint8_t CMD_QUERY_STATE = 224; static const uint8_t CMD_SAVE_STATE = 192; // ---------------event que--------------// // user defined event queue static QueueHandle_t gpio_evt_queue = NULL; void queue_message(uint16_t msg, uint16_t data) { // upper 16 bytes hold data, lower 16 bytes hold message code uint32_t m = ((data << 16) + msg); // RTOS https://www.freertos.org/a00119.html xQueueSendFromISR(gpio_evt_queue, (void*)&m, NULL); } //-----------------system timer events ---------------// gptimer_handle_t gptimer = NULL; static bool timer_isr_handler(gptimer_handle_t timer, const gptimer_alarm_event_data_t* edata, void* user_ctx) { queue_message(MSG_TIMER_TICK, 0); return false; } // ------------------ events of wifi driver --------------------- // #define ESP_MAXIMUM_RETRY 15 static int s_retry_num = 0; static void event_handler(void* arg, esp_event_base_t event_base, int32_t event_id, void* event_data) { if (WIFI_EVENT == event_base) { switch (event_id) { // station started case WIFI_EVENT_STA_START: { esp_wifi_connect(); } break; // wifi could not connect at all OR if it was connected, then some disruption occurred case WIFI_EVENT_STA_DISCONNECTED: { if (s_retry_num < ESP_MAXIMUM_RETRY) { vTaskDelay(4000 / portTICK_PERIOD_MS); esp_wifi_connect(); s_retry_num++; ESP_LOGI(TAGWIFI, "wifi state is disconnected, retrying..."); queue_message(MSG_WIFI_DISCONNECTED, 0); } else { // raise failure event queue_message(MSG_WIFI_FAILED, 0); } } break; case WIFI_EVENT_STA_CONNECTED: { wifi_event_sta_connected_t* event = (wifi_event_sta_connected_t*)event_data; ESP_LOGI(TAGWIFI, "Connected to: %s", (char*)event->ssid); s_retry_num = 0; } break; default: } } else if (IP_EVENT == event_base) { if (IP_EVENT_STA_GOT_IP == event_id) { ip_event_got_ip_t* event = (ip_event_got_ip_t*)event_data; ESP_LOGI(TAGWIFI, "Connected as IP: " IPSTR, IP2STR(&event->ip_info.ip)); s_retry_num = 0; queue_message(MSG_WIFI_CONNECTED, 0); } } } // -----------------forward declarations of helpers -----------// void tcp_server(); // called before restart void do_shutdown(); // ----------------- main -----------------// void app_main(void) { //---------------- basic setup and init-------------// ESP_LOGI(TAGAPP, "[APP] Startup.."); ESP_LOGI(TAGAPP, "[APP] Free memory: %lu bytes", esp_get_free_heap_size()); ESP_LOGI(TAGAPP, "[APP] IDF version: %s", esp_get_idf_version()); // levels NONE, ERROR, WARN, INFO, DEBUG, VERBOSE #ifdef HIDE_LOG esp_log_level_set("*", ESP_LOG_NONE); esp_log_level_set(TAGBLINK, ESP_LOG_INFO); #else esp_log_level_set("*", ESP_LOG_DEBUG); #endif 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); ESP_ERROR_CHECK(esp_netif_init()); ESP_ERROR_CHECK(esp_event_loop_create_default()); esp_register_shutdown_handler(do_shutdown); // ----------- event queue for messages ---------------// // message loop is running at the end of main gpio_evt_queue = xQueueCreate(MAX_QUE_SIZE, sizeof(uint32_t)); // -------------- configure wifi ----------// esp_netif_create_default_wifi_sta(); wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT(); ESP_ERROR_CHECK(esp_wifi_init(&cfg)); wifi_config_t wifi_config = { .sta = { .ssid = ESP_WIFI_SSID, .password = ESP_WIFI_PASS, // threshold auth mode WPA2 for home wifi .threshold.authmode = WIFI_AUTH_WPA2_PSK, .sae_pwe_h2e = WPA3_SAE_PWE_BOTH, }, }; // also saves to non-volatile-memory esp_wifi_set_config(WIFI_IF_STA, &wifi_config); 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)); ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA)); ESP_ERROR_CHECK(esp_wifi_start()); { uint8_t mac[8]; esp_efuse_mac_get_default(mac); sprintf(MAC_ADDRESS_WIFI, "%02x%02x%02x%02x%02x%02x%02x%02x", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5], mac[6], mac[7]); ESP_LOGI(TAGWIFI, "MAC Address %s", MAC_ADDRESS_WIFI); } //---------------- timer and its callback ISR ---------------------// { gptimer_config_t timer_config = { .clk_src = GPTIMER_CLK_SRC_DEFAULT, .direction = GPTIMER_COUNT_UP, // 1MHz, 1 tick = 1us .resolution_hz = 1 * 1000 * 1000, }; gptimer_new_timer(&timer_config, &gptimer); gptimer_alarm_config_t alarm_config = { // counter will reload with 0 on alarm event .reload_count = 0, // period = 1 x 1s @resolution 1MHz .alarm_count = 1 * 1000000, // enable auto-reload .flags.auto_reload_on_alarm = true, }; gptimer_set_alarm_action(gptimer, &alarm_config); gptimer_event_callbacks_t cbs = { // register user callback .on_alarm = timer_isr_handler, }; ESP_ERROR_CHECK(gptimer_register_event_callbacks(gptimer, &cbs, NULL)); } gptimer_enable(gptimer); gptimer_start(gptimer); //----------- configure IO Pins for output --------------- // const int BLINK_GPIO = GPIO_NUM_4; gpio_reset_pin(BLINK_GPIO); gpio_set_direction(BLINK_GPIO, GPIO_MODE_OUTPUT); // ----------- start tcp server -------------------// xTaskCreate(tcp_server, "tcp_server", 4096, NULL, 5, NULL); // --------------PWM setup ----------------------------// // Prepare and then apply the LEDC PWM timer configuration ledc_timer_config_t ledc_timer = { .speed_mode = LEDC_LOW_SPEED_MODE, .timer_num = LEDC_TIMER_0, // 3 - 13 for 5kHz .duty_resolution = LEDC_TIMER_7_BIT, // Set output frequency at 5 kHz .freq_hz = 5000, .clk_cfg = LEDC_AUTO_CLK }; ESP_ERROR_CHECK(ledc_timer_config(&ledc_timer)); // Prepare and then apply the LEDC PWM channel configuration ledc_channel_config_t ledc_channel = { .speed_mode = LEDC_LOW_SPEED_MODE, .channel = LEDC_CHANNEL_0, .timer_sel = LEDC_TIMER_0, .intr_type = LEDC_INTR_DISABLE, .gpio_num = GPIO_NUM_13, .duty = 0, .hpoint = 0 }; ESP_ERROR_CHECK(ledc_channel_config(&ledc_channel)); //----------- start the event message loop--------------- // uint32_t message_id; bool is_wifi_connected = false; while (true) { if (xQueueReceive(gpio_evt_queue, &message_id, portMAX_DELAY)) { uint16_t msg = (message_id & 0xff); switch (msg) { case MSG_WIFI_CONNECTED: { is_wifi_connected = true; } break; // raised multiple times during reconnection case MSG_WIFI_DISCONNECTED: { is_wifi_connected = false; } break; case MSG_WIFI_FAILED: { ESP_LOGI(TAGWIFI, "Wifi failed after %d attempts.", ESP_MAXIMUM_RETRY); goto gracefulRestart; } break; case MSG_TIMER_TICK: { static bool isOn = true; gpio_set_level(BLINK_GPIO, isOn = is_wifi_connected ? !isOn : false); // just a dummy blink of the red led ESP_LOGI(TAGBLINK, "timer ticking..."); ESP_LOGI(TAGBLINK, "timer ticking..."); } break; case MSG_SET_VALUE: { g_value = (uint8_t)(message_id >> 16); ESP_LOGD(TAGAPP, "data received %d", g_value); ledc_set_duty(LEDC_LOW_SPEED_MODE, LEDC_CHANNEL_0, (int)((126 * g_value) / 100)); ledc_update_duty(LEDC_LOW_SPEED_MODE, LEDC_CHANNEL_0); } break; case MSG_SAVE_LASTVAL: { // read last value from nvs nvs_handle_t h; if (ESP_OK == nvs_open(NS_STORAGE, NVS_READWRITE, &h)) { if (ESP_OK == nvs_set_u8(h, KEY_LAST_VAL, g_value)) { nvs_commit(h); ESP_LOGD(TAGAPP, "NVS cached = %d", g_value); } nvs_close(h); } } break; default: { ESP_LOGI(TAGAPP, "Unmapped message received . . ."); } break; } } } gracefulRestart: // cleanup - unregister esp_event_handler_instance_unregister(WIFI_EVENT, ESP_EVENT_ANY_ID, &instance_any_id); esp_event_handler_instance_unregister(IP_EVENT, IP_EVENT_STA_GOT_IP, &instance_got_ip); // restart esp_restart(); } // this function is called on a graceful restart or exit void do_shutdown() { // shutdown already done if (NULL == gptimer) { return; } ESP_LOGI(TAGAPP, "cleanup shutdown . . ."); gptimer_stop(gptimer); gptimer_disable(gptimer); gptimer_del_timer(gptimer); vQueueDelete(gpio_evt_queue); esp_wifi_stop(); gptimer = NULL; esp_unregister_shutdown_handler(do_shutdown); } void tcp_server() { { uint8_t lastValue = 0; // read last value from nvs nvs_handle_t h; if (ESP_OK == nvs_open(NS_STORAGE, NVS_READWRITE, &h)) { if (ESP_OK != nvs_get_u8(h, KEY_LAST_VAL, &lastValue)) { lastValue = 0; } nvs_close(h); } g_value = lastValue; queue_message(MSG_SET_VALUE, (uint16_t)lastValue); } ESP_LOGD(TAGAPP, "NVS last_value = %d", g_value); int keepAlive = 1; int keepIdle = 5; int keepInterval = 5; int keepCount = 3; int PORT = 50000; struct sockaddr_storage dest_addr; struct sockaddr_in* dest_addr_ip4 = (struct sockaddr_in*)&dest_addr; dest_addr_ip4->sin_addr.s_addr = htonl(INADDR_ANY); dest_addr_ip4->sin_family = AF_INET; dest_addr_ip4->sin_port = htons(PORT); int attempts = 0; while (attempts++ < 5) { int listen_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_IP); if (listen_socket >= 0) { ESP_LOGI(TAGTCP, "Socket created"); attempts = 0; int opt = 1; setsockopt(listen_socket, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)); int err = bind(listen_socket, (struct sockaddr*)&dest_addr, sizeof(dest_addr)); if (0 == err) { ESP_LOGI(TAGTCP, "Socket bound, port %d", PORT); err = listen(listen_socket, 1); if (0 == err) { int sock = -1; do { ESP_LOGI(TAGTCP, "waiting for connection..."); struct sockaddr_storage source_addr; socklen_t addr_len = sizeof(source_addr); sock = accept(listen_socket, (struct sockaddr*)&source_addr, &addr_len); if (sock < 0) { ESP_LOGE(TAGTCP, "Unable to accept connection: errno %d", errno); } else { ESP_LOGI(TAGTCP, "client connected!"); // Set tcp keepalive option setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, &keepAlive, sizeof(int)); setsockopt(sock, IPPROTO_TCP, TCP_KEEPIDLE, &keepIdle, sizeof(int)); setsockopt(sock, IPPROTO_TCP, TCP_KEEPINTVL, &keepInterval, sizeof(int)); setsockopt(sock, IPPROTO_TCP, TCP_KEEPCNT, &keepCount, sizeof(int)); unsigned char data; while (recv(sock, &data, sizeof(data), 0) > 0) { // signals from client are negative numbers if (data & 128) { // 1-1-1-x [don't care] read g_value if (data == CMD_QUERY_STATE) { ESP_LOGI(TAGTCP, "ping received sending %d...", g_value); if (send(sock, &g_value, sizeof(g_value), 0) <= 0) break; } // 1-1-x [don't care] save last value else if (data == CMD_SAVE_STATE) { // MSG_SAVE_LASTVAL queue_message(MSG_SAVE_LASTVAL, 0); } // it's a ping else { unsigned char resp = 0x1; if (send(sock, &resp, sizeof(resp), 0) <= 0) break; } } else { queue_message(MSG_SET_VALUE, (uint16_t)data); } }; ESP_LOGI(TAGTCP, "client disconnected"); ESP_LOGI(TAGTCP, "shutting down connection..."); shutdown(sock, 0); close(sock); } } while (sock >= 0); } else { ESP_LOGE(TAGTCP, "Error occurred during listen: errno %d", errno); } } else { ESP_LOGE(TAGTCP, "Socket unable to bind: errno %d", errno); } close(listen_socket); } ESP_LOGE(TAGTCP, "Socket closed. Retrying after 8 seconds..."); // very rarely expected to reach here. so wait 8 seconds vTaskDelay(8000 / portTICK_PERIOD_MS); } vTaskDelete(NULL); }
How to Upload to ESP32
Follow the third video of this playlist to upload "main.c" file.
This Blog Post/Article "(ESP32 Project) Light Dimmer and Intensity Control of LED" by Parveen is licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License.