2017-10-22 19:49:26 +00:00
import network
import socket
import ure
import time
2017-12-12 01:37:11 +00:00
ap_ssid = " WifiManager "
ap_password = " tayfunulu "
ap_authmode = 3 # WPA2
2017-11-19 10:02:15 +00:00
2018-05-31 14:09:17 +00:00
# If `link_to_next_webui` is set to `True` on the successfully connected page there is a link to the IP of the ESP in the newly connected WiFi.
# This is useful if the ESP shows an other web interface after the WiFiManager, because the user can just click the link and doesn't have to search the new IP of the ESP.
2018-05-30 11:24:06 +00:00
link_to_next_webui = True
2017-11-19 10:02:15 +00:00
2017-12-12 01:18:52 +00:00
NETWORK_PROFILES = ' wifi.dat '
2017-12-11 23:34:09 +00:00
2017-12-12 03:07:20 +00:00
wlan_ap = network . WLAN ( network . AP_IF )
wlan_sta = network . WLAN ( network . STA_IF )
server_socket = None
2017-12-12 01:05:11 +00:00
def get_connection ( ) :
""" return a working WLAN(STA_IF) instance or None """
2017-12-12 03:07:20 +00:00
# First check if there already is any connection:
if wlan_sta . isconnected ( ) :
return wlan_sta
connected = False
try :
# ESP connecting to WiFi takes time, wait a bit and try again:
time . sleep ( 3 )
if wlan_sta . isconnected ( ) :
return wlan_sta
# Read known network profiles from file
profiles = read_profiles ( )
# Search WiFis in range
2017-12-12 01:48:03 +00:00
wlan_sta . active ( True )
2017-12-12 03:07:20 +00:00
networks = wlan_sta . scan ( )
AUTHMODE = { 0 : " open " , 1 : " WEP " , 2 : " WPA-PSK " , 3 : " WPA2-PSK " , 4 : " WPA/WPA2-PSK " }
for ssid , bssid , channel , rssi , authmode , hidden in sorted ( networks , key = lambda x : x [ 3 ] , reverse = True ) :
ssid = ssid . decode ( ' utf-8 ' )
encrypted = authmode > 0
print ( " ssid: %s chan: %d rssi: %d authmode: %s " % ( ssid , channel , rssi , AUTHMODE . get ( authmode , ' ? ' ) ) )
if encrypted :
if ssid in profiles :
password = profiles [ ssid ]
connected = do_connect ( ssid , password )
else :
print ( " skipping unknown encrypted network " )
else : # open
connected = do_connect ( ssid , None )
if connected :
break
2017-12-12 01:48:03 +00:00
except OSError as e :
print ( " exception " , str ( e ) )
2017-12-12 03:07:20 +00:00
# start web server for connection manager:
if not connected :
connected = start ( )
return wlan_sta if connected else None
2017-12-11 23:34:09 +00:00
def read_profiles ( ) :
with open ( NETWORK_PROFILES ) as f :
lines = f . readlines ( )
profiles = { }
for line in lines :
ssid , password = line . strip ( " \n " ) . split ( " ; " )
profiles [ ssid ] = password
return profiles
def write_profiles ( profiles ) :
lines = [ ]
for ssid , password in profiles . items ( ) :
lines . append ( " %s ; %s \n " % ( ssid , password ) )
with open ( NETWORK_PROFILES , " w " ) as f :
f . write ( ' ' . join ( lines ) )
2017-12-11 13:38:41 +00:00
2017-12-11 21:11:44 +00:00
def do_connect ( ssid , password ) :
2017-12-12 03:07:20 +00:00
wlan_sta . active ( True )
if wlan_sta . isconnected ( ) :
2017-12-11 21:11:44 +00:00
return None
print ( ' Trying to connect to %s ... ' % ssid )
2017-12-12 03:07:20 +00:00
wlan_sta . connect ( ssid , password )
2023-01-01 10:02:42 +00:00
for retry in range ( 200 ) :
2017-12-12 03:07:20 +00:00
connected = wlan_sta . isconnected ( )
2017-12-11 21:11:44 +00:00
if connected :
break
time . sleep ( 0.1 )
print ( ' . ' , end = ' ' )
if connected :
2017-12-12 03:07:20 +00:00
print ( ' \n Connected. Network config: ' , wlan_sta . ifconfig ( ) )
2023-01-01 10:05:54 +00:00
2017-12-11 21:11:44 +00:00
else :
print ( ' \n Failed. Not Connected to: ' + ssid )
return connected
2017-12-11 13:38:41 +00:00
2017-10-22 19:49:26 +00:00
2018-04-09 22:39:43 +00:00
def send_header ( client , status_code = 200 , content_length = None ) :
2017-12-11 13:38:41 +00:00
client . sendall ( " HTTP/1.0 {} OK \r \n " . format ( status_code ) )
client . sendall ( " Content-Type: text/html \r \n " )
2018-04-09 22:39:43 +00:00
if content_length is not None :
client . sendall ( " Content-Length: {} \r \n " . format ( content_length ) )
2017-12-11 13:38:41 +00:00
client . sendall ( " \r \n " )
2018-05-25 20:23:52 +00:00
2018-04-09 22:39:43 +00:00
def send_response ( client , payload , status_code = 200 ) :
content_length = len ( payload )
send_header ( client , status_code , content_length )
if content_length > 0 :
2017-12-11 13:38:41 +00:00
client . sendall ( payload )
2018-04-09 22:39:43 +00:00
client . close ( )
2017-10-22 19:49:26 +00:00
2018-05-25 20:23:52 +00:00
2017-10-22 19:49:26 +00:00
def handle_root ( client ) :
2017-12-11 20:03:54 +00:00
wlan_sta . active ( True )
ssids = sorted ( ssid . decode ( ' utf-8 ' ) for ssid , * _ in wlan_sta . scan ( ) )
2018-04-09 22:39:43 +00:00
send_header ( client )
client . sendall ( """ \
2017-12-11 19:28:21 +00:00
< html >
< h1 style = " color: #5e9ca0; text-align: center; " >
< span style = " color: #ff0000; " >
Wi - Fi Client Setup
< / span >
< / h1 >
< form action = " configure " method = " post " >
< table style = " margin-left: auto; margin-right: auto; " >
< tbody >
2017-12-11 20:13:01 +00:00
""" )
2018-04-09 22:39:43 +00:00
while len ( ssids ) :
ssid = ssids . pop ( 0 )
client . sendall ( """ \
2017-12-11 20:03:54 +00:00
< tr >
< td colspan = " 2 " >
< input type = " radio " name = " ssid " value = " {0} " / > { 0 }
2017-12-11 19:28:21 +00:00
< / td >
< / tr >
2017-12-11 20:03:54 +00:00
""" .format(ssid))
2018-04-09 22:39:43 +00:00
client . sendall ( """ \
2017-12-11 19:28:21 +00:00
< tr >
2017-12-11 20:03:54 +00:00
< td > Password : < / td >
2017-12-11 19:28:21 +00:00
< td > < input name = " password " type = " password " / > < / td >
< / tr >
< / tbody >
< / table >
< p style = " text-align: center; " >
< input type = " submit " value = " Submit " / >
< / p >
< / form >
< p > & nbsp ; < / p >
< hr / >
< h5 >
< span style = " color: #ff0000; " >
Your ssid and password information will be saved into the
2017-12-11 23:34:09 +00:00
" %(filename)s " file in your ESP module for future usage .
2017-12-11 19:28:21 +00:00
Be careful about security !
< / span >
< / h5 >
< hr / >
< h2 style = " color: #2e6c80; " >
Some useful infos :
< / h2 >
< ul >
< li >
Original code from < a href = " https://github.com/cpopp/MicroPythonSamples "
target = " _blank " rel = " noopener " > cpopp / MicroPythonSamples < / a > .
< / li >
< li >
This code available at < a href = " https://github.com/tayfunulu/WiFiManager "
target = " _blank " rel = " noopener " > tayfunulu / WiFiManager < / a > .
< / li >
< / ul >
< / html >
2017-12-11 23:34:09 +00:00
""" % d ict(filename=NETWORK_PROFILES))
2018-04-09 22:39:43 +00:00
client . close ( )
2017-10-22 19:49:26 +00:00
2018-05-25 20:23:52 +00:00
2017-10-22 19:49:26 +00:00
def handle_configure ( client , request ) :
2017-12-11 13:38:41 +00:00
match = ure . search ( " ssid=([^&]*)&password=(.*) " , request )
2018-05-28 18:06:40 +00:00
2017-12-11 13:38:41 +00:00
if match is None :
send_response ( client , " Parameters not found " , status_code = 400 )
2017-12-11 14:12:22 +00:00
return False
2017-12-11 13:38:41 +00:00
# version 1.9 compatibility
try :
ssid = match . group ( 1 ) . decode ( " utf-8 " ) . replace ( " %3F " , " ? " ) . replace ( " % 21 " , " ! " )
password = match . group ( 2 ) . decode ( " utf-8 " ) . replace ( " %3F " , " ? " ) . replace ( " % 21 " , " ! " )
2018-05-28 18:06:40 +00:00
except Exception :
2017-12-11 13:38:41 +00:00
ssid = match . group ( 1 ) . replace ( " %3F " , " ? " ) . replace ( " % 21 " , " ! " )
password = match . group ( 2 ) . replace ( " %3F " , " ? " ) . replace ( " % 21 " , " ! " )
2018-05-28 18:06:40 +00:00
2017-12-11 13:38:41 +00:00
if len ( ssid ) == 0 :
send_response ( client , " SSID must be provided " , status_code = 400 )
2017-12-11 14:12:22 +00:00
return False
2018-05-28 18:06:40 +00:00
2017-12-11 13:38:41 +00:00
if do_connect ( ssid , password ) :
2017-12-11 20:13:01 +00:00
response = """ \
2017-12-11 19:28:21 +00:00
< html >
< center >
< br > < br >
< h1 style = " color: #5e9ca0; text-align: center; " >
< span style = " color: #ff0000; " >
2018-05-31 21:28:28 +00:00
ESP successfully connected to WiFi network % ( ssid ) s with IP % ( ip ) s .
2017-12-11 19:28:21 +00:00
< / span >
2018-05-31 21:28:28 +00:00
< / h1 > """ % d ict(ssid=ssid, ip=wlan_sta.ifconfig()[0])
2018-05-30 11:24:06 +00:00
if link_to_next_webui :
2018-05-28 18:32:22 +00:00
response + = """ \
< p style = " text-align: center; " >
2018-05-31 21:28:28 +00:00
< a href = " http:// %(ip)s / " > To new Interface < / a > < br >
2018-05-28 18:32:22 +00:00
( You must be connected to the set network to follow this Link )
< / p >
""" % d ict(ip=wlan_sta.ifconfig()[0])
response + = """ \
2017-12-11 19:28:21 +00:00
< br > < br >
< / center >
< / html >
2018-05-28 18:32:22 +00:00
"""
2017-12-11 20:13:01 +00:00
send_response ( client , response )
2023-01-02 20:49:37 +00:00
time . sleep ( 1 )
2023-01-01 10:05:54 +00:00
wlan_ap . active ( False )
2017-12-11 13:38:41 +00:00
try :
2017-12-11 23:34:09 +00:00
profiles = read_profiles ( )
except OSError :
profiles = { }
profiles [ ssid ] = password
write_profiles ( profiles )
2018-05-28 18:52:21 +00:00
time . sleep ( 5 )
2017-12-11 14:12:22 +00:00
return True
2017-12-11 13:38:41 +00:00
else :
2017-12-11 20:13:01 +00:00
response = """ \
2017-12-11 19:28:21 +00:00
< html >
< center >
< h1 style = " color: #5e9ca0; text-align: center; " >
< span style = " color: #ff0000; " >
ESP could not connect to WiFi network % ( ssid ) s .
< / span >
< / h1 >
< br > < br >
< form >
< input type = " button " value = " Go back! " onclick = " history.back() " > < / input >
< / form >
< / center >
< / html >
2017-12-11 20:13:01 +00:00
""" % d ict(ssid=ssid)
send_response ( client , response )
2017-12-11 14:12:22 +00:00
return False
2017-12-11 13:38:41 +00:00
2017-10-22 19:49:26 +00:00
def handle_not_found ( client , url ) :
2017-12-11 13:38:41 +00:00
send_response ( client , " Path not found: {} " . format ( url ) , status_code = 404 )
2017-10-22 19:49:26 +00:00
def stop ( ) :
2017-12-11 13:38:41 +00:00
global server_socket
2018-05-28 18:06:40 +00:00
2017-12-11 13:38:41 +00:00
if server_socket :
server_socket . close ( )
2017-12-12 00:06:12 +00:00
server_socket = None
2017-10-22 19:49:26 +00:00
def start ( port = 80 ) :
2017-12-12 01:37:11 +00:00
global server_socket
2018-05-28 18:06:40 +00:00
2017-12-11 13:38:41 +00:00
addr = socket . getaddrinfo ( ' 0.0.0.0 ' , port ) [ 0 ] [ - 1 ]
2018-05-28 18:06:40 +00:00
2017-12-11 13:38:41 +00:00
stop ( )
2018-05-28 18:06:40 +00:00
2017-12-11 13:38:41 +00:00
wlan_sta . active ( True )
wlan_ap . active ( True )
2018-05-28 18:06:40 +00:00
2017-12-12 01:37:11 +00:00
wlan_ap . config ( essid = ap_ssid , password = ap_password , authmode = ap_authmode )
2018-05-28 18:06:40 +00:00
2017-12-11 13:38:41 +00:00
server_socket = socket . socket ( )
server_socket . bind ( addr )
server_socket . listen ( 1 )
2018-05-28 18:06:40 +00:00
2017-12-12 01:37:11 +00:00
print ( ' Connect to WiFi ssid ' + ap_ssid + ' , default password: ' + ap_password )
2017-12-11 14:06:47 +00:00
print ( ' and access the ESP via your favorite web browser at 192.168.4.1. ' )
print ( ' Listening on: ' , addr )
2018-05-28 18:06:40 +00:00
2017-12-11 13:38:41 +00:00
while True :
if wlan_sta . isconnected ( ) :
2022-12-31 09:10:22 +00:00
wlan_ap . active ( False )
2017-12-11 14:12:22 +00:00
return True
2018-05-28 18:06:40 +00:00
2017-12-11 13:38:41 +00:00
client , addr = server_socket . accept ( )
print ( ' client connected from ' , addr )
try :
2017-12-12 00:06:12 +00:00
client . settimeout ( 5.0 )
2018-05-28 18:06:40 +00:00
2017-12-12 00:06:12 +00:00
request = b " "
try :
while " \r \n \r \n " not in request :
request + = client . recv ( 512 )
except OSError :
pass
2018-05-28 18:06:40 +00:00
2020-09-22 10:43:34 +00:00
# Handle form data from Safari on macOS and iOS; it sends \r\n\r\nssid=<ssid>&password=<password>
try :
2022-12-31 09:07:45 +00:00
request + = client . recv ( 1024 )
2020-09-22 10:43:34 +00:00
print ( " Received form data after \\ r \\ n \\ r \\ n(i.e. from Safari on macOS or iOS) " )
except OSError :
pass
2017-12-12 00:06:12 +00:00
print ( " Request is: {} " . format ( request ) )
2018-05-28 18:06:40 +00:00
if " HTTP " not in request : # skip invalid requests
2017-12-12 00:06:12 +00:00
continue
2018-05-28 18:06:40 +00:00
2017-12-12 00:06:12 +00:00
# version 1.9 compatibility
try :
url = ure . search ( " (?:GET|POST) /(.*?)(?: \\ ?.*?)? HTTP " , request ) . group ( 1 ) . decode ( " utf-8 " ) . rstrip ( " / " )
2018-05-28 18:06:40 +00:00
except Exception :
2017-12-12 00:06:12 +00:00
url = ure . search ( " (?:GET|POST) /(.*?)(?: \\ ?.*?)? HTTP " , request ) . group ( 1 ) . rstrip ( " / " )
print ( " URL is {} " . format ( url ) )
2018-05-28 18:06:40 +00:00
2017-12-12 00:06:12 +00:00
if url == " " :
handle_root ( client )
elif url == " configure " :
handle_configure ( client , request )
else :
handle_not_found ( client , url )
2018-05-28 18:06:40 +00:00
2017-12-12 00:06:12 +00:00
finally :
2017-12-11 13:38:41 +00:00
client . close ( )