Open-source weather station for astronomy
at main 10 kB view raw
1import network 2import socket 3import ure 4import time 5 6ap_ssid = "ESP32-weather" 7ap_password = "station" 8ap_authmode = 3 # WPA2 9 10NETWORK_PROFILES = 'wifi.dat' 11 12wlan_ap = network.WLAN(network.AP_IF) 13wlan_sta = network.WLAN(network.STA_IF) 14 15server_socket = None 16 17 18def get_connection(): 19 """return a working WLAN(STA_IF) instance or None""" 20 21 # First check if there already is any connection: 22 if wlan_sta.isconnected(): 23 return wlan_sta 24 25 connected = False 26 try: 27 # ESP connecting to WiFi takes time, wait a bit and try again: 28 time.sleep(3) 29 if wlan_sta.isconnected(): 30 return wlan_sta 31 32 # Read known network profiles from file 33 profiles = read_profiles() 34 35 # Search WiFis in range 36 wlan_sta.active(True) 37 networks = wlan_sta.scan() 38 39 AUTHMODE = {0: "open", 1: "WEP", 2: "WPA-PSK", 3: "WPA2-PSK", 4: "WPA/WPA2-PSK"} 40 for ssid, bssid, channel, rssi, authmode, hidden in sorted(networks, key=lambda x: x[3], reverse=True): 41 ssid = ssid.decode('utf-8') 42 encrypted = authmode > 0 43 print("ssid: %s chan: %d rssi: %d authmode: %s" % (ssid, channel, rssi, AUTHMODE.get(authmode, '?'))) 44 if encrypted: 45 if ssid in profiles: 46 password = profiles[ssid] 47 connected = do_connect(ssid, password) 48 else: 49 print("skipping unknown encrypted network") 50 else: # open 51 connected = do_connect(ssid, None) 52 if connected: 53 break 54 55 except OSError as e: 56 print("exception", str(e)) 57 58 # start web server for connection manager: 59 if not connected: 60 connected = start() 61 62 return wlan_sta if connected else None 63 64 65def read_profiles(): 66 with open(NETWORK_PROFILES) as f: 67 lines = f.readlines() 68 profiles = {} 69 for line in lines: 70 ssid, password = line.strip("\n").split(";") 71 profiles[ssid] = password 72 return profiles 73 74 75def write_profiles(profiles): 76 lines = [] 77 for ssid, password in profiles.items(): 78 lines.append("%s;%s\n" % (ssid, password)) 79 with open(NETWORK_PROFILES, "w") as f: 80 f.write(''.join(lines)) 81 82 83def do_connect(ssid, password): 84 wlan_sta.active(True) 85 if wlan_sta.isconnected(): 86 return None 87 print('Trying to connect to %s...' % ssid) 88 wlan_sta.connect(ssid, password) 89 for retry in range(200): 90 connected = wlan_sta.isconnected() 91 if connected: 92 break 93 time.sleep(0.1) 94 print('.', end='') 95 if connected: 96 print('\nConnected. Network config: ', wlan_sta.ifconfig()) 97 98 else: 99 print('\nFailed. Not Connected to: ' + ssid) 100 return connected 101 102 103def send_header(client, status_code=200, content_length=None ): 104 client.sendall("HTTP/1.0 {} OK\r\n".format(status_code)) 105 client.sendall("Content-Type: text/html\r\n") 106 if content_length is not None: 107 client.sendall("Content-Length: {}\r\n".format(content_length)) 108 client.sendall("\r\n") 109 110 111def send_response(client, payload, status_code=200): 112 content_length = len(payload) 113 send_header(client, status_code, content_length) 114 if content_length > 0: 115 client.sendall(payload) 116 client.close() 117 118 119def handle_root(client): 120 wlan_sta.active(True) 121 ssids = sorted(ssid.decode('utf-8') for ssid, *_ in wlan_sta.scan()) 122 send_header(client) 123 client.sendall("""\ 124 <html> 125 <h1 style="color: #5e9ca0; text-align: center;"> 126 <span style="color: #ff0000;"> 127 Wi-Fi Client Setup 128 </span> 129 </h1> 130 <form action="configure" method="post"> 131 <table style="margin-left: auto; margin-right: auto;"> 132 <tbody> 133 """) 134 while len(ssids): 135 ssid = ssids.pop(0) 136 client.sendall("""\ 137 <tr> 138 <td colspan="2"> 139 <input type="radio" name="ssid" value="{0}" />{0} 140 </td> 141 </tr> 142 """.format(ssid)) 143 client.sendall("""\ 144 <tr> 145 <td>Password:</td> 146 <td><input name="password" type="password" /></td> 147 </tr> 148 </tbody> 149 </table> 150 <p style="text-align: center;"> 151 <input type="submit" value="Submit" /> 152 </p> 153 </form> 154 <p>&nbsp;</p> 155 <hr /> 156 <h5> 157 <span style="color: #ff0000;"> 158 Your ssid and password information will be saved into the 159 "%(filename)s" file in your ESP module for future usage. 160 Be careful about security! 161 </span> 162 </h5> 163 <hr /> 164 <h2 style="color: #2e6c80;"> 165 Some useful infos: 166 </h2> 167 <ul> 168 <li> 169 Original code from <a href="https://github.com/cpopp/MicroPythonSamples" 170 target="_blank" rel="noopener">cpopp/MicroPythonSamples</a>. 171 </li> 172 <li> 173 This code available at <a href="https://github.com/tayfunulu/WiFiManager" 174 target="_blank" rel="noopener">tayfunulu/WiFiManager</a>. 175 </li> 176 </ul> 177 </html> 178 """ % dict(filename=NETWORK_PROFILES)) 179 client.close() 180 181 182def handle_configure(client, request): 183 match = ure.search("ssid=([^&]*)&password=(.*)", request) 184 185 if match is None: 186 send_response(client, "Parameters not found", status_code=400) 187 return False 188 # version 1.9 compatibility 189 try: 190 ssid = match.group(1).decode("utf-8").replace("%3F", "?").replace("%21", "!") 191 password = match.group(2).decode("utf-8").replace("%3F", "?").replace("%21", "!") 192 except Exception: 193 ssid = match.group(1).replace("%3F", "?").replace("%21", "!") 194 password = match.group(2).replace("%3F", "?").replace("%21", "!") 195 196 if len(ssid) == 0: 197 send_response(client, "SSID must be provided", status_code=400) 198 return False 199 200 if do_connect(ssid, password): 201 response = """\ 202 <html> 203 <center> 204 <br><br> 205 <h1 style="color: #5e9ca0; text-align: center;"> 206 <span style="color: #ff0000;"> 207 ESP successfully connected to WiFi network %(ssid)s. 208 </span> 209 </h1> 210 <br><br> 211 </center> 212 </html> 213 """ % dict(ssid=ssid) 214 send_response(client, response) 215 time.sleep(1) 216 wlan_ap.active(False) 217 try: 218 profiles = read_profiles() 219 except OSError: 220 profiles = {} 221 profiles[ssid] = password 222 write_profiles(profiles) 223 224 time.sleep(5) 225 226 return True 227 else: 228 response = """\ 229 <html> 230 <center> 231 <h1 style="color: #5e9ca0; text-align: center;"> 232 <span style="color: #ff0000;"> 233 ESP could not connect to WiFi network %(ssid)s. 234 </span> 235 </h1> 236 <br><br> 237 <form> 238 <input type="button" value="Go back!" onclick="history.back()"></input> 239 </form> 240 </center> 241 </html> 242 """ % dict(ssid=ssid) 243 send_response(client, response) 244 return False 245 246 247def handle_not_found(client, url): 248 send_response(client, "Path not found: {}".format(url), status_code=404) 249 250 251def stop(): 252 global server_socket 253 254 if server_socket: 255 server_socket.close() 256 server_socket = None 257 258 259def start(port=80): 260 global server_socket 261 262 addr = socket.getaddrinfo('0.0.0.0', port)[0][-1] 263 264 stop() 265 266 wlan_sta.active(True) 267 wlan_ap.active(True) 268 269 wlan_ap.config(essid=ap_ssid, password=ap_password) 270 271 server_socket = socket.socket() 272 server_socket.bind(addr) 273 server_socket.listen(1) 274 275 print('Connect to WiFi ssid ' + ap_ssid + ', default password: ' + ap_password) 276 print('and access the ESP via your favorite web browser at 192.168.4.1.') 277 print('Listening on:', addr) 278 279 while True: 280 if wlan_sta.isconnected(): 281 wlan_ap.active(False) 282 return True 283 284 client, addr = server_socket.accept() 285 print('client connected from', addr) 286 try: 287 client.settimeout(5.0) 288 289 request = b"" 290 try: 291 while "\r\n\r\n" not in request: 292 request += client.recv(512) 293 except OSError: 294 pass 295 296 # Handle form data from Safari on macOS and iOS; it sends \r\n\r\nssid=<ssid>&password=<password> 297 try: 298 request += client.recv(1024) 299 print("Received form data after \\r\\n\\r\\n(i.e. from Safari on macOS or iOS)") 300 except OSError: 301 pass 302 303 print("Request is: {}".format(request)) 304 if "HTTP" not in request: # skip invalid requests 305 continue 306 307 # version 1.9 compatibility 308 try: 309 url = ure.search("(?:GET|POST) /(.*?)(?:\\?.*?)? HTTP", request).group(1).decode("utf-8").rstrip("/") 310 except Exception: 311 url = ure.search("(?:GET|POST) /(.*?)(?:\\?.*?)? HTTP", request).group(1).rstrip("/") 312 print("URL is {}".format(url)) 313 314 if url == "": 315 handle_root(client) 316 elif url == "configure": 317 handle_configure(client, request) 318 else: 319 handle_not_found(client, url) 320 321 finally: 322 client.close()