Overview
In this article, we will learn how to make a Raspberry Pi Pico W based Web Server using MicroPython programming. The web server is mobile responsive and can be accessed with any device that has a browser on the local network. We’ll show you how to create the web server and how the code works.
Before going straight to the project, it is important to outline what our web server will do:
- The web server we will build controls RGB LED connected to the Pico W GP13, GP14 & GP15
- You can access Pi Pico W Web Server by typing the local IP address on a browser in local network.
- By clicking the buttons on your web server you can instantly change the state of RGB LED.
- The Webpage will also display the Pi Pico W internal temperature connected to the ADC4 pin.
Components Required
We need the following components for the Raspberry Pi Pico W Web Server Demo. You can purchase all these components from SunFounder Amazon link which consists of the necessary sensors & modules along with 200+ components.
- Raspberry Pi Pico W – 1
- RGB LED – 1
- Lipo Battery Charger – 1
- Samsung 18650 Battery with Holder – 1
- 220-ohm Resistors – 3
- Jumper Wires – 10
- Breadboard – 1
- Micro-USB Cable.
Circuit & Hardware Assembly
Start by building the circuit. Connect RGB LED to the Raspberry Pi Pico as shown in the following schematic diagram.
Connect the R, G, and B pin of RGB LED to GP13, GP14, and GP15 of Raspberry Pi Pico W respectively. You need to connect a 200-ohm resistor through each of the R, G, and B pins of the LED.
The Raspberry Pi Pico W has a buck-boost converter IC. Hence you can power the Raspberry Pi Pico W via a Lipo Battery. The Lipo Battery Charger Module which consists of LTC4054 IC has been modified and specially designed for powering Raspberry Pi Pico W using Lipo Battery.
Using the Lipo Charger Module and 3.7V Samsung 18650 Rechargeable Lithium-Ion Battery, you can power the Raspberry Pi Pico W & make the project portable.
MicroPython Code
The code for creating a Raspberry Pi Pico W based Web Server is simple. In the following code change the WiFi SSID and password.
Save the file to Raspberry Pi Pico W with the name main.py or anything else.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 |
import machine import socket import math import utime import network import time wlan = network.WLAN(network.STA_IF) wlan.active(True) wlan.connect("ssid","password") # rgb led red=machine.Pin(13,machine.Pin.OUT) green=machine.Pin(14,machine.Pin.OUT) blue=machine.Pin(15,machine.Pin.OUT) # Wait for connect or fail wait = 10 while wait > 0: if wlan.status() < 0 or wlan.status() >= 3: break wait -= 1 print('waiting for connection...') time.sleep(1) # Handle connection error if wlan.status() != 3: raise RuntimeError('wifi connection failed') else: print('connected') ip=wlan.ifconfig()[0] print('IP: ', ip) # Temperature Sensor sensor_temp = machine.ADC(4) conversion_factor = 3.3 / (65535) def temperature(): temperature_value = sensor_temp.read_u16() * conversion_factor temperature_Celcius = 27 - (temperature_value - 0.706)/0.00172169/ 8 print(temperature_Celcius) utime.sleep(2) return temperature_Celcius def webpage(value): html = f""" <!DOCTYPE html> <html> <body> <form action="./red"> <input type="submit" value="red " /> </form> <form action="./green"> <input type="submit" value="green" /> </form> <form action="./blue"> <input type="submit" value="blue" /> </form> <form action="./off"> <input type="submit" value="off" /> </form> <p>Temperature is {value} degrees Celsius</p> </body> </html> """ return html def serve(connection): while True: client = connection.accept()[0] request = client.recv(1024) request = str(request) try: request = request.split()[1] except IndexError: pass print(request) if request == '/off?': red.low() green.low() blue.low() elif request == '/red?': red.high() green.low() blue.low() elif request == '/green?': red.low() green.high() blue.low() elif request == '/blue?': red.low() green.low() blue.high() value='%.2f'%temperature() html=webpage(value) client.send(html) client.close() def open_socket(ip): # Open a socket address = (ip, 80) connection = socket.socket() connection.bind(address) connection.listen(1) print(connection) return(connection) try: if ip is not None: connection=open_socket(ip) serve(connection) except KeyboardInterrupt: machine.reset() |
Run the above script, so that the Python Shell will display the IP Address of the Raspberry Pi Pico W.
Copy the IP Address and paste it on any Web browser and hit enter.
By clicking the red, green, and blue buttons you can control the RGB LED.
The Webpage will also display the temperature reading of the internal temperature sensor.
Code Explanation & Working of Raspberry Pi Pico W Web Server
The web page you are visiting is actually hosted on some server, and the socket on the server will send the web page to us when we visit it. A socket is a way a server can listen to a client that wants to connect to it. In this project, Pico W is your server, and your computer is accessing the web page hosted on Pico W through a browser.
First, we create a socket, which requires an IP address and a port. First Raspberry Pi Pico W connects to a local Wi-Fi network and prints the Ip Address. For the port part, we use 80. After setting up the socket, return it and use it for the next step.
1 2 3 4 5 6 7 8 9 10 |
import socket def open_socket(ip): # Open a socket address = (ip, 80) connection = socket.socket() connection.bind(address) connection.listen(1) print(connection) return(connection) |
Then, set up your web service where the socket you set up earlier will be used. The following code will allow your Pico W to receive access requests from your browser.
1 2 3 4 5 |
def serve(connection): while True: client = connection.accept()[0] request = client.recv(1024) client.close() |
Next, you need an HTML page to send to the visitor. This example stores a simple HTML page in the form of characters in the variable html
.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
def webpage(value): html = f""" <!DOCTYPE html> <html> <body> <form action="./red"> <input type="submit" value="red " /> </form> <form action="./green"> <input type="submit" value="green" /> </form> <form action="./blue"> <input type="submit" value="blue" /> </form> <form action="./off"> <input type="submit" value="off" /> </form> <p>Temperature is {value} degrees Celsius</p> </body> </html> """ return html |
The first thing we need to know is what information the server receives when the browser accesses the web page. Therefore, change serve()
slightly to print request
.
1 2 3 4 5 6 7 8 9 |
def serve(connection): while True: client = connection.accept()[0] request = client.recv(1024) request = str(request) print(request) html=webpage(0) client.send(html) client.close() |
When we run the script, the Shell will print the following message when we press a key on the web page.
1 2 3 4 |
b'GET /red? HTTP/1.1\r\nHost: 192.168.18.162\r\nConnection: keep-alive.......q=0.5\r\n\r\n' b'GET /favicon.ico HTTP/1.1\r\nHost: 192.168.18.162\r\nConnection: keep-alive.......q=0.5\r\n\r\n' b'GET /blue? HTTP/1.1\r\nHost: 192.168.18.162\r\nConnection: keep-alive.......q=0.5\r\n\r\n' b'GET /favicon.ico HTTP/1.1\r\nHost: 192.168.18.162\r\nConnection: keep-alive.......q=0.5\r\n\r\n' |
They are too long to read. But all we really need is the small piece of information in front of /red?
, /blue?
. It tells us which button was pressed. So we refined serve()
a bit to extract the keystroke information.
1 2 3 4 5 6 7 8 9 10 11 12 13 |
def serve(connection): while True: client = connection.accept()[0] request = client.recv(1024) request = str(request) try: request = request.split()[1] except IndexError: pass print(request) html=webpage(0) client.send(html) client.close() |
Then, we just need to change the color of the RGB LED according to the value of request
.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
ef serve(connection): while True: client = connection.accept()[0] request = client.recv(1024) request = str(request) try: request = request.split()[1] except IndexError: pass print(request) if request == '/off?': red.low() green.low() blue.low() elif request == '/red?': red.high() green.low() blue.low() elif request == '/green?': red.low() green.high() blue.low() elif request == '/blue?': red.low() green.low() blue.high() html=webpage(0) client.send(html) client.close() |
The last thing is to display the Internal Temperature Sensor value on the web page.
1 2 3 4 5 6 |
def temperature(): temperature_value = sensor_temp.read_u16() * conversion_factor temperature_Celcius = 27 - (temperature_value - 0.706)/0.00172169/ 8 print(temperature_Celcius) utime.sleep(2) return temperature_Celcius |
This part is actually done by modifying the text on the HTML. We set the parameters in the webpage(value)
function and simply change the incoming parameters to change the number displayed on the web page.
1 2 3 4 |
value='%.2f'%temperature() html=webpage(value) client.send(html) client.close() |
Thats all from the Raspberry Pi Pico W Web Server part. If you want to learn more about the Web Server example, you may refer to Web Server Weather Station project using Raspberry Pi Pico W and BME 280 Sensor.
7 Comments
Great thanks for sharing ☺️
is there a way to make buttons larger when ip displayed on phone? can one change the code to make the html page appear larger? Thanks
You should use time or utime, not both (they are the same anyway). Even better: from time import sleep.
math is imported, but not used
musite si pred vsechen text napsat from machine import pin
this code can work in ESP32 ?
Really enjoyed this article on building a web server from scratch. Learning the nuts and bolts is super helpful.
i get on error on the webpage
“The server provided an invalid message!
Content-Length: 0”
what am i doing wrong