• Stars
    star
    184
  • Rank 203,570 (Top 5 %)
  • Language
    Python
  • License
    MIT License
  • Created almost 2 years ago
  • Updated 7 months ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

phew! the Pico (or Python) HTTP Endpoint Wrangler

A small webserver and templating library specifically designed for MicroPython on the Pico W. It aims to provide a complete toolkit for easily creating high quality web based interfaces for your projects.

phew! is ideal for creating web based provisioning interfaces for connected projects using the Raspberry Pi Pico W.

What phew! does:

  • a basic web server
  • optimised for speed (at import and during execution)
  • minimal use of memory
  • parameterised routing rules /greet/<name>
  • templating engine that allows inline python expressions {{name.lower()}}
  • GET, POST request methods
  • query string decoding and parsing
  • catchall handler for unrouted requests
  • multipart/form-data, x-www-form-urlencoded, and JSON POST bodies
  • string, byte, or generator based responses
  • connect_to_wifi and access_point convenience methods

Where possible phew! tries to minimise the amount of code and setup that you, the developer, has to do in favour of picking sane defaults and hiding away bits of minutiae that rarely needs to be tweaked.

How to use

phew! can be installed using pip from the command line or from your favourite IDE. In Thonny this can be achieved by clicking Tools -> Manage packages and searching for micropython-phew.

Basic example

An example web server that returns a random number between 1 and 100 (or optionally the range specified by the callee) when requested:

from phew import server, connect_to_wifi

connect_to_wifi("<ssid>", "<password>")

@server.route("/random", methods=["GET"])
def random_number(request):
  import random
  min = int(request.query.get("min", 0))
  max = int(request.query.get("max", 100))
  return str(random.randint(min, max))

@server.catchall()
def catchall(request):
  return "Not found", 404

server.run()

phew is designed specifically with performance and minimal resource use in mind. Generally this means it will prioritise doing as little work as possible including assuming the correctness of incoming requests.


Function reference

server module

The server module provides all functionality for running a web server with route handlers.

add_route

server.add_route(path, handler, methods=["GET"])

Adds a new route into the routing table. When an incoming request is received the server checks each route to find the most specific one that matches the request based on the path and method. If a route is found then the handler function is called with a request parameter that contains details about the request.

def my_handler(request):
  return "I got it!", 200

server.add_route("/testpath", my_handler, methods=["GET"])

Or, alternatively, using a decorator:

@server.route("/testpath", methods=["GET"])
def my_handler(request):
  return "I got it!", 200

set_catchall

server.set_catchall(handler)

Provide a catchall method for requests that didn't match a route.

def my_catchall(request):
  return "No matching route", 404

server.set_catchall(my_catchall)

Or, alternatively, using a decorator:

@server.catchall()
def my_catchall(request):
  return "No matching route", 404

run

server.run(host="0.0.0.0", port=80)

Starts up the web server and begins handling incoming requests.

server.run()

Types

Request

The Request object contains all of the information that was parsed out of the incoming request including form data, query string parameters, HTTP method, path, and more.

Handler functions provided to add_route and set_catchall will recieve a Request object as their first parameter.

member example type description
protocol "HTTP/1.1" string protocol version
method "GET" or "POST" string HTTP method used for this request
uri "/path/to/page?parameter=foo" string full URI of the request
path "/path/to/page" string just the path part of the URI
query_string "parameter=foo" string just the query string part of the URI
form {"foo": "bar", "name": "geoff"} dict POST body parsed as multipart/form-data
data [{"name": "jenny"}, {"name": "geoff"}] any POST body parsed as JSON
query {"parameter": "foo"} dict result of parsing the query string

At the time your route handler is being called the request has been fully parsed and you can access any properties that are relevant to the request (e.g. the form dictionary for a multipart/form-data request) any irrelevant properties will be set to None.

@server.route("/login", ["POST"])
def login_form(request):
  username = request.form.get("username", None)
  password = request.form.get("password", None)

  # check the user credentials with your own code
  # for example: 
  # 
  # logged_in = authenticate_user(username, password)

  if not logged_in:
    return "Username or password not recognised", 401

  return "Logged in!", 200

Response

The Response object encapsulates all of the attributes of your programs response to an incoming request. This include the status code of the result (e.g. 200 OK!) , the data to return, and any associated headers.

Handler functions can create and return a Response object explicitly or use a couple of shorthand forms to avoid writing the boilerplate needed.

member example type description
status 200 int HTTP status code
headers {"Content-Type": "text/html"} dict dictionary of headers to return
body "this is the response body" string or generator the content to be returned
@server.route("/greeting/<name>", ["GET"])
def user_details(request):
  return Response(f"Hello, {name}", status=200, {"Content-Type": "text/html"})
Shorthand

As shorthand instead of returning a Response object the handle may also return a tuple with between one and three values:

  • body - either a string or generator method
  • status code - defaults to 200 if not provided
  • headers - defaults to {"Content-Type": "text/html"} if not provided

For example:

@server.route("/greeting/<name>", ["GET"])
def user_details(request, name):
  return f"Hello, {name}", 200

Templates

A web server isn't much use without something to serve. While it's straightforward to serve the contents of a file or some generated JSON things get more complicated when we want to present a dynamically generated web page to the user.

phew! provides a templating engine which allows you to write normal HTML with fragments of Python code embedded to output variable values, parse input, or dynamically load assets.

render_template

render_template(template, param1="foo", param2="bar", ...):

The render_template method takes a path to a template file on the filesystem and a list of named paramaters which will be passed into the template when parsing.

The method is a generator which yields the parsing result in chunks, minimising the amount of memory used to hold the results as they can be streamed directly out rather than having to build the entire result as a string first.

Generally you will call render_template to create the body of a Response in one of your handler methods.

Template expressions

Templates are not much use if you can't inject dynamic data into them. With phew! you can embed Python expressions with {{<expression here>}} which will be evaluated during parsing.

Variables

In the simplest form you can embed a simple value by just enclosing it in double curly braces. It's also possible to perform more complicated transformations using any built in Python method.

  <div id="name">{{name}}</div>

  <div id="name">{{name.upper()}}</div>
  
  <div id="name">{{"/".join(name.split(" "))}}</div>
Conditional display

If you want to show a value only if some other condition is met then you can use the (slightly clunky) Python tenary operator.

<div>
  You won
  {{"1st" if prize == 1 else ""}}
  {{"2nd" if prize == 2 else ""}}
  {{"3rd" if prize == 3 else ""}}
  prize!
</div>

or

<div>
  You won
  {{["1st", "2nd", "3rd"][prize]}}
  prize!
</div>

While a bit unwieldy this methods works. An alternative would be to select the appropriate value in your handler and simply pass it into the template as a parameter however that would mean having some of your copy embedded into your Python code rather than all of it in one place in the template file.

Includes

You can include another template by calling render_template() again within your outer template.

include.html

Hello there {{name}}!

main.html

<!DOCTYPE html>
<body>
  {{render_template("include.html", name=name)}}
</body>

⚠️ Note: you need to explicitly pass through template parameters into the included template - they are not available by default.

logging module

log(level, text)

Add a new entry into the log file.

log("info", "> i'd like to take a minute, just sit right there")
log("error", "> the license plate said 'Fresh' and it had dice in the mirror")

The entry will automatically have the current date and time, the level value, and the amount of free memory in kB prepended:

2022-09-04 15:29:20 [debug    / 110kB] > performing startup
2022-09-04 15:30:42 [info     / 113kB]   - wake reason: rtc_alarm
2022-09-04 15:30:42 [debug    / 112kB]   - turn on activity led
2022-09-04 15:30:43 [info     / 102kB] > running pump 1 for 0.4 second
2022-09-04 15:30:46 [info     / 110kB] > 5 cache files need uploading
2022-09-04 15:30:46 [info     / 107kB] > connecting to wifi network 'yourssid'
2022-09-04 15:30:48 [debug    / 100kB]   - connecting
2022-09-04 15:30:51 [info     /  87kB]   - ip address:  192.168.x.x
2022-09-04 15:30:57 [info     /  79kB]   - uploaded 2022-09-04T15:19:03Z.json 2022-09-04 15:31:01 [info     /  82kB]   - uploaded 2022-09-04T15:28:17Z.json 2022-09-04 15:31:06 [info     /  88kB]   - uploaded 2022-09-04T15:30:43Z.json 2022-09-04 15:31:11 [info     /  95kB]   - uploaded 2022-09-04T15:29:00Z.json 2022-09-04 15:31:16 [info     / 100kB]   - uploaded 2022-09-04T15:29:21Z.json 2022-09-04 15:31:16 [info     /  98kB] > going to sleep

debug(*items)

Shorthand method for writing debug messages to the log.

warn("> this is a story")

info(*items)

Shorthand method for writing information to the log.

num = 123
info("> all about how", num, time.time())

warn(*items)

Shorthand method for writing warnings to the log.

warn("> my life got flipped")

error(*items)

Shorthand method for writing errors to the log.

warn("> turned upside down")

set_truncate_thresholds(truncate_at, truncate_to)

Will automatically truncate the log file to truncate_to bytes long when it reaches truncate_at bytes in length.

# automatically truncate when we're closed to the 
# filesystem block size to keep to a single block
set_truncate_thresholds(3.5 * 1024, 2 * 1.024)

Truncation always happens on the nearest line ending boundary so the truncated file may not exactly match the size specified.

dns module

To make implementing device provisioning interfaces (via captive portal) simple phew! provides a catchall DNS server.

If you put the Pico W into access point mode and then run the catchall DNS server it will route all DNS requests back to the local device so that they can be handled.

run_catchall

dns.run_catchall(ip_address)

Pass in the IP address of your device once in access point mode.

Helper functions

connect_to_wifi

connect_to_wifi(ssid, password, timeout=30)

Connects to the network specified by ssid with the provided password.

Returns the device IP address on success or None on failure.

access_point

access_point(ssid, password=None)

Create an access point with the specified SSID. Optionally password protected if provided.

is_connected_to_wifi

result = is_connected_to_wifi()

Returns True if there is an active WiFi connection.

get_ip_address

get_ip_address()

Returns the current IP address if connected to a network or acting as an access point or None otherwise.

Other Resources

Here are some Phew! community projects and guides that you might find useful. Note that code at the links below has not been tested by us and we're not able to offer support with it.

More Repositories

1

pimoroni-pico

Libraries and examples to support Pimoroni Pico add-ons in C++ and MicroPython.
C
1,209
star
2

inky

Combined library for V2/V3 Inky pHAT and Inky wHAT.
Python
552
star
3

enviroplus-python

Python library for the Enviro+ environmental monitoring board
Shell
377
star
4

unicorn-hat

Python library for Unicorn pHAT and HAT. 32 or 64 blinding ws2812 pixels for your Raspberry Pi
C
363
star
5

hyperpixel4

Driver for the Pimoroni HyperPixel 4.0" Touchscreen Display
Shell
313
star
6

blinkt

Python Library for Blinkt; 8 APA102 LEDs for your Raspberry Pi
C
304
star
7

fanshim-python

Python library for the Fan SHIM for Raspberry Pi
Python
290
star
8

bme680-python

Python library for the BME680 gas, temperature, humidity and pressure sensor.
Python
258
star
9

pirate-audio

Examples and documentation for the Pirate Audio range of Raspberry Pi add-ons
Python
235
star
10

st7789-python

Python library to control an ST7789 240x240 1.3" TFT LCD display.
Python
188
star
11

keybow-firmware

Keybow Firmware for the Raspberry Pi Zero
C
178
star
12

unicorn-hat-hd

Python library and examples for Unicorn HAT HD
Python
172
star
13

scroll-phat-hd

Python library for Scroll pHAT HD
Python
159
star
14

explorer-hat

Python library for Explorer HAT
Python
158
star
15

displayotron

Libraries and examples for the Display-o-Tron 3000 and Display-o-Tron HAT
Python
145
star
16

piglow

Python library & examples for the Pimoroni PiGlow
Python
133
star
17

picosystem

PicoSystem libraries and examples.
C++
128
star
18

badger2040

Examples and firmware for Badger 2040 and Badger 2040 W
Python
126
star
19

inky-phat

Python library for Inky pHAT
Python
125
star
20

clean-shutdown

Python daemon to watch a GPIO pin and trigger a clean shutdown.
Shell
123
star
21

automation-hat

Python library and examples for the Pimoroni Automation HAT, pHAT and HAT Mini
Python
116
star
22

enviro-phat

Python libraries and examples for the Pimoroni Enviro pHAT
Python
106
star
23

scroll-phat

Library and examples for Scroll pHAT. 11x5 LEDs of goodness!
Python
103
star
24

pantilt-hat

Python library for the Pimoroni PanTilt servo and lighting HAT
Python
102
star
25

phat-beat

Python library for PHAT BEAT - A stereo DAC, AMP and VU for the Raspberry Pi
Python
98
star
26

enviro

Python
96
star
27

hyperpixel

Setup for the Pimoroni Hyper Pixel 800x480 pixel multi-touch display
Python
95
star
28

vl53l1x-python

Python library for the VL53L1X Laser Ranger
C
89
star
29

skywriter-hat

Skywriter python libraries and examples
Python
87
star
30

pico-boilerplate

A boilerplate C++, CMake project for the Raspberry Pi Pico.
CMake
77
star
31

pmk-circuitpython

Python
77
star
32

rainbow-hat

Python library and examples for the Pimoroni Rainbow HAT
Python
73
star
33

pibrella

Pibrella python library & examples
Python
71
star
34

breakout-garden

Documentation, software, and examples for the Breakout Garden ecosystem.
Shell
71
star
35

keybow2040-circuitpython

CircuitPython library for the Pimoroni Keybow 2040
Python
67
star
36

bme280-python

Python library for the BME280 temperature, pressure and humidity sensor
Python
63
star
37

picade-hat

Picade HAT input daemon and setup script
Shell
60
star
38

pivumeter

ALSA plugin for displaying VU meters on various Raspberry Pi add-ons - derived from ameter
Shell
59
star
39

adxl345-python

Python library for the ADXL345
Python
55
star
40

python-multitouch

Multi-touch pure Python driver for the official 7" touchscreen display.
Python
55
star
41

Piano-HAT

Python library and examples for Piano HAT Raspberry Pi Add-on board
Python
53
star
42

grow-python

Python libs for controlling the Grow HATs
Python
53
star
43

bmp280-python

Python library for the BMP280 temperature, pressure, and altitude sensor.
Python
53
star
44

speaker-phat

Software installer for Speaker pHAT
Python
51
star
45

microdot-phat

Python Library and Examples for Micro Dot pHAT. A 6-matrix driver for retro 5x7 displays!
Python
49
star
46

pms5003-python

Python library for the PMS5003 particulate sensor
Shell
49
star
47

pidi-spotify

Python
44
star
48

PanTiltFacetracker

Face Tracking for the Adafruit Mini Pan Tilt kit and Raspberry Pi camera
Python
44
star
49

icm20948-python

Python library for the Pimoroni ICM20948 breakout
Python
43
star
50

picovision

C++
40
star
51

unicornhatmini-python

Python library for the Pimoroni Unicorn HAT Mini RGB LED Display
Python
40
star
52

Picade-Sketch

Picade Arduino sketch
C++
39
star
53

eagle

Custom Eagle parts that we've created where needed. Please feel free to use, extend, and share! (CC v3.0 Share-Alike You are welcome to use this library for commercial purposes.)
39
star
54

trackball-python

Python library for the Pimoroni Track Ball Breakout
Python
35
star
55

sgp30-python

Python library for the SGP30 air quality sensor
Shell
35
star
56

button-shim

Python library and examples for the Pimoroni Button SHIM
Python
33
star
57

led-shim

Python library for the Pimoroni LED SHIM
Python
31
star
58

keybow-python

Python library for the Pimoroni Keybow 3 and 12 key mechanical keyboard add-ons for Raspberry Pi
Python
31
star
59

hyperpixel2r

Shell
30
star
60

picade

All Picade related stuff.
C
30
star
61

fourletter-phat

Python library for the Pimoroni Four Letter pHAT
Python
28
star
62

drum-hat

Python library for the Pimoroni Drum HAT Raspberry Pi Add-on board.
Python
27
star
63

gfx-hat

Python library for the Pimoroni GFX HAT
Python
27
star
64

pmw3901-python

Python library for the PWM3901 optical flow-rate sensor
Python
26
star
65

rp_usbdisplay

Binary drivers for the RoboPeak/DFRobot 2.8 USB TFT, version 2
C
25
star
66

i2cdevice-python

Domain-specific language for describing smbus/i2c register maps
Python
24
star
67

flotilla-python

Python library for the Pimoroni Flotilla plug-and-play electronics ecosystem
Python
24
star
68

mote

Mote - drivers for the plug and play USB APA102 controller
Python
24
star
69

PiratePython

PiratePython: a minimal Raspbian for Python programmers
C
24
star
70

hyperpixel2r-python

Shell
23
star
71

propeller-hat

Propeller HAT library code, examples, documentation and SPIN source
Propeller Spin
23
star
72

displayhatmini-python

Python library for the Pimoroni Display HAT Mini
Shell
21
star
73

mopidy-raspberry-gpio

Mopidy GPIO Control Plugin for the Raspberry Pi (Using RPi.GPIO)
Python
20
star
74

weatherhat-python

Python
20
star
75

internet-of-seeds

The code that runs our IKEA VÄXER Internet of Seeds
Python
20
star
76

max30105-python

Python library for the Pimoroni MAX30105 breakout
Python
19
star
77

pico-circuitpython-examples

CircuitPython examples for Pimoroni RP2040 boards.
Python
18
star
78

as7262-python

Python library for the as7262 spectral sensor breakout
Python
17
star
79

node-red-nodes

Node-RED nodes for Pimoroni products
JavaScript
17
star
80

Raspberry-Pi-Web-RGB

Simple Raspberry Pi RGB LED control from your Web Browser using Python and Flask
HTML
17
star
81

trilobot-python

Python
17
star
82

plasma

Plasma LED driver, FX Sequencer and plugins
Python
16
star
83

fonts-python

Python font packaging framework
Python
15
star
84

ltr559-python

Python library for the LTR-559 optical presence/proximity sensor
Python
14
star
85

pa1010d-python

Python library for the Pimoroni PA1010D GPS Breakout
Shell
14
star
86

vl53l5cx-python

CTypes Python bindings for the VL53L5CX
C
13
star
87

programming-trinket-with-raspberry-pi

Programming Adafruit's Trinket (3v3) directly from a Raspberry Pi
C
13
star
88

drv2605-python

Python library for the Pimoroni Haptic Vibes DRV2605 breakout
Python
12
star
89

touch-phat

Python library and examples for Pimoroni Touch pHAT - six touch sensitive buttons to control your project.
Python
12
star
90

rgbmatrix5x5-python

Python library for the Pimoroni 5x5 RGB Matrix Breakout
Python
12
star
91

mote-phat

Drive four channels of APA102 pixels from your Pi Zero with Pimoroni Mote pHAT
Python
12
star
92

mopidy-pidi

Mopidy plugin host for pidi display plugins.
Python
11
star
93

sn3218

Python library for the SN3218 18-channel LED driver
Python
10
star
94

bh1745-python

Python library for the bh1745 colour sensor breakout
Python
10
star
95

EnviroPlus-FeatherWing

CircuitPython library for the Enviro+ FeatherWing
Python
10
star
96

pidi-plugins

🎵 plugins for Pirate Display. A mopidy/mpd album art downloader/displayer.
Python
10
star
97

pms5003-micropython

Python
10
star
98

enviro-ble

Python
9
star
99

rv3028-python

Python library for the RV3028 Real Time Clock
Python
9
star
100

st7036

Python library for the ST7036 LCD driver
Python
9
star