The SHT31 is Sensirion’s accurate temperature and humidity sensor (±0.3 °C, ±2 % RH). It needs no library on the Pico W: one I2C command starts a measurement and six bytes come back with checksums.
Wire it to 3V3 and I2C0 (GP4/GP5). The script prints a CRC-checked reading every two seconds.
Wiring
| Raspberry Pi Pico W | SHT31-D | Wire | Notes |
|---|---|---|---|
| 3V3 | VIN | red | 3V3 is pin 36. The breakout’s pull-ups follow VIN. |
| GND | GND | black | |
| GP5 | SCL | yellow | GP5 is physical pin 7 (I2C0 SCL). |
| GP4 | SDA | blue | GP4 is physical pin 6 (I2C0 SDA). ADR open = 0x44. |
2.4–5.5 V part, 3.3 V board. Power VCC from your board's logic voltage; the breakout's pull-ups follow VCC, so they match 3.3 V or 5 V boards.
Board quirks
- The single-shot command
0x24 0x00does not use clock stretching, which keeps it reliable on the RP2040’s I2C. - Both values carry a Sensirion CRC-8; a mismatch is reported instead of being printed as data.
- Two SHT31s can share the bus — pull ADR HIGH on one for 0x45. Handy for indoor vs outdoor readings.
- For a weather station, keep it out of direct sun and away from the Pico W; a ventilated radiation shield makes a bigger difference than the sensor choice.
Code
# SHT31 temperature + humidity on a Raspberry Pi Pico W (MicroPython, no library).
# Wiring: VIN -> 3V3 (pin 36), GND -> GND, SCL -> GP5 (pin 7), SDA -> GP4 (pin 6). I2C0.
# ADR unconnected/LOW = 0x44, HIGH = 0x45.
from machine import Pin, I2C
import time
i2c = I2C(0, sda=Pin(4), scl=Pin(5), freq=100_000)
found = i2c.scan()
addr = 0x44 if 0x44 in found else (0x45 if 0x45 in found else None)
if addr is None:
raise SystemExit("No SHT31 at 0x44/0x45 - found {}".format([hex(a) for a in found]))
def crc8(data): # Sensirion CRC-8: polynomial 0x31, init 0xFF
crc = 0xFF
for b in data:
crc ^= b
for _ in range(8):
crc = ((crc << 1) ^ 0x31) & 0xFF if crc & 0x80 else (crc << 1) & 0xFF
return crc
def read():
i2c.writeto(addr, b"\x24\x00") # single shot, high repeatability, no clock stretching
time.sleep_ms(16)
d = i2c.readfrom(addr, 6)
if crc8(d[0:2]) != d[2] or crc8(d[3:5]) != d[5]:
raise OSError("CRC mismatch - check wiring")
t = -45 + 175 * ((d[0] << 8) | d[1]) / 65535
rh = 100 * ((d[3] << 8) | d[4]) / 65535
return t, rh
i2c.writeto(addr, b"\x30\xA2") # soft reset
time.sleep_ms(2)
print("SHT31 at", hex(addr))
while True:
try:
t, rh = read()
print("Temp {:.2f} C Humidity {:.1f} %".format(t, rh))
except OSError as e:
print("Read failed:", e)
time.sleep(2)# SHT31 temperature + humidity on a Raspberry Pi Pico W (MicroPython, no library).
# Wiring: VIN -> 3V3 (pin 36), GND -> GND, SCL -> GP5 (pin 7), SDA -> GP4 (pin 6). I2C0.
# ADR unconnected/LOW = 0x44, HIGH = 0x45.
from machine import Pin, I2C
import time
i2c = I2C(0, sda=Pin(4), scl=Pin(5), freq=100_000)
found = i2c.scan()
addr = 0x44 if 0x44 in found else (0x45 if 0x45 in found else None)
if addr is None:
raise SystemExit("No SHT31 at 0x44/0x45 - found {}".format([hex(a) for a in found]))
def crc8(data): # Sensirion CRC-8: polynomial 0x31, init 0xFF
crc = 0xFF
for b in data:
crc ^= b
for _ in range(8):
crc = ((crc << 1) ^ 0x31) & 0xFF if crc & 0x80 else (crc << 1) & 0xFF
return crc
def read():
i2c.writeto(addr, b"\x24\x00") # single shot, high repeatability, no clock stretching
time.sleep_ms(16)
d = i2c.readfrom(addr, 6)
if crc8(d[0:2]) != d[2] or crc8(d[3:5]) != d[5]:
raise OSError("CRC mismatch - check wiring")
t = -45 + 175 * ((d[0] << 8) | d[1]) / 65535
rh = 100 * ((d[3] << 8) | d[4]) / 65535
return t, rh
i2c.writeto(addr, b"\x30\xA2") # soft reset
time.sleep_ms(2)
print("SHT31 at", hex(addr))
while True:
try:
t, rh = read()
print("Temp {:.2f} C Humidity {:.1f} %".format(t, rh))
except OSError as e:
print("Read failed:", e)
time.sleep(2)Expected serial output
SHT31 at 0x44
Temp 27.43 C Humidity 58.2 %
Temp 27.44 C Humidity 58.3 %SHT31 at 0x44 Temp 27.43 C Humidity 58.2 % Temp 27.44 C Humidity 58.3 %
Common errors
Read failed: CRC mismatch - check wiring
Noise on a long or loose SDA wire. Shorten the jumpers or drop the bus to 50 kHz.
Humidity reads high and slowly recovers after rain or a shower
Condensation on the sensor. The SHT31 has a built-in heater (command 0x30 0x6D) to dry it; turn it off again with 0x30 0x66.