Postlad/Guides/Raspberry Pi Pico W cloud data logger with MicroPython

Raspberry Pi Pico W cloud data logger with MicroPython

A Raspberry Pi Pico W can send a sensor reading to a live cloud chart with MicroPython's built-in WiFi and socket modules. The complete program below reads the RP2040's internal temperature sensor and sends it with one plain HTTP request, so there is no package to install and no MQTT broker to configure.

Pico W to Postlad data pathA Pico W reads a value, joins WiFi, sends one HTTP request and Postlad adds the timestamp and chart.Pico Wread ADCPostlad chartHTTP GET
The Pico sends only the value and key. Postlad timestamps the accepted request and updates the chart.

Search results for Pico data logging tend to stop at an SD card. That is useful for offline work, but it does not give you a graph you can check from another room or a link you can hand to somebody else.

Reviewed, not yet bench-tested on the exact boards named here. The internal temperature sensor is useful for proving the path, not for measuring room temperature accurately.

What you need

  • Raspberry Pi Pico W or Pico 2 W
  • USB cable
  • Current MicroPython firmware for the board
  • Thonny or another MicroPython editor
  • A 2.4 GHz WiFi network
  • A free Postlad account and write key

The non-W Pico has no radio. It needs an external network module and is not covered by this sketch.

Complete main.py

Replace the WiFi credentials and write key, save the file to the Pico as main.py, then reset the board.

python
import machine
import network
import socket
import time

WIFI_SSID = "YOUR_WIFI_SSID"
WIFI_PASSWORD = "YOUR_WIFI_PASSWORD"
WRITE_KEY = "YOUR_KEY"

HOST = "api.postlad.com"
PORT = 80
SEND_INTERVAL_SECONDS = 30

wlan = network.WLAN(network.STA_IF)
temperature_adc = machine.ADC(4)
conversion_factor = 3.3 / 65535


def connect_wifi():
    if wlan.isconnected():
        return

    wlan.active(True)
    wlan.connect(WIFI_SSID, WIFI_PASSWORD)
    print("Connecting to WiFi", end="")

    deadline = time.ticks_add(time.ticks_ms(), 20000)
    while not wlan.isconnected():
        if time.ticks_diff(deadline, time.ticks_ms()) <= 0:
            raise RuntimeError("WiFi connection timed out")
        print(".", end="")
        time.sleep_ms(500)

    print("\nConnected:", wlan.ifconfig()[0])


def read_chip_temperature_c():
    voltage = temperature_adc.read_u16() * conversion_factor
    return 27 - (voltage - 0.706) / 0.001721


def send_reading(value):
    path = "/u?k={}&f1={:.2f}".format(WRITE_KEY, value)
    request = (
        "GET {} HTTP/1.1\r\n"
        "Host: {}\r\n"
        "Connection: close\r\n"
        "User-Agent: Pico-W-MicroPython\r\n"
        "\r\n"
    ).format(path, HOST)

    address = socket.getaddrinfo(HOST, PORT)[0][-1]
    connection = socket.socket()
    connection.settimeout(10)

    try:
        connection.connect(address)
        connection.send(request.encode())

        response = b""
        while True:
            chunk = connection.recv(256)
            if not chunk:
                break
            response += chunk
            if len(response) > 2048:
                break
    finally:
        connection.close()

    text = response.decode("utf-8", "replace")
    first_line = text.split("\r\n", 1)[0]
    body = text.split("\r\n\r\n", 1)[-1].strip()
    print("{:.2f} C -> {} {}".format(value, first_line, body))

    if " 200 " not in first_line:
        raise RuntimeError("Postlad did not accept the reading: " + body)


connect_wifi()

while True:
    try:
        if not wlan.isconnected():
            connect_wifi()

        temperature = read_chip_temperature_c()
        send_reading(temperature)
    except Exception as error:
        print("Send failed:", error)

    time.sleep(SEND_INTERVAL_SECONDS)

The serial console should show a response similar to:

text
29.14 C -> HTTP/1.1 200 OK ok 12

The RP2040 sensor measures the chip, so it normally reads warmer than the room. Its job here is to produce a real changing number without extra wiring.

Why use a raw socket?

Many MicroPython examples depend on urequests. It is convenient, but its presence and installation path vary between firmware builds. The program above uses the modules that come with the network-enabled Pico firmware and makes the HTTP request visible.

The request itself is only:

http
GET /u?k=YOUR_KEY&f1=29.14 HTTP/1.1
Host: api.postlad.com
Connection: close

Postlad supports plain HTTP on the device hostname. That is why a small board can send a reading without loading certificates or maintaining a clock for TLS validation.

Add a real sensor

Keep send_reading() and replace read_chip_temperature_c(). For a BME280, read temperature, humidity and pressure and send them together:

python
path = "/u?k={}&f1={:.2f}&f2={:.1f}&f3={:.1f}".format(
    WRITE_KEY,
    temperature_c,
    humidity_percent,
    pressure_hpa,
)

Then name the fields in the Postlad stream:

FieldNameUnit
f1Temperature°C
f2Humidity%RH
f3PressurehPa

One request can carry up to 16 numeric fields. They share one timestamp and count as one stored reading.

Start automatically after power loss

MicroPython runs boot.py first and main.py second. Saving the program as main.py makes it start whenever the Pico boots.

Keep the top-level loop alive when a send fails. A field logger should recover from a router restart without somebody connecting a laptop and pressing Run again.

For a genuinely unattended installation, add a watchdog and local buffering. A reconnect loop keeps the program alive; it does not preserve measurements taken while the network is down.

Buffer readings during an outage

There are two honest choices:

  1. Skip samples while offline and make the gap visible on the chart.
  2. Store timestamped samples in flash or external storage, then use Postlad's batch endpoint when connectivity returns.

Do not pretend the current time is the measurement time during replay. Each buffered point needs its original Unix timestamp. Getting reliable wall-clock time on a disconnected Pico is the hard part; use NTP while connected and retain a calibrated tick offset, or add an RTC when long offline periods matter.

Troubleshooting

WiFi connection timed out

Pico W uses 2.4 GHz WiFi. Confirm the credentials and test with a simple SSID without a captive portal. School and hotel networks that require a web login will not work with this sketch.

OSError: -2 or DNS failure

The board joined WiFi but could not resolve the hostname. Print wlan.ifconfig() and check that the DNS address is sensible. A phone hotspot is a useful isolation test.

The response says bad_key

Use the write key shown for the stream, not its public URL or read token. If the key appeared in a public repository, rotate it before continuing.

The temperature is too high

That is expected from the internal chip sensor, especially while the radio is active. Use an external sensor away from the board for environmental measurements.

Should I use HTTPS?

Use it when the network is untrusted or the readings are sensitive. Plain HTTP exposes both the value and write key to somebody able to observe the connection. This example chooses compatibility and a small memory footprint; that trade is not right for every deployment.

What the cloud adds

An SD card holds data. A cloud logger adds a current value, a chart, a share link, an embed and an off-device copy. Postlad's Free plan keeps every reading at full detail for 30 days. After that it becomes an hourly minimum, maximum and average, kept for 12 months. Older than that is deleted.

FAQ

Can Raspberry Pi Pico W send data to the cloud?

Yes. Its WiFi interface can open HTTP, HTTPS, MQTT and socket connections. For an occasional numeric reading, one HTTP GET is the smallest useful integration.

Does Pico W MicroPython include requests?

Availability depends on the firmware and package set. This guide avoids that dependency by writing a small HTTP request directly to a socket.

Can I use this without an SD card?

Yes, while the network is available. Add storage only if measurements taken during an outage must be replayed later.

How often can the Pico W send data?

The Free Postlad plan accepts one reading every 5 seconds and stores 100,000 readings per account each month. The 30-second example interval is more appropriate for a slowly changing environmental value.

Can I share the chart without sharing my account?

Yes. Make the stream public or use a secret link. Viewers do not need a Postlad account, and the write key never belongs in the share URL.

Create the stream

Create a free account, copy the stream's write key, and paste it into main.py.

Create your free account →

Sources and verification