Raspberry Pi Pico W Web Server

by Ramatronics Laboratory in Circuits > Websites

8263 Views, 10 Favorites, 0 Comments

Raspberry Pi Pico W Web Server

n_page-0001.jpg

In my previous instructables, I showed you how you can blink the on board LED of the raspberry pi pico w. I had also interfaced an external LED to the raspberry pi pico w and blinked it but we can also do this job using raspberry pi pico. Now a question will be rising in your mind that why we are using the raspberry pi pico w for this instead of raspberry pi pico. The answer is that we can turn on and off our LED using the internet. This is because the raspberry pi pico w board has an on board wifi chip. Today In this instructables I am showing you how you can connect the pico w board to a network. I am creating a web server using raspberry pi pico w. Using this web server I am able to control the on board LED using a Web page and display the temperature of RP2040 chip on the web page. So let's get started.

Supplies

WhatsApp Image 2023-05-16 at 9.57.45 AM.jpeg
WhatsApp Image 2023-05-16 at 9.57.44 AM (1).jpeg
WhatsApp Image 2023-05-16 at 9.57.44 AM.jpeg
WhatsApp Image 2023-05-16 at 9.57.42 AM.jpeg
WhatsApp Image 2023-05-16 at 9.57.41 AM (1).jpeg
WhatsApp Image 2023-05-16 at 9.57.41 AM.jpeg

Connect Your Raspberry Pi Pico W to a WLAN

Here, you will learn to use MicroPython to connect your Raspberry Pi Pico W to a wireless local area network (WLAN), more commonly known as a WiFi network.

To connect to a WiFi network, you will need to know your service set identifier (SSID). This is the name of your WiFi network. You will also need your WiFi password. These can usually be found written on your wireless router, although you should have changed the default password to something unique.

Passwords need to be kept securely and privately. In this step, you will add your WiFi password into your Python file. Make sure you don’t share your file with anyone that you wouldn’t want to tell your password to.

In Thonny, import the packages you will need to connect to your WiFi network light the onboard light-emitting diode (LED).

web_server.py

import network
import socket
from time import sleep
from picozero import pico_temp_sensor, pico_led
import machine

you can download the picozero module from my GitHub repository. The kink is given below:

https://github.com/ramjipatel041/Raspberry-Pi-Pico-picozero-module

Save this code now, and choose the option to save to This computer

Next, set up your Raspberry Pi Pico W to use the onboard LED, and additionally add in the SSID and password for your network.

web_server.py

ssid = 'NAME OF YOUR WIFI NETWORK'
password = 'YOUR SECRET PASSWORD'

Now, begin to build a function to connect to your WLAN. You need to set up a wlan object, activate the wireless, and provide the object with your ssid and password.

web_server.py

def connect():
#Connect to WLAN
wlan = network.WLAN(network.STA_IF)
wlan.active(True)
wlan.connect(ssid, password)

If you’ve ever connected a device to a WiFi network, you will know that it doesn’t happen instantly. Your device will send requests to your WiFi router to connect, and when the router responds, they will perform what is called a handshake to establish a connection. To do this with Python, you can set up a loop that will keep sending requests each second until the connection handshake has been performed.

web_server.py

def connect():
#Connect to WLAN
wlan = network.WLAN(network.STA_IF)
wlan.active(True)
wlan.connect(ssid, password)
while wlan.isconnected() == False:
print('Waiting for connection...')
sleep(1)

Now print out your WLAN configuration, and test it all. You’ll need to call your function. Keep all your function calls at the bottom of your file, so they are the last lines of code that are run. Because the WiFi connection can stay up, even when you stop the code, you can add a try/except that will reset the Raspberry Pi Pico W when the script is stopped.

web_server.py

def connect():
#Connect to WLAN
wlan = network.WLAN(network.STA_IF)
wlan.active(True)
wlan.connect(ssid, password)
while wlan.isconnected() == False:
print('Waiting for connection...')
sleep(1)
print(wlan.ifconfig())

try:
connect()
except KeyboardInterrupt:
machine.reset()

Test: Save and run your code. You should see some output in the shell that looks something like this, although the specific IP addresses will be different.

Waiting for connection...
Waiting for connection...
Waiting for connection...
Waiting for connection...
Waiting for connection...
('192.168.1.143', '255.255.255.0', '192.168.1.254', '192.168.1.254')

The Raspberry Pi Pico W won't connect

You don’t need all the information provided by wlan.ifconfig(). The key information you need is the IP address of the Raspberry Pi Pico W, which is the first piece of information. You can use an fstring to output the IP address. By placing an f in front of your string, variables can be printed when they are surrounded by {}.

web_server.py

def connect():
#Connect to WLAN
wlan = network.WLAN(network.STA_IF)
wlan.active(True)
wlan.connect(ssid, password)
while wlan.isconnected() == False:
print('Waiting for connection...')
sleep(1)
ip = wlan.ifconfig()[0]
print(f'Connected on {ip}')


try:
connect()
except KeyboardInterrupt:
machine.reset()

You can now return the value for the IP address of your Raspberry Pi Pico W, and store it when you call your function.

web_server.py

def connect():
#Connect to WLAN
wlan = network.WLAN(network.STA_IF)
wlan.active(True)
wlan.connect(ssid, password)
while wlan.isconnected() == False:
print('Waiting for connection...')
sleep(1)
ip = wlan.ifconfig()[0]
print(f'Connected on {ip}')
return ip


try:
ip = connect()
except KeyboardInterrupt:
machine.reset()

Open a Socket

In this step, you will use the connection to your WLAN to open a socket.

A socket is the way a server can listen for a client that wants to connect to it. The webpage you are currently looking at is hosted on Raspberry Pi Foundation servers. These servers have an open socket that waits for your web browser to make a connection, at which point the contents of the webpage are sent to your computer. In this case, your server is going to be your Raspberry Pi Pico W and the client will be a web browser on another computer.

To open a socket, you need to provide the IP address and a port number. Port numbers are used by computers to identify where requests should be sent. For instance, port 80 is normally used for web traffic; Stardew Valley uses port 24642 when you’re playing a multiplayer game. As you are setting up a web server, you will be using port 80.

Create a new function that can be called to open a socket. It should be above your try/except. Start by giving the socket an IP address and a port number.

web_server.py

def open_socket(ip):
# Open a socket
address = (ip, 80)


try:
connect()
except KeyboardInterrupt:
machine.reset()

Now create your socket, and then have it listen for requests on port 80. Don’t forget to call your function at the bottom of your code.

web_server.py

def open_socket(ip):
# Open a socket
address = (ip, 80)
connection = socket.socket()
connection.bind(address)
connection.listen(1)
print(connection)

try:
ip = connect()
open_socket(ip)
except KeyboardInterrupt:
machine.reset()

Test: Run your code, and you should see an output that looks something like this.

>>> %Run -c $EDITOR_CONTENT
Waiting for connection...
Waiting for connection...
Waiting for connection...
Waiting for connection...
Waiting for connection...
Connected on 192.168.1.143
<socket state=1 timeout=-1 incoming=0 off=0>

socket state=1 tells you that your socket is working.

Lastly, replace your print with a return and then store the returned socket connection as a variable.

web_server.py

def open_socket(ip):
# Open a socket
address = (ip, 80)
connection = socket.socket()
connection.bind(address)
connection.listen(1)
return connection


try:
ip = connect()
connection = open_socket(ip)
except KeyboardInterrupt:
machine.reset()

You now have your Raspberry Pi Pico W listening for connections to its IP address on port 80. This means that it is ready to start serving HTML code, so that a connected web browser can see a webpage.

Create a Webpage

In this step, you will create a webpage that the web server, running on your Raspberry Pi Pico W, can send to a client web browser. You’re going to test the webpage on your computer first though, to make sure it displays as it should. In the next step, you can add the code to your Python script, so that your Raspberry Pi Pico W can serve the webpage.

A webpage can be as simple as some text, formatted in such a way that a web browser will render it and provide some interactivity. Although Thonny is not designed to write HTML, it can be used for this purpose. However, you can use your preferred text editor if you like, be that VSCode, TextEdit, or Notepad.

In your text editor or in Thonny, create a new file. You can call it whatever you like, but index.html is the standard name for the first page that a user interacts with. Make sure you add the .html file extension. If using Thonny, make sure to save to This computer.

There is some standard HTML code that you will need to include to begin with.

index.html

<!DOCTYPE html>
<html>
<body>
</body>
</html>

Next, you can create a button that will be used to turn the onboard LED on or off.

index.html

<!DOCTYPE html>
<html>
<body>
<form action="./lighton">
<input type="submit" value="Light on" />
</form>
</body>
</html>

Save your file and then find it in your file manager. When you double click the file, it should open in your default web browser. Here is what the webpage looks like in Google Chrome.

Add a second button to turn the LED off.

index.html

<!DOCTYPE html>
<html>
<body>
<form action="./lighton">
<input type="submit" value="Light on" />
</form>
<form action="./lightoff">
<input type="submit" value="Light off" />
</form>
</body>
</html>

To finish off the webpage, you can add in some extra data, such as the state of the LED and the temperature of your Raspberry Pi Pico W.

index.html

<!DOCTYPE html>
<html>
<body>
<form action="./lighton">
<input type="submit" value="Light on" />
</form>
<form action="./lightoff">
<input type="submit" value="Light off" />
</form>
<p>LED is {state}</p>
<p>Temperature is {temperature}</p>
</body>
</html>

Your webpage should look like this:

Now that you have a working webpage, you can add this code into your Python script. You’ll need to switch back to your Python code in Thonny first.

Create a new function called webpage, that has two parameters. These are temperature and state.

web_server.py

def webpage(temperature, state):
#Template HTML

You can now store all your HTML code that you have written and tested in a variable. Using fstrings for the text means that the placeholders you have in the HTML for temperature and state can be inserted into your string.

web_server.py

def webpage(temperature, state):
#Template HTML
html = f"""
<!DOCTYPE html>
<html>
<form action="./lighton">
<input type="submit" value="Light on" />
</form>
<form action="./lightoff">
<input type="submit" value="Light off" />
</form>
<p>LED is {state}</p>
<p>Temperature is {temperature}</p>
</body>
</html>
"""

Lastly, you can return the html string from your function.

web_server.py

def webpage(temperature, state):
#Template HTML
html = f"""
<!DOCTYPE html>
<html>
<form action="./lighton">
<input type="submit" value="Light on" />
</form>
<form action="./lightoff">
<input type="submit" value="Light off" />
</form>
<p>LED is {state}</p>
<p>Temperature is {temperature}</p>
</body>
</html>
"""
return str(html)


The simple HTML code we have just written will be stored used in your MicroPython script and served to the browser of any computers that connect to it over your network, just like a webpage stored on any other server in the world. An important difference is that only devices connected to your WiFi network can access the webpage or control your Raspberry Pi Pico W. This page is a very simple demonstration of what is possible. To learn more about HTML coding and creating websites, see some of our other projects on this site!

Serve Your Webpage

WhatsApp Image 2023-05-16 at 12.06.58 PM (1).jpeg
WhatsApp Image 2023-05-16 at 12.06.58 PM.jpeg
WhatsApp Image 2023-05-16 at 12.06.57 PM.jpeg
Screenshot 2023-05-16 123434.png

In this step, you will start up your web server so that a client can connect to it, and control your LED and read the temperature.

Create a function that will start your web server, using the connection object you saved as a parameter. The state and temperature variables need to be set for your HTML data. The state is going to start as being set to 'OFF', and the temperature to 0, which means you should also ensure that the LED is off when the server starts.

web_server.py

def serve(connection):
#Start a web server
state = 'OFF'
pico_led.off()
temperature = 0

When your web browser asks for a connection to your Raspberry Pi Pico W, the connection needs to be accepted. After that, the data that is sent from your web browser must be done in specific chunks (in this case, 1024 bytes). You also need to know what request your web browser is making — is it asking for just a simple page? Is it asking for a page that doesn’t exist?

You want to keep the web server up and listening all the time, so that any client can connect to it. You can do this by adding a while True: loop. Add these five lines of code so that you can accept a request, and print() to see what the request was. Add a call to your serve function in your calls at the bottom of your code.

web_server.py

def serve(connection):
#Start a web server
state = 'OFF'
pico_led.off()
temperature = 0
while True:
client = connection.accept()[0]
request = client.recv(1024)
request = str(request)
print(request)
client.close()


try:
ip = connect()
connection = open_socket(ip)
serve(connection)
except KeyboardInterrupt:
machine.reset()

Test: Run your program and then type in the IP address into a web browser’s address bar on your computer.

You should see something like this in the shell output in Thonny.

>>> %Run -c $EDITOR_CONTENT
Waiting for connection...
Waiting for connection...
Waiting for connection...
Connected on 192.168.1.143
b'GET / HTTP/1.1\r\nHost: 192.168.1.143\r\nUser-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:101.0) Gecko/20100101 Firefox/101.0\r\nAccept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8\r\nAccept-Language: en-GB,en;q=0.5\r\nAccept-Encoding: gzip, deflate\r\nConnection: keep-alive\r\nUpgrade-Insecure-Requests: 1\r\n\r\n'
b'GET /favicon.ico HTTP/1.1\r\nHost: 192.168.1.143\r\nUser-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:101.0) Gecko/20100101 Firefox/101.0\r\nAccept: image/avif,image/webp,*/*\r\nAccept-Language: en-GB,en;q=0.5\r\nAccept-Encoding: gzip, deflate\r\nConnection: keep-alive\r\nReferer: http://192.168.1.143/\r\n\r\n'

Next, you need to send the HTML code you have written to the client web browser.

web_server.py

def serve(connection):
#Start a web server
state = 'OFF'
pico_led.off()
temperature = 0
while True:
client = connection.accept()[0]
request = client.recv(1024)
request = str(request)
print(request)
html = webpage(temperature, state)
client.send(html)
client.close()


try:
ip = connect()
connection = open_socket(ip)
serve(connection)
except KeyboardInterrupt:
machine.reset()

Refresh your page when you’ve run the code again. Click on the buttons that are displayed. In Thonny, you should then see that there are two different outputs from your shell.

b'GET /lighton? HTTP/1.1\r\nHost: 192.168.1.143\r\nUser-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:101.0) Gecko/20100101 Firefox/101.0\r\nAccept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8\r\nAccept-Language: en-GB,en;q=0.5\r\nAccept-Encoding: gzip, deflate\r\nConnection: keep-alive\r\nReferer: http://192.168.1.143/\r\nUpgrade-Insecure-Requests: 1\r\n\r\n'

and

b'GET /lightoff? HTTP/1.1\r\nHost: 192.168.1.143\r\nUser-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:101.0) Gecko/20100101 Firefox/101.0\r\nAccept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8\r\nAccept-Language: en-GB,en;q=0.5\r\nAccept-Encoding: gzip, deflate\r\nConnection: keep-alive\r\nReferer: http://192.168.1.143/lighton?\r\nUpgrade-Insecure-Requests: 1\r\n\r\n'

Notice that you have /lighton? and lightoff? in the requests. These can be used to control the onboard LED of your Raspberry Pi Pico W.

Split the request string and then fetch the first item in the list. Sometimes the request string might not be able to be split, so it’s best to handle this in a try/except.

If the first item in the split is lighton? then you can switch the LED on. If it is lightoff? then you can switch the LED off.

web_server.py

def serve(connection):
#Start a web server
state = 'OFF'
pico_led.off()
temperature = 0
while True:
client = connection.accept()[0]
request = client.recv(1024)
request = str(request)
try:
request = request.split()[1]
except IndexError:
pass
if request == '/lighton?':
pico_led.on()
elif request =='/lightoff?':
pico_led.off()
html = webpage(temperature, state)
client.send(html)
client.close()

Run your code again. This time, when you refresh your browser window and click on the buttons, the onboard LED should turn on and off.

You can also tell the user of the webpage what the state of the LED is.

web_server.py

def serve(connection):
#Start a web server
state = 'OFF'
pico_led.off()
temperature = 0
while True:
client = connection.accept()[0]
request = client.recv(1024)
request = str(request)
try:
request = request.split()[1]
except IndexError:
pass
if request == '/lighton?':
pico_led.on()
state = 'ON'
elif request =='/lightoff?':
pico_led.off()
state = 'OFF'
html = webpage(temperature, state)
client.send(html)
client.close()

Now when you run the code, the text for the state of the LED should also change on the refreshed webpage.

Lastly, you can use the onboard temperature sensor to get an approximate reading of the CPU temperature, and display that on your webpage as well.

web_server.py

def serve(connection):
#Start a web server
state = 'OFF'
pico_led.off()
temperature = 0
while True:
client = connection.accept()[0]
request = client.recv(1024)
request = str(request)
try:
request = request.split()[1]
except IndexError:
pass
if request == '/lighton?':
pico_led.on()
state = 'ON'
elif request =='/lightoff?':
pico_led.off()
state = 'OFF'
temperature = pico_temp_sensor.temp
html = webpage(temperature, state)
client.send(html)
client.close()


Test: You can hold your hand over your Raspberry Pi Pico W to increase its temperature, then refresh the webpage on your computer to see the new value that is displayed.

Make a Prototype Circuit on Bread Board

pico w_page-0001.jpg
WhatsApp Image 2023-05-16 at 9.57.46 AM (1).jpeg
WhatsApp Image 2023-05-16 at 9.57.46 AM.jpeg
WhatsApp Image 2023-05-16 at 9.57.45 AM (2).jpeg
WhatsApp Image 2023-05-16 at 9.57.45 AM (1).jpeg

Control an External LED Using Web Page

WhatsApp Image 2023-05-16 at 12.32.58 PM (1).jpeg
WhatsApp Image 2023-05-16 at 12.32.58 PM.jpeg
WhatsApp Image 2023-05-16 at 12.32.57 PM (1).jpeg
WhatsApp Image 2023-05-16 at 12.32.57 PM.jpeg
Screenshot 2023-05-16 123414.png

To control the external LED again open a new script in thonny and write the following program and save it with name as main.py.

import machine
import network
import socket
from time import sleep

led = machine.Pin(15, machine.Pin.OUT)

ssid = 'Redmi Note 10'
password = '12345678'

def connect():
  #Connect to WLAN
  wlan = network.WLAN(network.STA_IF)
  wlan.active(True)
  wlan.connect(ssid, password)
  while wlan.isconnected() == False:
    print('Waiting for connection...')
    sleep(1)     
  ip = wlan.ifconfig()[0]
  print(f'Connected on {ip}')
  return ip

def open_socket(ip):
  # Open a socket
  address = (ip, 80)
  connection = socket.socket()
  connection.bind(address)
  connection.listen(1)
  return connection

def webpage(state):
  #Template HTML
  html = f"""
      <!DOCTYPE html>
      <html>
      <form action="./lighton">
      <input type="submit" value="Light on" />
      </form>
      <form action="./lightoff">
      <input type="submit" value="Light off" />
      </form>
      <p>LED is {state}</p>
      </body>
      </html>
      """
  return str(html)

def serve(connection):
  #Start a web server
  state = 'OFF'
  led.off()
  while True:
    client = connection.accept()[0]
    request = client.recv(1024)
    request = str(request)
    try:
      request = request.split()[1]
    except IndexError:
      pass
    if request == '/lighton?':
      led.on()
      state = 'ON'
    elif request =='/lightoff?':
      led.off()
      state = 'OFF'
    html = webpage(state)
    client.send(html)
    client.close()

try:
  ip = connect()
  connection = open_socket(ip)
  serve(connection)
except KeyboardInterrupt:
  machine.reset()

 Now edit the ssid and password according to your network and save this file on your raspberry pi pico w board. Now click on run option. After few seconds your pico w will be connected to your network. Copy the IP address from the shell and paste it on your browser(Google chrome or Firefox) and press enter. Now control the LED.