Exciting news

I have been working on the weather station project over the last few days. I have been using a Raspberry Pi Pico as a replacement for one of my other Raspberry Pi's to run the temperature sensors from.

I have had a setback or two. One big one was that I may have burnt out the DHT11 sensor that I was going to use to test the setup. I had just put the wires in on the breadboard and about to put the resistor in, as the DHT11 is only the sensor and not the module. I then smelt burning, I quickly pulled all cables out of the breadboard and the Pico. It was still quite a strong smell, so I started to sniff the Pico and DHT11, it turned out to be that. I didn't realize that I had placed it into the breadboard backwards to my diagram, so I had placed the 3v3 cable into the rail that had the DHT ground pin in, and the ground wire into the rail that contained the DHT VCC pin. So there is a nice burn hole in the back of the sensor now.

Thanks to my slight error, I decided to pick up a DHT22 module, so I don't have to deal with the resistor separately. This will help as my overall plan is to mount and solder it all onto some perf board and then maybe a custom PCB for it all if I get that far.

So then on with what I have done to get it working.


Equipment

So for this project I will be using:

  1. Raspberry Pi Pico W
  2. Breadboard
  3. Jumper cables
  4. DHT11/22
  5. IDE (Thonny, Arduino)
  6. 10kΩ Resistors (if using a DHT sensor and not module)

Raspberry Pi Pico W

Raspberry Pi Pico W
Raspberry Pi Pico W

I will be using the Pico W for this project as it has built in Wi-Fi, so reduces the costs slightly as I won't need to purchase another module such as a ESP32 Wi-Fi coprocessor like the Adafruit Airlift FeatherWing.


Breadboard

Breadboard
Breadboard

I will be using the breadboard to hold the Raspberry Pi Pico and the DHT22 module. I will be connecting the two together with the cables.


Jumper Cables (DuPont Cables)

Jumper (DuPont) Cables
cables

There are different styles of cables, some are rigid, sit flush to the breadboard, and are premeasured to different lengths that you may need. Others are like mine that while they are premeasured they don't sit flat to the breadboard but arch over the board.


DHT11/DHT22

As I mentioned further up in the post, I was originally going to build this project with a DHT11 sensor, but due to melting a hole in it, I have a DHT22 module which has the sensor and required 10kΩ resistor soldered onto a PCB for ease of use.
The DHT11 and DHT22 are very similar in what they do and how they look

Module Pins

Pin Label Raspberry Pi Pico W
1 VCC+ 36 3V3(OUT)
2 OUT 4 SDA
3 GND- 38 GND

Sensor Pins

Pin Label Raspberry Pi Pico W
1 VCC+ 36 3V3(OUT)
2 DATA 4 SDA
3 NC
4 GND- 38 GND

The 10k resistor will need to be placed between pins 1 (VCC) and 2 (DATA).


Thonny IDE

Thonny IDE

While you could use any Integrated Development Environment (IDE) and then copy the files to the Raspberry Pi Pico W I will be using Thonny as this allows us to connect to the Pico W and save directly to the Pico W, as well as allowing us to search and install any libraries we might need onto the Pico W too.

Modules

With in Thonny we can install the library's and packages that we need. In this project I will be needing to install pizozero this will allow me to easily use the onboard LED amongst other things.

To install, I will go to the Tools>Manage packages... in the Thonny toolbar

Then in the box that shows up, I will search for picozero and click on the install button.

Then to be able to use the library I can just import it in python

import picozero

Wiring Diagram

DHT22 Module Diagram

DHT22 Module Diagram
Wire Colour DHT22 Module Raspberry Pi Pico W
Green OUT 4 SDA
Red VCC+ 36 3V3(OUT)
Black GND- 38 GND

DHT Sensor Diagram

DHT11 Sensor Diagram

Wire Colour DHT Sensor Raspberry Pi Pico W 10kΩ Resistor
Red VCC+ 36 3V3(OUT)
Green DATA 4 SDA
Black GND- 38 GND
Blue DATA Right
Blue VCC+ Left


Measuring Temperature, Humidity, and Pressure

To get a reading for the temperature and humidity from the sensor I will need to import the library's, I will also have the LED on the Pico flash every time a reading is taken.

First the library's to be imported are

from machine import Pin
from time import sleep
from picozero import pico_let, LED
import dht

I'll then create the variable for the DHT22

sensor = dht.DHT22(Pin(2))

Then I will use while True to create an infinite loop that waits for two seconds before starting again. Within the loop, I will create two more variables, one for the temperature and one for the humidity.

while True:
  pico_sensor.on()
  sensor.measure()
  temp = sensor.temperature()
  hum = sensor.humidity()
  print('Temperature: {}C Humidity:{:.of}%'.format(temp,hum))
  pico_led.off()
  sleep(2)

The output of the script is

Thonny Output with Temperature and Humidity Readings

Connecting to Wi-Fi

For both this section and the next, I will be using the tutorial available from the Raspberry Pi Foundation called Getting started with your Raspberry Pi Pico W.

First, I will import the required library's.

import network
import machine
from time import sleep 

Then I will create the variables for the routers SSID and password.

ssid = 'YOUR WiFi NAME HERE'
password = 'YOUR WiFi PASSWORD HERE' 

Then I will create a function to connect to the WLAN, loop every second until it is connected and then print out the IP address of the Raspberry Pi Pico W. At the end I will place a try/except to reset the Raspberry Pi Pico W as the Wi-Fi connection will stay active even after the code is stopped. This will also contain a variable to store the returned IP address

def connect():
    #connect to WiFi Network
    wlan = network.WLAN(network.STA_IF)
    wlan.active(True)
    wlan.connect(ssid, password)
    #Loop until connected
    while wlan.isconnected() == False:
        print('Witing for connection...')
        sleep(1)
    #Get just IP address
    ip = wlan.ifconfig()[0]
    #Print out IP address
    print(f'Connected on {ip}')
    return ip

#Reset machine to sever WiFi connection
try:
    ip = connect()
except KeyboardInterrupt:
    machine.reset() 

When I start the script, I should get the following output

Raspberry Pi Pico trying to connect to the WiFi

Adding Web server and HTML

While still following the tutorial from the previous section, I will now have to create a function above the try/except to open the HTTP socket 80 and have it listen for requests to allow web connections.

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

Just below this I will create a function named webpage that contains two parameters, these will be the temp and hum from the readings we took previously. This function will then create a webpage that contains a table that will display the temperature and humidity in a nice format. This table and formatting came from a similar project that I found on Instructables called 'Make a Simple Raspberry Pi Pico W Weather Station' that has since been removed, sadly.

def webpage(temp, hum):
    html = """<html>
              <head>
              <meta http-equiv="refresh" content="5">
              <meta name="viewport" content="width=device-width, initial-scale=1">
              <link rel="icon" href="data:,">
              <style>
              body { text-align: center; font-family: "Helvetica", Arial;}
              table { border-collapse: collapse; width:55%; margin-left:auto; margin-right:auto; }
              th { padding: 12px; background-color: #87034F; color: white; }
              tr { border: 2px solid #000556; padding: 12px; }
              tr:hover { background-color: #bcbcbc; }
              td { border: none; padding: 14px; }
              .sensor { color:DarkBlue; font-weight: bold; background-color: #ffffff; padding: 1px;  
              </style>
              </head>
              <body>
              <h1>BME280 Pi Pico W Weather Station</h1>
              <table><tr><th>Parameters</th><th>Value</th></tr>
              <tr><td>Temperature</td><td><span class="sensor">""" + "{}C".format(temp) + """</span></td></tr>
              <tr><td>Humidity</td><td><span class="sensor">""" + "{:.02f}%".format(hum) + """</span></td></tr> 
              </html>"""
    return html  

Below the webpage function I will create a new function called serve that has the parameter connection this function will contain the temperature, humidity, and sensor variables that were created earlier as well as the size of the data chunks that the web browser is served (which will be in 1024 bytes) and it will send the HTML to the client.

def serve(connection):
    sensor = dht.DHT22(Pin(2))   
    while True:
        client = connection.accept()[0]
        request = client.recv(1024)
        request = str(request)
        try:
            request = request.split()[1]
        except IndexError:
            pass
        pico_led.on()
        sensor.measure()
        temp = sensor.temperature()
        hum = sensor.humidity()
        pico_led.off()
        sleep(2)
        html = webpage(temp, hum)
        client.send(html)
        client.close() 

I will then add a variable connection and serve function to the try/except to store the returned connection and to serve the webpage and content. The try/except should now look like this.

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

Conclusion

The final file should look something like this:

import machine
from machine import Pin
from picozero import pico_led, LED
from time import sleep
import network
import socket
import dht

ssid = 'YOUR WiFi NAME HERE'
password = 'YOUR WiFi PASSWORD HERE'

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(temp, hum):
    html = """<html>
              <head>
              <meta http-equiv="refresh" content="5">
              <meta name="viewport" content="width=device-width, initial-scale=1">
              <link rel="icon" href="data:,">
              <style>
              body { text-align: center; font-family: "Helvetica", Arial;}
              table { border-collapse: collapse; width:55%; margin-left:auto; margin-right:auto; }
              th { padding: 12px; background-color: #87034F; color: white; }
              tr { border: 2px solid #000556; padding: 12px; }
              tr:hover { background-color: #bcbcbc; }
              td { border: none; padding: 14px; }
              .sensor { color:DarkBlue; font-weight: bold; background-color: #ffffff; padding: 1px;  
              </style>
              </head>
              <body>
              <h1>BME280 Pi Pico W Weather Station</h1>
              <table><tr><th>Parameters</th><th>Value</th></tr>
              <tr><td>Temperature</td><td><span class="sensor">""" + "{}C".format(temp) + """</span></td></tr>
              <tr><td>Humidity</td><td><span class="sensor">""" + "{:.02f}%".format(hum) + """</span></td></tr> 
              </html>"""
    return html

def serve(connection):
    sensor = dht.DHT22(Pin(2))   
    while True:
        client = connection.accept()[0]
        request = client.recv(1024)
        request = str(request)
        try:
            request = request.split()[1]
        except IndexError:
            pass
        pico_led.on()
        sensor.measure()
        temp = sensor.temperature()
        hum = sensor.humidity()
        pico_led.off()
        sleep(2)
        html = webpage(temp, hum)
        client.send(html)
        client.close()

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

main.py

The output in the web browser will look like this

Pico output in web browser

If you would like the Pico W to take readings when it is not connected to the computer the file needs to be called main.py as this is the file that is looked for when the Pico boots.

While this does look nice and serves the readings from the DHT22 very well. It only shows the current readings, so I would like to have some past readings being visible. I may even change it from serving a web page with the readings to having a MQTT client that can then be input into something like Grafana along with the air quality monitor hat I have, so I can see the temperature, humidity and air quality on a nice dashboard.