Raspberry Pi

Raspberry Pi Sense HAT y MQTT: publica datos ambientales e IMU y muestra mensajes en la matriz LED

Convierte un Raspberry Pi Sense HAT en un dispositivo MQTT bidireccional: publica lecturas ambientales y de orientación como JSON y haz desfilar por la matriz LED de 8x8 los mensajes enviados desde cualquier cliente MQTT.

Raspberry Pi con un Sense HAT mostrando un mensaje en su matriz LED mientras envía datos de sensores a la nube en un proyecto Raspberry Pi Sense HAT MQTT
Pruébalo en tu propio broker MQTTConsigue un broker MQTT privado y gestionado con el plan Free y empieza con ejemplos de código listos para usar.
Pruébalo gratis Ejemplos de código Sin tarjeta

Un proyecto Raspberry Pi Sense HAT MQTT es una de las formas más rápidas de construir un dispositivo IoT bidireccional de verdad: la placa ya incluye sensores de temperatura, humedad y presión, un acelerómetro, un giroscopio y un magnetómetro, un joystick y una matriz LED RGB de 8x8. En este tutorial publicarás datos ambientales e IMU como JSON en un broker MQTT y harás desfilar por la matriz LED cualquier mensaje enviado a la Pi, todo en un único script de Python.

Qué te ofrece el Sense HAT

Sensor o salida Llamada en Python Unidades
Temperatura sense.get_temperature() grados Celsius
Humedad relativa sense.get_humidity() porcentaje
Presión sense.get_pressure() milibares (hPa)
Orientación sense.get_orientation() pitch, roll, yaw en grados
Aceleración sense.get_accelerometer_raw() x, y, z en g
Joystick sense.stick.get_events() dirección y acción
Matriz LED sense.show_message(), sense.clear() RGB de 8x8

El HAT se conecta directamente al conector de 40 pines de cualquier Pi que lo tenga, incluidas la Pi 4 y la Pi 5. No hace falta cablear nada, lo que lo hace ideal para aulas, demos y prototipos rápidos. La documentación oficial del Sense HAT explica el hardware en profundidad.

Instalación del software

La librería del Sense HAT se distribuye como paquete Debian. Instálala a nivel de sistema y después crea un entorno virtual que pueda verla:

sudo apt update
sudo apt install -y sense-hat python3-venv
mkdir -p ~/sensehat-mqtt && cd ~/sensehat-mqtt
python3 -m venv --system-site-packages .venv
source .venv/bin/activate
pip install "paho-mqtt>=2.0"

Comprueba que se detecta el HAT antes de escribir código MQTT:

python -c "from sense_hat import SenseHat; s = SenseHat(); print(s.get_temperature(), s.get_humidity()); s.show_message('OK')"

Si ves dos números y "OK" desfila por la matriz, el hardware está listo. Si obtienes un error sobre el framebuffer o I2C, confirma que el HAT está bien encajado y que I2C está activado en sudo raspi-config, en Interface Options.

Estructura de topics

Mantén los topics del Sense HAT bajo un prefijo único para que nada choque con otros usuarios del servidor de pruebas compartido:

Topic Dirección Frecuencia Retained
connectmq/demo/5d82be/sensehat/env La Pi publica Cada 10 s No
connectmq/demo/5d82be/sensehat/imu La Pi publica Cada 1 s No
connectmq/demo/5d82be/sensehat/joystick La Pi publica Por evento No
connectmq/demo/5d82be/sensehat/display La Pi se suscribe Bajo demanda No
connectmq/demo/5d82be/sensehat/status La Pi publica y last will Al conectar Sí

Sustituye 5d82be por tu propia cadena aleatoria. El broker público permite 10 mensajes por segundo por cliente, así que un mensaje IMU por segundo más los eventos ambientales y del joystick ocasionales quedan holgadamente por debajo del límite.

El script Raspberry Pi Sense HAT MQTT

El punto de diseño importante es que show_message() bloquea mientras el texto se desplaza. Si la llamas desde el callback MQTT, el bucle de red se detiene y el cliente puede perder keepalives. El script de abajo mete los mensajes entrantes en una cola y deja que un hilo de visualización aparte los muestre, mientras el hilo principal lee los sensores y publica. Guárdalo como sensehat_mqtt.py:

#!/usr/bin/env python3
"""Publish Sense HAT data over MQTT and show incoming messages on the LED matrix."""
import json
import os
import queue
import threading
import time
import uuid

import paho.mqtt.client as mqtt
from sense_hat import SenseHat

BROKER = os.getenv("MQTT_HOST", "broker.connectmq.com")
PORT = int(os.getenv("MQTT_PORT", "1883"))
USERNAME = os.getenv("MQTT_USERNAME")
PASSWORD = os.getenv("MQTT_PASSWORD")
CLIENT_ID = os.getenv("MQTT_CLIENT_ID", f"sensehat-{uuid.uuid4().hex[:8]}")
PREFIX = os.getenv("MQTT_PREFIX", "connectmq/demo/5d82be/sensehat")
ENV_INTERVAL = 10
IMU_INTERVAL = 1
CPU_FACTOR = 2.0  # calibrar con un termómetro de referencia

sense = SenseHat()
sense.set_imu_config(True, True, True)  # brújula, giroscopio, acelerómetro
sense.low_light = True
messages = queue.Queue(maxsize=20)


def cpu_temperature():
    with open("/sys/class/thermal/thermal_zone0/temp") as f:
        return int(f.read()) / 1000.0


def corrected_temperature():
    raw = sense.get_temperature_from_humidity()
    cpu = cpu_temperature()
    # El HAT está encima de la CPU, así que sus sensores marcan de más. Esta
    # heurística sencilla resta parte de la diferencia; ajusta CPU_FACTOR a tu caso.
    return raw - (cpu - raw) / CPU_FACTOR, raw


def display_worker():
    while True:
        text, colour = messages.get()
        try:
            sense.show_message(text, scroll_speed=0.06, text_colour=colour)
        finally:
            sense.clear()


def on_connect(client, userdata, flags, reason_code, properties):
    if reason_code.is_failure:
        print(f"Connection refused: {reason_code}")
        return
    print(f"Connected as {CLIENT_ID}")
    client.publish(f"{PREFIX}/status", "online", qos=1, retain=True)
    client.subscribe(f"{PREFIX}/display", qos=1)


def on_message(client, userdata, msg):
    raw = msg.payload.decode(errors="ignore").strip()
    colour = [255, 255, 255]
    text = raw
    if raw.startswith("{"):
        try:
            data = json.loads(raw)
            text = str(data.get("text", ""))
            colour = data.get("colour", colour)
        except json.JSONDecodeError:
            pass
    text = text[:80]
    if text:
        try:
            messages.put_nowait((text, colour))
        except queue.Full:
            print("Display queue full, dropping message")


client = mqtt.Client(mqtt.CallbackAPIVersion.VERSION2, client_id=CLIENT_ID)
client.on_connect = on_connect
client.on_message = on_message
client.will_set(f"{PREFIX}/status", "offline", qos=1, retain=True)
client.reconnect_delay_set(min_delay=1, max_delay=60)
if USERNAME:
    client.username_pw_set(USERNAME, PASSWORD)
if PORT == 8883:
    client.tls_set()

threading.Thread(target=display_worker, daemon=True).start()
client.connect(BROKER, PORT, keepalive=30)
client.loop_start()

last_env = 0.0
last_imu = 0.0
try:
    while True:
        now = time.time()
        # Consultar la orientación a menudo para que la fusión de sensores sea precisa.
        orientation = sense.get_orientation()

        if now - last_imu >= IMU_INTERVAL:
            accel = sense.get_accelerometer_raw()
            imu = {
                "pitch": round(orientation["pitch"], 1),
                "roll": round(orientation["roll"], 1),
                "yaw": round(orientation["yaw"], 1),
                "ax": round(accel["x"], 3),
                "ay": round(accel["y"], 3),
                "az": round(accel["z"], 3),
                "ts": int(now),
            }
            client.publish(f"{PREFIX}/imu", json.dumps(imu), qos=0)
            last_imu = now

        if now - last_env >= ENV_INTERVAL:
            temp, raw_temp = corrected_temperature()
            env = {
                "temperature": round(temp, 1),
                "temperature_raw": round(raw_temp, 1),
                "humidity": round(sense.get_humidity(), 1),
                "pressure": round(sense.get_pressure(), 1),
                "cpu_temp": round(cpu_temperature(), 1),
                "ts": int(now),
            }
            client.publish(f"{PREFIX}/env", json.dumps(env), qos=1)
            last_env = now

        for event in sense.stick.get_events():
            if event.action == "pressed":
                payload = {"direction": event.direction, "ts": int(event.timestamp)}
                client.publish(f"{PREFIX}/joystick", json.dumps(payload), qos=1)

        time.sleep(0.05)
except KeyboardInterrupt:
    pass
finally:
    client.publish(f"{PREFIX}/status", "offline", qos=1, retain=True).wait_for_publish(2)
    client.loop_stop()
    client.disconnect()
    sense.clear()

Ejecútalo con python sensehat_mqtt.py. El bucle principal consulta la orientación cada 50 ms porque la fusión de sensores del Sense HAT necesita lecturas frecuentes para mantener estables pitch, roll y yaw, pero solo publica una vez por segundo.

Enviar mensajes a la matriz LED

Desde cualquier equipo, suscríbete primero a los datos:

mosquitto_sub -h broker.connectmq.com -p 1883 -i viewer-5d82be \
  -t 'connectmq/demo/5d82be/sensehat/#' -v

Después envía texto plano o un mensaje JSON con un color:

mosquitto_pub -h broker.connectmq.com -p 1883 -i sender-5d82be \
  -t 'connectmq/demo/5d82be/sensehat/display' -m 'Hello from MQTT'

mosquitto_pub -h broker.connectmq.com -p 1883 -i sender-5d82be \
  -t 'connectmq/demo/5d82be/sensehat/display' \
  -m '{"text":"Door open","colour":[255,80,0]}'

El mensaje desfila en blanco o naranja mientras la temperatura y la orientación siguen llegando. Inclina la Pi y observa cómo cambian pitch y roll en la ventana del suscriptor; pulsa el joystick para ver llegar los eventos. El topic de visualización no es retained a propósito; de lo contrario, el último mensaje se repetiría cada vez que la Pi se reconecta.

Lecturas de temperatura fiables

El Sense HAT está justo encima del procesador, así que sus sensores de temperatura marcan varios grados de más, todavía más en una Pi 4 o Pi 5 con carga. El script publica tanto el valor en bruto como una estimación corregida. Para calibrar la corrección:

  1. Coloca un termómetro fiable junto a la Pi y deja que ambos se estabilicen durante 20 minutos.
  2. Compara la referencia con temperature_raw y cpu_temp de los mensajes MQTT.
  3. Ajusta CPU_FACTOR hasta que temperature coincida con la referencia.
  4. Para mayor precisión, conecta el HAT mediante un cable plano de extensión de 40 pines para que quede alejado de la CPU.

Si necesitas una temperatura ambiente precisa en lugar de una demo, una sonda dedicada es la mejor herramienta. Nuestras guías de Raspberry Pi con DHT22 y MQTT y de la sonda 1-Wire DS18B20 muestran cómo publicar sensores externos con el mismo estilo de topics.

Visualizar los datos

Como todo viaja como JSON compacto por MQTT, cualquier suscriptor puede usarlo. Node-RED puede dibujar un indicador en vivo, Telegraf puede escribirlo en InfluxDB y Grafana puede graficar meses de histórico; la guía de Raspberry Pi con Grafana e InfluxDB construye esa pila. Para echar un vistazo rápido sin instalar nada, el cliente MQTT en el navegador y el explorador de topics en vivo del portal de ConnectMQ muestran cada mensaje env e imu en cuanto llega.

De la demo a un broker privado

El servidor MQTT público gratuito es legible por cualquiera, lo que está bien para un saludo en la matriz pero no para un sensor en tu casa o tu aula. ConnectMQ te ofrece un broker privado con credenciales generadas y TLS. Define cuatro variables de entorno y el script se conecta de forma segura:

export MQTT_HOST=broker.connectmq.com
export MQTT_PORT=8883
export MQTT_USERNAME=YOUR_USERNAME
export MQTT_PASSWORD=YOUR_PASSWORD
export MQTT_CLIENT_ID=YOUR_CLIENT_ID
export MQTT_PREFIX=classroom/lab1/sensehat
python sensehat_mqtt.py

Para que el script siga funcionando tras un reinicio, envuélvelo en un servicio systemd como se muestra en el tutorial de MQTT con Raspberry Pi.

Ideas para ampliar el proyecto

Cuando el bucle básico funcione, el Sense HAT se convierte en un banco de pruebas práctico para patrones MQTT que reutilizarás en dispositivos reales:

  1. Alarma de inclinación: haz que un segundo script se suscriba al topic imu y publique un aviso cuando pitch o roll superen un límite, un sustituto sencillo para vigilar una máquina que no debería moverse.
  2. Tablero de estado remoto: publica cadenas de estado cortas desde un pipeline de CI, un flujo de domótica o un chequeo de salud de un servidor en el topic display y usa la matriz como notificador de escritorio.
  3. Joystick como mando a distancia: suscríbete al topic joystick desde Node-RED y asigna cada dirección a una escena, un relé o una página de dashboard.
  4. Alertas por umbral sin código: en un broker privado de ConnectMQ, define en el portal una regla de alerta sobre el valor de humedad del topic env y revisa las alertas disparadas en el registro de alertas.
  5. Varias aulas: da a cada Pi su propio nivel de prefijo, como school/room12/sensehat, y suscríbete con un comodín + para comparar las aulas lado a lado.

Cada idea solo necesita un nuevo suscriptor o un nuevo topic. El script de la Pi sigue igual, que es justo el desacoplamiento que hace agradable trabajar con MQTT.

Solución de problemas

  • OSError: Cannot detect RPi-Sense FB device: no se detecta el HAT; vuelve a encajarlo con la Pi apagada.
  • El yaw deriva o salta: calibra el magnetómetro y mantén la Pi alejada de motores y altavoces; la orientación también necesita consultas frecuentes.
  • Los mensajes desfilan pero los datos de los sensores se detienen: algo bloquea el bucle principal; nunca llames a show_message() desde un callback.
  • La humedad marca 0: el sensor de humedad necesita un momento tras el arranque; descarta la primera lectura.

Empieza con ConnectMQ

Pasa tu Sense HAT del entorno público de pruebas a un broker privado en pocos minutos. Crea un broker Serverless gratuito, sin tarjeta de crédito, y conéctate por TLS con las credenciales generadas. Obtienes un broker MQTT gestionado compatible con MQTT 3.1.1 y 5.0, además de un portal desde el que puedes enviar mensajes a la matriz y ver cada lectura en vivo.

Preguntas frecuentes

¿Por qué la temperatura del Sense HAT es más alta que la de la habitación?

El calor del procesador de la Raspberry Pi calienta el HAT. Usa la corrección basada en la CPU de este tutorial, un cable plano de extensión o un sensor externo para obtener lecturas precisas.

¿Puedo publicar datos del Sense HAT más de una vez por segundo?

Sí, pero respeta los límites de tasa de tu broker; el servidor público de pruebas permite 10 mensajes por segundo por cliente. Para datos de movimiento de alta frecuencia, agrupa varias muestras en un solo mensaje JSON.

¿Funciona el Sense HAT en una Raspberry Pi 5?

Sí, usa el conector estándar de 40 pines y el paquete sense-hat de Raspberry Pi OS. Espera desfases de temperatura mayores porque la Pi 5 se calienta más.

¿Cómo envío texto en color a la matriz LED?

Publica un JSON como {"text":"Hi","colour":[0,255,0]} en el topic de visualización. El script lee el color como una lista RGB y usa blanco por defecto para el texto plano.

Artículos relacionados

Fiabilidad de la Raspberry Pi: cómo usar una Pi 24/7 como gateway IoT

Una guía práctica para mantener un gateway MQTT con Raspberry Pi funcionando durante meses: desgaste del almacenamiento, sistemas de archivos de solo lectura, alimentación, refrigeración, watchdogs de hardware y software y monitorización remota de la salud.

9 min de lectura

Pico W vs Pico 2 W para MQTT: rendimiento, memoria y TLS de RP2040 frente a RP2350

La Pico 2 W mantiene el formato y el chip Wi-Fi de la Pico W, pero sustituye el RP2040 por el RP2350, más rápido. Esta comparativa analiza qué significa para los dispositivos MQTT: CPU, memoria, TLS, funciones de seguridad, soporte de software y qué placa comprar para cada proyecto.

9 min de lectura

Registro de accesos Raspberry Pi RFID MQTT con el lector RC522

Conecta un lector RFID RC522 a una Raspberry Pi, lee etiquetas en Python, compáralas con una lista blanca local y publica cada intento de acceso como un evento MQTT que pueden consumir registradores, dashboards y herramientas de alertas.

8 min de lectura

Todos los artículos →

Tu broker MQTT privado, a unos pocos clics

Crea una cuenta, obtén las credenciales de tu broker y conecta tu primer dispositivo, sin servidores que instalar, parchear ni escalar.