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()