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()
复制代码

 

posted @   辛河  阅读(150)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET10 - 预览版1新功能体验(一)
点击右上角即可分享
微信分享提示