Raspberry Pi: Sense HAT (LEDs, sensors, joystick)
Plug a Sense HAT onto a Raspberry Pi and read temperature, humidity, pressure, and orientation from Python, drive the LED matrix, and fix the two traps every owner hits.
The Sense HAT is the least wiring of any board I own: it plugs straight onto the Pi’s 40-pin header and you are done. No breadboard, no jumper wires, no pin table. For that you get an 8x8 LED matrix, a five-way joystick, and four sensors (temperature, humidity, pressure, and an IMU that knows which way the board is tilted). It is the same hardware the Raspberry Pi Foundation flies on the International Space Station for the Astro Pi competitions, and it costs about $40.
The trap is the temperature reading. The main sensor sits on the board,
a few centimeters above the Pi’s CPU, so what it measures most of the
time is heat rising off the Pi (e.g. my bench Pi reported 33 C while a
thermometer next to it said 21). Nothing is broken and there is nothing
to return. The reading needs compensating, and I will show the fix. The
second trap, the one that sends people back to the store, is i2cdetect
showing UU where they expected an address. That one means it is
working. Both traps are covered below.
What you need
Needed
- Raspberry Pi with the 40-pin header (Pi 3, 4, or 5 all work; the Pi Zero 2 W needs a soldered or hammer-fit header plus the adapter)
- Sense HAT board
- A spare microSD card with Raspberry Pi OS flashed on it (Bookworm or newer; use the spare card so your main Pi’s services stay out of the experiment)
- The official USB-C power supply
Nice to have
- A case or mounting plate: the joystick and display are meant to be touched, so a flat layout beats a stacked one
- Heatsinks for the Pi’s CPU (they drop the CPU temperature, which slightly shrinks the sensor error too)
- A small screwdriver kit
- An anti-static wristband (the Sense HAT is a bare PCB until it is mounted; treat it like any other board)
- A multimeter, if you plan to stack a second HAT and want to check the 5V pin under load
Setup
Flash the spare card with Raspberry Pi Imager, and turn SSH on while you are there (Raspberry Pi Imager >> Choose OS >> pick Raspberry Pi OS, then the gear icon >> Services >> Enable SSH). Boot the Pi and connect from your laptop.
The Sense HAT talks to the Pi over I2C, so turn the bus on:
sudo raspi-config
Then: Interface Options >> I2C >> Enable. Reboot, and check the bus:
sudo reboot
# after the reboot
i2cdetect -y 1
You should see a grid with a handful of filled cells (or UU marks).
Hold that thought: the grid is the first entry in the troubleshooting
section, because almost everyone misreads it the first time.
Install
One apt package installs the Python library, the device-tree overlay, and the drivers:
sudo apt update
sudo apt install -y sense-hat
sudo reboot
The reboot matters: the overlay that hands the IMU to the kernel loads at boot. The first time I installed, I skipped the reboot and the orientation readings sat at zero for an hour while I doubted the board. After the Pi comes back, verify:
python3 -c "from sense_hat import SenseHat; print('ok')"
If that prints ok, everything on the board is reachable.
The code
This script reads all four sensors, prints a full readout in the
terminal, draws a humidity bar on the LED matrix, and then turns the
joystick into a control pad: up for temperature, down for humidity,
left for pressure, right for orientation, middle to clear the display.
Save it as sensehat_demo.py and run it with python3 sensehat_demo.py.
# ~/sensehat/sensehat_demo.py
from sense_hat import SenseHat
from time import sleep
sense = SenseHat()
sense.clear()
GREEN = (0, 255, 0)
OFF = (0, 0, 0)
def cpu_temp():
# The Pi's own temperature, used to correct the sensor below.
with open("/sys/class/thermal/thermal_zone0/temp") as f:
return int(f.read()) / 1000
def temp_corrected():
# Astro Pi compensation: the sensor sits over the CPU and picks up
# its heat. The 1.5 factor comes from the Foundation's own guide.
t = sense.get_temperature()
return t - ((cpu_temp() - t) / 1.5)
def draw_bar():
# 8 columns of the matrix as a humidity bar, filling bottom-up.
level = round(sense.get_humidity() / 12.5) # maps 0-100% to 0-8
for x in range(8):
for y in range(8):
color = GREEN if y < level else OFF
sense.set_pixel(x, 7 - y, color)
# One full readout in the terminal first
print(f"Temperature: {temp_corrected():.1f} C (compensated)")
print(f"Humidity: {sense.get_humidity():.1f} %rH")
print(f"Pressure: {sense.get_pressure():.1f} hPa")
o = sense.get_orientation()
print(f"Orientation: pitch {o['pitch']:.1f}, roll {o['roll']:.1f}, "
f"yaw {o['yaw']:.1f}")
draw_bar()
# Joystick control pad. Ctrl-C exits.
while True:
for event in sense.stick.get_events():
if event.action != "pressed":
continue
if event.direction == "up":
sense.show_message(f"{temp_corrected():.1f} C",
scroll_speed=0.06)
elif event.direction == "down":
sense.show_message(f"{sense.get_humidity():.1f} %",
scroll_speed=0.06)
elif event.direction == "left":
sense.show_message(f"{sense.get_pressure():.0f} hPa",
scroll_speed=0.06)
elif event.direction == "right":
o = sense.get_orientation()
sense.show_message(
f"P{o['pitch']:.0f} R{o['roll']:.0f} Y{o['yaw']:.0f}")
elif event.direction == "middle":
sense.clear()
sleep(0.1)
Tilt the board while the script runs and watch the pitch and roll numbers move. Pick the Pi up and put it down on a different edge; the numbers follow. That is the IMU doing its job, and it is the same pattern you would use for a tilt alarm or a level.
What you learned
- You plugged a board in with zero wires and read four sensors, drew on an 8x8 matrix, and used a joystick, all through one Python library.
- The pattern in one sentence: the Sense HAT hides a stack of I2C
devices behind a single
SenseHatobject, so the interesting work is interpreting the readings, not talking to the hardware.
When something breaks
The I2C grid looks wrong: UU, or more addresses than you expected
The Sense HAT is not one I2C device. It is four of them on one board: the LED matrix controller at 0x46, the pressure sensor at 0x5C, the humidity sensor at 0x5F, and the IMU at 0x6A (with its magnetometer at 0x1C). Guides that say “the Sense HAT is at one address” are simplifying, and the confusion costs people real debugging time. Two things that look like failures and are not:
UUat 0x6A: the kernel driver claimed that address when the overlay loaded.UUmeans “in use”, not “broken”.- More addresses than you expected: every cell belongs to the board. If Python can read the sensors, the grid is fine.
If the grid is completely empty (all dashes), that IS a hardware problem: power off, lift the board, reseat it squarely on the header, and power back on. Every dead-looking Sense HAT I have debugged was a half-seated header, in first place, and a flaky SD card, in a distant second.
Temperature reads 8 to 12 C too high
That is the CPU’s heat, and it gets worse the harder the Pi works. The
temp_corrected() function in the code above is the fix, and it is
worth copying into any project that uses this board. The honest version
of the rule: skip the correction for relative questions (e.g. “is the
garage hotter than it was yesterday”), and use the corrected number
when you compare against a real thermometer or log data you will graph
later.
Orientation is garbage, or yaw never settles
Pitch and roll come from the accelerometer, which measures gravity, so they settle within a second. Yaw comes from the magnetometer, which measures the Earth’s magnetic field, and indoors that field is full of lies (speakers, magnets, steel shelf brackets, and the Pi’s own power supply all bend it). If yaw wanders, first delete the calibration file and reboot so it regenerates:
rm ~/.config/RTIMULib.ini
sudo reboot
Then move the Pi away from anything magnetic. If yaw still drifts after that, do what I did: trust pitch and roll, and treat yaw as a rough heading. Calibrating a magnetometer properly is a whole afternoon, and for most projects you do not need it.
ModuleNotFoundError: No module named ‘sense_hat’
The apt package installs into the system Python only. If you are inside
a virtualenv (e.g. one you made for the Flask API tutorial), either
recreate it with --system-site-packages, or run the script with the
system interpreter directly:
/usr/bin/python3 sensehat_demo.py
Check which interpreter you are actually running with
which python3; nine times out of ten the module is installed and the
script is just running under the wrong Python.
What to build next
- Log every reading to SQLite with the SQLite logging tutorial on this site. The Sense HAT slots in as the sensor; the schema and the insert loop do not change at all.
- Graph a week of pressure with the InfluxDB + Grafana tutorial. A pressure graph is the one home-weather trick that genuinely predicts weather changes before your phone app does.
- Serve the live readings as JSON with the Flask API tutorial, and anything on your network can ask the room for its numbers (e.g. a dashboard tablet in the hallway hitting one endpoint).
- The book Home Automation with Raspberry Pi on this site collects the service side of these builds; the Sense HAT is a good first sensor to hang off that stack.
The whole point of this board is that it removes the wiring excuse. Once the readings are flowing, the interesting decisions are all about what to store and what to show, and the tutorials above cover both ends. Send me the rough edges if you try it.