Skip to content

Commit 5b8866a

Browse files
authored
Merge pull request #19 from jedie/develop
Develop
2 parents ce5748d + 5384dad commit 5b8866a

9 files changed

+318
-41
lines changed

helpers/clear_reset.py

Lines changed: 24 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -3,23 +3,34 @@
33
"""
44

55
import sys
6+
67
sys.modules.clear()
78

8-
import gc
9-
gc.collect()
109

11-
print('DELETE: main.py !!!')
12-
import uos
13-
uos.remove('main.py')
10+
def main():
11+
import gc
12+
gc.collect()
1413

15-
print('Hard reset !')
14+
print('DELETE: main.py !!!')
15+
import uos
16+
try:
17+
uos.remove('main.py')
18+
except BaseException:
19+
# already deleted?
20+
pass
1621

17-
import machine
18-
machine.reset()
22+
print('Hard reset !')
1923

20-
import utime
21-
utime.sleep(1)
24+
import machine
25+
machine.reset()
2226

23-
print('sys.exit()')
24-
import sys
25-
sys.exit()
27+
import utime
28+
utime.sleep(1)
29+
30+
print('sys.exit()')
31+
import sys
32+
sys.exit()
33+
34+
35+
if __name__ == '__main__':
36+
main()

helpers/minimal_webserver.py

Lines changed: 208 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,208 @@
1+
import gc
2+
import sys
3+
4+
import uasyncio as asyncio
5+
6+
_HEX = '0123456789ABCDEF'
7+
8+
_HTML_PREFIX = b"""
9+
<html>
10+
<head><title>Minimal MicroPython Webserver</title></head>
11+
<body>
12+
<h1>Minimal MicroPython Webserver</h1>
13+
<pre>
14+
"""
15+
_HTML_SUFFIX = b"""
16+
</pre>
17+
<hr>
18+
<h2>POST test form:</h2>
19+
<form action="/test/post/" method="post">
20+
<textarea name="text" rows="4" cols="20">POST text
21+
from textarea!</textarea>
22+
<p>
23+
<input type="checkbox" id="c1" name="c1" checked><label for="c1">c1</label>
24+
<input type="checkbox" id="c2" name="c2"><label for="c2">c2</label>
25+
</p>
26+
<input type="submit">
27+
</form>
28+
<hr>
29+
<h2>GET test form:</h2>
30+
<form action="/test/get/" method="get">
31+
<textarea name="text" rows="4" cols="20">GET text
32+
from textarea!</textarea>
33+
<p>
34+
<input type="checkbox" id="c1" name="c1"><label for="c1">c1</label>
35+
<input type="checkbox" id="c2" name="c2" checked><label for="c2">c2</label>
36+
</p>
37+
<input type="submit">
38+
</form>
39+
<hr>
40+
<p>
41+
"""
42+
_HTML_FOOTER = """
43+
</p>
44+
</body>"""
45+
46+
47+
def unquote(string):
48+
string = string.replace('+', ' ')
49+
if '%' not in string:
50+
return string
51+
52+
bits = string.split('%')
53+
if len(bits) == 1:
54+
return string
55+
56+
res = [bits[0]]
57+
for item in bits[1:]:
58+
if len(item) >= 2:
59+
a, b = item[:2].upper()
60+
if a in _HEX and b in _HEX:
61+
res.append(chr(int(a + b, 16)))
62+
res.append(item[2:])
63+
continue
64+
65+
res.append('%')
66+
res.append(item)
67+
68+
return ''.join(res)
69+
70+
71+
def parse_qsl(qs):
72+
if qs is None:
73+
return ()
74+
qs = str(qs)
75+
pairs = [s2 for s1 in qs.split('&') for s2 in s1.split(';')]
76+
res = []
77+
for name_value in pairs:
78+
try:
79+
name, value = name_value.split('=', 1)
80+
except ValueError:
81+
res.append((unquote(name_value), ''))
82+
else:
83+
res.append((unquote(name), unquote(value)))
84+
return res
85+
86+
87+
def request_query2dict(qs):
88+
return dict(parse_qsl(qs))
89+
90+
91+
class WebServer:
92+
async def parse_request(self, reader):
93+
method, url, http_version = (await reader.readline()).decode().strip().split()
94+
print(http_version)
95+
96+
if '?' in url:
97+
url, querystring = url.split('?', 1)
98+
else:
99+
querystring = None
100+
101+
# Consume all headers but use only content-length
102+
content_length = None
103+
while True:
104+
line = await reader.readline()
105+
if line == b'\r\n':
106+
break # header ends
107+
108+
try:
109+
header, value = line.split(b':', 1)
110+
except ValueError:
111+
break
112+
113+
value = value.strip()
114+
115+
if header == b'Content-Length':
116+
content_length = int(value.decode())
117+
118+
print(header, value)
119+
120+
print('content length:', content_length)
121+
122+
# get body
123+
if content_length:
124+
body = await reader.read(content_length)
125+
else:
126+
body = None
127+
128+
return method, url, querystring, body
129+
130+
async def send_response(self, reader, writer):
131+
peername = writer.get_extra_info('peername')
132+
print('\nRequest from:', peername)
133+
await writer.awrite(b'HTTP/1.0 200 OK\r\n')
134+
await writer.awrite(b'Content-type: text/html; charset=utf-8\r\n\r\n')
135+
136+
await writer.awrite(_HTML_PREFIX)
137+
138+
await writer.awrite(b'Your IP: %s port:%s\n' % peername)
139+
140+
await writer.awrite(b'\n')
141+
142+
method, url, querystring, body = await self.parse_request(reader)
143+
144+
await writer.awrite(b'Method: %s\n' % method)
145+
await writer.awrite(b'URL: %s\n' % url)
146+
await writer.awrite(b'querystring: %s\n' % querystring)
147+
await writer.awrite(b'parsed querystring: %s\n' % request_query2dict(querystring))
148+
await writer.awrite(b'body: %s\n' % body)
149+
await writer.awrite(b'parsed body: %s\n' % request_query2dict(body))
150+
151+
await writer.awrite(_HTML_SUFFIX)
152+
153+
alloc = gc.mem_alloc() / 1024
154+
free = gc.mem_free() / 1024
155+
156+
await writer.awrite(
157+
b'RAM total: {total:.2f} KB, used: {alloc:.2f} KB, free: {free:.2f} KB'.format(
158+
total=alloc + free,
159+
alloc=alloc,
160+
free=free
161+
)
162+
)
163+
164+
await writer.awrite(_HTML_FOOTER)
165+
await writer.aclose()
166+
167+
async def request_handler(self, reader, writer):
168+
await self.send_response(reader, writer)
169+
gc.collect()
170+
171+
def run(self):
172+
loop = asyncio.get_event_loop()
173+
loop.create_task(asyncio.start_server(self.request_handler, '0.0.0.0', 80))
174+
print('\nWeb server started...')
175+
loop.run_forever()
176+
177+
178+
def main():
179+
from wifi import WiFi
180+
wifi = WiFi()
181+
if not wifi.is_connected:
182+
wifi.ensure_connection()
183+
del wifi
184+
del WiFi
185+
del sys.modules['wifi']
186+
gc.collect()
187+
188+
server = WebServer()
189+
server.run()
190+
191+
192+
if __name__ == '__main__':
193+
try:
194+
main()
195+
except Exception as e:
196+
sys.print_exception(e)
197+
198+
print('Hard reset !')
199+
200+
import machine
201+
machine.reset()
202+
203+
import utime
204+
utime.sleep(1)
205+
206+
print('sys.exit()')
207+
import sys
208+
sys.exit()

helpers/test_times_utils.py

Lines changed: 33 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,14 @@
66
77
Note: Will overwrite existing saved timers!
88
"""
9-
from times_utils import parse_timers, restore_timers, save_timers
9+
10+
11+
import uos as os
12+
from times_utils import get_active_days, parse_timers, restore_timers, save_active_days, save_timers
1013

1114

1215
def run_device_test():
16+
1317
print('test parse_timers()...', end=' ')
1418
results = tuple(parse_timers('''
1519
0:00 - 1:00
@@ -25,7 +29,16 @@ def run_device_test():
2529
((22, 1), (22, 30)),
2630
((23, 12), (23, 59))
2731
), results
28-
print('OK')
32+
print('OK\n')
33+
34+
print('test not existing "timers.txt"...', end=' ')
35+
try:
36+
os.remove('timers.txt')
37+
except BaseException:
38+
pass
39+
results = tuple(restore_timers())
40+
assert results == (), results
41+
print('OK\n')
2942

3043
print('test save_timers()...', end=' ')
3144
save_timers([
@@ -37,16 +50,32 @@ def run_device_test():
3750
((6, 0), (7, 0)),
3851
((19, 0), (22, 0))
3952
), results
40-
print('OK')
53+
print('OK\n')
54+
55+
print('test not existing "timer_days.txt"...', end=' ')
56+
try:
57+
os.remove('timer_days.txt')
58+
except BaseException:
59+
pass
60+
results = tuple(get_active_days())
61+
assert results == (0, 1, 2, 3, 4, 5, 6), results
62+
print('OK\n')
63+
64+
print('test save_active_days()...', end=' ')
65+
save_active_days(active_days=(0, 1, 2, 3, 4))
66+
results = tuple(get_active_days())
67+
assert results == (0, 1, 2, 3, 4), results
68+
print('OK\n')
4169

4270

4371
if __name__ == '__main__':
4472
print('Run tests on device...')
73+
4574
import sys
4675
sys.modules.clear()
4776

4877
import gc
4978
gc.collect()
5079

5180
run_device_test()
52-
print('OK')
81+
print('OK\n')

src/http_set_timer.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -40,9 +40,9 @@ async def get_form(server, reader, writer, querystring, timers=None):
4040

4141

4242
async def get_submit(server, reader, writer, querystring):
43-
from urllib_parse import querystring2dict
44-
get_parameters = querystring2dict(querystring)
45-
del querystring2dict
43+
from urllib_parse import request_query2dict
44+
get_parameters = request_query2dict(querystring)
45+
del request_query2dict
4646
del sys.modules['urllib_parse']
4747
gc.collect()
4848

src/main.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ def main():
1616

1717
from wifi import WiFi
1818

19-
__version__ = 'v0.6.1'
19+
__version__ = 'v0.6.2'
2020

2121
# Init device button IRQ:
2222
Pins.button_pin.irq(Button().irq_handler)

src/times_utils.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,6 @@ def restore_timers():
7474
yield from parse_timers(f.read())
7575
except OSError:
7676
print('File not exists: %r' % _TIMERS_FILENAME)
77-
yield ()
7877

7978

8079
def get_active_days():

src/urllib_parse.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,9 @@ def unquote(string):
2626

2727

2828
def parse_qsl(qs):
29+
if qs is None:
30+
return ()
31+
qs = str(qs)
2932
pairs = [s2 for s1 in qs.split('&') for s2 in s1.split(';')]
3033
res = []
3134
for name_value in pairs:
@@ -38,5 +41,5 @@ def parse_qsl(qs):
3841
return res
3942

4043

41-
def querystring2dict(qs):
44+
def request_query2dict(qs):
4245
return dict(parse_qsl(qs))

0 commit comments

Comments
 (0)