IoTSimulator

Build a Smart Climate Monitor with a Raspberry Pi Pico W

Build an environmental weather station with the Raspberry Pi Pico W. Acquire temperature and humidity metrics from a digital DHT22 sensor, render a real-time 128x64 dashboard on an SSD1306 OLED display, and stream JSON telemetry.
Muhammad Ichsanul Fadhil
IoTSim Editor
October 10, 2026
Build a Smart Climate Monitor with a Raspberry Pi Pico W

Live project track

Interactive hardware & logic preview

Keeping indoor spaces healthy and comfortable requires paying attention to both temperature and moisture levels. High humidity encourages mold growth and makes rooms feel muggy, while dry air causes static electricity and irritates your respiratory system. Having a dedicated desk monitor that shows current room conditions at a glance makes it easy to know when to open a window or adjust your thermostat.

In this project, you will build a smart climate monitor using a Raspberry Pi Pico W, a digital DHT22 temperature and humidity sensor, and a high-contrast 128x64 SSD1306 OLED display. You will learn how to read digital environmental data, draw custom text and status cards onto an OLED screen over a two-wire I2C bus, pulse a heartbeat activity LED, and format structured JSON readings over USB serial.

Digital Climate Sensing with the DHT22

Smart Climate Telemetry Data Flow
Figure 1: The DHT22 transmits digital temperature and humidity data packets to the Pico W, which updates the OLED.

Unlike analog temperature sensors that output small variable voltages prone to electrical noise, the DHT22 sensor contains its own internal measurement chip. It measures temperature using an internal thermistor and humidity using a capacitive moisture element, converts the readings into digital numbers, and sends them out as a clean series of binary pulses over a single data wire.

Climate MetricMeasurement RangeAccuracySampling Rate
Ambient Temperature-40°C to +80°C±0.5°CEvery 2 seconds (0.5 Hz)
Relative Humidity0% to 100% RH±2% to ±5% RHEvery 2 seconds (0.5 Hz)
Operating Voltage3.3V to 5.5V DCRegulated on-boardDraws ~1 mA during reading
Data Output FormatDigital single-wire pulsesVerified by checksumSent to pin GP2 on Pico W

Because the DHT22 requires approximately two seconds between readings to stabilize its internal sensing elements, our firmware updates the screen every two seconds. Querying the sensor any faster would cause internal self-heating and produce inaccurate temperature readings.

Driving a Graphical OLED Display Over I2C

RP2040 Hardware I2C Pin Configuration and Bus Topology
Figure 2: The SSD1306 OLED display connects to hardware I2C pins GP4 (SDA) and GP5 (SCL) at address 0x3C.

Traditional character LCDs can only show fixed grids of text letters. In contrast, an SSD1306 OLED display gives you a graphical canvas of 128 pixels wide by 64 pixels tall—a total of 8,192 individual self-lit pixels. This allows you to draw dividing lines, vary font sizes, and create a modern dashboard layout.

Screen RegionPixel CoordinatesVisual ElementFunction on Dashboard
Top Header BarY = 0 to 10System Title & Status LineDisplays 'PICO-W [WiFi:OK]' with an underline
Temperature CardY = 18 to 36Large Double-Sized NumberShows current temperature in °C with decimal precision
Humidity CardY = 44 to 62Large Double-Sized NumberShows relative humidity percentage (e.g. 58.2 %)
I2C CommunicationPins GP4 & GP5Hardware I2C Bus @ 400 kHzTransfers full screen buffer in a single burst

On the Raspberry Pi Pico W, the hardware I2C controller can be routed to different GPIO pins using software commands. By calling Wire.setSDA(4) and Wire.setSCL(5), we assign pins GP4 and GP5 to handle display communication, leaving other pins completely free.

Everyday Magic: Room Comfort at a Glance

Smart climate station showing happy comfort face versus hot sweating face
Figure 3: Visual comfort indicator: the weather station turns raw temperature and humidity numbers into friendly faces you can read in a split second.

Think of this project like a desk weather companion. Instead of just displaying plain digits that you have to analyze, the Raspberry Pi Pico W evaluates the comfort index. When the room is between 20°C and 26°C with moderate humidity, it displays a cheerful smiling face. When the air turns sweltering or muggy, it instantly warns you to open a window or turn on a fan. The interactive connection tables below show how each module connects to the Raspberry Pi Pico W.

Pin Connection Map
DHT22 Climate Sensor Pin
SDA (Data Lead)
→
Raspberry Pi Pico W Pin
GP2 (Physical Pin 4)
Explanation
Carries 40-bit digital climate packet stream
DHT22 Climate Sensor Pin
VCC (Power)
→
Raspberry Pi Pico W Pin
3V3 (Physical Pin 36)
Explanation
Regulated 3.3V power supply rail
DHT22 Climate Sensor Pin
GND (Ground)
→
Raspberry Pi Pico W Pin
GND (Physical Pin 8)
Explanation
Sensor ground return connection

The DHT22 data pin connects directly to pin GP2 on the Pico W. Because DHT22 sensor modules include an on-board pull-up resistor on the data line, you do not need an external resistor on your breadboard.

Pin Connection Map
SSD1306 OLED Display Pin
SDA (Data)
→
Raspberry Pi Pico W Pin
GP4 (Physical Pin 6 / I2C0 SDA)
Explanation
I2C Serial Data bus line
SSD1306 OLED Display Pin
SCL (Clock)
→
Raspberry Pi Pico W Pin
GP5 (Physical Pin 7 / I2C0 SCL)
Explanation
I2C Serial Clock bus line
SSD1306 OLED Display Pin
VCC (Power)
→
Raspberry Pi Pico W Pin
3V3 (Physical Pin 36)
Explanation
Regulated 3.3V operating voltage
SSD1306 OLED Display Pin
GND (Ground)
→
Raspberry Pi Pico W Pin
GND (Physical Pin 8)
Explanation
Display ground return connection

The SSD1306 OLED uses standard I2C wiring: SDA connects to GP4 and SCL connects to GP5. Built-in pull-up resistors on the OLED breakout module ensure clean high-speed clock and data signals.

Pin Connection Map
Heartbeat LED Pin
Anode (+)
→
Raspberry Pi Pico W Pin
GP15 (Physical Pin 20)
Explanation
Digital output pulsed during every sensor reading
Heartbeat LED Pin
Cathode (-)
→
Raspberry Pi Pico W Pin
GND (Physical Pin 18 / GND)
Explanation
Ground return for indicator LED

The blue LED on pin GP15 serves as an activity indicator. It flashes briefly each time the Pico W queries the DHT22 and refreshes the screen, confirming at a glance that the monitoring loop is actively running.

Complete Code

Here is the full Arduino sketch for your smart climate monitor. Upload this code to your Raspberry Pi Pico W and open the Serial Monitor at 115200 baud to view incoming JSON telemetry:

C++ Source
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
// ============================================================================
// Raspberry Pi Pico W Smart Climate Monitor with OLED
// DHT22 Climate on GP2
// SSD1306 128x64 OLED on GP4 (SDA) & GP5 (SCL)
// Telemetry Heartbeat LED on GP15
// ============================================================================

#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <DHT.h>

#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, -1);

#define DHTPIN 2
#define DHTTYPE DHT22
DHT dht(DHTPIN, DHTTYPE);

const int HEARTBEAT_LED = 15;

void setup() {
  Serial.begin(115200);
  delay(200); // USB settling delay
  
  // Configure hardware I2C0 pins on Raspberry Pi Pico W
  Wire.setSDA(4);
  Wire.setSCL(5);
  Wire.begin();
  
  dht.begin();
  pinMode(HEARTBEAT_LED, OUTPUT);

  if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
    Serial.println(F("SSD1306 OLED initialization failed!"));
    while (1);
  }

  display.clearDisplay();
  display.setTextSize(1);
  display.setTextColor(SSD1306_WHITE);
  display.setCursor(18, 26);
  display.print(F("PICO W IOT NODE"));
  display.display();
  delay(1200);
}

void loop() {
  // Pulse heartbeat activity LED
  digitalWrite(HEARTBEAT_LED, HIGH);

  // 1. Read calibrated digital climate telemetry from DHT22
  float h = dht.readHumidity();
  float t = dht.readTemperature();

  // 2. Render graphical dashboard onto 128x64 OLED
  display.clearDisplay();
  
  // Top Header Status Banner
  display.setTextSize(1);
  display.setCursor(0, 0);
  display.print(F("PICO-W  [WiFi:OK]"));
  display.drawLine(0, 10, 128, 10, SSD1306_WHITE);

  // Temperature Card
  display.setCursor(4, 18);
  display.print(F("Temp: "));
  display.setTextSize(2);
  if (isnan(t)) display.print(F("--.- "));
  else display.print(t, 1);
  display.setTextSize(1);
  display.print(F(" C"));

  // Humidity Card
  display.setCursor(4, 44);
  display.print(F("Hum : "));
  display.setTextSize(2);
  if (isnan(h)) display.print(F("--.- "));
  else display.print(h, 1);
  display.setTextSize(1);
  display.print(F(" %"));

  display.display(); // Burst framebuffer over I2C

  // 3. Format structured JSON payload over high-speed Serial
  Serial.print(F("{\"node\":\"pico-w-01\",\"temp\":"));
  Serial.print(t, 2);
  Serial.print(F(",\"humidity\":"));
  Serial.print(h, 2);
  Serial.println(F("}"));

  digitalWrite(HEARTBEAT_LED, LOW);
  delay(2000); // 2-second telemetry refresh cycle
}

How the Code Works, Part by Part

The firmware follows three distinct stages: setting up the communication buses, acquiring sensor readings, and updating both the visual display and serial telemetry.

Initializing I2C Pins and the OLED Screen

In setup(), the code explicitly maps the Pico W's hardware I2C peripheral to the chosen pins before booting the screen:

C++ Source
1
2
3
4
5
6
7
8
Wire.setSDA(4);
Wire.setSCL(5);
Wire.begin();

if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
  Serial.println(F("SSD1306 OLED initialization failed!"));
  while (1);
}

Setting pins GP4 and GP5 ensures the I2C library communicates on the correct header pins. Address 0x3C is the standard 7-bit I2C address used by most 0.96-inch SSD1306 OLED displays.

Reading Climate Metrics and Handling Errors

At the start of loop(), the DHT library samples the sensor and converts the pulses into floating-point numbers:

C++ Source
1
2
3
4
5
float h = dht.readHumidity();
float t = dht.readTemperature();

if (isnan(t)) display.print(F("--.- "));
else display.print(t, 1);

Single-wire digital sensors can occasionally miss a pulse if communication timing fluctuates. The isnan() check detects when an invalid reading occurs, displaying placeholder dashes instead of corrupting the screen layout.

Drawing the Dashboard and Outputting JSON

After rendering text and lines in memory, display.display() sends all pixel data to the OLED in one fast burst, while Serial outputs a structured JSON string:

C++ Source
1
2
3
4
5
6
7
display.display();

Serial.print(F("{\"node\":\"pico-w-01\",\"temp\":"));
Serial.print(t, 2);
Serial.print(F(",\"humidity\":"));
Serial.print(h, 2);
Serial.println(F("}"));

Formatting data as JSON makes it easy for desktop programs, Node.js servers, or cloud dashboards to parse incoming readings automatically without needing custom text scrapers.

Fixing Common Problems

If your OLED monitor is blank or showing incorrect values, review the table below for quick fixes:

Observed ProblemLikely CauseHow to Fix
OLED screen remains completely blackIncorrect I2C address or swapped SDA/SCL wiresVerify address is 0x3C in code, and ensure SDA connects to GP4 and SCL connects to GP5.
Temperature displays '--.- C' constantlyDHT22 data pin wired to wrong header pinVerify that the sensor data lead connects to pin GP2 (Physical Pin 4) on the Pico W.
Screen content appears scrambled or offsetDisplay dimensions mismatch in libraryEnsure SCREEN_WIDTH is set to 128 and SCREEN_HEIGHT is set to 64.
Serial Monitor displays unreadable symbolsTerminal baud rate mismatchSet the Serial Monitor baud rate in the bottom right corner to 115200 baud.

If the screen fails to start, verify your 3.3V power and ground jumpers with a multimeter to ensure stable voltage is reaching both modules.

Try It in the Simulator

Click the Start Simulation button in the top toolbar to boot up your climate node. Click on the DHT22 sensor to reveal its interactive temperature and humidity sliders. Move the temperature slider up to 30°C and humidity to 75%: watch the OLED screen update with large crisp numbers and observe the formatted JSON string print to the Serial Monitor console.

Keywords
#Raspberry Pi Pico W #RP2040 #DHT22 #SSD1306 #OLED #I2C #IoT #Climate #Telemetry #Intermediate
Total word count: 1184 words

Project discussion

Questions, feedback, and community insights
No discussions yet. Be the first to start!