2018-11-19 17:07:25 +00:00
/*
2019-10-27 10:13:24 +00:00
support_wifi . ino - wifi support for Tasmota
2018-11-19 17:07:25 +00:00
2019-12-31 13:23:34 +00:00
Copyright ( C ) 2020 Theo Arends
2018-11-19 17:07:25 +00:00
This program is free software : you can redistribute it and / or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation , either version 3 of the License , or
( at your option ) any later version .
This program is distributed in the hope that it will be useful ,
but WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
GNU General Public License for more details .
You should have received a copy of the GNU General Public License
along with this program . If not , see < http : //www.gnu.org/licenses/>.
*/
/*********************************************************************************************\
* Wifi
\ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2018-11-20 13:10:32 +00:00
# ifndef WIFI_RSSI_THRESHOLD
2020-01-26 14:52:26 +00:00
// Decrease the roam threshold from 10 to 5 to address devices connecting at very low RSSI and being close to inoperative
2020-01-25 18:22:40 +00:00
# define WIFI_RSSI_THRESHOLD 5 // Difference in dB between current network and scanned network
2018-11-20 13:10:32 +00:00
# endif
# ifndef WIFI_RESCAN_MINUTES
2020-01-26 14:52:26 +00:00
// Increase rescan interval from 44 to 5 minutes to improve ability for devices to reach network harmony
# define WIFI_RESCAN_MINUTES 5 // Number of minutes between wifi network rescan
2018-11-20 13:10:32 +00:00
# endif
2019-03-31 10:59:04 +01:00
const uint8_t WIFI_CONFIG_SEC = 180 ; // seconds before restart
2020-01-26 14:52:26 +00:00
// Drop from 20 seconds to 5 seconds since we control the reconnections, not the Arduino SDK
2020-01-25 18:22:40 +00:00
const uint8_t WIFI_CHECK_SEC = 5 ; // seconds
2019-03-31 10:59:04 +01:00
const uint8_t WIFI_RETRY_OFFSET_SEC = 20 ; // seconds
2018-11-19 17:07:25 +00:00
2019-08-18 12:23:43 +01:00
# include <ESP8266WiFi.h> // Wifi, MQTT, Ota, WifiManager
2019-10-11 06:40:55 +01:00
# if LWIP_IPV6
# include <AddrList.h> // IPv6 DualStack
2019-10-14 11:34:01 +01:00
# endif // LWIP_IPV6=1
2018-11-19 17:07:25 +00:00
2019-08-17 16:13:09 +01:00
struct WIFI {
2019-08-18 12:23:43 +01:00
uint32_t last_event = 0 ; // Last wifi connection event
uint32_t downtime = 0 ; // Wifi down duration
uint16_t link_count = 0 ; // Number of wifi re-connect
2019-08-17 16:13:09 +01:00
uint8_t counter ;
uint8_t retry_init ;
uint8_t retry ;
uint8_t status ;
uint8_t config_type = 0 ;
uint8_t config_counter = 0 ;
2019-08-18 12:23:43 +01:00
uint8_t mdns_begun = 0 ; // mDNS active
2019-08-17 16:13:09 +01:00
uint8_t scan_state ;
2020-01-25 18:22:40 +00:00
uint8_t bssid [ 6 ] = { 0 } ;
uint8_t bssid_last [ 6 ] = { 0 } ; // store the last connect bssid
2020-01-26 14:52:26 +00:00
int8_t best_network_db ;
2019-08-17 16:13:09 +01:00
} Wifi ;
2018-11-19 17:07:25 +00:00
int WifiGetRssiAsQuality ( int rssi )
{
int quality = 0 ;
if ( rssi < = - 100 ) {
quality = 0 ;
} else if ( rssi > = - 50 ) {
quality = 100 ;
} else {
quality = 2 * ( rssi + 100 ) ;
}
return quality ;
}
2019-01-28 13:08:33 +00:00
bool WifiConfigCounter ( void )
2018-11-19 17:07:25 +00:00
{
2019-08-17 16:13:09 +01:00
if ( Wifi . config_counter ) {
Wifi . config_counter = WIFI_CONFIG_SEC ;
2018-11-19 17:07:25 +00:00
}
2019-08-17 16:13:09 +01:00
return ( Wifi . config_counter ) ;
2018-11-19 17:07:25 +00:00
}
void WifiConfig ( uint8_t type )
{
2019-08-17 16:13:09 +01:00
if ( ! Wifi . config_type ) {
2018-11-19 17:07:25 +00:00
if ( ( WIFI_RETRY = = type ) | | ( WIFI_WAIT = = type ) ) { return ; }
2019-05-20 14:09:42 +01:00
# ifdef USE_EMULATION
2018-11-19 17:07:25 +00:00
UdpDisconnect ( ) ;
# endif // USE_EMULATION
WiFi . disconnect ( ) ; // Solve possible Wifi hangs
2019-08-17 16:13:09 +01:00
Wifi . config_type = type ;
2018-11-19 17:07:25 +00:00
# ifndef USE_WEBSERVER
2019-10-22 15:34:25 +01:00
if ( WIFI_MANAGER = = Wifi . config_type ) {
Wifi . config_type = WIFI_SERIAL ;
}
2018-11-19 17:07:25 +00:00
# endif // USE_WEBSERVER
2019-08-17 16:13:09 +01:00
Wifi . config_counter = WIFI_CONFIG_SEC ; // Allow up to WIFI_CONFIG_SECS seconds for phone to provide ssid/pswd
Wifi . counter = Wifi . config_counter + 5 ;
2018-11-19 17:07:25 +00:00
blinks = 1999 ;
2019-08-17 16:13:09 +01:00
if ( WIFI_RESTART = = Wifi . config_type ) {
2018-11-19 17:07:25 +00:00
restart_flag = 2 ;
}
2019-08-17 16:13:09 +01:00
else if ( WIFI_SERIAL = = Wifi . config_type ) {
2018-11-19 17:07:25 +00:00
AddLog_P ( LOG_LEVEL_INFO , S_LOG_WIFI , PSTR ( D_WCFG_6_SERIAL " " D_ACTIVE_FOR_3_MINUTES ) ) ;
}
# ifdef USE_WEBSERVER
2019-08-17 16:13:09 +01:00
else if ( WIFI_MANAGER = = Wifi . config_type | | WIFI_MANAGER_RESET_ONLY = = Wifi . config_type ) {
2018-11-19 17:07:25 +00:00
AddLog_P ( LOG_LEVEL_INFO , S_LOG_WIFI , PSTR ( D_WCFG_2_WIFIMANAGER " " D_ACTIVE_FOR_3_MINUTES ) ) ;
2019-08-17 16:13:09 +01:00
WifiManagerBegin ( WIFI_MANAGER_RESET_ONLY = = Wifi . config_type ) ;
2018-11-19 17:07:25 +00:00
}
# endif // USE_WEBSERVER
}
}
2019-11-08 12:00:32 +00:00
void WifiSetMode ( WiFiMode_t wifi_mode )
{
if ( WiFi . getMode ( ) = = wifi_mode ) { return ; }
if ( wifi_mode ! = WIFI_OFF ) {
// See: https://github.com/esp8266/Arduino/issues/6172#issuecomment-500457407
WiFi . forceSleepWake ( ) ; // Make sure WiFi is really active.
delay ( 100 ) ;
}
2019-12-02 10:56:40 +00:00
uint32_t retry = 2 ;
while ( ! WiFi . mode ( wifi_mode ) & & retry - - ) {
AddLog_P ( LOG_LEVEL_INFO , S_LOG_WIFI , PSTR ( " Retry set Mode... " ) ) ;
delay ( 100 ) ;
2019-11-09 13:26:17 +00:00
}
2019-11-08 12:00:32 +00:00
if ( wifi_mode = = WIFI_OFF ) {
delay ( 1000 ) ;
WiFi . forceSleepBegin ( ) ;
delay ( 1 ) ;
} else {
delay ( 30 ) ; // Must allow for some time to init.
}
}
2018-11-19 17:07:25 +00:00
void WiFiSetSleepMode ( void )
{
/* Excerpt from the esp8266 non os sdk api reference (v2.2.1):
* Sets sleep type for power saving . Set WIFI_NONE_SLEEP to disable power saving .
* - Default mode : WIFI_MODEM_SLEEP .
* - In order to lower the power comsumption , ESP8266 changes the TCP timer
* tick from 250 ms to 3 s in WIFI_LIGHT_SLEEP mode , which leads to increased timeout for
* TCP timer . Therefore , the WIFI_MODEM_SLEEP or deep - sleep mode should be used
* where there is a requirement for the accurancy of the TCP timer .
*
* Sleep is disabled in core 2.4 .1 and 2.4 .2 as there are bugs in their SDKs
2019-10-27 10:13:24 +00:00
* See https : //github.com/arendst/Tasmota/issues/2559
2018-11-19 17:07:25 +00:00
*/
// Sleep explanation: https://github.com/esp8266/Arduino/blob/3f0c601cfe81439ce17e9bd5d28994a7ed144482/libraries/ESP8266WiFi/src/ESP8266WiFiGeneric.cpp#L255
# if defined(ARDUINO_ESP8266_RELEASE_2_4_1) || defined(ARDUINO_ESP8266_RELEASE_2_4_2)
# else // Enabled in 2.3.0, 2.4.0 and stage
2019-11-03 12:51:22 +00:00
if ( sleep & & Settings . flag3 . sleep_normal ) { // SetOption60 - Enable normal sleep instead of dynamic sleep
WiFi . setSleepMode ( WIFI_LIGHT_SLEEP ) ; // Allow light sleep during idle times
2018-11-19 17:07:25 +00:00
} else {
2019-11-03 12:51:22 +00:00
WiFi . setSleepMode ( WIFI_MODEM_SLEEP ) ; // Disable sleep (Esp8288/Arduino core and sdk default)
2018-11-19 17:07:25 +00:00
}
# endif
2019-11-11 16:39:24 +00:00
WifiSetOutputPower ( ) ;
2018-11-19 17:07:25 +00:00
}
2018-11-19 22:06:42 +00:00
void WifiBegin ( uint8_t flag , uint8_t channel )
2018-11-19 17:07:25 +00:00
{
const char kWifiPhyMode [ ] = " BGN " ;
2019-05-20 14:09:42 +01:00
# ifdef USE_EMULATION
2018-11-19 17:07:25 +00:00
UdpDisconnect ( ) ;
# endif // USE_EMULATION
# ifdef ARDUINO_ESP8266_RELEASE_2_3_0 // (!strncmp_P(ESP.getSdkVersion(),PSTR("1.5.3"),5))
AddLog_P ( LOG_LEVEL_DEBUG , S_LOG_WIFI , PSTR ( D_PATCH_ISSUE_2186 ) ) ;
2019-11-08 12:00:32 +00:00
// WiFi.mode(WIFI_OFF); // See https://github.com/esp8266/Arduino/issues/2186
WifiSetMode ( WIFI_OFF ) ;
2018-11-19 17:07:25 +00:00
# endif
WiFi . persistent ( false ) ; // Solve possible wifi init errors (re-add at 6.2.1.16 #4044, #4083)
WiFi . disconnect ( true ) ; // Delete SDK wifi config
delay ( 200 ) ;
2019-11-08 12:00:32 +00:00
// WiFi.mode(WIFI_STA); // Disable AP mode
WifiSetMode ( WIFI_STA ) ;
2018-11-19 17:07:25 +00:00
WiFiSetSleepMode ( ) ;
2019-02-18 14:41:41 +00:00
// if (WiFi.getPhyMode() != WIFI_PHY_MODE_11N) { WiFi.setPhyMode(WIFI_PHY_MODE_11N); } // B/G/N
// if (WiFi.getPhyMode() != WIFI_PHY_MODE_11G) { WiFi.setPhyMode(WIFI_PHY_MODE_11G); } // B/G
2018-11-19 17:07:25 +00:00
if ( ! WiFi . getAutoConnect ( ) ) { WiFi . setAutoConnect ( true ) ; }
2020-02-12 15:55:39 +00:00
2020-01-26 14:52:26 +00:00
// Handle the reconnection in WifiCheckIp() since the autoreconnect keeps sending deauthentication messages which causes the AP to block traffic as it looks like an DoS attack
// This needs to be explicitly called as "false" otherwise the default is enabled
2020-02-12 15:55:39 +00:00
// WiFi.setAutoReconnect(false); // See #7621
2018-11-19 17:07:25 +00:00
switch ( flag ) {
case 0 : // AP1
case 1 : // AP2
Settings . sta_active = flag ;
break ;
case 2 : // Toggle
Settings . sta_active ^ = 1 ;
} // 3: Current AP
2019-12-21 16:57:54 +00:00
if ( ! strlen ( SettingsText ( SET_STASSID1 + Settings . sta_active ) ) ) {
2019-12-16 14:13:57 +00:00
Settings . sta_active ^ = 1 ; // Skip empty SSID
}
2018-11-19 17:07:25 +00:00
if ( Settings . ip_address [ 0 ] ) {
WiFi . config ( Settings . ip_address [ 0 ] , Settings . ip_address [ 1 ] , Settings . ip_address [ 2 ] , Settings . ip_address [ 3 ] ) ; // Set static IP
}
WiFi . hostname ( my_hostname ) ;
2020-01-26 14:52:26 +00:00
char stemp [ 40 ] = { 0 } ;
2018-11-19 22:06:42 +00:00
if ( channel ) {
2019-12-16 14:13:57 +00:00
WiFi . begin ( SettingsText ( SET_STASSID1 + Settings . sta_active ) , SettingsText ( SET_STAPWD1 + Settings . sta_active ) , channel , Wifi . bssid ) ;
2020-01-26 14:52:26 +00:00
// Add connected BSSID and channel for multi-AP installations
char hex_char [ 18 ] ;
snprintf_P ( stemp , sizeof ( stemp ) , PSTR ( " Channel %d BSSId %s " ) , channel , ToHex_P ( ( unsigned char * ) Wifi . bssid , 6 , hex_char , sizeof ( hex_char ) , ' : ' ) ) ;
2018-11-19 17:07:25 +00:00
} else {
2019-12-16 14:13:57 +00:00
WiFi . begin ( SettingsText ( SET_STASSID1 + Settings . sta_active ) , SettingsText ( SET_STAPWD1 + Settings . sta_active ) ) ;
2018-11-19 17:07:25 +00:00
}
2020-01-26 14:52:26 +00:00
AddLog_P2 ( LOG_LEVEL_INFO , PSTR ( D_LOG_WIFI D_CONNECTING_TO_AP " %d %s%s " D_IN_MODE " 11%c " D_AS " %s... " ) ,
Settings . sta_active + 1 , SettingsText ( SET_STASSID1 + Settings . sta_active ) , stemp , kWifiPhyMode [ WiFi . getPhyMode ( ) & 0x3 ] , my_hostname ) ;
2020-01-26 13:30:11 +00:00
2019-10-11 06:40:55 +01:00
# if LWIP_IPV6
for ( bool configured = false ; ! configured ; ) {
2019-10-11 13:39:58 +01:00
uint16_t cfgcnt = 0 ;
for ( auto addr : addrList ) {
if ( ( configured = ! addr . isLocal ( ) & & addr . isV6 ( ) ) | | cfgcnt = = 30 ) {
2019-10-13 13:15:32 +01:00
AddLog_P2 ( LOG_LEVEL_INFO , PSTR ( D_LOG_WIFI " Got IPv6 global address %s " ) , addr . toString ( ) . c_str ( ) ) ;
2019-10-11 13:39:58 +01:00
break ; // IPv6 is mandatory but stop after 15 seconds
}
2019-10-11 06:40:55 +01:00
delay ( 500 ) ; // Loop until real IPv6 address is aquired or too many tries failed
cfgcnt + + ;
}
}
2019-10-14 11:34:01 +01:00
# endif // LWIP_IPV6=1
2018-11-19 17:07:25 +00:00
}
2019-11-20 19:53:12 +00:00
void WifiBeginAfterScan ( void )
2018-11-19 22:06:42 +00:00
{
// Not active
2019-08-17 16:13:09 +01:00
if ( 0 = = Wifi . scan_state ) { return ; }
2018-11-19 22:06:42 +00:00
// Init scan when not connected
2019-08-17 16:13:09 +01:00
if ( 1 = = Wifi . scan_state ) {
memset ( ( void * ) & Wifi . bssid , 0 , sizeof ( Wifi . bssid ) ) ;
2020-01-26 14:52:26 +00:00
Wifi . best_network_db = - 127 ;
2019-08-17 16:13:09 +01:00
Wifi . scan_state = 3 ;
2018-11-19 22:06:42 +00:00
}
// Init scan when connected
2019-08-17 16:13:09 +01:00
if ( 2 = = Wifi . scan_state ) {
2018-11-20 11:03:42 +00:00
uint8_t * bssid = WiFi . BSSID ( ) ; // Get current bssid
2019-08-17 16:13:09 +01:00
memcpy ( ( void * ) & Wifi . bssid , ( void * ) bssid , sizeof ( Wifi . bssid ) ) ;
2020-01-26 14:52:26 +00:00
Wifi . best_network_db = WiFi . RSSI ( ) ; // Get current rssi and add threshold
if ( Wifi . best_network_db < - WIFI_RSSI_THRESHOLD ) {
Wifi . best_network_db + = WIFI_RSSI_THRESHOLD ;
}
2019-08-17 16:13:09 +01:00
Wifi . scan_state = 3 ;
2018-11-19 22:06:42 +00:00
}
// Init scan
2019-08-17 16:13:09 +01:00
if ( 3 = = Wifi . scan_state ) {
2018-11-19 22:06:42 +00:00
if ( WiFi . scanComplete ( ) ! = WIFI_SCAN_RUNNING ) {
WiFi . scanNetworks ( true ) ; // Start wifi scan async
2019-08-17 16:13:09 +01:00
Wifi . scan_state + + ;
2018-11-19 22:06:42 +00:00
AddLog_P ( LOG_LEVEL_DEBUG , S_LOG_WIFI , PSTR ( " Network (re)scan started... " ) ) ;
return ;
}
}
int8_t wifi_scan_result = WiFi . scanComplete ( ) ;
// Check scan done
2019-08-17 16:13:09 +01:00
if ( 4 = = Wifi . scan_state ) {
2018-11-19 22:06:42 +00:00
if ( wifi_scan_result ! = WIFI_SCAN_RUNNING ) {
2019-08-17 16:13:09 +01:00
Wifi . scan_state + + ;
2018-11-19 22:06:42 +00:00
}
}
// Scan done
2019-08-17 16:13:09 +01:00
if ( 5 = = Wifi . scan_state ) {
2020-01-25 18:22:40 +00:00
uint32_t number_known = 0 ; // count the number of known AP's so we can clear the Wifi.bssid_last if there is only one
int32_t channel_max = 0 ; // No scan result
int8_t ap_max = 3 ; // AP default if not found
uint8_t bssid_max [ 6 ] ; // Save last bssid
memcpy ( ( void * ) & bssid_max , ( void * ) & Wifi . bssid , sizeof ( bssid_max ) ) ; // store the strongest bssid
2018-11-19 22:06:42 +00:00
int32_t channel = 0 ; // No scan result
int8_t ap = 3 ; // AP default if not found
2018-11-20 11:03:42 +00:00
uint8_t last_bssid [ 6 ] ; // Save last bssid
2019-08-17 16:13:09 +01:00
memcpy ( ( void * ) & last_bssid , ( void * ) & Wifi . bssid , sizeof ( last_bssid ) ) ;
2018-11-19 22:06:42 +00:00
if ( wifi_scan_result > 0 ) {
// Networks found
2019-06-30 15:44:36 +01:00
for ( uint32_t i = 0 ; i < wifi_scan_result ; + + i ) {
2018-11-19 22:06:42 +00:00
String ssid_scan ;
int32_t rssi_scan ;
uint8_t sec_scan ;
uint8_t * bssid_scan ;
int32_t chan_scan ;
bool hidden_scan ;
WiFi . getNetworkInfo ( i , ssid_scan , sec_scan , rssi_scan , bssid_scan , chan_scan , hidden_scan ) ;
bool known = false ;
2019-06-30 15:44:36 +01:00
uint32_t j ;
2020-01-12 12:10:21 +00:00
for ( j = 0 ; j < MAX_SSIDS ; j + + ) {
2019-12-16 14:13:57 +00:00
if ( ssid_scan = = SettingsText ( SET_STASSID1 + j ) ) { // SSID match
2018-11-19 22:06:42 +00:00
known = true ;
2020-01-25 18:22:40 +00:00
number_known + + ;
2020-01-26 14:52:26 +00:00
if ( rssi_scan > Wifi . best_network_db ) { // Best network
2019-12-16 14:13:57 +00:00
if ( sec_scan = = ENC_TYPE_NONE | | SettingsText ( SET_STAPWD1 + j ) ) { // Check for passphrase if not open wlan
2020-01-25 18:22:40 +00:00
// store the max values in case there is only one AP and we need to try to reconnect
memcpy ( ( void * ) & bssid_max , ( void * ) bssid_scan , sizeof ( bssid_max ) ) ;
channel_max = chan_scan ;
ap_max = j ;
// if the bssid is not the same as the last failed attempt, force picking the next strongest AP to prevent getting stuck on a strong RSSI, but poor channel health
for ( uint32_t i = 0 ; i < sizeof ( Wifi . bssid_last ) ; i + + ) {
if ( bssid_scan [ i ] ! = Wifi . bssid_last [ i ] ) {
2020-01-26 14:52:26 +00:00
Wifi . best_network_db = ( int8_t ) rssi_scan ;
2020-01-25 18:22:40 +00:00
channel = chan_scan ;
ap = j ; // AP1 or AP2
memcpy ( ( void * ) & Wifi . bssid , ( void * ) bssid_scan , sizeof ( Wifi . bssid ) ) ;
// save the last bssid used
memcpy ( ( void * ) & Wifi . bssid_last , ( void * ) bssid_scan , sizeof ( Wifi . bssid_last ) ) ;
break ;
}
}
2018-11-19 22:06:42 +00:00
}
}
break ;
}
}
2019-08-10 16:34:59 +01:00
char hex_char [ 18 ] ;
AddLog_P2 ( LOG_LEVEL_DEBUG , PSTR ( D_LOG_WIFI " Network %d, AP%c, SSId %s, Channel %d, BSSId %s, RSSI %d, Encryption %d " ) ,
i ,
( known ) ? ( j ) ? ' 2 ' : ' 1 ' : ' - ' ,
ssid_scan . c_str ( ) ,
chan_scan ,
2019-08-13 18:53:12 +01:00
ToHex_P ( ( unsigned char * ) bssid_scan , 6 , hex_char , sizeof ( hex_char ) , ' : ' ) ,
2019-08-10 16:34:59 +01:00
rssi_scan ,
( sec_scan = = ENC_TYPE_NONE ) ? 0 : 1 ) ;
2018-11-19 22:06:42 +00:00
delay ( 0 ) ;
}
WiFi . scanDelete ( ) ; // Clean up Ram
delay ( 0 ) ;
}
2020-01-25 18:22:40 +00:00
// reset the last bssid if there is only one AP to allow the reconnect of the same AP on the next cycle
if ( number_known = = 1 ) {
// clear the last value
memset ( ( void * ) & Wifi . bssid_last , 0 , sizeof ( Wifi . bssid_last ) ) ;
memcpy ( ( void * ) & Wifi . bssid , ( void * ) bssid_max , sizeof ( Wifi . bssid ) ) ;
channel = channel_max ;
ap = ap_max ;
}
2019-08-17 16:13:09 +01:00
Wifi . scan_state = 0 ;
2018-11-20 11:03:42 +00:00
// If bssid changed then (re)connect wifi
2019-08-17 16:13:09 +01:00
for ( uint32_t i = 0 ; i < sizeof ( Wifi . bssid ) ; i + + ) {
if ( last_bssid [ i ] ! = Wifi . bssid [ i ] ) {
2018-11-19 22:06:42 +00:00
WifiBegin ( ap , channel ) ; // 0 (AP1), 1 (AP2) or 3 (default AP)
break ;
}
}
}
}
2019-11-20 19:53:12 +00:00
uint16_t WifiLinkCount ( void )
2019-02-18 14:41:41 +00:00
{
2019-08-17 16:13:09 +01:00
return Wifi . link_count ;
2019-02-18 14:41:41 +00:00
}
2019-11-20 19:53:12 +00:00
String WifiDowntime ( void )
2019-02-18 17:02:22 +00:00
{
2019-08-17 16:13:09 +01:00
return GetDuration ( Wifi . downtime ) ;
2019-02-18 17:02:22 +00:00
}
2018-11-19 17:07:25 +00:00
void WifiSetState ( uint8_t state )
{
if ( state = = global_state . wifi_down ) {
if ( state ) {
rules_flag . wifi_connected = 1 ;
2019-08-17 16:13:09 +01:00
Wifi . link_count + + ;
Wifi . downtime + = UpTime ( ) - Wifi . last_event ;
2018-11-19 17:07:25 +00:00
} else {
rules_flag . wifi_disconnected = 1 ;
2019-08-17 16:13:09 +01:00
Wifi . last_event = UpTime ( ) ;
2018-11-19 17:07:25 +00:00
}
}
global_state . wifi_down = state ^ 1 ;
}
2019-10-14 11:34:01 +01:00
# if LWIP_IPV6
2019-10-13 13:15:32 +01:00
bool WifiCheckIPv6 ( void )
{
bool ipv6_global = false ;
for ( auto a : addrList ) {
if ( ! a . isLocal ( ) & & a . isV6 ( ) ) ipv6_global = true ;
}
return ipv6_global ;
}
2019-10-24 12:13:16 +01:00
2019-12-11 14:53:19 +00:00
String WifiGetIPv6 ( void )
{
for ( auto a : addrList ) {
if ( ! a . isLocal ( ) & & a . isV6 ( ) ) return a . toString ( ) ;
}
return " " ;
}
2019-10-24 12:13:16 +01:00
bool WifiCheckIPAddrStatus ( void ) // Return false for 169.254.x.x or fe80::/64
{
bool ip_global = false ;
for ( auto a : addrList ) {
if ( ! a . isLocal ( ) ) ip_global = true ;
}
return ip_global ;
}
2019-10-14 11:34:01 +01:00
# endif // LWIP_IPV6=1
2019-10-13 13:15:32 +01:00
2018-11-19 17:07:25 +00:00
void WifiCheckIp ( void )
{
2019-10-14 11:34:01 +01:00
# if LWIP_IPV6
2019-10-24 12:13:16 +01:00
if ( WifiCheckIPAddrStatus ( ) ) {
2019-10-13 13:15:32 +01:00
Wifi . status = WL_CONNECTED ;
# else
2018-11-19 17:07:25 +00:00
if ( ( WL_CONNECTED = = WiFi . status ( ) ) & & ( static_cast < uint32_t > ( WiFi . localIP ( ) ) ! = 0 ) ) {
2019-10-14 11:34:01 +01:00
# endif // LWIP_IPV6=1
2020-01-25 18:22:40 +00:00
// initialize the last connect bssid since we had a successful connection
memset ( ( void * ) & Wifi . bssid_last , 0 , sizeof ( Wifi . bssid_last ) ) ;
2018-11-19 17:07:25 +00:00
WifiSetState ( 1 ) ;
2019-08-17 16:13:09 +01:00
Wifi . counter = WIFI_CHECK_SEC ;
Wifi . retry = Wifi . retry_init ;
2020-02-13 11:46:06 +00:00
if ( Wifi . status ! = WL_CONNECTED ) {
AddLog_P ( LOG_LEVEL_INFO , S_LOG_WIFI , PSTR ( D_CONNECTED ) ) ;
}
Wifi . status = WL_CONNECTED ;
2019-01-17 11:34:06 +00:00
# ifdef USE_DISCOVERY
# ifdef WEBSERVER_ADVERTISE
2019-08-17 16:13:09 +01:00
if ( 2 = = Wifi . mdns_begun ) {
2019-01-16 16:53:23 +00:00
MDNS . update ( ) ;
AddLog_P ( LOG_LEVEL_DEBUG_MORE , D_LOG_MDNS , " MDNS.update " ) ;
}
2019-01-17 11:34:06 +00:00
# endif // USE_DISCOVERY
# endif // WEBSERVER_ADVERTISE
2018-11-19 17:07:25 +00:00
} else {
WifiSetState ( 0 ) ;
uint8_t wifi_config_tool = Settings . sta_config ;
2019-08-17 16:13:09 +01:00
Wifi . status = WiFi . status ( ) ;
switch ( Wifi . status ) {
2018-11-19 17:07:25 +00:00
case WL_CONNECTED :
AddLog_P ( LOG_LEVEL_INFO , S_LOG_WIFI , PSTR ( D_CONNECT_FAILED_NO_IP_ADDRESS ) ) ;
2020-01-25 18:22:40 +00:00
// if poor channel health prevents DHCP broadcast from succeeding, restart the request
// The code will eventually do a recoonect when the 1/2 interval is hit to try another access point if this remains unsuccessful
wifi_station_dhcpc_start ( ) ;
2018-11-19 17:07:25 +00:00
break ;
case WL_NO_SSID_AVAIL :
AddLog_P ( LOG_LEVEL_INFO , S_LOG_WIFI , PSTR ( D_CONNECT_FAILED_AP_NOT_REACHED ) ) ;
2020-02-13 11:46:06 +00:00
if ( WIFI_WAIT = = Settings . sta_config ) {
Wifi . retry = Wifi . retry_init ;
} else {
if ( Wifi . retry > ( Wifi . retry_init / 2 ) ) {
Wifi . retry = Wifi . retry_init / 2 ;
}
else if ( Wifi . retry ) {
Wifi . retry = 0 ;
}
}
2018-11-19 17:07:25 +00:00
break ;
case WL_CONNECT_FAILED :
AddLog_P ( LOG_LEVEL_INFO , S_LOG_WIFI , PSTR ( D_CONNECT_FAILED_WRONG_PASSWORD ) ) ;
2020-02-13 11:46:06 +00:00
if ( Wifi . retry > ( Wifi . retry_init / 2 ) ) {
Wifi . retry = Wifi . retry_init / 2 ;
}
else if ( Wifi . retry ) {
Wifi . retry = 0 ;
}
2018-11-19 17:07:25 +00:00
break ;
default : // WL_IDLE_STATUS and WL_DISCONNECTED
2020-01-25 18:22:40 +00:00
// log on the 1/2 or full interval
2019-08-17 16:13:09 +01:00
if ( ! Wifi . retry | | ( ( Wifi . retry_init / 2 ) = = Wifi . retry ) ) {
2018-11-19 17:07:25 +00:00
AddLog_P ( LOG_LEVEL_INFO , S_LOG_WIFI , PSTR ( D_CONNECT_FAILED_AP_TIMEOUT ) ) ;
} else {
2019-12-21 16:57:54 +00:00
if ( ! strlen ( SettingsText ( SET_STASSID1 ) ) & & ! strlen ( SettingsText ( SET_STASSID2 ) ) ) {
2019-10-22 15:34:25 +01:00
wifi_config_tool = WIFI_MANAGER ; // Skip empty SSIDs and start Wifi config tool
2019-08-17 16:13:09 +01:00
Wifi . retry = 0 ;
2018-11-19 17:07:25 +00:00
} else {
AddLog_P ( LOG_LEVEL_DEBUG , S_LOG_WIFI , PSTR ( D_ATTEMPTING_CONNECTION ) ) ;
}
}
}
2020-01-25 18:22:40 +00:00
2019-08-17 16:13:09 +01:00
if ( Wifi . retry ) {
2019-11-03 12:51:22 +00:00
if ( Settings . flag3 . use_wifi_scan ) { // SetOption56 - Scan wifi network at restart for configured AP's
2020-01-25 18:22:40 +00:00
// check the 1/2 interval as well when rescanning - scan state machine takes 4 seconds
if ( ( Wifi . retry_init = = Wifi . retry ) | | ( ( Wifi . retry_init / 2 ) = = Wifi . retry ) ) {
2019-08-17 16:13:09 +01:00
Wifi . scan_state = 1 ; // Select scanned SSID
2018-11-20 13:10:32 +00:00
}
} else {
2019-08-17 16:13:09 +01:00
if ( Wifi . retry_init = = Wifi . retry ) {
2018-11-19 22:06:42 +00:00
WifiBegin ( 3 , 0 ) ; // Select default SSID
2018-11-19 17:07:25 +00:00
}
2019-08-17 16:13:09 +01:00
if ( ( Settings . sta_config ! = WIFI_WAIT ) & & ( ( Wifi . retry_init / 2 ) = = Wifi . retry ) ) {
2018-11-19 22:06:42 +00:00
WifiBegin ( 2 , 0 ) ; // Select alternate SSID
2018-11-19 17:07:25 +00:00
}
}
2019-08-17 16:13:09 +01:00
Wifi . counter = 1 ;
Wifi . retry - - ;
2018-11-19 17:07:25 +00:00
} else {
WifiConfig ( wifi_config_tool ) ;
2019-08-17 16:13:09 +01:00
Wifi . counter = 1 ;
Wifi . retry = Wifi . retry_init ;
2018-11-19 17:07:25 +00:00
}
}
}
void WifiCheck ( uint8_t param )
{
2019-08-17 16:13:09 +01:00
Wifi . counter - - ;
2018-11-19 17:07:25 +00:00
switch ( param ) {
case WIFI_SERIAL :
case WIFI_MANAGER :
WifiConfig ( param ) ;
break ;
default :
2019-08-17 16:13:09 +01:00
if ( Wifi . config_counter ) {
Wifi . config_counter - - ;
Wifi . counter = Wifi . config_counter + 5 ;
if ( Wifi . config_counter ) {
if ( ! Wifi . config_counter ) {
2018-11-19 17:07:25 +00:00
if ( strlen ( WiFi . SSID ( ) . c_str ( ) ) ) {
2019-12-16 14:13:57 +00:00
SettingsUpdateText ( SET_STASSID1 , WiFi . SSID ( ) . c_str ( ) ) ;
2018-11-19 17:07:25 +00:00
}
if ( strlen ( WiFi . psk ( ) . c_str ( ) ) ) {
2019-12-16 14:13:57 +00:00
SettingsUpdateText ( SET_STAPWD1 , WiFi . psk ( ) . c_str ( ) ) ;
2018-11-19 17:07:25 +00:00
}
Settings . sta_active = 0 ;
2019-12-16 14:13:57 +00:00
AddLog_P2 ( LOG_LEVEL_INFO , PSTR ( D_LOG_WIFI D_WCFG_2_WIFIMANAGER D_CMND_SSID " 1 %s " ) , SettingsText ( SET_STASSID1 ) ) ;
2018-11-19 17:07:25 +00:00
}
}
2019-08-17 16:13:09 +01:00
if ( ! Wifi . config_counter ) {
2018-11-19 17:07:25 +00:00
// SettingsSdkErase(); // Disabled v6.1.0b due to possible bad wifi connects
restart_flag = 2 ;
}
} else {
2019-08-17 16:13:09 +01:00
if ( Wifi . scan_state ) { WifiBeginAfterScan ( ) ; }
2018-11-19 22:06:42 +00:00
2019-08-17 16:13:09 +01:00
if ( Wifi . counter < = 0 ) {
2018-11-19 17:07:25 +00:00
AddLog_P ( LOG_LEVEL_DEBUG_MORE , S_LOG_WIFI , PSTR ( D_CHECKING_CONNECTION ) ) ;
2019-08-17 16:13:09 +01:00
Wifi . counter = WIFI_CHECK_SEC ;
2018-11-19 17:07:25 +00:00
WifiCheckIp ( ) ;
}
2019-10-14 11:34:01 +01:00
# if LWIP_IPV6
2019-10-24 12:13:16 +01:00
if ( WifiCheckIPAddrStatus ( ) ) {
2019-10-13 13:15:32 +01:00
# else
2019-08-17 16:13:09 +01:00
if ( ( WL_CONNECTED = = WiFi . status ( ) ) & & ( static_cast < uint32_t > ( WiFi . localIP ( ) ) ! = 0 ) & & ! Wifi . config_type ) {
2019-10-14 11:34:01 +01:00
# endif // LWIP_IPV6=1
2018-11-19 17:07:25 +00:00
WifiSetState ( 1 ) ;
2018-11-19 22:06:42 +00:00
2019-11-03 12:51:22 +00:00
if ( Settings . flag3 . use_wifi_rescan ) { // SetOption57 - Scan wifi network every 44 minutes for configured AP's
2018-11-20 13:10:32 +00:00
if ( ! ( uptime % ( 60 * WIFI_RESCAN_MINUTES ) ) ) {
2019-08-17 16:13:09 +01:00
Wifi . scan_state = 2 ;
2018-11-19 22:06:42 +00:00
}
}
2019-02-08 13:55:45 +00:00
# ifdef FIRMWARE_MINIMAL
2018-11-19 17:07:25 +00:00
if ( 1 = = RtcSettings . ota_loader ) {
RtcSettings . ota_loader = 0 ;
ota_state_flag = 3 ;
}
2019-02-08 13:55:45 +00:00
# endif // FIRMWARE_MINIMAL
2018-11-19 17:07:25 +00:00
# ifdef USE_DISCOVERY
2019-11-03 12:51:22 +00:00
if ( Settings . flag3 . mdns_enabled ) { // SetOption55 - Control mDNS service
2019-08-17 16:13:09 +01:00
if ( ! Wifi . mdns_begun ) {
2019-01-03 16:30:54 +00:00
// if (mdns_delayed_start) {
// AddLog_P(LOG_LEVEL_INFO, PSTR(D_LOG_MDNS D_ATTEMPTING_CONNECTION));
// mdns_delayed_start--;
// } else {
// mdns_delayed_start = Settings.param[P_MDNS_DELAYED_START];
2019-08-17 16:13:09 +01:00
Wifi . mdns_begun = ( uint8_t ) MDNS . begin ( my_hostname ) ;
AddLog_P2 ( LOG_LEVEL_INFO , PSTR ( D_LOG_MDNS " %s " ) , ( Wifi . mdns_begun ) ? D_INITIALIZED : D_FAILED ) ;
2019-01-03 16:30:54 +00:00
// }
2018-11-19 17:07:25 +00:00
}
}
# endif // USE_DISCOVERY
# ifdef USE_WEBSERVER
if ( Settings . webserver ) {
StartWebserver ( Settings . webserver , WiFi . localIP ( ) ) ;
# ifdef USE_DISCOVERY
# ifdef WEBSERVER_ADVERTISE
2019-08-17 16:13:09 +01:00
if ( 1 = = Wifi . mdns_begun ) {
Wifi . mdns_begun = 2 ;
2018-11-19 17:07:25 +00:00
MDNS . addService ( " http " , " tcp " , WEB_PORT ) ;
}
# endif // WEBSERVER_ADVERTISE
# endif // USE_DISCOVERY
} else {
StopWebserver ( ) ;
}
# ifdef USE_EMULATION
if ( Settings . flag2 . emulation ) { UdpConnect ( ) ; }
# endif // USE_EMULATION
# endif // USE_WEBSERVER
# ifdef USE_KNX
2019-11-03 11:33:36 +00:00
if ( ! knx_started & & Settings . flag . knx_enabled ) { // CMND_KNX_ENABLED
2018-11-19 17:07:25 +00:00
KNXStart ( ) ;
knx_started = true ;
}
# endif // USE_KNX
} else {
WifiSetState ( 0 ) ;
2019-05-20 14:09:42 +01:00
# ifdef USE_EMULATION
2018-11-19 17:07:25 +00:00
UdpDisconnect ( ) ;
# endif // USE_EMULATION
2019-08-17 16:13:09 +01:00
Wifi . mdns_begun = 0 ;
2018-11-19 17:07:25 +00:00
# ifdef USE_KNX
knx_started = false ;
# endif // USE_KNX
}
}
}
}
int WifiState ( void )
{
int state = - 1 ;
if ( ! global_state . wifi_down ) { state = WIFI_RESTART ; }
2019-08-17 16:13:09 +01:00
if ( Wifi . config_type ) { state = Wifi . config_type ; }
2018-11-19 17:07:25 +00:00
return state ;
}
2019-12-27 10:13:22 +00:00
String WifiGetOutputPower ( void )
{
char stemp1 [ TOPSZ ] ;
dtostrfd ( ( float ) ( Settings . wifi_output_power ) / 10 , 1 , stemp1 ) ;
return String ( stemp1 ) ;
}
2019-11-08 12:00:32 +00:00
void WifiSetOutputPower ( void )
{
WiFi . setOutputPower ( ( float ) ( Settings . wifi_output_power ) / 10 ) ;
}
2018-11-19 17:07:25 +00:00
void WifiConnect ( void )
{
WifiSetState ( 0 ) ;
2019-11-08 12:00:32 +00:00
WifiSetOutputPower ( ) ;
2018-11-19 17:07:25 +00:00
WiFi . persistent ( false ) ; // Solve possible wifi init errors
2019-08-17 16:13:09 +01:00
Wifi . status = 0 ;
2020-01-25 18:22:40 +00:00
// lower the rety times now Tasmota control the reconnections, not the Arduino SDK
// Wifi.retry_init = WIFI_RETRY_OFFSET_SEC + ((ESP.getChipId() & 0xF) * 2);
Wifi . retry_init = WIFI_RETRY_OFFSET_SEC + ( ESP . getChipId ( ) & 0xF ) ;
2019-08-17 16:13:09 +01:00
Wifi . retry = Wifi . retry_init ;
Wifi . counter = 1 ;
2018-11-19 17:07:25 +00:00
}
// Enable from 6.0.0a until 6.1.0a - disabled due to possible cause of bad wifi connect on core 2.3.0
// Re-enabled from 6.3.0.7 with ESP.restart replaced by ESP.reset
void WifiDisconnect ( void )
{
// Courtesy of EspEasy
WiFi . persistent ( true ) ; // use SDK storage of SSID/WPA parameters
ETS_UART_INTR_DISABLE ( ) ;
wifi_station_disconnect ( ) ; // this will store empty ssid/wpa into sdk storage
ETS_UART_INTR_ENABLE ( ) ;
WiFi . persistent ( false ) ; // Do not use SDK storage of SSID/WPA parameters
}
2019-11-12 21:30:44 +00:00
void WifiShutdown ( void )
2018-11-19 17:07:25 +00:00
{
delay ( 100 ) ; // Allow time for message xfer - disabled v6.1.0b
2019-11-03 11:33:36 +00:00
if ( Settings . flag . mqtt_enabled ) { // SetOption3 - Enable MQTT
MqttDisconnect ( ) ;
}
2018-11-19 17:07:25 +00:00
WifiDisconnect ( ) ;
2019-11-12 21:30:44 +00:00
}
void EspRestart ( void )
{
WifiShutdown ( ) ;
2019-12-07 17:32:39 +00:00
CrashDumpClear ( ) ; // Clear the stack dump in RTC
2018-11-19 17:07:25 +00:00
// ESP.restart(); // This results in exception 3 on restarts on core 2.3.0
ESP . reset ( ) ;
}