diff --git a/Makefile b/Makefile index 3a6dfbb..8de4074 100644 --- a/Makefile +++ b/Makefile @@ -19,9 +19,37 @@ # The Wifi station configuration can be hard-coded here, which makes esp-link come up in STA+AP # mode trying to connect to the specified AP *only* if the flash wireless settings are empty! # This happens on a full serial flash and avoids having to hunt for the AP... -# STA_SSID ?= +# STA_SSID ?= # STA_PASS ?= +# The SOFTAP configuration can be hard-coded here, the minimum parameters to set are AP_SSID && AP_PASS +# The AP SSID has to be at least 8 characters long, same for AP PASSWORD +# The AP AUTH MODE can be set to: +# 0 = AUTH_OPEN, +# 1 = AUTH_WEP, +# 2 = AUTH_WPA_PSK, +# 3 = AUTH_WPA2_PSK, +# 4 = AUTH_WPA_WPA2_PSK +# SSID hidden default 0, ( 0 | 1 ) +# Max connections default 4, ( 1 ~ 4 ) +# Beacon interval default 100, ( 100 ~ 60000ms ) + +# AP_SSID ?=esp_link_test +# AP_PASS ?=esp_link_test +# AP_AUTH_MODE ?=4 +# AP_SSID_HIDDEN ?=0 +# AP_MAX_CONN ?=4 +# AP_BEACON_INTERVAL ?=100 + + +# If CHANGE_TO_STA is set to "yes" the esp-link module will switch to station mode +# once successfully connected to an access point. Else it will stay in STA+AP mode. + +CHANGE_TO_STA ?= yes + +# hostname or IP address for wifi flashing +ESP_HOSTNAME ?= esp-link + # --------------- toolchain configuration --------------- # Base directory for the compiler. Needs a / at the end. @@ -39,15 +67,6 @@ ESPTOOL ?= $(abspath ../esp-open-sdk/esptool/esptool.py) ESPPORT ?= /dev/ttyUSB0 ESPBAUD ?= 460800 -# The Wifi station configuration can be hard-coded here, which makes esp-link come up in STA+AP -# mode trying to connect to the specified AP *only* if the flash wireless settings are empty! -# This happens on a full serial flash and avoids having to hunt for the AP... -# STA_SSID ?= -# STA_PASS ?= - -# hostname or IP address for wifi flashing -ESP_HOSTNAME ?= esp-link - # --------------- chipset configuration --------------- # Pick your flash size: "512KB", "1MB", or "4MB" @@ -64,14 +83,9 @@ LED_CONN_PIN ?= 0 # GPIO pin used for "serial activity" LED, active low LED_SERIAL_PIN ?= 14 -# --------------- esp-link config options --------------- +# --------------- esp-link modules config options --------------- -# If CHANGE_TO_STA is set to "yes" the esp-link module will switch to station mode -# once successfully connected to an access point. Else it will stay in AP+STA mode. - -CHANGE_TO_STA ?= yes - -# Optional Modules +# Optional Modules mqtt MODULES ?= mqtt rest syslog # --------------- esphttpd config options --------------- @@ -268,6 +282,30 @@ ifneq ($(strip $(STA_PASS)),) CFLAGS += -DSTA_PASS="$(STA_PASS)" endif +ifneq ($(strip $(AP_SSID)),) +CFLAGS += -DAP_SSID="$(AP_SSID)" +endif + +ifneq ($(strip $(AP_PASS)),) +CFLAGS += -DAP_PASS="$(AP_PASS)" +endif + +ifneq ($(strip $(AP_AUTH_MODE)),) +CFLAGS += -DAP_AUTH_MODE="$(AP_AUTH_MODE)" +endif + +ifneq ($(strip $(AP_SSID_HIDDEN)),) +CFLAGS += -DAP_SSID_HIDDEN="$(AP_SSID_HIDDEN)" +endif + +ifneq ($(strip $(AP_MAX_CONN)),) +CFLAGS += -DAP_MAX_CONN="$(AP_MAX_CONN)" +endif + +ifneq ($(strip $(AP_BEACON_INTERVAL)),) +CFLAGS += -DAP_BEACON_INTERVAL="$(AP_BEACON_INTERVAL)" +endif + ifeq ("$(GZIP_COMPRESSION)","yes") CFLAGS += -DGZIP_COMPRESSION endif diff --git a/esp-link/cgi.c b/esp-link/cgi.c index 081ef49..6879cd6 100644 --- a/esp-link/cgi.c +++ b/esp-link/cgi.c @@ -206,7 +206,8 @@ int ICACHE_FLASH_ATTR cgiMenu(HttpdConnData *connData) { "{ " "\"menu\": [ " "\"Home\", \"/home.html\", " - "\"WiFI\", \"/wifi/wifi.html\", " + "\"WiFi Station\", \"/wifi/wifiSta.html\", " + "\"WiFi Soft-AP\", \"/wifi/wifiAp.html\", " "\"µC Console\", \"/console.html\", " "\"Services\", \"/services.html\", " #ifdef MQTT diff --git a/esp-link/cgiwifi.c b/esp-link/cgiwifi.c old mode 100644 new mode 100755 index b83a330..f5da2a3 --- a/esp-link/cgiwifi.c +++ b/esp-link/cgiwifi.c @@ -26,11 +26,20 @@ Cgi/template routines for the /wifi url. #define DBG(format, ...) do { } while(0) #endif +# define VERS_STR_STR(V) #V +# define VERS_STR(V) VERS_STR_STR(V) + bool mdns_started = false; // ===== wifi status change callbacks static WifiStateChangeCb wifi_state_change_cb[4]; +// Temp store for new staion config +struct station_config stconf; + +// Temp store for new ap config +struct softap_config apconf; + uint8_t wifiState = wifiIsDisconnected; // reasons for which a connection failed uint8_t wifiReason = 0; @@ -265,14 +274,21 @@ static int ICACHE_FLASH_ATTR cgiWiFiGetScan(HttpdConnData *connData) { } int ICACHE_FLASH_ATTR cgiWiFiScan(HttpdConnData *connData) { - if (connData->requestType == HTTPD_METHOD_GET) { - return cgiWiFiGetScan(connData); - } else if (connData->requestType == HTTPD_METHOD_POST) { - return cgiWiFiStartScan(connData); - } else { - jsonHeader(connData, 404); - return HTTPD_CGI_DONE; - } + if (connData->requestType == HTTPD_METHOD_GET) { + return cgiWiFiGetScan(connData); + }else if(connData->requestType == HTTPD_METHOD_POST) { + // DO NOT start APs scan in AP mode + int mode = wifi_get_opmode(); + if(mode==2){ + jsonHeader(connData, 400); + return HTTPD_CGI_DONE; + }else{ + return cgiWiFiStartScan(connData); + } + }else{ + jsonHeader(connData, 404); + return HTTPD_CGI_DONE; + } } // ===== timers to change state and rescue from failed associations @@ -288,9 +304,10 @@ static void ICACHE_FLASH_ATTR resetTimerCb(void *arg) { int x = wifi_station_get_connect_status(); int m = wifi_get_opmode() & 0x3; DBG("Wifi check: mode=%s status=%d\n", wifiMode[m], x); - - if (x == STATION_GOT_IP) { - if (m != 1) { + + if(m!=2){ + if ( x == STATION_GOT_IP ) { + if (m != 1) { #ifdef CHANGE_TO_STA // We're happily connected, go to STA mode DBG("Wifi got IP. Going into STA mode..\n"); @@ -300,19 +317,19 @@ static void ICACHE_FLASH_ATTR resetTimerCb(void *arg) { } log_uart(false); // no more resetTimer at this point, gotta use physical reset to recover if in trouble - } else { - if (m != 3) { - DBG("Wifi connect failed. Going into STA+AP mode..\n"); - wifi_set_opmode(3); + } else { + if (m != 3) { + DBG("Wifi connect failed. Going into STA+AP mode..\n"); + wifi_set_opmode(3); + wifi_softap_set_config(&apconf); } log_uart(true); DBG("Enabling/continuing uart log\n"); os_timer_arm(&resetTimer, RESET_TIMEOUT, 0); + } } } -// Temp store for new ap info. -static struct station_config stconf; // Reassociate timer to delay change of association so the original request can finish static ETSTimer reassTimer; @@ -334,6 +351,12 @@ static void ICACHE_FLASH_ATTR reassTimerCb(void *arg) { // This cgi uses the routines above to connect to a specific access point with the // given ESSID using the given password. int ICACHE_FLASH_ATTR cgiWiFiConnect(HttpdConnData *connData) { + int mode = wifi_get_opmode(); + if(mode == 2){ + jsonHeader(connData, 400); + httpdSend(connData, "Can't associate to an AP en SoftAP mode", -1); + return HTTPD_CGI_DONE; + } char essid[128]; char passwd[128]; @@ -482,38 +505,206 @@ int ICACHE_FLASH_ATTR cgiWiFiSpecial(HttpdConnData *connData) { return HTTPD_CGI_DONE; } +// ==== Soft-AP related functions + +// Change Soft-AP main settings +int ICACHE_FLASH_ATTR cgiApSettingsChange(HttpdConnData *connData) { + + if (connData->conn==NULL) return HTTPD_CGI_DONE; // Connection aborted. Clean up. + + // No changes for Soft-AP in STA mode + int mode = wifi_get_opmode(); + if ( mode == 1 ){ + jsonHeader(connData, 400); + httpdSend(connData, "No changes allowed in STA mode", -1); + return HTTPD_CGI_DONE; + } + + char buff[96]; + int len; + // Do we need a password or auth mode? + bool pass_need=true; + + // Check extra security measure, this must be 1 + len=httpdFindArg(connData->getArgs, "100", buff, sizeof(buff)); + if(len>0){ + if(atoi(buff)!=1){ + jsonHeader(connData, 400); + return HTTPD_CGI_DONE; + } + } + // Set new SSID + len=httpdFindArg(connData->getArgs, "ap_ssid", buff, sizeof(buff)); + if(checkString(buff) && len>7 && len<32){ + // STRING PREPROCESSING DONE IN CLIENT SIDE + os_memset(apconf.ssid, 0, 32); + os_memcpy(apconf.ssid, buff, len); + apconf.ssid_len = len; + pass_need = true; // ssid ok, look for a valid password + }else{ + pass_need = false; // ssid wrong, neither pass nor auth mode are needed + jsonHeader(connData, 400); + httpdSend(connData, "SSID not valid or out of range", -1); + return HTTPD_CGI_DONE; + } + // Set new PASSWORD + if( pass_need ){ + len=httpdFindArg(connData->getArgs, "ap_password", buff, sizeof(buff)); + if(checkString(buff) && len>7 && len<64){ + // String preprocessing done in client side, wifiap.js line 31 + os_memset(apconf.password, 0, 64); + os_memcpy(apconf.password, buff, len); + pass_need = true; // pass ok, look for auth mode + }else if (len == 0){ + pass_need = false; // pass wrong, don't look for auth mode + os_memset(apconf.password, 0, 64); + }else{ + jsonHeader(connData, 400); + httpdSend(connData, "PASSWORD not valid or out of range", -1); + return HTTPD_CGI_DONE; + } + } + // Set auth mode + if(pass_need){ + // Set authentication mode, before password to check open settings + len=httpdFindArg(connData->getArgs, "ap_authmode", buff, sizeof(buff)); + if(len>0){ + int value = atoi(buff); + if(value >= 0 && value <= 4){ + apconf.authmode = value; + }else{ + // If out of range set by default + apconf.authmode = 4; + } + }else{ + // Valid password but wrong auth mode, default 4 + apconf.authmode = 4; + } + }else{ + apconf.authmode = 0; + } + // Set max connection number + len=httpdFindArg(connData->getArgs, "ap_maxconn", buff, sizeof(buff)); + if(len>0){ + + int value = atoi(buff); + if(value > 0 && value <= 4){ + apconf.max_connection = value; + }else{ + // If out of range, set by default + apconf.max_connection = 4; + } + } + // Set beacon interval value + len=httpdFindArg(connData->getArgs, "ap_beacon", buff, sizeof(buff)); + if(len>0){ + int value = atoi(buff); + if(value >= 100 && value <= 60000){ + apconf.beacon_interval = value; + }else{ + // If out of range, set by default + apconf.beacon_interval = 100; + } + } + // Set ssid to be hidden or not + len=httpdFindArg(connData->getArgs, "ap_hidden", buff, sizeof(buff)); + if(len>0){ + int value = atoi(buff); + if(value == 0 || value == 1){ + apconf.ssid_hidden = value; + }else{ + // If out of range, set by default + apconf.ssid_hidden = 0; + } + } + // Store new configuration + wifi_softap_set_config(&apconf); + + jsonHeader(connData, 200); + return HTTPD_CGI_DONE; +} + +// Get current Soft-AP settings +int ICACHE_FLASH_ATTR cgiApSettingsInfo(HttpdConnData *connData) { + + char buff[1024]; + if (connData->conn == NULL) return HTTPD_CGI_DONE; // Connection aborted. Clean up. + os_sprintf(buff, + "{ " + "\"ap_ssid\": \"%s\", " + "\"ap_password\": \"%s\", " + "\"ap_authmode\": %d, " + "\"ap_maxconn\": %d, " + "\"ap_beacon\": %d, " + "\"ap_hidden\": \"%s\" " + " }", + apconf.ssid, + apconf.password, + apconf.authmode, + apconf.max_connection, + apconf.beacon_interval, + apconf.ssid_hidden ? "enabled" : "disabled" + ); + + jsonHeader(connData, 200); + httpdSend(connData, buff, -1); + return HTTPD_CGI_DONE; +} + //This cgi changes the operating mode: STA / AP / STA+AP int ICACHE_FLASH_ATTR cgiWiFiSetMode(HttpdConnData *connData) { int len; char buff[1024]; - + int previous_mode = wifi_get_opmode(); if (connData->conn==NULL) return HTTPD_CGI_DONE; // Connection aborted. Clean up. len=httpdFindArg(connData->getArgs, "mode", buff, sizeof(buff)); - if (len!=0) { - int m = atoi(buff); - DBG("Wifi switching to mode %d\n", m); - wifi_set_opmode(m&3); - if (m == 1) { - // STA-only mode, reset into STA+AP after a timeout if we don't get an IP address - os_timer_disarm(&resetTimer); - os_timer_setfn(&resetTimer, resetTimerCb, NULL); - os_timer_arm(&resetTimer, RESET_TIMEOUT, 0); + int next_mode = atoi(buff); + + if (len!=0) { + if (next_mode == 2){ + // moving to AP mode, so disconnect before leave STA mode + wifi_station_disconnect(); + } + + DBG("Wifi switching to mode %d\n", next_mode); + wifi_set_opmode(next_mode&3); + + if (previous_mode == 2) { + // moving to STA or STA+AP mode from AP, try to connect and set timer + stconf.bssid_set = 0; + wifi_station_set_config(&stconf); + wifi_station_connect(); + os_timer_disarm(&resetTimer); + os_timer_setfn(&resetTimer, resetTimerCb, NULL); + os_timer_arm(&resetTimer, RESET_TIMEOUT, 0); + } + if(previous_mode == 1){ + // moving to AP or STA+AP from STA, so softap config call needed + wifi_softap_set_config(&apconf); + } + jsonHeader(connData, 200); + } else { + jsonHeader(connData, 400); } - jsonHeader(connData, 200); - } else { - jsonHeader(connData, 400); - } - return HTTPD_CGI_DONE; + return HTTPD_CGI_DONE; } static char *connStatuses[] = { "idle", "connecting", "wrong password", "AP not found", "failed", "got IP address" }; static char *wifiWarn[] = { 0, - "Switch to STA+AP mode", - "Can't scan in this mode! Switch to STA+AP mode", - "Switch to STA mode", + "Switch to STA+AP mode", + "Switch to STA+AP mode", + "Switch to STA mode", + "Switch to AP mode", +}; + +static char *apAuthMode[] = { "OPEN", + "WEP", + "WPA_PSK", + "WPA2_PSK", + "WPA_WPA2_PSK", }; #ifdef CHANGE_TO_STA @@ -525,43 +716,50 @@ static char *wifiWarn[] = { 0, // print various Wifi information into json buffer int ICACHE_FLASH_ATTR printWifiInfo(char *buff) { int len; - - struct station_config stconf; - wifi_station_get_config(&stconf); - - uint8_t op = wifi_get_opmode() & 0x3; - char *mode = wifiMode[op]; - char *status = "unknown"; - int st = wifi_station_get_connect_status(); - if (st >= 0 && st < sizeof(connStatuses)) status = connStatuses[st]; - int p = wifi_get_phy_mode(); - char *phy = wifiPhy[p&3]; - char *warn = wifiWarn[op]; - sint8 rssi = wifi_station_get_rssi(); - if (rssi > 0) rssi = 0; - uint8 mac_addr[6]; - wifi_get_macaddr(0, mac_addr); - uint8_t chan = wifi_get_channel(); - - len = os_sprintf(buff, - "\"mode\": \"%s\", \"modechange\": \"%s\", \"ssid\": \"%s\", \"status\": \"%s\", \"phy\": \"%s\", " - "\"rssi\": \"%ddB\", \"warn\": \"%s\", \"mac\":\"%02x:%02x:%02x:%02x:%02x:%02x\", \"chan\":%d", - mode, MODECHANGE, (char*)stconf.ssid, status, phy, rssi, warn, - mac_addr[0], mac_addr[1], mac_addr[2], mac_addr[3], mac_addr[4], mac_addr[5], chan); - - struct ip_info info; - if (wifi_get_ip_info(0, &info)) { - len += os_sprintf(buff+len, ", \"ip\": \"%d.%d.%d.%d\"", IP2STR(&info.ip.addr)); - len += os_sprintf(buff+len, ", \"netmask\": \"%d.%d.%d.%d\"", IP2STR(&info.netmask.addr)); - len += os_sprintf(buff+len, ", \"gateway\": \"%d.%d.%d.%d\"", IP2STR(&info.gw.addr)); - len += os_sprintf(buff+len, ", \"hostname\": \"%s\"", flashConfig.hostname); - } else { - len += os_sprintf(buff+len, ", \"ip\": \"-none-\""); - } - len += os_sprintf(buff+len, ", \"staticip\": \"%d.%d.%d.%d\"", IP2STR(&flashConfig.staticip)); - len += os_sprintf(buff+len, ", \"dhcp\": \"%s\"", flashConfig.staticip > 0 ? "off" : "on"); - - return len; + //struct station_config stconf; + wifi_station_get_config(&stconf); + //struct softap_config apconf; + wifi_softap_get_config(&apconf); + + uint8_t op = wifi_get_opmode() & 0x3; + char *mode = wifiMode[op]; + char *status = "unknown"; + int st = wifi_station_get_connect_status(); + if (st >= 0 && st < sizeof(connStatuses)) status = connStatuses[st]; + int p = wifi_get_phy_mode(); + char *phy = wifiPhy[p&3]; + char *warn = wifiWarn[op]; + if (op == 3) op = 4; // Done to let user switch to AP only mode from Soft-AP settings page, using only one set of warnings + char *apwarn = wifiWarn[op]; + char *apauth = apAuthMode[apconf.authmode]; + sint8 rssi = wifi_station_get_rssi(); + if (rssi > 0) rssi = 0; + uint8 mac_addr[6]; + uint8 apmac_addr[6]; + wifi_get_macaddr(0, mac_addr); + wifi_get_macaddr(1, apmac_addr); + uint8_t chan = wifi_get_channel(); + + len = os_sprintf(buff, + "\"mode\": \"%s\", \"modechange\": \"%s\", \"ssid\": \"%s\", \"status\": \"%s\", \"phy\": \"%s\", " + "\"rssi\": \"%ddB\", \"warn\": \"%s\", \"apwarn\": \"%s\",\"mac\":\"%02x:%02x:%02x:%02x:%02x:%02x\", \"chan\":\"%d\", \"apssid\": \"%s\", " + "\"appass\": \"%s\", \"apchan\": \"%d\", \"apmaxc\": \"%d\", \"aphidd\": \"%s\", \"apbeac\": \"%d\", \"apauth\": \"%s\",\"apmac\":\"%02x:%02x:%02x:%02x:%02x:%02x\"", + mode, MODECHANGE, (char*)stconf.ssid, status, phy, rssi, warn, apwarn, + mac_addr[0], mac_addr[1], mac_addr[2], mac_addr[3], mac_addr[4], mac_addr[5], chan, (char*)apconf.ssid,(char*)apconf.password,apconf.channel,apconf.max_connection,apconf.ssid_hidden?"enabled":"disabled",apconf.beacon_interval, apauth,apmac_addr[0], apmac_addr[1], apmac_addr[2], apmac_addr[3], apmac_addr[4], apmac_addr[5]); + + struct ip_info info; + if (wifi_get_ip_info(0, &info)) { + len += os_sprintf(buff+len, ", \"ip\": \"%d.%d.%d.%d\"", IP2STR(&info.ip.addr)); + len += os_sprintf(buff+len, ", \"netmask\": \"%d.%d.%d.%d\"", IP2STR(&info.netmask.addr)); + len += os_sprintf(buff+len, ", \"gateway\": \"%d.%d.%d.%d\"", IP2STR(&info.gw.addr)); + len += os_sprintf(buff+len, ", \"hostname\": \"%s\"", flashConfig.hostname); + } else { + len += os_sprintf(buff+len, ", \"ip\": \"-none-\""); + } + len += os_sprintf(buff+len, ", \"staticip\": \"%d.%d.%d.%d\"", IP2STR(&flashConfig.staticip)); + len += os_sprintf(buff+len, ", \"dhcp\": \"%s\"", flashConfig.staticip > 0 ? "off" : "on"); + + return len; } int ICACHE_FLASH_ATTR cgiWiFiConnStatus(HttpdConnData *connData) { @@ -614,24 +812,123 @@ int ICACHE_FLASH_ATTR cgiWifiInfo(HttpdConnData *connData) { return HTTPD_CGI_DONE; } -// Init the wireless, which consists of setting a timer if we expect to connect to an AP -// so we can revert to STA+AP mode if we can't connect. -void ICACHE_FLASH_ATTR wifiInit() { - // wifi_set_phy_mode(2); // limit to 802.11b/g 'cause n is flaky - int x = wifi_get_opmode() & 0x3; - x = x; - DBG("Wifi init, mode=%s\n", wifiMode[x]); - configWifiIP(); - - // The default sleep mode should be modem_sleep, but we set it here explicitly for good - // measure. We can't use light_sleep because that powers off everthing and we would loose - // all connections. - wifi_set_sleep_type(MODEM_SLEEP_T); - - wifi_set_event_handler_cb(wifiHandleEventCb); - // check on the wifi in a few seconds to see whether we need to switch mode - os_timer_disarm(&resetTimer); - os_timer_setfn(&resetTimer, resetTimerCb, NULL); - os_timer_arm(&resetTimer, RESET_TIMEOUT, 0); +// Check string againt invalid characters +int ICACHE_FLASH_ATTR checkString(char *str){ + int i = 0; + for(; i < os_strlen(str); i++) + { + // Alphanumeric and underscore allowed + if (!(isalnum((unsigned char)str[i]) || str[i] == '_')) + { + DBG("Error: String has non alphanumeric chars\n"); + return 0; + } + } + return 1; } +/* Init the wireless + * + * Call both Soft-AP and Station default config + * Change values according to Makefile hard-coded variables + * Anyway set wifi opmode to STA+AP, it will change to STA if CHANGE_TO_STA is set to yes in Makefile + * Call a timer to check the STA connection + */ +void ICACHE_FLASH_ATTR wifiInit() { + + // Check te wifi opmode + int x = wifi_get_opmode() & 0x3; + + // Set opmode to 3 to let system scan aps, otherwise it won't scan + wifi_set_opmode(3); + + // Call both STATION and SOFTAP default config + wifi_station_get_config_default(&stconf); + wifi_softap_get_config_default(&apconf); + + DBG("Wifi init, mode=%s\n",wifiMode[x]); + + // STATION parameters +#if defined(STA_SSID) && defined(STA_PASS) + // Set parameters + if (os_strlen((char*)stconf.ssid) == 0 && os_strlen((char*)stconf.password) == 0) { + os_strncpy((char*)stconf.ssid, VERS_STR(STA_SSID), 32); + os_strncpy((char*)stconf.password, VERS_STR(STA_PASS), 64); + + DBG("Wifi pre-config trying to connect to AP %s pw %s\n",(char*)stconf.ssid, (char*)stconf.password); + + // wifi_set_phy_mode(2); // limit to 802.11b/g 'cause n is flaky + stconf.bssid_set = 0; + wifi_station_set_config(&stconf); + } +#endif + + // Change SOFT_AP settings if defined +#if defined(AP_SSID) + // Check if ssid and pass are alphanumeric values + int ssidlen = os_strlen(VERS_STR(AP_SSID)); + if(checkString(VERS_STR(AP_SSID)) && ssidlen > 7 && ssidlen < 32){ + // Clean memory and set the value of SSID + os_memset(apconf.ssid, 0, 32); + os_memcpy(apconf.ssid, VERS_STR(AP_SSID), os_strlen(VERS_STR(AP_SSID))); + // Specify the length of ssid + apconf.ssid_len= ssidlen; +#if defined(AP_PASS) + // If pass is at least 8 and less than 64 + int passlen = os_strlen(VERS_STR(AP_PASS)); + if( checkString(VERS_STR(AP_PASS)) && passlen > 7 && passlen < 64 ){ + // Clean memory and set the value of PASS + os_memset(apconf.password, 0, 64); + os_memcpy(apconf.password, VERS_STR(AP_PASS), passlen); + // Can't choose auth mode without a valid ssid and password +#ifdef AP_AUTH_MODE + // If set, use specified auth mode + if(AP_AUTH_MODE >= 0 && AP_AUTH_MODE <=4) + apconf.authmode = AP_AUTH_MODE; +#else + // If not, use WPA2 + apconf.authmode = AUTH_WPA_WPA2_PSK; +#endif + }else if ( passlen == 0){ + // If ssid is ok and no pass, set auth open + apconf.authmode = AUTH_OPEN; + // Remove stored password + os_memset(apconf.password, 0, 64); + } +#endif + }// end of ssid and pass check +#ifdef AP_SSID_HIDDEN + // If set, use specified ssid hidden parameter + if(AP_SSID_HIDDEN == 0 || AP_SSID_HIDDEN ==1) + apconf.ssid_hidden = AP_SSID_HIDDEN; +#endif +#ifdef AP_MAX_CONN + // If set, use specified max conn number + if(AP_MAX_CONN > 0 && AP_MAX_CONN <5) + apconf.max_connection = AP_MAX_CONN; +#endif +#ifdef AP_BEACON_INTERVAL + // If set use specified beacon interval + if(AP_BEACON_INTERVAL >= 100 && AP_BEACON_INTERVAL <= 60000) + apconf.beacon_interval = AP_BEACON_INTERVAL; +#endif + // Check softap config + bool softap_set_conf = wifi_softap_set_config(&apconf); + // Debug info + + DBG("Wifi Soft-AP parameters change: %s\n",softap_set_conf? "success":"fail"); +#endif // AP_SSID && AP_PASS + + configWifiIP(); + + // The default sleep mode should be modem_sleep, but we set it here explicitly for good + // measure. We can't use light_sleep because that powers off everthing and we would loose + // all connections. + wifi_set_sleep_type(MODEM_SLEEP_T); + + wifi_set_event_handler_cb(wifiHandleEventCb); + // check on the wifi in a few seconds to see whether we need to switch mode + os_timer_disarm(&resetTimer); + os_timer_setfn(&resetTimer, resetTimerCb, NULL); + os_timer_arm(&resetTimer, RESET_TIMEOUT, 0); +} \ No newline at end of file diff --git a/esp-link/cgiwifi.h b/esp-link/cgiwifi.h index e2e98bc..667f27d 100644 --- a/esp-link/cgiwifi.h +++ b/esp-link/cgiwifi.h @@ -13,10 +13,13 @@ int cgiWiFiConnect(HttpdConnData *connData); int cgiWiFiSetMode(HttpdConnData *connData); int cgiWiFiConnStatus(HttpdConnData *connData); int cgiWiFiSpecial(HttpdConnData *connData); +int cgiApSettingsChange(HttpdConnData *connData); +int cgiApSettingsInfo(HttpdConnData *connData); void configWifiIP(); void wifiInit(void); void wifiAddStateChangeCb(WifiStateChangeCb cb); void wifiStartMDNS(struct ip_addr); +int checkString(char *str); extern uint8_t wifiState; extern bool mdns_started; diff --git a/esp-link/main.c b/esp-link/main.c index 09904e1..4f7de35 100644 --- a/esp-link/main.c +++ b/esp-link/main.c @@ -72,6 +72,8 @@ HttpdBuiltInUrl builtInUrls[] = { { "/wifi/connstatus", cgiWiFiConnStatus, NULL }, { "/wifi/setmode", cgiWiFiSetMode, NULL }, { "/wifi/special", cgiWiFiSpecial, NULL }, + { "/wifi/apinfo", cgiApSettingsInfo, NULL }, + { "/wifi/apchange", cgiApSettingsChange, NULL }, { "/system/info", cgiSystemInfo, NULL }, { "/system/update", cgiSystemSet, NULL }, { "/services/info", cgiServicesInfo, NULL }, @@ -86,7 +88,6 @@ HttpdBuiltInUrl builtInUrls[] = { #ifdef SHOW_HEAP_USE static ETSTimer prHeapTimer; - static void ICACHE_FLASH_ATTR prHeapTimerCb(void *arg) { os_printf("Heap: %ld\n", (unsigned long)system_get_free_heap_size()); } @@ -110,47 +111,23 @@ void user_rf_pre_init(void) { // Main routine to initialize esp-link. void user_init(void) { // get the flash config so we know how to init things -// configWipe(); // uncomment to reset the config for testing purposes + //configWipe(); // uncomment to reset the config for testing purposes bool restoreOk = configRestore(); - // init gpio pin registers + // Init gpio pin registers gpio_init(); gpio_output_set(0, 0, 0, (1<<15)); // some people tie it to GND, gotta ensure it's disabled // init UART uart_init(flashConfig.baud_rate, 115200); logInit(); // must come after init of uart - // say hello (leave some time to cause break in TX after boot loader's msg + // Say hello (leave some time to cause break in TX after boot loader's msg os_delay_us(10000L); os_printf("\n\n** %s\n", esp_link_version); os_printf("Flash config restore %s\n", restoreOk ? "ok" : "*FAILED*"); - -#if defined(STA_SSID) && defined(STA_PASS) - int x = wifi_get_opmode() & 0x3; - if (x == 2) { - // we only force the STA settings when a full flash of the module has been made, which - // resets the wifi settings not to have anything configured - struct station_config stconf; - wifi_station_get_config(&stconf); - - if (os_strlen((char*)stconf.ssid) == 0 && os_strlen((char*)stconf.password) == 0) { - os_strncpy((char*)stconf.ssid, VERS_STR(STA_SSID), 32); - os_strncpy((char*)stconf.password, VERS_STR(STA_PASS), 64); -#ifdef CGIWIFI_DBG - os_printf("Wifi pre-config trying to connect to AP %s pw %s\n", - (char*)stconf.ssid, (char*)stconf.password); -#endif - wifi_set_opmode(3); // sta+ap, will switch to sta-only 15 secs after connecting - stconf.bssid_set = 0; - wifi_station_set_config(&stconf); - } - } -#endif - // Status LEDs statusInit(); serledInit(); // Wifi wifiInit(); - // init the flash filesystem with the html stuff espFsInit(&_binary_espfs_img_start); //EspFsInitResult res = espFsInit(&_binary_espfs_img_start); @@ -175,16 +152,14 @@ void user_init(void) { NOTICE("Flash map %s, manuf 0x%02lX chip 0x%04lX", flash_maps[system_get_flash_size_map()], fid & 0xff, (fid&0xff00)|((fid>>16)&0xff)); NOTICE("** esp-link ready"); - + + // Init SNTP service cgiServicesSNTPInit(); - #ifdef MQTT NOTICE("initializing MQTT"); mqtt_client_init(); #endif - NOTICE("initializing user application"); app_init(); - - NOTICE("waiting for work to do..."); + NOTICE("Waiting for work to do..."); } diff --git a/html/wifi/wifiAp.html b/html/wifi/wifiAp.html new file mode 100644 index 0000000..e93e54d --- /dev/null +++ b/html/wifi/wifiAp.html @@ -0,0 +1,124 @@ +
+
+

WiFi Soft-AP Configuration

+
+ +
+
+
+
+

Soft-AP State

+
+
+ + + + + + + + + + + + +
+
+
+ +
+

Soft-AP Settings

+
+ + +
+
+
+
+
+ + + + + + diff --git a/html/wifi/wifiAp.js b/html/wifi/wifiAp.js new file mode 100644 index 0000000..e2fef60 --- /dev/null +++ b/html/wifi/wifiAp.js @@ -0,0 +1,98 @@ +var specials = []; +specials["ap_ssid"] = "SSID name"; +specials["ap_password"] = "PASSWORD"; +specials["ap_maxconn"] = "Max Connections number"; +specials["ap_beacon"] = "Beacon Interval"; + +function changeWifiMode(m) { + blockScan = 1; + hideWarning(); + ajaxSpin("POST", "setmode?mode=" + m, function(resp) { + showNotification("Mode changed"); + window.setTimeout(getWifiInfo, 100); + blockScan = 0; + }, function(s, st) { + showWarning("Error changing mode: " + st); + window.setTimeout(getWifiInfo, 100); + blockScan = 0; + }); +} + +function changeApSettings(e) { + e.preventDefault(); + var url = "/wifi/apchange?100=1"; + var i, inputs = document.querySelectorAll("#" + e.target.id + " input,select"); + for (i = 0; i < inputs.length; i++) { + if (inputs[i].type == "checkbox") { + var val = (inputs[i].checked) ? 1 : 0; + url += "&" + inputs[i].name + "=" + val; + } + else{ + var clean = inputs[i].value.replace(/[^\w]/gi, ""); + var comp = clean.localeCompare(inputs[i].value); + if ( comp != 0 ){ + showWarning("Invalid characters in " + specials[inputs[i].name]); + return; + } + url += "&" + inputs[i].name + "=" + clean; + } + }; + + hideWarning(); + var n = e.target.id.replace("-form", ""); + var cb = $("#" + n + "-button"); + addClass(cb, "pure-button-disabled"); + ajaxSpin("POST", url, function (resp) { + showNotification(n + " updated"); + removeClass(cb, "pure-button-disabled"); + window.setTimeout(getWifiInfo, 100); + }, function (s, st) { + showWarning(st); + removeClass(cb, "pure-button-disabled"); + window.setTimeout(fetchApSettings, 2000); + }); +} + +function displayApSettings(data) { + Object.keys(data).forEach(function (v) { + el = $("#" + v); + if (el != null) { + if (el.nodeName === "INPUT") el.value = data[v]; + else el.innerHTML = data[v]; + return; + } + + el = document.querySelector('input[name="' + v + '"]'); + if (el == null) + el = document.querySelector('select[name="' + v + '"]'); + + if (el != null) { + if (el.type == "checkbox") { + el.checked = data[v] == "enabled"; + } else el.value = data[v]; + } + }); + + $("#AP_Settings-spinner").setAttribute("hidden", ""); + $("#AP_Settings-form").removeAttribute("hidden"); + showWarning("Don't modify SOFTAP parameters with active connections"); + window.setTimeout(hideWarning(), 2000); +} + +function fetchApSettings() { + ajaxJson("GET", "/wifi/apinfo", displayApSettings, function () { + window.setTimeout(fetchApSettings, 1000); + }); +} + +function doApAdvanced() { + $('#AP_Settings-on').removeAttribute('hidden'); + $("#AP_Settings-off").setAttribute("hidden", ""); + $("#AP_Settings-roff").removeAttribute("checked"); +} + +function undoApAdvanced(){ + $("#AP_Settings-on").setAttribute("hidden", ""); + $("#AP_Settings-off").removeAttribute("hidden"); + $("#AP_Settings-roff").setAttribute("checked", ""); +} \ No newline at end of file diff --git a/html/wifi/wifi.html b/html/wifi/wifiSta.html similarity index 96% rename from html/wifi/wifi.html rename to html/wifi/wifiSta.html index f6d6646..bdc6dca 100644 --- a/html/wifi/wifi.html +++ b/html/wifi/wifiSta.html @@ -1,6 +1,6 @@
-

WiFi Configuration

+

WiFi Station Configuration

@@ -19,7 +19,9 @@ WiFi MAC -
+ + +

WiFi Association

@@ -70,7 +72,7 @@ - +