Skip to content

Commit ff3f9b6

Browse files
committed
First commit
0 parents  commit ff3f9b6

File tree

6 files changed

+279
-0
lines changed

6 files changed

+279
-0
lines changed

.gitignore

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
/.idea
2+
/__pycache__

README.md

+86
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
# MicroPyServer
2+
3+
MicroPyServer is a simple HTTP server for MicroPython projects.
4+
5+
## Install
6+
7+
Download a code and unpack it on your project folder.
8+
Use Thonny IDE or other IDE for upload your code in ESP8266/ESP32 board.
9+
10+
## Quick start
11+
12+
### Hello world example
13+
14+
```
15+
from micropyserver import MicroPyServer
16+
17+
def show_message(request):
18+
''' request handler '''
19+
server.send("HELLO WORLD!")
20+
21+
server = MicroPyServer()
22+
''' add request handler '''
23+
server.add_route("/", show_message)
24+
''' start server '''
25+
server.start()
26+
```
27+
28+
### Add some routes
29+
```
30+
from micropyserver import MicroPyServer
31+
32+
def show_index(request):
33+
''' main request handler '''
34+
server.send("THIS IS INDEX PAGE!")
35+
36+
def show_info(request, address):
37+
''' info request handler '''
38+
server.send("Your IP:" + str(address))
39+
40+
server = MicroPyServer()
41+
''' add request handlers '''
42+
server.add_route("/", show_index)
43+
server.add_route("/info", show_info)
44+
''' start server '''
45+
server.start()
46+
```
47+
48+
49+
### Send JSON response example
50+
51+
```
52+
from micropyserver import MicroPyServer
53+
import json
54+
55+
def return_json(request):
56+
''' request handler '''
57+
json_str = json.dumps({"param_one": 1, "param_two": 2})
58+
server.send(json_str, content_type="Content-Type: application/json")
59+
60+
server = MicroPyServer()
61+
''' add request handler '''
62+
server.add_route("/", return_json)
63+
''' start server '''
64+
server.start()
65+
```
66+
67+
### More examples
68+
69+
More examples you can find in a folder "examples".
70+
71+
## MicroPyServer methods
72+
73+
Constructor - srv = MicroPyServer(host="0.0.0.0", port=80)
74+
75+
Start server - srv.start()
76+
77+
Add new route - srv.add_route(path, handler, method="GET")
78+
79+
Send response to client - srv.send(response, status=200, content_type="Content-Type: text/plain", extra_headers=[])
80+
81+
Send 404 to client - srv.not_found()
82+
83+
Send 500 to client - srv.internal_error(error)
84+
85+
86+

examples/example1.py

+32
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
"""
2+
Example 1
3+
4+
Needed ESP8266 or ESP32 board
5+
6+
@see https://github.com/troublegum/micropyserver
7+
"""
8+
import esp
9+
import network
10+
from micropyserver import MicroPyServer
11+
12+
wlan_id = "your wi-fi"
13+
wlan_pass = "your password"
14+
15+
wlan = network.WLAN(network.STA_IF)
16+
wlan.active(True)
17+
if not wlan.isconnected():
18+
wlan.connect(wlan_id, wlan_pass)
19+
20+
21+
def show_index_page(request):
22+
server.send("THIS IS INDEX PAGE")
23+
24+
25+
def show_info_page(request):
26+
server.send("THIS IS INFO PAGE")
27+
28+
29+
server = MicroPyServer()
30+
server.add_route("/info", show_info_page)
31+
server.add_route("/", show_index_page)
32+
server.start()

examples/example2.py

+31
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
"""
2+
Example 2
3+
4+
Needed ESP8266 or ESP32 board
5+
6+
@see https://github.com/troublegum/micropyserver
7+
"""
8+
9+
import esp
10+
import network
11+
from micropyserver import MicroPyServer
12+
13+
wlan_id = "your wi-fi"
14+
wlan_pass = "your password"
15+
16+
wlan = network.WLAN(network.STA_IF)
17+
wlan.active(True)
18+
if not wlan.isconnected():
19+
wlan.connect(wlan_id, wlan_pass)
20+
21+
22+
def show_index_page(request):
23+
html_file = open("index.html")
24+
html = html_file.read()
25+
html_file.close()
26+
server.send(html, content_type="Content-Type: text/html")
27+
28+
29+
server = MicroPyServer()
30+
server.add_route("/", show_index_page)
31+
server.start()

examples/index.html

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
<!DOCTYPE html>
2+
<html>
3+
<body>
4+
<h1>Hello, MicroPyServer!</h1>
5+
</body>
6+
</html>

micropyserver.py

+122
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
"""
2+
MicroPyServer is a simple HTTP server for MicroPython projects.
3+
4+
@see https://github.com/troublegum/micropyserver
5+
6+
The MIT License
7+
8+
Copyright (c) 2019 troublegum. https://github.com/troublegum/micropyserver
9+
10+
Permission is hereby granted, free of charge, to any person obtaining a copy
11+
of this software and associated documentation files (the "Software"), to deal
12+
in the Software without restriction, including without limitation the rights
13+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14+
copies of the Software, and to permit persons to whom the Software is
15+
furnished to do so, subject to the following conditions:
16+
17+
The above copyright notice and this permission notice shall be included in
18+
all copies or substantial portions of the Software.
19+
20+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
26+
THE SOFTWARE.
27+
"""
28+
import re
29+
import socket
30+
import sys
31+
32+
33+
class MicroPyServer(object):
34+
35+
def __init__(self, host="0.0.0.0", port=80):
36+
""" Constructor """
37+
self._host = host
38+
self._port = port
39+
self._routes = []
40+
self._connect = None
41+
self._on_request_handler = None
42+
43+
def start(self):
44+
""" Start server """
45+
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
46+
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
47+
sock.bind((self._host, self._port))
48+
sock.listen(1)
49+
while True:
50+
try:
51+
self._connect, address = sock.accept()
52+
request = self._get_request()
53+
if len(request) == 0:
54+
self._connect.close()
55+
continue
56+
if self._on_request_handler:
57+
if not self._on_request_handler(request, address):
58+
continue
59+
route = self.find_route(request)
60+
if route:
61+
route["handler"](request)
62+
else:
63+
self.not_found()
64+
except Exception as e:
65+
try:
66+
self.internal_error(str(e))
67+
except Exception as e:
68+
sys.print_exception(e)
69+
finally:
70+
self._connect.close()
71+
72+
def add_route(self, path, handler, method="GET"):
73+
""" Add new route """
74+
self._routes.append({"path": path, "handler": handler, "method": method})
75+
76+
def send(self, response, status=200, content_type="Content-Type: text/plain", extra_headers=[]):
77+
""" Send response to client """
78+
if self._connect is None:
79+
raise Exception("Can't send response, no connection instance")
80+
81+
status_message = {200: "OK", 400: "Bad Request", 403: "Forbidden", 404: "Not Found",
82+
500: "Internal Server Error"}
83+
self._connect.sendall("HTTP/1.0 " + str(status) + " " + status_message[status] + "\r\n")
84+
self._connect.sendall(content_type + "\r\n")
85+
for header in extra_headers:
86+
self._connect.sendall(header + "\r\n")
87+
self._connect.sendall("X-Powered-By: MicroPyServer\r\n")
88+
self._connect.sendall("\r\n")
89+
self._connect.sendall(response)
90+
91+
def find_route(self, request):
92+
""" Find route """
93+
lines = request.split("\r\n")
94+
method = re.search("^([A-Z]+)", lines[0]).group(1)
95+
path = re.search("^[A-Z]+\\s+(/[-a-zA-Z0-9_.]*)", lines[0]).group(1)
96+
for route in self._routes:
97+
if method != route["method"]:
98+
continue
99+
if path == route["path"]:
100+
return route
101+
else:
102+
match = re.search("^" + route["path"] + "$", path)
103+
if match:
104+
print(method, path, route["path"])
105+
return route
106+
107+
def not_found(self):
108+
""" Not found action """
109+
self.send("404", status=404)
110+
111+
def internal_error(self, error):
112+
""" Catch error action """
113+
self.send("Error: " + error, status=500)
114+
sys.exc_info()
115+
116+
def on_request(self, handler):
117+
""" Set request handler """
118+
self._on_request_handler = handler
119+
120+
def _get_request(self):
121+
""" Return request body """
122+
return str(self._connect.recv(4096), "utf8")

0 commit comments

Comments
 (0)