ESP32-micropython- DIY-WebServer -(三) 完整的例子
1 import socket 2 import time 3 import network 4 import machine 5 import _thread 6 import ure 7 import gc 8 import micropython 9 #---------------------------------------------------------------------------------------------- 10 # html 文本 11 #---------------------------------------------------------------------------------------------- 12 13 #---------------------------------------------------------------------- 14 response_headers =micropython.const(""" 15 HTTP/1.1 200 OK 16 Content-Type:text/html;charset=utf-8 17 """) 18 #---------------------------------------------------------------------- 19 response_html_head=micropython.const(""" 20 <!DOCTYPE html> 21 <html> 22 <head> 23 <title>Web控制设备</title> 24 <meta name="viewport" content="width=device-width, initial-scale=1.0"> 25 <style> 26 h2{text-align:center} 27 28 table{ 29 width:100%; 30 text-align:center 31 } 32 33 input[type=text], [type=number],select,p { 34 width: 100%; 35 padding: 12px 20px; 36 margin: 8px 0; 37 display: inline-block; 38 border: 1px solid #ccc; 39 border-radius: 4px; 40 box-sizing: border-box; 41 } 42 43 input[type=submit] { 44 width: 100%; 45 background-color: #4CAF50; 46 color: white; 47 padding: 14px 20px; 48 margin: 8px 0; 49 border: none; 50 border-radius: 4px; 51 cursor: pointer; 52 } 53 54 input[type=submit]:hover { 55 background-color: rgb(0,0,0); 56 } 57 div { 58 border-radius: 5px; 59 background-color: #f2f2f2; 60 padding: 20px; 61 } 62 </style> 63 </head>""") 64 #------------------------------------------------------------------------------------------- 65 # 主菜单 66 response_index_page =micropython.const(""" 67 <body> 68 <h2>功能菜单</h2> 69 <form action="/index_plan" method="get" accept-charset="ISO-8859-1"> 70 <input type="submit" value="计划管理"> 71 </form> 72 73 <form action="/index_rtu" method="get" accept-charset="ISO-8859-1"> 74 <input type="submit" value="RTU管理"> 75 </form> 76 77 <form action="/func_manual" method="get" accept-charset="ISO-8859-1"> 78 <input type="submit" value="手动控制"> 79 </form> 80 81 <form action="/func_com" method="get" accept-charset="ISO-8859-1"> 82 <input type="submit" value="通信配置"> 83 </form> 84 </body> 85 </html> 86 """) 87 #------------------------------------------------------------------------------------------- 88 # 主菜单显示 89 def index_main_page_response(url="",form_dict=dict(),clientSocket=None): 90 if clientSocket is None: 91 return False 92 #给浏览器回送对应的数据 93 clientSocket.send(response_headers.encode("ISO-8859-1")) 94 clientSocket.send(response_html_head.encode("ISO-8859-1")) 95 clientSocket.send(response_index_page.encode("ISO-8859-1")) 96 return True 97 #------------------------------------------------------------------------------------------- 98 # 手动控制 url = "func_menual" 99 # RTU复位,正转,反转 100 # "结束标志",#31 自有,通信成功,相应的位置1。 101 hostRegEx = dict() 102 hostRegEx[32] = 0 #RTU正转标志 32 103 hostRegEx[33] = 0 #RTU反转标志 33 104 hostRegEx[34] = 0 #RTU重新启动 34 105 106 def func_manual_page_response(url="func_manual",form_dict=dict(),clientSocket=None): 107 #提取FORM表单提交的寄存器值 108 hostRegEx[32] = 0 #RTU正转标志 109 hostRegEx[33] = 0 #RTU反转标志 110 hostRegEx[34] = 0 #RTU重新启动 111 #------------------------------------------------------------------ 112 Word_Reg = dict() 113 for each in form_dict.keys(): 114 ret = ure.match("W([0-9]+)b([0-9]+)",each.strip()) #"W1b2" 寄存器1第2位 115 if ret: 116 print(each) 117 value = int(form_dict[each].strip()) 118 if value !=0: 119 value = 0x0001<<( int( ret.group(2).strip() ) ) 120 121 if ret.group(1) not in Word_Reg.keys(): 122 Word_Reg[ret.group(1)]=value 123 else: 124 Word_Reg[ret.group(1)]=value+Word_Reg[ret.group(1)] 125 126 for each in Word_Reg.keys(): 127 #保存新的寄存器值 128 hostRegEx[ int(each) ] = Word_Reg[each] 129 130 print(hostRegEx) 131 #------------------------------------------------------------------ 132 #给浏览器回送html开头 133 clientSocket.send(response_headers.encode("ISO-8859-1")) 134 clientSocket.send(response_html_head.encode("ISO-8859-1")) 135 #------------------------------------------------------------------ 136 #------------------------------------------------------------------ 137 # 138 response_html = """ 139 <body> 140 <h2>手动控制</h2> 141 """ 142 clientSocket.send(response_html.encode("ISO-8859-1")) 143 #------------------------------------------------------------------ 144 # hostRegEx[32] = 0 #RTU正转标志 32 145 # hostRegEx[33] = 0 #RTU反转标志 33 146 # hostRegEx[34] = 0 #RTU重新启动 34 147 #------------------------------------------------------------------ 148 # hostRegEx[32] = 0 #RTU正转标志 32 149 # 给浏览器回送对应的html表单 150 reg_add = 32 151 check_ls =["","","","","","","","","","","","","","",""] 152 for i in range(len(check_ls)): 153 word_bit_flag = 0x0001<<i 154 155 if(word_bit_flag&hostRegEx[reg_add])== word_bit_flag: 156 check_ls[i] ="checked" 157 # 表单头 158 response_html ="""\ 159 <form action="/%s" method="get" accept-charset="ISO-8859-1"> 160 """%(url) 161 clientSocket.send(response_html.encode("ISO-8859-1")) 162 163 response_html =""" 164 <label>选择RTU正转:</label> <br> 165 <p><input type="checkbox" name="W32b0" value=1 %s> RTU终端-01\ 166 <input type="checkbox" name="W32b1" value=1 %s> RTU终端-02\ 167 <input type="checkbox" name="W32b2" value=1 %s> RTU终端-03\ 168 <input type="checkbox" name="W32b3" value=1 %s> RTU终端-04\ 169 <input type="checkbox" name="W32b4" value=1 %s> RTU终端-05\ 170 </p> 171 <p><input type="checkbox" name="W32b5" value=1 %s> RTU终端-06\ 172 <input type="checkbox" name="W32b6" value=1 %s> RTU终端-07\ 173 <input type="checkbox" name="W32b7" value=1 %s> RTU终端-08\ 174 <input type="checkbox" name="W32b8" value=1 %s> RTU终端-09\ 175 <input type="checkbox" name="W32b9" value=1 %s> RTU终端-10\ 176 </p> 177 <p><input type="checkbox" name="W32b10" value=1 %s> RTU终端-11\ 178 <input type="checkbox" name="W32b11" value=1 %s> RTU终端-12\ 179 <input type="checkbox" name="W32b12" value=1 %s> RTU终端-13\ 180 <input type="checkbox" name="W32b13" value=1 %s> RTU终端-14\ 181 <input type="checkbox" name="W32b14" value=1 %s> RTU终端-15\ 182 </p> 183 184 <input type="submit" value="启动正转"> 185 </form> 186 """%tuple(check_ls) 187 clientSocket.send(response_html.encode("ISO-8859-1")) 188 189 #------------------------------------------------------------------ 190 # hostRegEx[33] = 0 #RTU反转标志 33 191 reg_add = 33 192 check_ls =["","","","","","","","","","","","","","",""] 193 for i in range(len(check_ls)): 194 word_bit_flag = 0x0001<<i 195 196 if(word_bit_flag&hostRegEx[reg_add])== word_bit_flag: 197 check_ls[i] ="checked" 198 # 表单头 199 response_html ="""\ 200 <form action="/%s" method="get" accept-charset="ISO-8859-1"> 201 """%(url) 202 clientSocket.send(response_html.encode("ISO-8859-1")) 203 204 response_html =""" 205 <label>选择RTU反转:</label> <br> 206 <p><input type="checkbox" name="W33b0" value=1 %s> RTU终端-01\ 207 <input type="checkbox" name="W33b1" value=1 %s> RTU终端-02\ 208 <input type="checkbox" name="W33b2" value=1 %s> RTU终端-03\ 209 <input type="checkbox" name="W33b3" value=1 %s> RTU终端-04\ 210 <input type="checkbox" name="W33b4" value=1 %s> RTU终端-05\ 211 </p> 212 <p><input type="checkbox" name="W33b5" value=1 %s> RTU终端-06\ 213 <input type="checkbox" name="W33b6" value=1 %s> RTU终端-07\ 214 <input type="checkbox" name="W33b7" value=1 %s> RTU终端-08\ 215 <input type="checkbox" name="W33b8" value=1 %s> RTU终端-09\ 216 <input type="checkbox" name="W33b9" value=1 %s> RTU终端-10\ 217 </p> 218 <p><input type="checkbox" name="W33b10" value=1 %s> RTU终端-11\ 219 <input type="checkbox" name="W33b11" value=1 %s> RTU终端-12\ 220 <input type="checkbox" name="W33b12" value=1 %s> RTU终端-13\ 221 <input type="checkbox" name="W33b13" value=1 %s> RTU终端-14\ 222 <input type="checkbox" name="W33b14" value=1 %s> RTU终端-15\ 223 </p> 224 225 <input type="submit" value="启动反转"> 226 </form> 227 """%tuple(check_ls) 228 clientSocket.send(response_html.encode("ISO-8859-1")) 229 #------------------------------------------------------------------ 230 # hostRegEx[34] = 0 #RTU重新启动 34 231 reg_add = 34 232 check_ls =["","","","","","","","","","","","","","",""] 233 for i in range(len(check_ls)): 234 word_bit_flag = 0x0001<<i 235 236 if(word_bit_flag&hostRegEx[reg_add])== word_bit_flag: 237 check_ls[i] ="checked" 238 # 表单头 239 response_html ="""\ 240 <form action="/%s" method="get" accept-charset="ISO-8859-1"> 241 """%(url) 242 clientSocket.send(response_html.encode("ISO-8859-1")) 243 244 response_html =""" 245 <label>选择RTU重新启动:</label> <br> 246 <p><input type="checkbox" name="W34b0" value=1 %s> RTU终端-01\ 247 <input type="checkbox" name="W34b1" value=1 %s> RTU终端-02\ 248 <input type="checkbox" name="W34b2" value=1 %s> RTU终端-03\ 249 <input type="checkbox" name="W34b3" value=1 %s> RTU终端-04\ 250 <input type="checkbox" name="W34b4" value=1 %s> RTU终端-05\ 251 </p> 252 <p><input type="checkbox" name="W34b5" value=1 %s> RTU终端-06\ 253 <input type="checkbox" name="W34b6" value=1 %s> RTU终端-07\ 254 <input type="checkbox" name="W34b7" value=1 %s> RTU终端-08\ 255 <input type="checkbox" name="W34b8" value=1 %s> RTU终端-09\ 256 <input type="checkbox" name="W34b9" value=1 %s> RTU终端-10\ 257 </p> 258 <p><input type="checkbox" name="W34b10" value=1 %s> RTU终端-11\ 259 <input type="checkbox" name="W34b11" value=1 %s> RTU终端-12\ 260 <input type="checkbox" name="W34b12" value=1 %s> RTU终端-13\ 261 <input type="checkbox" name="W34b13" value=1 %s> RTU终端-14\ 262 <input type="checkbox" name="W34b14" value=1 %s> RTU终端-15\ 263 </p> 264 265 <input type="submit" value="重新启动"> 266 </form> 267 """%tuple(check_ls) 268 clientSocket.send(response_html.encode("ISO-8859-1")) 269 #------------------------------------------------------------------ 270 # 给浏览器回送对应的html结尾 271 response_html = """ 272 <form action="/index_main" method="get" accept-charset="ISO-8859-1"> 273 <input type="submit" value="退出返回"> 274 </form> 275 <!--END 表单--> 276 </body> 277 </html> 278 """ 279 clientSocket.send(response_html.encode("ISO-8859-1")) 280 281 #------------------------------------------------------------------ 282 #------------------------------------------------------------------ 283 #------------------------------------------------------------------ 284 # 根据hostRegEx, 串口通信控制RTU。 285 # hostRegEx[32] = 0 #RTU正转标志 32 286 # hostRegEx[33] = 0 #RTU反转标志 33 287 # hostRegEx[34] = 0 #RTU重新启动 34 288 return True 289 290 #---------------------------------------------------------------------------------------------- 291 # 292 #---------------------------------------------------------------------------------------------- 293 # 294 # url 与 处理函数 295 url_func_dict=dict() 296 297 #---------------------------------------------------------------------------------------------- 298 # 从 浏览器发回的Request中提取方法和参数字典。 299 class parse_url_request: 300 def __init__(self, request) : 301 self.request = request 302 self.method = None 303 self.url = None 304 self.paras_dict = dict() 305 306 def parse_request(self): 307 self.paras_dict = dict() 308 request_lines = self.request.split("\n") 309 print(request_lines) 310 311 for line in request_lines: 312 line=line.strip("\r").strip(" ") 313 if len(line)==0 or len(line)>256: 314 continue 315 # URL 316 search = ure.search("(?:GET|POST) /(.*?)(?:\?.*?)? HTTP", line) 317 if search: 318 try: 319 self.url = search.group(1).decode("utf-8").rstrip("/") 320 except Exception: 321 self.url = search.group(1).rstrip("/") 322 print("URL is {}".format(self.url)) 323 # GET 方法 324 regex = ure.compile(".*GET /(.*?)(\\?.*?)? HTTP")# 定义正则表达式模式 325 ret = regex.search(line)# 匹配字符串 326 if ret != None: 327 print("GET方法") 328 self.method ="GET" 329 regex = ure.compile(r"[/?&]+") 330 ls = regex.split(ret.group(0)) 331 for item in ls: 332 #print(item) 333 regex= ure.compile(r'(.*)=(\d*)') 334 match = regex.match(item) 335 if match: 336 #print(match.group(1)," : ",match.group(2)) 337 self.paras_dict[match.group(1).strip()] = match.group(2).strip() 338 return 339 # POST 方法 340 regex = ure.compile(".*POST /(.*?)(\\?.*?)? HTTP")# 定义正则表达式模式 341 ret = regex.search(line)# 匹配字符串 342 if ret != None: 343 print("POST方法") 344 self.method ="POST" 345 if self.method !="POST": 346 continue 347 regex = ure.compile("(.+=.+)&(.+=.+)")# 定义正则表达式模式 348 ret = regex.search(line)# 匹配字符串 349 if ret != None: 350 #print(ret.group(0)) 351 regex = ure.compile(r"[ &]+") 352 ls = regex.split(ret.group(0)) 353 #print(ls) 354 for item in ls: 355 #print(item) 356 regex= ure.compile(r'(\w+)=(\w+)') 357 match = regex.match(item) 358 if match: 359 #print("#---") 360 #print(match.group(1)," : ",match.group(2)) 361 self.paras_dict[match.group(1).strip()] = match.group(2).strip() 362 return 363 364 #---------------------------------------------------------------------------------------------- 365 def connect_wifi_ap(): 366 wlan = network.WLAN(network.STA_IF) 367 wlan.active(True) 368 if not wlan.isconnected(): 369 print('connecting to network...') 370 wlan.connect('fireworm', '1234567899') # 手机热点 账号,密码 371 i = 1 372 while not wlan.isconnected(): 373 print("正在链接...{}".format(i)) 374 i += 1 375 time.sleep(1) 376 print('network config:', wlan.ifconfig()) 377 return wlan.ifconfig()[0] 378 379 #---------------------------------------------------------------------------------------------- 380 def open_wifi_ap(): 381 ap = network.WLAN(network.AP_IF) #设置开发板为AP模式 382 ap.active(True) 383 ap.config(essid='ZhimaDIY') #配置接入点信息 384 ap.config(authmode=3, password='12345678')#WIFI热点,用户名与密码 385 ap.ifconfig((micropython.const('192.168.3.1'), '255.255.255.0', '192.168.3.1', '8.8.8.8'))# 服务器IP地址 386 print('network config:', ap.ifconfig()) 387 return ap.ifconfig()[0] 388 389 #---------------------------------------------------------------------------------------------- 390 def handle_request(client_socket): 391 """ 392 处理浏览器发送过来的数据 393 然后回送相对应的数据(html、css、js、img。。。) 394 :return: 395 """ 396 print("---handle_request-1") 397 # 用新的套接字为已经连接好的客户端服务器 398 recv_content = client_socket.recv(1024).decode("utf-8") 399 if not recv_content: 400 # 当客户端调用了close后,recv返回值为空,此时服务套接字就可以close了 401 # 4. 关闭套接字 402 client_socket.close() 403 return False 404 print("---handle_request-2") 405 print("-----接收到的客户端(浏览器)发来的数据如下----:") 406 print(recv_content) 407 print("---handle_request-3") 408 # 解析 url、表单 409 parse_cls=parse_url_request(recv_content) 410 parse_cls.parse_request() 411 print(parse_cls.url) 412 print(parse_cls.method) 413 print(parse_cls.paras_dict) 414 url = parse_cls.url 415 url = url.partition("@")# 切分,取url 416 if url[0] in url_func_dict.keys(): 417 # 2. 处理请求(此时忽略) 418 func = url_func_dict[url[0]] 419 # 3.1 整理要回送的数据 420 print(client_socket) 421 func(url=parse_cls.url,form_dict=parse_cls.paras_dict,clientSocket=client_socket) 422 else: 423 #response_boy 424 print("---handle_request-4") 425 # 3.2 给浏览器回送对应的数据 426 index_main_page_response(url="index_main",form_dict=dict(),clientSocket=client_socket) # 主菜单 427 print("---handle_request-5") 428 429 # 4. 关闭套接字 430 client_socket.close() 431 return True 432 433 #---------------------------------------------------------------------------------------------- 434 def url_func_link(): 435 # 绑定 链接与html处理函数 436 url_func_dict["index_main"] = index_main_page_response 437 url_func_dict["index_plan"] = index_main_page_response 438 url_func_dict["index_rtu"] = index_main_page_response 439 440 url_func_dict["func_manual"] = func_manual_page_response 441 442 #---------------------------------------------------------------------------------------------- 443 def tcp_html_server(): 444 print("---html_server-1") 445 # 0.绑定链接与html处理函数 446 url_func_link() 447 # 1. 创建套接字 448 tcp_server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 449 # 为了保证在tcp先断开的情况下,下一次依然能够使用指定的端口,需要设置 450 tcp_server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) 451 print("---html_server-2---") 452 # 2. 绑定本地信息 453 tcp_server_socket.bind(("", 80)) 454 print("---html_server-3") 455 # 3. 变成监听套接字 456 tcp_server_socket.listen(0) 457 print("---html_server-4") 458 while True: 459 # 4. 等待客户端的链接 460 try: 461 client_socket, client_info = tcp_server_socket.accept() 462 print("---html_server-5") 463 464 print("Client:",client_info) # 打印 当前是哪个客户端进行了请求 465 print("---html_server-6") 466 # 5. 为客户端服务 467 #线程方式处理客户端链接 468 _thread.stack_size(10*1024)# 设置足够深的Stack,防止RuntimeError: maximum recursion depth exceeded 469 _thread.start_new_thread(handle_request,(client_socket,)) 470 #普通方式处理客户端链接 471 #handle_request(client_socket) 472 print("---html_server-7") 473 except: 474 print("IOError") 475 finally: 476 pass 477 # 6. 关闭套接字 478 tcp_server_socket.close() 479 480 #---------------------------------------------------------------------------------------------- 481 def web_server(): 482 # 1. 链接wifi 483 #ip = connect_wifi_ap() 484 ip = open_wifi_ap() 485 print("Wifi链接ESP32热点,浏览器输入ip地址是:", ip) 486 487 # 2. 创建tcp服务器,等待客户端链接,然后根据客户端的命令控制设备 488 _thread.stack_size(10*1024)# 设置足够深的Stack 489 _thread.start_new_thread(tcp_html_server,()) 490 #tcp_html_server() 491 492 493 if __name__ == "__main__": 494 #open_wifi_ap() 495 496 web_server()
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET10 - 预览版1新功能体验(一)