/* * tempstick_wifi_server.c * * Created on: Jul 28, 2023 * Author: Sword */ #include "esp_system.h" #include "sdkconfig.h" #include "esp_wifi.h" #include "esp_netif.h" #include "esp_event.h" #include "freertos/event_groups.h" #include "lwip/sockets.h" #include "lwip/dns.h" #include "lwip/netdb.h" #include "esp_tls_crypto.h" #include "esp_mac.h" #include "wifi_Client.h" #include "wifi_WebServer.h" #include "wifi_Init.h" #include "comms.h" #include "data_processing.h" #include "hmi.h" #include "nvm.h" #include "modem.h" #include "i2c_sensors.h" #include "mbedtls/base64.h" #include #include #include "lwip/tcp.h" #include "lwip/udp.h" #if (WIFI_NEEDED == 1) static const char* TAG = "SERVER"; #define LOG_LOCAL_LEVEL ESP_LOG_INFO #include "esp_log.h" //#define BOARD_TEST #define SSID_MAX_LENGTH 32 // Max length corrected to 32 bytes in board version 3.1.1 in ESP8266WiFiSTA.cpp file #define PASSWORD_MAX_LENGTH 64 // Set by the ESP32 typedef enum { WLAN_NOT_TESTING, WLAN_WIFI_CONNECTING, WLAN_WIFI_WAITING_TO_CONNECT, WLAN_WIFI_CONNECTED, WLAN_TEST_SUCCESS, WLAN_CONNECT_TO_SERVER_2, WLAN_SERVER_1_WAITING_TO_CONNECT, WLAN_SERVER_2_WAITING_TO_CONNECT }wlanTesting_t; typedef enum { WLAN_NO_ERROR, WLAN_SSID_TOO_LONG, WLAN_PASSWORD_TOO_LONG, WLAN_FAILED_WIFI, WLAN_FAILED_INTERNET, WLAN_SSID_EMPTY }wlanError_t; typedef enum { WLAN_IDLE, WLAN_WORKING, WLAN_ERROR, WLAN_DONE, WLAN_TRY_WIFI, WLAN_TRY_INTERNET }wlanStatus_t; extern uint32_t g_version; uint8_t g_onboarding_status = 99; bool g_onboardingCompleted = false; bool g_wlanOnboardingDone = false; bool g_pageServed = false; uint32_t g_onboardingStepStartTime; // Used for on-boarding time-out. uint32_t g_onboardingStepTimeout; // Used for on-boarding time-out. /*char g_wlanPasswordStr[PASSWORD_MAX_LENGTH + 1] = {0}; char g_wlanSsidStr[SSID_MAX_LENGTH + 1] = {0};*/ char g_wlanTargetSsid = 0; wlanError_t g_wlanError = WLAN_NO_ERROR; wlanStatus_t g_wlanStatus = WLAN_IDLE; wlanTesting_t g_wlanTesting = WLAN_NOT_TESTING; wlanTesting_t g_wlanTestingPreviousState = WLAN_NOT_TESTING; bool g_servedRoot; bool g_servedSid; bool g_servedStatus; static httpd_handle_t serverHandle; static bool acc_registered; extern uint8_t device_wifi_onboarded; /* Function to filter multipart form data */ //////////////////////////////////////////////////////////// // Function to extract the value between two boundaries void extract_field_value(const char *start, const char *end, char *result, int max_length) { int length = end - start; if (length > max_length) { length = max_length; } strncpy(result, start, length); // TODO : Test when length is exceeded result[length] = '\0'; // Null-terminate the string } // Function to find and extract SSID and Password from the content void extract_ssid_and_password(const char *content, char *ssid, char *password) { const char *ssid_start, *ssid_end; const char *password_start, *password_end; // Find the SSID field ssid_start = strstr(content, "Content-Disposition: form-data; name=\"ssid\""); if (ssid_start) { ssid_start = strstr(ssid_start, "\r\n\r\n"); // Skip the header and find the actual value if (ssid_start) { ssid_start += 4; // Skip the "\r\n\r\n" part ssid_end = strstr(ssid_start, "\r\n"); if (ssid_end) { extract_field_value(ssid_start, ssid_end, ssid, SSID_MAX_LENGTH); } } } // Find the Password field password_start = strstr(content, "Content-Disposition: form-data; name=\"password\""); if (password_start) { password_start = strstr(password_start, "\r\n\r\n"); // Skip the header and find the actual value if (password_start) { password_start += 4; // Skip the "\r\n\r\n" part password_end = strstr(password_start, "\r\n"); if (password_end) { extract_field_value(password_start, password_end, password, PASSWORD_MAX_LENGTH); } } } } ////////////////////////////////////end ////////////////////// /* Function to get millis */ uint32_t get_millis(void) { TickType_t ticks = xTaskGetTickCount(); return ((ticks * 1000) / configTICK_RATE_HZ); } /* Converts a hex character to its integer value */ char from_hex(char ch) { return isdigit(ch) ? ch - '0' : tolower(ch) - 'a' + 10; } /* Converts an integer value to its hex character*/ char to_hex(char code) { static char hex[] = "0123456789abcdef"; return hex[code & 15]; } char *url_decode(char *str) { char *pstr = str, *buf = pvPortMalloc(strlen(str) + 1), *pbuf = buf; while (*pstr) { if (*pstr == '%') { if (pstr[1] && pstr[2]) { *pbuf++ = from_hex(pstr[1]) << 4 | from_hex(pstr[2]); pstr += 2; } } else if (*pstr == '+') { *pbuf++ = ' '; } else { *pbuf++ = *pstr; } pstr++; } *pbuf = '\0'; return buf; } #ifdef BOARD_TEST const char *main_resp = " Temp Stick Setup - Ideal Sciences

Temp Stick Setup

Step 1 Select WiFi Network
Step 2 Test Connection
Step 3 Complete

Select a WiFi Network

(Leave blank if no password required)

Test Connection

Give us about 30 seconds as we test your WiFi connection

WiFi Setup Complete

The sensor successfully connected to your WiFi network

Let's assign your sensor to an Ideal Sciences account:

-or-


Create Account

Login

The email and/or password you submitted is incorrect.

Account Setup Complete


SENSOR ID:

MAC ADDR:

Board Testing

Battery
Light
ENS210
MC3419
MCP9600T
BG77

LEDs

"; #else const char *main_resp = " Temp Stick Setup - Ideal Sciences

Temp Stick Setup

Step 1 Select WiFi Network
Step 2 Test Connection
Step 3 Complete

Select a WiFi Network

(Leave blank if no password required)

Test Connection

Give us about 30 seconds as we test your WiFi connection

WiFi Setup Complete

The sensor successfully connected to your WiFi network

Let's assign your sensor to an Ideal Sciences account:

-or-


Create Account

Login

The email and/or password you submitted is incorrect.

Account Setup Complete


SENSOR ID:

MAC ADDR:

"; #endif static esp_err_t root_handler(httpd_req_t *req) { httpd_resp_send(req, main_resp, strlen(main_resp)); vTaskDelay(50/portTICK_PERIOD_MS); g_onboardingStepStartTime = get_millis(); g_onboardingStepTimeout = (10 * 60 * 1000); // 10 minutes. return ESP_OK; } static const httpd_uri_t root = { .uri = "/", .method = HTTP_GET, .handler = root_handler, .user_ctx = NULL }; const char *promise_min_js = "(function(a){function b(){this._callbacks=[];}b.prototype.then=function(a,c){var d;if(this._isdone)d=a.apply(c,this.result);else{d=new b();this._callbacks.push(function(){var b=a.apply(c,arguments);if(b&&typeof b.then==='function')b.then(d.done,d);});}return d;};b.prototype.done=function(){this.result=arguments;this._isdone=true;for(var a=0;a=300)&&j.status!==304);h.done(a,j.responseText,j);}};j.send(k);return h;}function h(a){return function(b,c,d){return g(a,b,c,d);};}var i={Promise:b,join:c,chain:d,ajax:g,get:h('GET'),post:h('POST'),put:h('PUT'),del:h('DELETE'),ENOXHR:1,ETIMEOUT:2,ajaxTimeout:0};if(typeof define==='function'&&define.amd)define(function(){return i;});else a.promise=i;})(this);"; static esp_err_t promise_min_js_handler(httpd_req_t *req) { /* Respond with empty body */ httpd_resp_send(req, promise_min_js, strlen(promise_min_js)); vTaskDelay(50/portTICK_PERIOD_MS); g_onboardingStepStartTime = get_millis(); g_onboardingStepTimeout = (10 * 60 * 1000); // 10 minutes. return ESP_OK; } static const httpd_uri_t promise_min_js_t = { .uri = "/promise.min.js", .method = HTTP_GET, .handler = promise_min_js_handler, .user_ctx = NULL }; const char *ki_min_js = "!function(a,b,c,d){function e(c){b.push.apply(this,c&&c.nodeType?[c]:\"\"+c===c?a.querySelectorAll(c):d)}$=function(b){return/^f/.test(typeof b)?/c/.test(a.readyState)?b():$(a).on(\"DOMContentLoaded\",b):new e(b)},$[c]=e[c]=$.fn=e.fn={length:0,on:function(a,b){return this.each(function(c){c.addEventListener(a,b)})},off:function(a,b){return this.each(function(c){c.removeEventListener(a,b)})},each:function(a,c){return b.forEach.call(this,a,c),this},splice:b.splice}}(document,[],\"prototype\");"; static esp_err_t ki_min_js_handler(httpd_req_t *req) { /* Respond with empty body */ httpd_resp_send(req, ki_min_js, strlen(ki_min_js)); vTaskDelay(50/portTICK_PERIOD_MS); g_onboardingStepStartTime = get_millis(); g_onboardingStepTimeout = (10 * 60 * 1000); // 10 minutes. return ESP_OK; } static const httpd_uri_t ki_min_js_t = { .uri = "/ki.min.js", .method = HTTP_GET, .handler = ki_min_js_handler, .user_ctx = NULL }; const char *style = "body{font-family: Arial, sans-serif; background-color: #eaeaea; padding: 0; margin: 0;}h2{margin: 0 0 10px 0;}label{display: block; margin: 10px 0px;}button{font-size: 18px; font-family: DroidSans, Arial, sans-serif; border: 0; background-color: #0b5bb5; color: #fff; padding: 15px; cursor: pointer; display: block; width: 100%;}button:disabled{background-color: #eaeaea; color:#aaaaaa; cursor:not-allowed;}.header{padding: 15px 0; background: #111; color: #fff; margin-bottom: 8px;}.header h1{font-size:26px; line-height: 26px; font-weight: bold; margin: 0; text-align: center;}.container{padding: 15px;}#setup-steps{list-style-type: none; padding: 0px; margin: 0px; position: relative;}#setup-steps li{position: absolute; display: inline-block;}#setup-steps li span{padding: 10px; font-size: 18px; background-color: #a8a8a8; color: white; font-weight: normal; border-radius: 20px; min-width: 20px; display: inline-block; text-align: center;}#setup-steps li.active span{/*background-color: #7ed600;*/ background-color: #0b5bb5; font-weight: bold;}#setup-step-1{left:0px;}#setup-step-2{left:42%;}#setup-step-3{right:0px;}input:not([type=\"radio\"]):not([type=\"checkbox\"]), select{font-size: 18px; font-family: DroidSans, Arial, sans-serif; padding: 10px; width: 95%}input[type=\"checkbox\"]{float: left; margin-right: 10px;}.col_50{width: 49%; display: inline-block;}.section{transition: margin-left ease-in 0.5s}.step_name{display: inline-block; min-width: 260px; background-color: #a8a8a8; color: white; padding: 10px; display: inline-block; text-shadow: 1px 1px 1px black; position: relative;}.step_name.active{background-color: #7ed600}.show-for-medium-down{display:none;}@media screen and (max-width: 800px){.col_50{width: 100%; display: block; margin-bottom: 15px;}.section{width: 100%; max-width: 100% !important;}.show-for-medium-down{display:block;}}@media screen and (max-width:1023px){.hide_for_medium_down{display:none;}}.step_name .step_num{font-weight: bold; font-size: 30px; text-transform: uppercase;}.step_name .step_label{position: absolute; right: 15px; top: 18px;}.align-top{vertical-align: top;}.loader{content:url('data:image/gif;base64,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');}.hide{display:none;}.button_account{background-color: white; color: #444; padding: 10px 8px; border: 1px solid #444; margin-right: 15px;}.button_account.active{background-color: #0b5bb5; color:white;}.red{color:red;}"; static esp_err_t style_css_handler(httpd_req_t *req) { /* Respond with empty body */ httpd_resp_send(req, style, strlen(style)); vTaskDelay(50/portTICK_PERIOD_MS); g_onboardingStepStartTime = get_millis(); g_onboardingStepTimeout = (10 * 60 * 1000); // 10 minutes. return ESP_OK; } static const httpd_uri_t style_css = { .uri = "/style.css", .method = HTTP_GET, .handler = style_css_handler, .user_ctx = NULL }; char *sid = "{\"sid\":\"%s\",\"mac\":\"%s\",\"version\":\"%ld\"}"; char *sid_data; static esp_err_t sid_handler(httpd_req_t *req) { char mac_str[20]; uint8_t mac_base[6] = {0}; g_onboardingStepStartTime = get_millis(); g_onboardingStepTimeout = (10 * 60 * 1000); // 10 minutes. esp_efuse_mac_get_default(mac_base); esp_read_mac(mac_base, ESP_MAC_WIFI_STA); sprintf(mac_str, "%02X%02X%02X%02X%02X%02X", mac_base[0], mac_base[1], mac_base[2], mac_base[3], mac_base[4], mac_base[5]); sid_data = pvPortMalloc(100 * sizeof(char)); sprintf(sid_data, sid, mac_str, mac_str,g_version); httpd_resp_send(req, sid_data, strlen(sid_data)); vTaskDelay(50/portTICK_PERIOD_MS); vPortFree(sid_data); return ESP_OK; } static const httpd_uri_t sid_t = { .uri = "/sid", .method = HTTP_GET, .handler = sid_handler, .user_ctx = NULL }; char *scan_response; static esp_err_t wirelessNetworks_handler(httpd_req_t *req) { uint16_t apCount = 0; wifi_ap_record_t *list = 0; char temp[50]; bool duplicateSsid; int x; ESP_LOGI(TAG,"OnBoarding : Step 1 > Scanning for Networks... Waiting for User to enter SSID and Password and click 'Next'..."); g_onboardingStepStartTime = get_millis(); g_onboardingStepTimeout = (10 * 60 * 1000); // 10 minutes. scan_response = pvPortMalloc(1024 * sizeof(char)); if( (WLAN_IDLE == g_wlanStatus) || (WLAN_DONE == g_wlanStatus) ) { wifi_scan_start(&apCount, &list); } ESP_LOGI(TAG,"Access points found: %d",apCount); if(apCount) { strcpy(scan_response, "["); for(int ap_idx = 0; ap_idx < apCount; ap_idx++) { // CHECK FOR DUPLICATE SSIDs. (SAME NETWORK, BUT SOMETIMES ON A DIFFERENT CHANNEL, SOMETIMES ON SAME CHANNEL) duplicateSsid = false; for(x=0; x 0) { strcat(scan_response, ","); } strcat(scan_response, "{\"ssid\":\""); strcat(scan_response, (char *)list[ap_idx].ssid); strcat(scan_response, "\",\"password\":"); if(list[ap_idx].group_cipher == WIFI_CIPHER_TYPE_NONE) { sprintf(temp, "0"); } else { sprintf(temp, "1"); } strcat(scan_response, temp); /*sprintf(temp, "%d", list[ap_idx].rssi); strcat(scan_response, "\",\"rssi\":"); strcat(scan_response, temp);*/ strcat(scan_response, "}"); } ESP_LOGI(TAG,"Index: %d, SSID: %s, Encryption: %d, RSSI: %d",ap_idx,(char *)list[ap_idx].ssid,list[ap_idx].group_cipher,list[ap_idx].rssi); } strcat(scan_response, "]"); //vPortFree(list); } else { strcpy(scan_response, "{\"error\":\"No available wifi networks\"}"); } httpd_resp_send(req, scan_response, strlen(scan_response)); vTaskDelay(100/portTICK_PERIOD_MS); vPortFree(scan_response); return ESP_OK; } static const httpd_uri_t wirelessNetworks = { .uri = "/wirelessNetworks", .method = HTTP_GET, .handler = wirelessNetworks_handler, .user_ctx = NULL }; static esp_err_t wlan_handler(httpd_req_t *req) { char *content; char temp[30]; memset(temp, 0, 30); ESP_LOGI(TAG,"OnBoarding : Step 2 > Testing Connection..."); g_onboardingStepStartTime = get_millis(); g_onboardingStepTimeout = (10 * 60 * 1000); // 10 minutes. content = pvPortMalloc(300 * sizeof(char)); memset(content, 0, 300); httpd_req_recv(req, content, 300); if(strlen(content)) { g_wlanError = WLAN_NO_ERROR; startOnboardingGetSsidAndPassword(content); Connect_wifi_sta(WIFI_CLIENT_AP_MODE); /* Start LED blinking */ if(wifi_station_connected()) { // STORE WIFI CREDENTIALS TEMPORARILY. THEY ARE NOT COMMITTED TO FLASH UNTIL /restart memset(wifi_get_ssidA(), 0, (SSID_MAX_LENGTH + 1)); memset(wifi_get_pswdA(), 0, (PASSWORD_MAX_LENGTH + 1)); memset(wifi_get_ssidB(), 0, (SSID_MAX_LENGTH + 1)); memset(wifi_get_pswdB(), 0, (PASSWORD_MAX_LENGTH + 1)); strncpy(wifi_get_ssidA(), wifi_get_ssid(), SSID_MAX_LENGTH); strncpy(wifi_get_pswdA(), wifi_get_pswd(), PASSWORD_MAX_LENGTH); // SAVE AP'S MAC ADDR //data_set_ap_mac_addr(data_get_ap_mac_addr()); // ESP_LOGI(TAG,"find heap size"); // int mem = esp_get_free_heap_size(); // ESP_LOGI(TAG, "Free heap size: %u", mem); vTaskDelay(2000/portTICK_PERIOD_MS); ESP_LOGI(TAG, "Attempting connection to google.com"); if(ESP_OK == http_client_test("https://www.google.com")) { ESP_LOGI(TAG, "Connection to internet successful.\nOnBoarding : Step 2 > Wifi Connection Success!\nOnBoarding : Step 3 > Waiting for User to create or assign an account..."); g_onboarding_status = 9; } else { ESP_LOGI(TAG, "Connection to google.com failed.\n\nAttempting connection to tempstick.com"); vTaskDelay(2000/portTICK_PERIOD_MS); if(ESP_OK == http_client_test("http://www.tempstick.com")) { ESP_LOGI(TAG, "Connection to internet successful.\nOnBoarding : Step 2 > Wifi Connection Success!\nOnBoarding : Step 3 > Waiting for User to create or assign an account..."); g_onboarding_status = 9; } else { ESP_LOGI(TAG, "Connection to tempstick.com failed.\nUnable to connect to the internet."); g_onboarding_status = 1; } } } else { ESP_LOGI(TAG,"Failed to connect to WiFi. No SSID available."); g_onboarding_status = 0; } } vPortFree(content); httpd_resp_send(req, "", 0); vTaskDelay(50/portTICK_PERIOD_MS); return ESP_OK; } static const httpd_uri_t wlan = { .uri = "/wlan", .method = HTTP_POST, .handler = wlan_handler, .user_ctx = NULL }; static esp_err_t status_handler(httpd_req_t *req) { char response[10]; g_onboardingStepStartTime = get_millis(); g_onboardingStepTimeout = (10 * 60 * 1000); // 10 minutes. strcpy(response, ""); strcpy(response, "0"); switch(g_onboarding_status) { case 0: strcpy(response, "0"); break; case 1: strcpy(response, "1"); break; case 9: // WIFI CREDENTIALS WORKED strcpy(response, "9"); break; case 99: strcpy(response, "99"); break; default: strcpy(response, "99"); break; } httpd_resp_send(req, response, strlen(response)); vTaskDelay(50/portTICK_PERIOD_MS); return ESP_OK; } static const httpd_uri_t status = { .uri = "/status", .method = HTTP_GET, .handler = status_handler, .user_ctx = NULL }; static esp_err_t acc_handler(httpd_req_t *req) { char response[180];// = (char *)pvPortMalloc(100 * sizeof(char)); char t[50];//= (char *)pvPortMalloc(50 * sizeof(char)); char e[50];// = (char *)pvPortMalloc(50 * sizeof(char)); char p[50];// = (char *)pvPortMalloc(50 * sizeof(char)); char pa[50];// = (char *)pvPortMalloc(50 * sizeof(char)); char content[100];// = (char *)pvPortMalloc(100 * sizeof(char)); g_onboardingStepStartTime = get_millis(); g_onboardingStepTimeout = (10 * 60 * 1000); // 10 minutes. bool restart_cond = false; memset(content, 0, 100); memset(t, 0, 50); memset(e, 0, 50); memset(p, 0, 50); memset(pa, 0, 50); httpd_req_recv(req, content, 100); if(strlen(content)) { //ESP_LOGI(TAG, "%s", content); char *h = strtok(content, "&"); strcpy(t, h); h = strtok(NULL, "&"); strcpy(e, h); h = strtok(NULL, "&"); strcpy(p, h); h = strtok(NULL, "&"); if(h != NULL) { strcpy(pa, h); } h = strtok(t, "="); if(!strcmp(h, "t")) { h = strtok(NULL, "="); strcpy(t, h); } h = strtok(e, "="); if(!strcmp(h, "e")) { h = strtok(NULL, "="); strcpy(e, h); } h = strtok(p, "="); if(!strcmp(h, "p")) { h = strtok(NULL, "="); strcpy(p, h); } if(!strcmp(t, "c")) { h = strtok(pa, "="); if(!strcmp(h, "pa")) { h = strtok(NULL, "="); strcpy(pa, h); } } else { strcpy(pa, ""); } //ESP_LOGI(TAG, "t=%s e=%s p=%s pa=%s", t, e, p, pa); } if(!registerAcctWithServer(t, e, p, pa, response, strlen(response))) { ESP_LOGI(TAG,"Connection to server failed."); restart_cond = true; } ESP_LOGI(TAG,"Server response is: %s",response); httpd_resp_send(req, response, strlen(response)); if(restart_cond) { esp_restart(); } //vTaskDelay(200/portTICK_PERIOD_MS); /*vPortFree(t); vPortFree(e); vPortFree(p); vPortFree(pa); vPortFree(urlConnectionString); vPortFree(content); vPortFree(post_params); vPortFree(mac_str); vPortFree(response);*/ //start_remaining_tasks(); return ESP_OK; } static const httpd_uri_t acc = { .uri = "/acc", .method = HTTP_POST, .handler = acc_handler, .user_ctx = NULL }; static esp_err_t restart_handler(httpd_req_t *req) { if(acc_registered) { ESP_LOGI(TAG,"OnBoarding : Step 3 > Account Creation Success!"); httpd_resp_send(req, "", 0); #ifdef STORING_TO_NVM /* CLEAR SIMULATED EEPROMS AND HISTORY SECTORS */ nvm_clear(); #endif g_onboardingCompleted = true; /* Set the wifi-onboarded flag to be true */ device_wifi_onboarded = true; g_onboardingStepStartTime = get_millis(); g_onboardingStepTimeout = (10 * 60 * 1000); // 10 minutes. } else { ESP_LOGI(TAG,"OnBoarding : Step 3 > Try to register the account again"); } vTaskDelay(50/portTICK_PERIOD_MS); return ESP_OK; } static const httpd_uri_t restart = { .uri = "/restart", .method = HTTP_POST, .handler = restart_handler, .user_ctx = NULL }; static esp_err_t getWlan_handler(httpd_req_t *req) { char response[100]; g_onboardingStepStartTime = get_millis(); g_onboardingStepTimeout = (10 * 60 * 1000); // 10 minutes. sprintf(response,"{\"wlanA\":\"%s\",\"wlanB\":\"%s\"}",wifi_get_ssidA(),wifi_get_ssidB()); httpd_resp_send(req, response, strlen(response)); vTaskDelay(50/portTICK_PERIOD_MS); return ESP_OK; } static const httpd_uri_t getWlan = { .uri = "/get/wlan", .method = HTTP_GET, .handler = getWlan_handler, .user_ctx = NULL }; static esp_err_t setWlan_handler(httpd_req_t *req) { char *content; char *pPassword; char *pSsid; char val[10]; char buf[100]; int ret, buflen; g_onboardingStepStartTime = get_millis(); g_onboardingStepTimeout = (10 * 60 * 1000); // 10 minutes. content = pvPortMalloc(100 * sizeof(char)); memset(content, 0, 100); httpd_req_recv(req, content, 100); if( (WLAN_IDLE == g_wlanStatus) || (WLAN_DONE == g_wlanStatus) ) { ESP_LOGI(TAG,"Get SSID and password"); g_wlanTargetSsid = 0; // Default /*memset(g_wlanSsidStr, 0, (SSID_MAX_LENGTH + 1)); memset(g_wlanPasswordStr, 0, (PASSWORD_MAX_LENGTH + 1));*/ wifi_update_credentials((char*)0, (char*)0); g_wlanError = WLAN_NO_ERROR; // Update global copy of SSID and password for wlan testing state machine to be able to store the SSID and password after successful testing. startOnboardingGetSsidAndPassword(content); // Check to see if WiFi credentials testing is requested if(WLAN_NO_ERROR == g_wlanError) { // Determine target SSID and password buflen = httpd_req_get_url_query_len(req) + 1; if (buflen > 1) { ret = httpd_req_get_url_query_str(req, buf, buflen); if (ret == ESP_OK) { char param[32]; if (httpd_query_key_value(buf, "wlan", param, sizeof(param)) == ESP_OK) { if (strcmp(param, "A") == 0) { g_wlanTargetSsid = 'A'; } else if (strcmp(param, "B") == 0) { g_wlanTargetSsid = 'B'; } } } } // Update global copy of SSID and password for wlan testing state machine to be able to store the SSID and password after successful testing. /*strncpy(g_wlanSsidStr, ssidStr, SSID_MAX_LENGTH); strncpy(g_wlanPasswordStr, passwordStr, PASSWORD_MAX_LENGTH);*/ //wifi_update_credentials(ssidStr, passwordStr); // Determine if WiFi testing is requested if(ESP_OK == httpd_req_get_hdr_value_str(req,"test",val,strlen(val))) { if(0 == strcmp("1", val)) { ESP_LOGI(TAG,"Begin testing WiFi credentials"); // Begin testing WiFi credentials if(wifi_station_connected()) // Disconnect if WiFi is already connected. { wifi_sta_disconnecting(); vTaskDelay(10); // Delay after disconnect function call } vTaskDelay(10); // Most of the other WiFi routines require a minimum of 4 millisecond vTaskDelay. This delay is added just to be safe. //WiFi.config(IPAddress(0,0,0,0), IPAddress(0,0,0,0), IPAddress(0,0,0,0), IPAddress(0,0,0,0), IPAddress(0,0,0,0)); if (/*0 != passwordStr[0]*/wifi_get_pswd()) Connect_wifi_sta(WIFI_CLIENT_AP_MODE); else Connect_wifi_sta(WIFI_CLIENT_AP_MODE); vTaskDelay(10); // Update WLAN validation state g_wlanStatus = WLAN_TRY_WIFI; g_wlanError = WLAN_NO_ERROR; g_wlanTesting = WLAN_WIFI_CONNECTING; // Set the status here instead of in the wifi testing state machine, because the smart phone app could poll the status before the state machine could set it. } } if(WLAN_WIFI_CONNECTING != g_wlanTesting) // Is testing being skipped? { ESP_LOGI(TAG,"WiFi credentials testing skipped"); pSsid = NULL; pPassword = NULL; // Prevent compiler error // Save WiFi credentials if('A' == g_wlanTargetSsid) { pSsid = wifi_get_ssidA(); pPassword = wifi_get_pswdA(); } if('B' == g_wlanTargetSsid) { pSsid = wifi_get_ssidB(); pPassword = wifi_get_pswdB(); } if(NULL != pSsid) // Make sure the pointers are set. { memset(pSsid, 0, (SSID_MAX_LENGTH + 1)); memset(pPassword, 0, (PASSWORD_MAX_LENGTH + 1)); strncpy(pSsid, wifi_get_ssid(), SSID_MAX_LENGTH); strncpy(pPassword, wifi_get_pswd(), PASSWORD_MAX_LENGTH); //writeWifiCredentialsToFlash(); } } } } vTaskDelay(50/portTICK_PERIOD_MS); return ESP_OK; } static const httpd_uri_t setWlan = { .uri = "/set/wlan", .method = HTTP_GET, .handler = setWlan_handler, .user_ctx = NULL }; static esp_err_t deleteWlanA_handler(httpd_req_t *req) { char response[100]; char *sidA = wifi_get_ssidA(); char *pwdA = wifi_get_ssidA(); char *sidB = wifi_get_ssidB(); char *pwdB = wifi_get_pswdB(); g_onboardingStepStartTime = get_millis(); g_onboardingStepTimeout = (10 * 60 * 1000); // 10 minutes. // Delete SSID A memset(sidA, 0, (SSID_MAX_LENGTH + 1)); memset(pwdA, 0, (PASSWORD_MAX_LENGTH + 1)); if(sidB) // If SSID B exists, bump it up to become SSID A { strncpy(sidA, sidB, SSID_MAX_LENGTH); strncpy(pwdA, sidB, PASSWORD_MAX_LENGTH); memset(sidB, 0, (SSID_MAX_LENGTH + 1)); memset(pwdB, 0, (PASSWORD_MAX_LENGTH + 1)); } //writeWifiCredentialsToFlash(); strcpy(response,"{\"success\":\"1\"}"); httpd_resp_send(req, response, strlen(response)); vTaskDelay(50/portTICK_PERIOD_MS); return ESP_OK; } static const httpd_uri_t deleteWlanA = { .uri = "/delete/wlanA", .method = HTTP_GET, .handler = deleteWlanA_handler, .user_ctx = NULL }; static esp_err_t deleteWlanB_handler(httpd_req_t *req) { char response[100]; char *sidB = wifi_get_ssidB(); char *pwdB = wifi_get_pswdB(); g_onboardingStepStartTime = get_millis(); g_onboardingStepTimeout = (10 * 60 * 1000); // 10 minutes. // Delete SSID B memset(sidB, 0, (SSID_MAX_LENGTH + 1)); memset(pwdB, 0, (PASSWORD_MAX_LENGTH + 1)); //writeWifiCredentialsToFlash(); strcpy(response,"{\"success\":\"1\"}"); httpd_resp_send(req, response, strlen(response)); vTaskDelay(50/portTICK_PERIOD_MS); return ESP_OK; } static const httpd_uri_t deleteWlanB = { .uri = "/delete/wlanB", .method = HTTP_GET, .handler = deleteWlanB_handler, .user_ctx = NULL }; static esp_err_t getWlanStatus_handler(httpd_req_t *req) { char response[100]; g_onboardingStepStartTime = get_millis(); g_onboardingStepTimeout = (10 * 60 * 1000); // 10 minutes. safeStrCat(response, sizeof(response), (char*)"{\"status\":\""); switch(g_wlanStatus) { case WLAN_IDLE: safeStrCat(response, sizeof(response), (char*)"idle"); ESP_LOGI(TAG,"WLAN status: idle"); break; case WLAN_WORKING: safeStrCat(response, sizeof(response), (char*)"working"); ESP_LOGI(TAG,"WLAN status: working"); break; case WLAN_ERROR: safeStrCat(response, sizeof(response), (char*)"error"); ESP_LOGI(TAG,"WLAN status: error"); g_wlanStatus = WLAN_IDLE; break; // Clear the error flag because it was reported. case WLAN_DONE: safeStrCat(response, sizeof(response), (char*)"done"); ESP_LOGI(TAG,"WLAN status: done"); break; case WLAN_TRY_WIFI: safeStrCat(response, sizeof(response), (char*)"try_wifi"); ESP_LOGI(TAG,"WLAN status: try_wifi"); break; case WLAN_TRY_INTERNET: safeStrCat(response, sizeof(response), (char*)"try_internet"); ESP_LOGI(TAG,"WLAN status: try_internet"); break; default: safeStrCat(response, sizeof(response), (char*)"undefined_status"); ESP_LOGI(TAG,"WLAN status: undefined_status"); break; } safeStrCat(response, sizeof(response), (char*)"\",\"error\":\""); switch(g_wlanError) { case WLAN_NO_ERROR: safeStrCat(response, sizeof(response), (char*)"\"}"); ESP_LOGI(TAG,"WLAN error: no_error\n"); break; case WLAN_SSID_TOO_LONG: safeStrCat(response, sizeof(response), (char*)"ssid_too_long\"}"); ESP_LOGI(TAG,"WLAN error: ssid_too_long\n"); break; case WLAN_PASSWORD_TOO_LONG: safeStrCat(response, sizeof(response), (char*)"password_too_long\"}"); ESP_LOGI(TAG,"WLAN error: password_too_long\n"); break; case WLAN_FAILED_WIFI: safeStrCat(response, sizeof(response), (char*)"failed_wifi\"}"); ESP_LOGI(TAG,"WLAN error: failed_wifi\n"); break; case WLAN_FAILED_INTERNET: safeStrCat(response, sizeof(response), (char*)"failed_internet\"}"); ESP_LOGI(TAG,"WLAN error: failed_internet\n"); break; default: safeStrCat(response, sizeof(response), (char*)"undefined_error\"}"); ESP_LOGI(TAG,"WLAN error: undefined_error\n"); break; } g_wlanError = WLAN_NO_ERROR; strcpy(response,"{\"success\":\"1\"}"); httpd_resp_send(req, response, strlen(response)); vTaskDelay(50/portTICK_PERIOD_MS); return ESP_OK; } static const httpd_uri_t getWlanStatus = { .uri = "/get/wlanStatus", .method = HTTP_GET, .handler = getWlanStatus_handler, .user_ctx = NULL }; static esp_err_t readSensors_handler(httpd_req_t *req) { char response[200]; char floatStr[32]; g_onboardingStepStartTime = get_millis(); g_onboardingStepTimeout = (10 * 60 * 1000); // 10 minutes. //getSensorsDataDirectly(); response[0] = 0; safeStrCat(response, sizeof(response), (char*)"{\"tempC\":"); sprintf(floatStr, "%.2f", get_temperature_data()); safeStrCat(response, sizeof(response), floatStr); safeStrCat(response, sizeof(response), (char*)"{,\"humidity\":"); sprintf(floatStr, "%.2f", get_humidity_data()); safeStrCat(response, sizeof(response), floatStr); safeStrCat(response, sizeof(response), (char*)"}"); httpd_resp_send(req, response, strlen(response)); vTaskDelay(50/portTICK_PERIOD_MS); return ESP_OK; } static const httpd_uri_t readSensors = { .uri = "/get/readings", .method = HTTP_GET, .handler = readSensors_handler, .user_ctx = NULL }; static esp_err_t done_handler(httpd_req_t *req) { g_onboardingStepStartTime = get_millis(); g_onboardingStepTimeout = (10 * 60 * 1000); // 10 minutes. g_wlanOnboardingDone = true; vTaskDelay(50/portTICK_PERIOD_MS); return ESP_OK; } static const httpd_uri_t doneOn = { .uri = "/done", .method = HTTP_GET, .handler = done_handler, .user_ctx = NULL }; static esp_err_t factoryReset_handler(httpd_req_t *req) { g_onboardingStepStartTime = get_millis(); g_onboardingStepTimeout = (10 * 60 * 1000); // 10 minutes. startOnboardingShutdown(); esp_restart(); vTaskDelay(50/portTICK_PERIOD_MS); return ESP_OK; } static const httpd_uri_t factoryReset = { .uri = "/factoryReset", .method = HTTP_GET, .handler = factoryReset_handler, .user_ctx = NULL }; void startOnboarding(void *pvParameters) { char *pPassword; char *pSsid; char initialPasswordA[PASSWORD_MAX_LENGTH + 1]; char initialPasswordB[PASSWORD_MAX_LENGTH + 1]; char initialSsidA[SSID_MAX_LENGTH + 1]; char initialSsidB[SSID_MAX_LENGTH + 1]; httpd_config_t config = HTTPD_DEFAULT_CONFIG(); config.lru_purge_enable = true; config.max_uri_handlers = 19; uint32_t timeout = 0; uint8_t serverConnectionAttempt = 0; //int8_t currentWifiChannel; g_wlanError = WLAN_NO_ERROR; g_wlanStatus = WLAN_IDLE; g_wlanTesting = WLAN_NOT_TESTING; g_wlanTestingPreviousState = WLAN_NOT_TESTING; g_servedRoot = false; g_servedSid = false; g_servedStatus = false; //currentWifiChannel = -1; // Initialized so that the current wifi channel will be printed to the monitor. memcpy(initialSsidA, wifi_get_ssidA(), sizeof(initialSsidA)); memcpy(initialPasswordA, wifi_get_pswdA(), sizeof(initialPasswordA)); memcpy(initialSsidB, wifi_get_ssidB(), sizeof(initialSsidB)); memcpy(initialPasswordB, wifi_get_pswdB(), sizeof(initialPasswordB)); // Start the httpd server ESP_LOGI(TAG, "******** START ON-BOARDING ********\nStarting server on port: '%d'", config.server_port); /* Start the hmi-not-onbooarded LED-event */ hmi_set_leds_state(RED_LED_FLASHING); if (httpd_start(&serverHandle, &config) == ESP_OK) { /**/ g_onboardingStepStartTime = get_millis(); g_onboardingStepTimeout = (20 * 60 * 1000); // 20 minutes. // Set URI handlers ESP_ERROR_CHECK(httpd_register_uri_handler(serverHandle, &root)); ESP_ERROR_CHECK(httpd_register_uri_handler(serverHandle, &ki_min_js_t)); ESP_ERROR_CHECK(httpd_register_uri_handler(serverHandle, &promise_min_js_t)); ESP_ERROR_CHECK(httpd_register_uri_handler(serverHandle, &style_css)); ESP_ERROR_CHECK(httpd_register_uri_handler(serverHandle, &sid_t)); ESP_ERROR_CHECK(httpd_register_uri_handler(serverHandle, &wirelessNetworks)); ESP_ERROR_CHECK(httpd_register_uri_handler(serverHandle, &wlan)); ESP_ERROR_CHECK(httpd_register_uri_handler(serverHandle, &status)); ESP_ERROR_CHECK(httpd_register_uri_handler(serverHandle, &acc)); ESP_ERROR_CHECK(httpd_register_uri_handler(serverHandle, &restart)); ESP_ERROR_CHECK(httpd_register_uri_handler(serverHandle, &getWlan)); ESP_ERROR_CHECK(httpd_register_uri_handler(serverHandle, &setWlan)); ESP_ERROR_CHECK(httpd_register_uri_handler(serverHandle, &deleteWlanA)); ESP_ERROR_CHECK(httpd_register_uri_handler(serverHandle, &deleteWlanB)); ESP_ERROR_CHECK(httpd_register_uri_handler(serverHandle, &getWlanStatus)); ESP_ERROR_CHECK(httpd_register_uri_handler(serverHandle, &readSensors)); ESP_ERROR_CHECK(httpd_register_uri_handler(serverHandle, &doneOn)); //ESP_ERROR_CHECK(httpd_register_uri_handler(serverHandle, &deleteWifiAndReset)); ESP_ERROR_CHECK(httpd_register_uri_handler(serverHandle, &factoryReset)); ESP_LOGI(TAG, "OnBoarding : Step 0 > Waiting for User to connect to soft AP and download configuration page..."); while(1) { // Exit onboarding? if(g_onboardingCompleted || g_wlanOnboardingDone) { ESP_LOGI(TAG,"On-boarding complete."); #ifdef STORING_TO_NVM /* Store the wifi-onboarded flag in nvs */ nvm_write_onboarding_flag(WIFI_ONBOARDING_KEY, device_wifi_onboarded); /* Store the wifi-credentials to nvm */ nvm_write_wifi_credentials(wifi_get_ssid(), (uint8_t)strlen(wifi_get_ssid()), wifi_get_pswd(), (uint8_t)strlen(wifi_get_pswd())); #endif break; } // Onboarding timeout? if ( ((get_millis() - g_onboardingStepStartTime) > g_onboardingStepTimeout)) { ESP_LOGI(TAG,"\nOn-boarding timed-out.\n"); g_onboardingCompleted = false; g_wlanOnboardingDone = false; break; } // Process the wlan testing state machine if(g_wlanTestingPreviousState != g_wlanTesting) { g_wlanTestingPreviousState = g_wlanTesting; ESP_LOGI(TAG,"\nWLAN testing switched to state: %d",g_wlanTesting); } // Test if pushbutton requested server mode has timed out. /*if( g_serverModeRequested && *g_pWifiSsidA && !g_pageServed && (300000 < (millis() - serverModeStartTime)) ) { Serial.println(F("\nPushbutton initiated server mode timed out.\n")); g_onboardingCompleted = false; g_wlanOnboardingDone = true; break; }*/ switch(g_wlanTesting) { case WLAN_NOT_TESTING: break; case WLAN_WIFI_CONNECTING: //currentWifiChannel = -1; ESP_LOGI(TAG,"Attempting to connect using WiFi channel:"); timeout = get_millis(); g_wlanTesting = WLAN_WIFI_WAITING_TO_CONNECT; break; case WLAN_WIFI_WAITING_TO_CONNECT: if(wifi_station_connected()) { ESP_LOGI(TAG,"\nConnected to WiFi on channel: %d",data_get_wifi_channel()); // Save AP's MAC address //data_set_ap_mac_addr(data_get_ap_mac_addr()); serverConnectionAttempt = 0; g_wlanTesting = WLAN_WIFI_CONNECTED; } else { if(30000 < (get_millis() - timeout)) // WiFi connection attempt timed out? { ESP_LOGI(TAG,"Failed to connect to WiFi!"); if(wifi_station_connected()) // Disconnect if WiFi is connected. { wifi_sta_disconnecting(); vTaskDelay(10/portTICK_PERIOD_MS); // Delay after disconnect function call } g_wlanStatus = WLAN_ERROR; g_wlanError = WLAN_FAILED_WIFI; g_wlanTesting = WLAN_NOT_TESTING; // Reset state machine. } } break; case WLAN_WIFI_CONNECTED: ESP_LOGI(TAG,"Attempting connection to google.com"); g_wlanStatus = WLAN_TRY_INTERNET; serverConnectionAttempt++; vTaskDelay(50/portTICK_PERIOD_MS); // Feed the watchdog timer /*if(g_client.connected()) { g_client.stop(); yield(); // Feed the watchdog timer g_client.flush(); yield(); // Feed the watchdog timer }*/ if(http_client_test("https://www.google.com")) { ESP_LOGI(TAG,"Connected to google.com"); vTaskDelay(100/portTICK_PERIOD_MS); // Feed the watchdog timer /*if(g_client.connected()) { g_client.stop(); yield(); // Feed the watchdog timer g_client.flush(); yield(); // Feed the watchdog timer }*/ g_wlanTesting = WLAN_TEST_SUCCESS; } else { if(10 < serverConnectionAttempt) // MAKE REPEATED ATTEMPTS OVER 10 SECONDS // http://forum.arduino.cc/index.php?topic=433836.0 { ESP_LOGI(TAG,"Failed to connect to google.com"); serverConnectionAttempt = 0; g_wlanTesting = WLAN_CONNECT_TO_SERVER_2; } else { timeout = get_millis(); g_wlanTesting = WLAN_SERVER_1_WAITING_TO_CONNECT; } } break; case WLAN_SERVER_1_WAITING_TO_CONNECT: if(1000 < (get_millis() - timeout)) g_wlanTesting = WLAN_WIFI_CONNECTED; break; case WLAN_CONNECT_TO_SERVER_2: ESP_LOGI(TAG,"Attempting connection to tempstick.com"); serverConnectionAttempt++; vTaskDelay(50/portTICK_PERIOD_MS); // Feed the watchdog timer /*if(g_client.connected()) { g_client.stop(); yield(); // Feed the watchdog timer g_client.flush(); yield(); // Feed the watchdog timer }*/ if(http_client_test("http://www.tempstick.com")) { ESP_LOGI(TAG,"Connected to tempstick.com"); vTaskDelay(50/portTICK_PERIOD_MS); // Feed the watchdog timer /*if(g_client.connected()) { g_client.stop(); yield(); // Feed the watchdog timer g_client.flush(); yield(); // Feed the watchdog timer }*/ g_wlanTesting = WLAN_TEST_SUCCESS; } else { if(10 < serverConnectionAttempt) // MAKE REPEATED ATTEMPTS OVER 10 SECONDS // http://forum.arduino.cc/index.php?topic=433836.0 { ESP_LOGI(TAG,"Failed to connect to tempstick.com"); vTaskDelay(50/portTICK_PERIOD_MS); // Feed the watchdog timer /*if(g_client.connected()) { g_client.stop(); yield(); // Feed the watchdog timer g_client.flush(); yield(); // Feed the watchdog timer }*/ if(wifi_station_connected()) // Disconnect if WiFi is connected. { wifi_sta_disconnecting(); vTaskDelay(100/portTICK_PERIOD_MS); // Delay after disconnect function call } g_wlanStatus = WLAN_ERROR; g_wlanError = WLAN_FAILED_INTERNET; g_wlanTesting = WLAN_NOT_TESTING; // Reset state machine. } else { timeout = get_millis(); g_wlanTesting = WLAN_SERVER_2_WAITING_TO_CONNECT; } } break; case WLAN_SERVER_2_WAITING_TO_CONNECT: if(1000 < (get_millis() - timeout)) g_wlanTesting = WLAN_CONNECT_TO_SERVER_2; break; case WLAN_TEST_SUCCESS: ESP_LOGI(TAG,"WLAN test success"); // Save WiFi credentials pSsid = NULL; pPassword = NULL; // Prevent compiler error. if('A' == g_wlanTargetSsid) { pSsid = wifi_get_ssidA(); pPassword = wifi_get_pswdA(); } if('B' == g_wlanTargetSsid) { pSsid = wifi_get_ssidB(); pPassword = wifi_get_pswdB(); } if(NULL != pSsid) { memset(pSsid, 0, (SSID_MAX_LENGTH + 1)); memset(pPassword, 0, (PASSWORD_MAX_LENGTH + 1)); /*strncpy(pSsid, g_wlanSsidStr, SSID_MAX_LENGTH); strncpy(pPassword, g_wlanPasswordStr, PASSWORD_MAX_LENGTH);*/ strncpy(pSsid, wifi_get_ssid(), SSID_MAX_LENGTH); strncpy(pPassword, wifi_get_pswd(), PASSWORD_MAX_LENGTH); //writeWifiCredentialsToFlash(); } g_wlanStatus = WLAN_DONE; g_wlanError = WLAN_NO_ERROR; g_wlanTesting = WLAN_NOT_TESTING; // Reset state machine. break; default: ESP_LOGI(TAG,"\nWLAN testing programming error. Locking up."); while(1) { vTaskDelay(100/portTICK_PERIOD_MS); } break; } // End of switch(g_wlanTesting) vTaskDelay(100/portTICK_PERIOD_MS); } startOnboardingShutdown(); if(g_wlanOnboardingDone) // Real-time server mode exit. { //readWifiCredentialsFromFlash(NULL, 0, NULL, 0, NULL, 0, NULL, 0); if(wifi_get_ssidA()) // SSID set? { if( (0 != strcmp(initialSsidA, wifi_get_ssidA())) || (0 != strcmp(initialPasswordA, wifi_get_pswdA())) || (0 != strcmp(initialSsidB, wifi_get_ssidB())) || (0 != strcmp(initialPasswordB, wifi_get_pswdB())) ) // Did the customer change any WiFi settings? { ESP_LOGI(TAG,"Smart phone app done. WiFi settings exist. WiFi changed. Resetting."); wifi_switchToPrimaryNetwork(); esp_restart(); //resetCoprocessor(); // Reset Temp Stick to force a check in with the new WiFi settings. This function does not return. } else { ESP_LOGI(TAG,"Smart phone app done. WiFi settings exist. WiFi not changed. Returning to sleep"); //goToSleep(0xFFFFFFFE, _rtcRamData.rfWakeMode); // Return to sleep. (Sleep may have been interrupted by the server mode request). This function does not return. } } else { ESP_LOGI(TAG,"Smart phone app done. No WiFi settings. Resetting."); esp_restart(); //resetCoprocessor(); // Reset Temp Stick to re-enter onboarding. This function does not return. } } else { if(g_onboardingCompleted) { ESP_LOGI(TAG,"Legacy onboarding completed. Resetting."); wifi_switchToPrimaryNetwork(); #ifdef STORING_TO_NVM esp_restart(); //resetCoprocessor(); // Reset Temp Stick to force check in with the new WiFi settings. This function does not return. #endif } else { // Onboarding timed out. if( (g_servedSid || g_servedStatus) && (!g_servedRoot) ) // Did smartphone app connection timeout, instead of legacy 10.10.1.1? { ESP_LOGI(TAG,"Smart phone app connection timed out. Returning to sleep."); //goToSleep(0xFFFFFFFE, _rtcRamData.rfWakeMode); // Return to sleep. (Sleep may have been interrupted by the server mode request). This function does not return. } else { ESP_LOGI(TAG,"Legacy onboarding timed out. Locking up."); //goToSleep(0xFFFFFFFF, RF_CAL); // Onboarding timed out. Shut down until a POR occurs. The 0xFFFFFFFF is a special argument that puts the coprocessor into its own deep sleep until a POR occurs. This function does not return. } } } vTaskDelete(NULL); //return; } ESP_LOGI(TAG, "Error starting server!"); vTaskDelete(NULL); //return NULL; } void webserver_stop(httpd_handle_t server) { if (server) { /* Stop the httpd server */ if(ESP_FAIL == httpd_stop(server)) { ESP_LOGI(TAG, "Failed to stop server"); } } } void webserver_start(void) { #ifdef STORING_TO_NVM device_wifi_onboarded = nvm_read_onboarding_flag(WIFI_ONBOARDING_KEY); #endif if(!device_wifi_onboarded) { wifi_first_init(); Wifi_Init_SoftAp(); xTaskCreate(startOnboarding, "onboarding_task", 8192, NULL, 16, NULL); } else { g_onboardingCompleted = true; } } bool webserver_get_status(void) { if(g_onboardingCompleted && device_wifi_onboarded) return true; else return false; } void startOnboardingShutdown(void) { ESP_LOGI(TAG,"Shutting down on-boaring server"); /* Stop the on-boarding server */ webserver_stop(serverHandle); /* Disconnecting the wifi-station from wifi-network */ wifi_sta_disconnecting(); /* Stop the wifi service */ wifi_stop(); ESP_LOGI(TAG," ----> on-boaring server has been shut down"); /* wait for 1.5sec */ vTaskDelay(1500/portTICK_PERIOD_MS); /* Turn off on_boarding led event */ hmi_stop_red_flashing(); } void startOnboardingGetSsidAndPassword(char *content) { char *ssid; char *pwd_encoded; char *pwd; ssid = pvPortMalloc((SSID_MAX_LENGTH + 1) * sizeof(char)); pwd_encoded = pvPortMalloc((PASSWORD_MAX_LENGTH + 1) * sizeof(char)); pwd = pvPortMalloc((PASSWORD_MAX_LENGTH + 1) * sizeof(char)); if (!(*content == '-')) // Content conforms to query parameters { /* Fetch SSID from query parameter */ if ( httpd_query_key_value(content, "ssid", ssid, SSID_MAX_LENGTH ) != ESP_OK ) ESP_LOGI(TAG, "Failed to get SSID : %s", ssid); /* Fetch password from query parameter */ if ( httpd_query_key_value(content, "password", pwd_encoded,PASSWORD_MAX_LENGTH ) == ESP_OK ) { pwd = url_decode(pwd_encoded); } else ESP_LOGI(TAG, "Failed to fetch WiFi password"); } else { // Check if Content starts wit Multi-part form data format extract_field_value(content, "ssid", ssid, SSID_MAX_LENGTH); extract_field_value(content, "password", pwd_encoded, PASSWORD_MAX_LENGTH); pwd = url_decode(pwd_encoded); } wifi_update_credentials(ssid, pwd); vPortFree(ssid); vPortFree(pwd_encoded); vPortFree(pwd); } bool registerAcctWithServer(char *typeStr, char *customerAccountIdStr, char *customerAccountPasswordStr, char *customerAccountPasswordAgainStr, char *responseStr, uint16_t responseStrSize) { char urlConnectionString[100];// = (char *)pvPortMalloc(100 * sizeof(char)); char *post_params = modem_get_rxbuf();// = (char *)pvPortMalloc(1024 * sizeof(char)); char mac_str[20];// = (char *)pvPortMalloc(20 * sizeof(char)); uint8_t mac_base[6] = {0}; char chipId[7]; bool retval = false; uint8_t connection_test = 1; esp_err_t connection_result = ESP_FAIL; memset(chipId, 0, 7); memset(post_params, 0, 100); esp_efuse_mac_get_default(mac_base); esp_read_mac(mac_base, ESP_MAC_WIFI_STA); sprintf(mac_str, "%02X%02X%02X%02X%02X%02X", mac_base[0], mac_base[1], mac_base[2], mac_base[3], mac_base[4], mac_base[5]); strcpy(chipId, mac_str + 6); sprintf(post_params, "type=%s&email=%s&pass=%s&pass_again=%s&sensor=%s&mac=%s&wifi=%s&wallEquip=%d&version=%ld", typeStr, customerAccountIdStr, customerAccountPasswordStr, customerAccountPasswordAgainStr, chipId, mac_str, wifi_get_ssid(), 0, g_version); ESP_LOGI(TAG,"On-boarding string length is: %u\nOn-boarding string content is: %s",strlen(post_params),post_params); do { /* Setup the URL of the target onboarding server */ //sprintf(urlConnectionString, MCU_ONBOARDING_URL,connection_test); strcpy(urlConnectionString, "https://device-status.idealsciences.com"); ESP_LOGI(TAG, "Attempting connection to on-boarding server: %s", urlConnectionString); /* Setup and concatenate the path of the target URL */ strcat(urlConnectionString, "/sensor-account.php"); ESP_LOGI(TAG, "Sending POST data to %s", urlConnectionString); /* Setup the posting-string to be ON_BOARDING_STR */ wifi_set_post_str_type(ON_BOARDING_STR); /* wait for 5 seconds before doing any connection with the server (just to give some time of disconnection with server if the device has connected to it before that) */ vTaskDelay(5000/portTICK_PERIOD_MS); /* Do the HTTP-POST request with the onboarding string */ connection_result = http_client_post(urlConnectionString, post_params, responseStr); /* Close the connection of http-post */ http_client_post_stop(); /**/ //sprintf(onboarding_host,ON_BOARDING_SERVER_DOMAIN_NAME,connection_test); /* Test the connection with the onboarding server */ //connection_result = http_client_test(urlConnectionString); /* Check the result of the connection */ if(ESP_OK == connection_result) break; /* Increase the connection_test counter by 1 */ connection_test++; }while(connection_test < 4); /* Check if the connection was successful */ if(connection_test < 4/*ESP_OK == connection_result*/) { /* Print this LOG */ //ESP_LOGI(TAG, "Connected to on-boarding server."); // ///* Delay for 8 seconds */ //vTaskDelay(8000/portTICK_PERIOD_MS); // ///**/ //strcat(urlConnectionString, "/sensor-account.php"); //ESP_LOGI(TAG, "Sending POST data to %s", urlConnectionString); // ///**/ //wifi_set_post_str_type(ON_BOARDING_STR); /**/ if(ESP_OK == connection_result/*http_client_post(urlConnectionString, post_params, responseStr)*/) { ESP_LOGI(TAG, "Response OK\n%s", responseStr); acc_registered = true; retval = true; } else { ESP_LOGI(TAG, "Error Response"); strcpy(responseStr, "{\"err\":1,\"msg\":\"Server timed out, refresh the page and try again.\"}"); retval = true; } } else { strcpy(responseStr, "{\"err\":1,\"msg\":\"Server or internet unavailable, Server will restart. connect,refresh the page and try again.\"}"); retval = false; } wifi_set_post_str_type(CHECK_IN_STR); return retval; } #endif