Categories
Tutorials

Build a cloud Raspberry Pi Pico W temperature/humidity logger

I live in a pretty humid part of the world and that has left me worried for some of my valuables.

If you live in a place with high humidity, your camera lenses, inflatable watercraft and leather shoes can break down much faster.

I have designated a cabinet as a “low-humidity zone”, in an air-conditioned room and desiccant pellets within this cabinet.

I found myself needing something that could tell me the temperature and humidity of the cabinet. Plus, I wanted to connect it online for temperature logging purposes.

Here’s how to build something like this.

Parts needed

  • Raspberry Pi Pico W with headers (or buy a Pico WH)
  • Quad 7-segment LED display modules using the TM1637 LED driver
  • DHT22 (or DHT11, BME*** board)
  • Breadboard
  • Jumper wires

I used a DHT22 but you can use a DHT11 or a BME280, 680, 688 board. The code below uses a DHT22, so you will have to modify the code if you use something else.

Pico W references

Flashing your Pico W

Uploading files to Pico W

A basic Raspberry Pi Pico W temperature/humidity reader

Let’s build a basic temperature/humidity reader

I generally prefer to build a basic device before I start connecting it online.

First up, let’s connect the components up.

The diagram is a bit complicated, so here’s how you can connect everything.

3V3/GND connections

Pin on Pico WDestination
3.3VVCC on display and DHT22
GNDGND on both devices

DHT22 connections

With the DHT22 facing you, the pins are, from left to right:

VCC, DATA, null pin, GND

Pin on Pico WDestination
GPIO10DHT22 DATA with 10K resistor in between

LED display with TM1637

Pin on Pico WDestination
GPIO16CLK
GPIO17DIO

Coding the Pico W temp/humidity logger

import tm1637
from machine import Pin
import dht
import time

tm = tm1637.TM1637(clk=Pin(16), dio=Pin(17))

dht22 = dht.DHT22(Pin(10))

while True:
    try:
        dht22.measure()
        print(f"temp:{dht22.temperature()}, humidity:{dht22.humidity()}")
        tm.numbers(int(dht22.temperature()), int(dht22.humidity()), colon=True)
        time.sleep(2)
        
    except:
        tm.show('errr')

You will need the TM1637 library. Here’s how to use it:

Copying a library into the Pico W.
Here’s how you put a library on the Pico W. The “…” is actually an __init__.py file.
  • Go to the link. Download the tm1637.py file.
  • In your Pico W, create a folder called tm1637. In it, copy the downloaded Python file and rename it __init__.py . Two underscores on each side.

The code should be self-explanatory. Or maybe it’s because I coded it so it’s obvious. Here’s an explanation of the specific choices I have made:

        dht22.measure()

        tm.numbers(int(dht22.temperature()), int(dht22.humidity()), colon=True)

        time.sleep(2)
        
    except:
        tm.show('errr')

In order to get a reading from a DHT22, you must “kickstart it” using the measure() method.

Then, the next line tells the TM1637 library to display two numbers, separated by a colon. On the left of the colon is the temperature. On the right is the relative humidity.

Randoms who see this won’t get it. It’s one of those IYKYK situations.

If you’re American, you might want to change it to display Fahrenheit. Use these line instead:

    print(f"temp:{dht22.temperature() * 9/5 + 32}, humidity:{dht22.humidity()}")

    tm.numbers(int(dht22.temperature() * 9/5 + 32), int(dht22.humidity()), colon=True)

If you live in places where it gets over 99 F or below zero C/F, you’re going to get an error. I didn’t handle these errors because my device is meant to be indoors.

At the end, there’s a time.sleep(2). This means the values refresh every two seconds.

Thonny Pico W device is busy fix
Press CTRL+C to get out of this problem with the Pico W.

This makes the Pico W very busy. You might notice that Thonny can’t access the Pico W. In this case, just use CTRL+C to interrupt the process.

Logging your Pico W data to the cloud using Anvil

This is where the Pico W becomes the tool of choice.

You could achieve the above with the regular Pico, but it’s only with a Pico W would you be able to log data online.

I wanted to log temperate and humidity data online because I want to identify trends. For example: how much do conditions change when I open the door? It might also help me recognize issues such as my desiccant losing its efficacy.

I decided to use Anvil.

Anvil is amazing because it cuts your workload significantly. Your other options are to connect your Pico W to Google Sheets directly (tough because of OAuth), or use an intermediary like IFTTT (no GUI).

Anvil gives you the ability to build a GUI using its drag-and-drop interface. It also allows you to skip writing a lot of code such as the WiFi connection code, error handling and many more. It’s impressive.

Read Anvil’s quickstart guide which will walk you through connecting the Pico W with Anvil’s servers.

Download the UF2 file here.

For this tutorial, the quickstart’s relevancy ends at the heading “Understanding the main.py file”. Everything before that should be read.

Coding the Pico W for Anvil

After you have flashed the UF2 file, the Pico W will have two files: boot.py and main.py.

You should go into boot.py and type in your WiFi creds.

Anvil Pico W boot.py. Add your SSID and password here. Save. That's all.
Anvil Pico W boot.py. Add your SSID and password here. Save. That’s all.

Create an app in Anvil

Sign up for Anvil. Log into your dashboard. Click “New Blank App”. In the pop-up, choose Material Design 3.

Note that I am using the Beta editor.

For now, we want to be able to get the Pico W to log data into a Data Table (i.e. a spreadsheet).

You can use the Client Uplink Key in your main.py constant UPLINK_KEY.

Add Anvil Server Module

Add a server module on the left sidebar.

You will need this code in order to log time, temp and humidity into a Data Table named dht22.

import anvil.tables as tables
import anvil.tables.query as q
from anvil.tables import app_tables
import anvil.server
from datetime import datetime

@anvil.server.callable
def log_dht22(t, h):
  print ("successfully logged")
  app_tables.dht22.add_row(timestamp= datetime.now(), temp = t, humidity = h)

Add a Data Table in Anvil

Click on the barrel on the sidebar and click “Add New Table”. Rename the Data Table as “dht22” by double-clicking,

Add three columns:

  • timestamp (Date and Time)
  • temp (number)
  • humidity (number)

Coding the Pico W to log data to Anvil

pico w temperature humidity cloud logger
import anvil.pico
import uasyncio as a
import tm1637
from machine import Pin
import dht
import time

UPLINK_KEY = "XXXXXXXXXXXXXXXX-CLIENT"

# init components
tm = tm1637.TM1637(clk=Pin(16), dio=Pin(17))
dht22 = dht.DHT22(Pin(10))


async def start_log():
    time_elapsed = 0  # counter so that logs to Anvil happen only once time_elapsed = x

    while True:
        try:
            dht22.measure()
            t = int(dht22.temperature())
            h = int(dht22.humidity())

            tm.numbers(t, h, colon=True)  # colon = middle colon of display

            if time_elapsed >= 5:
                print(f"temp:{t}, humidity:{h}, time_elapsed:{time_elapsed}")
                # call server func log_dht22 and pass args
                x = await anvil.pico.call("log_dht22", t, h)
                time_elapsed = 0  # reset time_elapsed
                tm.show('logg')

            time_elapsed += 1
            time.sleep(1)

        except Exception as e:
            print(e)
            tm.show('errr')


anvil.pico.connect(UPLINK_KEY, on_first_connect=start_log(),
                   on_every_connect=start_log())

As you can see, there are a few changes here as compared to the original code.

Creating a graphical representation on Anvil

You can see your data in table format by going to Data Tables -> dht22.

But if you want it in a graphical view, here’s how:

This guide by Anvil is pretty useful on pulling data from the Data Table to the dashboard, but you must follow the steps 1-3 and modify it to suit your use case.

Basically, you drag and drop a Plot to your dashboard in the Design tab, then go into the Code or Split tab and add these lines of codes (in bold)

#imports truncated.

class Form1(Form1Template):
  def __init__(self, **properties):
    # Set Form properties and Data Bindings.
    self.init_components(**properties)

    self.build_dht_graph()

    # Any code you write here will run before the form opens.

  def plot_1_click(self, points, **event_args):
    """This method is called when a data point is clicked."""
    pass

  def build_dht_graph(self):
    # Get the data from our server function, and store it as 'db_data'
    db_data = anvil.server.call('get_data')

    # Create a Bar plot with this data, and change the colour of the markers
    self.plot_1.data = go.Bar(
    x = [x['timestamp'] for x in db_data],
    y = [x['humidity'] for x in db_data],
    marker=dict(color='#2196f3')
    )

Have a project in mind?

Websites. Graphics. SEO-oriented content.

I can get your next project off the ground.

See how I have helped my clients.