Caso práctico: contador de pulsos con Raspberry Pi

Caso práctico: monitor consumo con Raspberry Pi — hero

Objetivo y caso de uso

Lo que construirás: Un registrador de pulsos de contador de suministros para Raspberry Pi que lee una salida de pulsos segura de bajo voltaje en un pin GPIO, elimina el rebote de cada evento y escribe marcas de tiempo, totales de pulsos y consumo calculado en un archivo CSV local. Está diseñado para pulsos LED de electricidad, interruptores reed de gas o salidas de contacto de agua, con una precisión temporal práctica en el rango de milisegundos y una carga del sistema muy baja, normalmente <5% de CPU y uso de GPU despreciable.

Por qué importa / Casos de uso

  • Hacer seguimiento del consumo eléctrico de una casa o taller a partir de una constante del contador como 1000 pulsos/kWh y estimar la demanda casi en tiempo real a partir del espaciado entre pulsos.
  • Registrar el consumo de gas o agua desde salidas reed/de contacto para informes de uso diario, detección de fugas o comparación entre ocupación y uso de suministros.
  • Crear una configuración simple de monitorización sin conexión y sin dependencia de la nube, usando datos CSV para hojas de cálculo, paneles o importación posterior a Home Assistant/Grafana.
  • Validar cambios de ahorro energético comparando tasas de pulsos antes y después de sustituir electrodomésticos, iluminación o programaciones de bombas.

Resultado esperado

  • Un contador de pulsos fiable que ignora el rebote del interruptor y los falsos disparos, con una latencia de gestión de eventos normalmente inferior a 10 ms para pulsos de contador de baja frecuencia.
  • Un registro CSV que contiene marca de tiempo, conteo de pulsos y unidades convertidas como kWh, m³ o litros según la constante de tu contador.
  • Un prototipo local funcional adecuado para tasas de pulsos muy por debajo de los límites GPIO de Raspberry Pi, sin requisito de FPS y con 0% de dependencia de GPU.
  • Una base reutilizable para añadir alertas, gráficos o resúmenes periódicos una vez verificado el registro básico.

Audiencia: Principiantes de Raspberry Pi, makers y propietarios de viviendas que crean monitorización básica de suministros; Nivel: Básico

Arquitectura/flujo: Salida de pulsos del contador o sensor óptico → entrada GPIO de Raspberry Pi con lógica antirrebote → marcado temporal de eventos de pulso → cálculo de consumo a partir de la constante de pulsos → registro en archivo CSV

Nota educativa de validación

Antes de publicar este caso, el contenido pasó la puerta automática de validación de Prometeo con estado PASS. El validador comprobó los bloques de código, la estructura del artículo, los comandos copiables y la coherencia con el catálogo de dispositivos soportados.

Evidencia de validación publicada

  • Resultado automático: PASS.
  • Estructura parseada: 3 apartados, 2 tablas y 11 bloques de código detectados antes de publicar.
  • Código comprobado: 3 Python/py_compile, 1 bloques de configuración/servicio, 6 Bash/copy-paste checks.
  • Catálogo soportado: el texto se contrastó contra los perfiles de dispositivo validables de Prometeo y los stacks no soportados bloquean la publicación.
  • Hallazgos del informe: sin hallazgos bloqueantes.

Esta validación confirma compatibilidad sintáctica y de herramientas para el material publicado, pero no sustituye la prueba física sobre tu hardware, cableado y entorno exactos.

Nota educativa de seguridad

Este proyecto es un prototipo educativo, no un producto certificado. Antes de alimentar la configuración, verifica el pinout de la revisión exacta de tu placa ULX3S, mantén las señales de E/S del FPGA a 3.3 V, nunca conectes 5 V directamente a los pines de E/S, desconecta la alimentación antes de cambiar el cableado y usa fuentes externas adecuadas para cargas, motores o servos compartiendo tierra solo cuando el cableado lo requiera.


title: Caso práctico: Registrador de pulsos de contador de suministros para Raspberry Pi
slug: practical-case-raspberry-pi
level: Basic


Registrador de pulsos de contador de suministros para Raspberry Pi

Este caso práctico muestra cómo construir un registrador de pulsos de contador de suministros en una Raspberry Pi. El registrador cuenta pulsos desde una salida de contador de suministros como:

  • una salida de pulsos LED de contador eléctrico
  • una salida de pulsos de interruptor reed de contador de gas
  • un contacto de pulsos de contador de agua

El resultado es un registro CSV local con marcas de tiempo, conteos de pulsos y consumo calculado según la constante de tu contador.

Nota de seguridad

Los contadores de suministros pueden estar conectados a equipos de red peligrosos. No abras, modifiques ni inspecciones el interior de una carcasa de contador de suministros. Usa solo una salida de pulsos de bajo voltaje proporcionada por el fabricante, un sensor óptico de pulsos aprobado o una salida reed de contacto seco. Si no estás seguro de que la señal sea de voltaje extrabajo y esté aislada, no la conectes a una Raspberry Pi.

Diagrama de bloques conceptual

Vista de alto nivel: qué entra, qué procesa cada bloque y qué sale del sistema.

Arquitectura funcional

Salida de pulsos del contador o sensor óp…

entrada GPIO de Raspberry Pi con lógica a…

marcado temporal de eventos de pulso

cálculo de consumo a partir de la constan…

registro en archivo CSV

Flujo conceptual de señales y responsabilidades entre bloques del dispositivo.

Ruta de validación

Código fuente

PlatformIO build

Flash

Monitor serie

Resumen conceptual de las herramientas usadas para comprobar el material publicado.

Objetivo y caso de uso

Construir un registrador de pulsos de contador de suministros que:

  1. lea una entrada de pulsos en un pin GPIO de Raspberry Pi
  2. elimine el rebote de la señal
  3. almacene eventos de pulsos en un archivo CSV
  4. calcule el consumo a partir de una constante de pulsos conocida del contador

Ejemplos de constantes de pulsos:

  • contador eléctrico: 1000 pulses/kWh
  • contador de agua: 1 pulse/litre
  • contador de gas: depende del modelo del contador

Hardware

  • Raspberry Pi con cabecera de 40 pines
  • tarjeta microSD con Raspberry Pi OS
  • fuente de pulsos del contador de suministros:
  • interruptor reed de contacto seco, o
  • salida de colector abierto / optoacoplador, o
  • sensor óptico de pulsos con salida aislada
  • cables jumper
  • resistencia externa opcional si tu sensor la requiere

Cableado

Este ejemplo usa GPIO17 como entrada de pulsos y la resistencia pull-up interna de Raspberry Pi. El sensor debe llevar el pin GPIO a GND brevemente por cada pulso.

Pin de Raspberry Pi BCM GPIO Conecta a Notas
Pin 11 GPIO17 Señal de pulsos del contador Entrada de pulsos activa en bajo
Pin 6 GND Tierra / retorno de pulsos del contador Referencia común necesaria para contacto seco
3V3 No se usa en este ejemplo básico de contacto seco No apliques 5 V al GPIO

Cableado de pulsos por contacto seco

Usa esto si el contador de suministros proporciona un interruptor reed o contacto seco:

  • un contacto -> GPIO17
  • otro contacto -> GND

Cuando el contacto se cierra, la entrada pasa a nivel bajo y se cuenta un pulso.

Cableado de pulsos por colector abierto

Usa esto solo si la salida es compatible con 3.3 V y comparte una tierra segura de bajo voltaje:

  • colector/salida -> GPIO17
  • emisor/tierra -> GND

La pull-up interna mantiene la línea en alto cuando está inactiva.

Configuración del software

Actualiza el sistema e instala soporte GPIO para Python.

sudo apt update
sudo apt install -y python3-rpi.gpio
mkdir -p ~/utility-meter-logger
cd ~/utility-meter-logger

Registrador en Python

Crea meter_logger.py:

#!/usr/bin/env python3
import csv
import os
import signal
import sys
import time
from datetime import datetime, timezone

import RPi.GPIO as GPIO

GPIO_PIN = 17
CSV_PATH = os.path.expanduser("~/utility-meter-logger/meter_log.csv")
STATE_PATH = os.path.expanduser("~/utility-meter-logger/state.txt")

# Example: 1000 pulses per kWh for an electricity meter.
# Change this value to match your utility meter.
PULSES_PER_UNIT = 1000.0
UNIT_NAME = "kWh"

# Debounce time in milliseconds. Increase if your contact bounces.
BOUNCE_MS = 50

running = True
pulse_count = 0


def load_state(path: str) -> int:
    if not os.path.exists(path):
        return 0
    with open(path, "r", encoding="utf-8") as f:
        text = f.read().strip()
    if text == "":
        return 0
    return int(text)


def save_state(path: str, count: int) -> None:
    tmp_path = path + ".tmp"
    with open(tmp_path, "w", encoding="utf-8") as f:
        f.write(f"{count}\n")
    os.replace(tmp_path, path)


def ensure_csv_header(path: str) -> None:
    if os.path.exists(path) and os.path.getsize(path) > 0:
        return
    os.makedirs(os.path.dirname(path), exist_ok=True)
    with open(path, "a", newline="", encoding="utf-8") as f:
        writer = csv.writer(f)
        writer.writerow(
            ["timestamp_utc", "pulse_count_total", "delta_pulses", "consumption_total", "unit"]
        )


def append_csv(path: str, count: int, delta: int) -> None:
    consumption = count / PULSES_PER_UNIT
    timestamp = datetime.now(timezone.utc).isoformat()
    with open(path, "a", newline="", encoding="utf-8") as f:
        writer = csv.writer(f)
        writer.writerow([timestamp, count, delta, f"{consumption:.6f}", UNIT_NAME])


def handle_pulse(channel: int) -> None:
    global pulse_count
    pulse_count += 1
    save_state(STATE_PATH, pulse_count)
    append_csv(CSV_PATH, pulse_count, 1)
    print(
        f"{datetime.now(timezone.utc).isoformat()} pulse={pulse_count} "
        f"consumption={pulse_count / PULSES_PER_UNIT:.6f} {UNIT_NAME}",
        flush=True,
    )


def handle_signal(signum, frame) -> None:
    global running
    running = False


def main() -> int:
    global pulse_count

    pulse_count = load_state(STATE_PATH)
    ensure_csv_header(CSV_PATH)

    GPIO.setmode(GPIO.BCM)
    GPIO.setup(GPIO_PIN, GPIO.IN, pull_up_down=GPIO.PUD_UP)

    signal.signal(signal.SIGINT, handle_signal)
    signal.signal(signal.SIGTERM, handle_signal)

    GPIO.add_event_detect(
        GPIO_PIN,
        GPIO.FALLING,
        callback=handle_pulse,
        bouncetime=BOUNCE_MS,
    )

    print(
        f"Utility meter pulse logger started on GPIO{GPIO_PIN}. "
        f"Current total pulses: {pulse_count}",
        flush=True,
    )

    try:
        while running:
            time.sleep(1.0)
    finally:
        GPIO.cleanup()

    return 0


if __name__ == "__main__":
    sys.exit(main())

Hazlo ejecutable:

chmod +x ~/utility-meter-logger/meter_logger.py

Ejecutar el registrador de pulsos del contador de suministros

Inícialo manualmente para una primera prueba:

cd ~/utility-meter-logger
python3 meter_logger.py

Comportamiento esperado:

  • el script imprime un mensaje de inicio
  • cada pulso válido imprime una nueva línea
  • se crea meter_log.csv
  • state.txt almacena el conteo total de pulsos para recuperación tras reinicio

Ejemplo de salida

Algunas líneas de la consola serie pueden verse así:

Utility meter pulse logger started on GPIO17. Current total pulses: 0
2026-06-27T12:00:01.100000+00:00 pulse=1 consumption=0.001000 kWh
2026-06-27T12:00:03.700000+00:00 pulse=2 consumption=0.002000 kWh
2026-06-27T12:00:04.900000+00:00 pulse=3 consumption=0.003000 kWh

Formato CSV

El registrador escribe una fila por cada evento de pulso.

Columna Significado
timestamp_utc Marca de tiempo UTC del pulso
pulse_count_total Conteo total acumulado de pulsos
delta_pulses Pulsos añadidos por este evento, normalmente 1
consumption_total pulse_count_total / PULSES_PER_UNIT
unit Unidad de consumo, por ejemplo kWh o litre

Iniciar automáticamente al arrancar

Crea un archivo de servicio systemd en /etc/systemd/system/utility-meter-logger.service:

[Unit]
Description=Utility Meter Pulse Logger
After=network.target

[Service]
Type=simple
User=pi
WorkingDirectory=/home/pi/utility-meter-logger
ExecStart=/usr/bin/python3 /home/pi/utility-meter-logger/meter_logger.py
Restart=always
RestartSec=2

[Install]
WantedBy=multi-user.target

Habilita e inicia el servicio:

sudo systemctl daemon-reload
sudo systemctl enable utility-meter-logger.service
sudo systemctl start utility-meter-logger.service
sudo systemctl status utility-meter-logger.service --no-pager

Método de validación

Para validar que este registrador de pulsos de contador de suministros funciona correctamente, usa una fuente de pulsos conocida.

Método 1: Prueba manual de contacto seco

  1. Detén el servicio si está en ejecución:
   sudo systemctl stop utility-meter-logger.service
   ```

2. Ejecuta el registrador en una terminal:

```bash
   cd ~/utility-meter-logger
   python3 meter_logger.py
   ```

3. Cortocircuita brevemente `GPIO17` con `GND` exactamente 10 veces usando un pulsador o un cable jumper.
4. Comprueba que se imprimen 10 líneas nuevas y que el conteo total de pulsos aumenta en 10.

Evidencia esperada:

- la salida de consola incrementa una vez por cada cortocircuito
- `tail -n 10 ~/utility-meter-logger/meter_log.csv` muestra 10 filas nuevas
- `cat ~/utility-meter-logger/state.txt` coincide con el conteo total esperado

### Método 2: Comprobación de la constante del contador

Si tu contador eléctrico está etiquetado como `1000 imp/kWh` o `1000 pulses/kWh`, entonces:

- 1000 pulsos registrados deben equivaler a `1.000000 kWh`
- 100 pulsos deben equivaler a `0.100000 kWh`

Evidencia esperada:

- el campo `consumption_total` en el CSV coincide con `pulse_count_total / 1000`

## Solución de problemas

### No se cuentan pulsos

Comprueba:

- que la salida del sensor realmente lleva la línea a GND
- que el número GPIO es correcto: `GPIO17`, no el número de pin físico `17`
- que la salida del contador es segura y de bajo voltaje
- que el tiempo antirrebote no es demasiado corto para un contacto reed

### Conteo doble

Si ves conteos extra desde un interruptor reed, aumenta:


```python
BOUNCE_MS = 100

Luego reinicia el script.

Unidades de consumo incorrectas

Configura correctamente estos valores para tu contador de suministros:

PULSES_PER_UNIT = 1000.0
UNIT_NAME = "kWh"

Ejemplos:

  • contador de agua con 1 pulse/litre:
  • PULSES_PER_UNIT = 1.0
  • UNIT_NAME = "litre"
  • contador eléctrico con 1000 pulses/kWh:
  • PULSES_PER_UNIT = 1000.0
  • UNIT_NAME = "kWh"

Resultado

Ahora tienes un registrador de pulsos de contador de suministros para Raspberry Pi que registra eventos de pulso, conserva el conteo total entre reinicios y almacena datos de consumo con marca de tiempo en formato CSV.

Encuentra este producto y/o libros sobre este tema en Amazon

Ir a Amazon

Como afiliado de Amazon, gano con las compras que cumplan los requisitos. Si compras a través de este enlace, ayudas a mantener este proyecto.

Quiz rápido

Pregunta 1: ¿Cuál es el objetivo principal del sistema descrito en el artículo?




Pregunta 2: ¿Qué dispositivo se utiliza como base para construir el registrador de pulsos?




Pregunta 3: ¿Qué tipo de señal lee el sistema en un pin GPIO?




Pregunta 4: ¿Qué problema intenta evitar el sistema en cada evento de pulso?




Pregunta 5: ¿En qué formato se almacenan localmente los datos registrados?




Pregunta 6: ¿Qué constante de contador se menciona como ejemplo para seguir el consumo eléctrico?




Pregunta 7: Además de electricidad, ¿qué otros suministros puede registrar este sistema?




Pregunta 8: ¿Qué datos escribe el sistema en el archivo CSV?




Pregunta 9: ¿Qué ventaja tiene esta configuración respecto a la conectividad?




Pregunta 10: ¿Qué carga del sistema se indica normalmente para esta solución?




Carlos Núñez Zorrilla
Carlos Núñez Zorrilla
Electronics & Computer Engineer

Ingeniero Superior en Electrónica de Telecomunicaciones e Ingeniero en Informática (titulaciones oficiales en España).

Sígueme:


Caso práctico: aviso de buzón con Raspberry Pi

Caso práctico: monitor de buzón Raspberry Pi — hero

Objetivo y caso de uso

Lo que construirás: Un monitor de buzón con Raspberry Pi que detecta cuando la puerta se abre con un interruptor magnético de láminas, elimina el rebote de la señal, registra el evento con una marca de tiempo y envía una alerta al teléfono mediante ntfy.sh. Es un proyecto ligero de automatización GPIO con notificación casi instantánea, normalmente por debajo de 1 segundo en una conexión Wi‑Fi estable.

Por qué importa / Casos de uso

  • Recibe una alerta en tiempo real cuando se entrega el correo en lugar de revisar el buzón manualmente.
  • Reduce activaciones falsas eliminando el rebote de la entrada del interruptor, útil para gabinetes exteriores con viento o puertas metálicas que vibran.
  • Crea un sensor de automatización del hogar de bajo consumo con carga de cómputo mínima, a menudo por debajo del 2% de CPU y uso de GPU despreciable en una Raspberry Pi.
  • Mantén un historial local de eventos para verificar horas de entrega, por ejemplo registrando eventos de apertura del buzón a las 10:14:32 para paquetes o cartas.
  • Usa el mismo patrón para alertas de apertura de portones, notificaciones de acceso a cobertizos o monitoreo de puertas de armarios.

Resultado esperado

  • Un circuito funcional con interruptor de láminas conectado de forma segura al GPIO de Raspberry Pi con una resistencia pull-up o pull-down.
  • Detección confiable de eventos de apertura con un tiempo de eliminación de rebote que filtra rebotes breves de contacto en milisegundos.
  • Alertas de tipo push enviadas a tu teléfono mediante ntfy.sh con una latencia típica de extremo a extremo de aproximadamente 0.5–2 segundos, según la calidad de la red.
  • Inicio automático al arrancar usando systemd para que el monitoreo se reanude tras un corte de energía o reinicio.
  • Registros locales con marca de tiempo que puedes revisar para resolución de problemas, seguimiento de entregas o comprobación de notificaciones perdidas.

Público: Principiantes de Raspberry Pi, aficionados al DIY de automatización del hogar y estudiantes que aprenden manejo de entradas GPIO; Nivel: Básico

Arquitectura/flujo: El interruptor de láminas cambia el estado GPIO cuando se abre la puerta del buzón → el script de Raspberry Pi lee la entrada y elimina el rebote → el evento se registra localmente → se envía una notificación HTTP a ntfy.sh → el teléfono recibe la alerta.

Nota educativa de validación

Antes de publicar este caso, el contenido pasó la puerta automática de validación de Prometeo con estado PASS. El validador comprobó los bloques de código, la estructura del artículo, los comandos copiables y la coherencia con el catálogo de dispositivos soportados.

Evidencia de validación publicada

  • Resultado automático: PASS.
  • Estructura parseada: 3 apartados, 3 tablas y 14 bloques de código detectados antes de publicar.
  • Código comprobado: 1 Python/py_compile, 1 bloques de configuración/servicio, 10 Bash/copy-paste checks.
  • Catálogo soportado: el texto se contrastó contra los perfiles de dispositivo validables de Prometeo y los stacks no soportados bloquean la publicación.
  • Hallazgos del informe: sin hallazgos bloqueantes.

Esta validación confirma compatibilidad sintáctica y de herramientas para el material publicado, pero no sustituye la prueba física sobre tu hardware, cableado y entorno exactos.

Nota educativa de seguridad

Este proyecto es un prototipo educativo, no un producto certificado. Antes de energizar la instalación, verifica el pinout de la revisión exacta de tu placa ULX3S, mantén las señales de E/S de la FPGA a 3.3 V, nunca conectes 5 V directamente a los pines de E/S, desconecta la alimentación antes de cambiar el cableado y usa fuentes de alimentación externas adecuadas para cargas, motores o servos, compartiendo tierra solo cuando el cableado lo requiera.


title: Alerta inteligente de apertura de buzón con Raspberry Pi
level: Básico
slug: practical-case-raspberry-pi


Alerta inteligente de apertura de buzón con Raspberry Pi

Este proyecto práctico con Raspberry Pi construye una alerta inteligente de apertura de buzón.
Un interruptor magnético de láminas detecta cuándo se abre la puerta del buzón, y la Raspberry Pi envía una alerta a tu teléfono usando ntfy.sh.

Diagrama de bloques conceptual

Vista de alto nivel: qué entra, qué procesa cada bloque y qué sale del sistema.

Arquitectura funcional

El interruptor de láminas cambia el estad…

el script de Raspberry Pi lee la entrada…

el evento se registra localmente

se envía una notificación HTTP a ntfy.sh

el teléfono recibe la alerta

Flujo conceptual de señales y responsabilidades entre bloques del dispositivo.

Ruta de validación

Código fuente

PlatformIO build

Flash

Monitor serie

Resumen conceptual de las herramientas usadas para comprobar el material publicado.

Qué hace este proyecto

  • Detecta el estado de la puerta del buzón con un interruptor de láminas
  • Elimina el rebote de la entrada para reducir activaciones falsas
  • Envía una alerta de red tipo push cuando se abre el buzón
  • Registra localmente cada evento de apertura con una marca de tiempo
  • Se ejecuta automáticamente al arrancar con systemd

Nota de seguridad
Este proyecto es solo para GPIO de bajo voltaje. No conectes los pines GPIO de la Raspberry Pi directamente a tensión de red, timbres alimentados, cerraduras eléctricas ni cableado desconocido dentro de un buzón metálico. Si el buzón está en exteriores, protege la Pi y el cableado de la humedad y usa alivio de tensión adecuado.

Componentes

  • Raspberry Pi con acceso a red
  • Tarjeta microSD con Raspberry Pi OS
  • 1 interruptor magnético de láminas, normalmente abierto
  • 1 resistencia de 10 kOhm
  • Cables jumper
  • Protoboard o placa prototipo soldada

Cableado

El interruptor de láminas se usa como sensor de contacto. Cuando se abre la puerta del buzón, el interruptor cambia de estado y la Raspberry Pi puede activar la alerta inteligente de apertura del buzón.

Tabla de pines

Función Pin del componente Pin de Raspberry Pi
Fuente pull-up de 3.3 V extremo 1 de la resistencia de 10 kOhm 3.3 V, pin físico 1
Nodo de señal extremo 2 de la resistencia de 10 kOhm + extremo 1 del interruptor de láminas GPIO17, pin físico 11
Ruta a tierra extremo 2 del interruptor de láminas GND, pin físico 6

Lógica

Estado del buzón Interruptor de láminas Estado de GPIO17
Cerrado, imán cerca del interruptor Contacto cerrado LOW
Abierto, imán lejos del interruptor Contacto abierto HIGH

Este cableado usa una resistencia pull-up externa a 3.3 V. El GPIO lee:

  • 0 cuando el buzón está cerrado
  • 1 cuando el buzón está abierto

Configuración del sistema

Actualiza el sistema e instala los paquetes necesarios:

sudo apt update
sudo apt install -y python3 python3-gpiozero python3-requests

Crea un directorio de proyecto:

mkdir -p /home/pi/mailbox-alert

Aplicación en Python

Guarda este archivo como /home/pi/mailbox-alert/mailbox_alert.py.

#!/usr/bin/env python3
from gpiozero import Button
from signal import pause
from datetime import datetime
import os
import socket
import requests

PIN = 17
LOG_FILE = "/home/pi/mailbox-alert/mailbox_events.log"
HOSTNAME = socket.gethostname()
TOPIC = f"{HOSTNAME}-smart-mailbox-open-alert"
NTFY_URL = f"https://ntfy.sh/{TOPIC}"

sensor = Button(PIN, pull_up=False, bounce_time=0.2)

def write_log(message: str) -> None:
    timestamp = datetime.now().isoformat(timespec="seconds")
    line = f"{timestamp} {message}\n"
    with open(LOG_FILE, "a", encoding="utf-8") as log_file:
        log_file.write(line)

def send_alert() -> None:
    now = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
    title = "Mailbox opened"
    body = f"Smart mailbox open alert from {HOSTNAME} at {now}"
    headers = {
        "Title": title,
        "Priority": "default",
        "Tags": "mailbox,postbox,package"
    }

    try:
        response = requests.post(
            NTFY_URL,
            data=body.encode("utf-8"),
            headers=headers,
            timeout=10
        )
        response.raise_for_status()
        write_log(f"ALERT_SENT topic={TOPIC} status={response.status_code}")
    except requests.RequestException as exc:
        write_log(f"ALERT_FAILED error={exc}")

def on_open() -> None:
    write_log("MAILBOX_OPEN")
    send_alert()

def main() -> None:
    write_log(f"START topic={TOPIC} pin={PIN}")
    sensor.when_pressed = on_open
    pause()

if __name__ == "__main__":
    os.makedirs("/home/pi/mailbox-alert", exist_ok=True)
    main()

Hazlo ejecutable:

chmod +x /home/pi/mailbox-alert/mailbox_alert.py

Prueba manualmente la alerta inteligente de apertura de buzón

Ejecuta la aplicación en una terminal:

python3 /home/pi/mailbox-alert/mailbox_alert.py

Luego abre la puerta del buzón. Deberías ver un nuevo evento en el archivo de registro:

tail -f /home/pi/mailbox-alert/mailbox_events.log

Suscríbete en tu teléfono u otro dispositivo a:

https://ntfy.sh/<your-hostname>-smart-mailbox-open-alert

Por ejemplo, si el hostname de tu Raspberry Pi es raspberrypi, el tema es:

https://ntfy.sh/raspberrypi-smart-mailbox-open-alert

Puedes comprobar tu hostname con:

hostname

Ejecutar al arranque con systemd

Crea /etc/systemd/system/mailbox-alert.service:

[Unit]
Description=Smart Mailbox Open Alert
After=network-online.target
Wants=network-online.target

[Service]
Type=simple
User=pi
WorkingDirectory=/home/pi/mailbox-alert
ExecStart=/usr/bin/python3 /home/pi/mailbox-alert/mailbox_alert.py
Restart=on-failure
RestartSec=5

[Install]
WantedBy=multi-user.target

Habilita e inicia el servicio:

sudo systemctl daemon-reload
sudo systemctl enable mailbox-alert.service
sudo systemctl start mailbox-alert.service
sudo systemctl status mailbox-alert.service --no-pager

Método de validación

Para validar que esta alerta inteligente de apertura de buzón funciona correctamente:

  1. Inicia el servicio.
  2. Cierra el buzón para que el imán quede cerca del interruptor de láminas.
  3. Abre el buzón una vez.
  4. Confirma:
  5. que aparece una entrada MAILBOX_OPEN en el registro local
  6. que aparece una entrada ALERT_SENT en el registro local
  7. que llega una notificación al tema ntfy.sh suscrito
  8. Repite 10 ciclos de apertura/cierre.

Evidencia esperada

Comprobación Resultado esperado
Detección GPIO Un disparo cuando se abre la puerta
Registro local Líneas MAILBOX_OPEN y ALERT_SENT con marca de tiempo
Alerta de red Una notificación por cada evento de apertura
Repetibilidad Comportamiento consistente en ciclos repetidos de apertura/cierre

Solución de problemas

No llega ninguna alerta

Comprueba que la Pi tenga acceso a internet:

ping -c 3 ntfy.sh

Comprueba los registros del servicio:

journalctl -u mailbox-alert.service --no-pager -n 50

Activaciones falsas

  • Aumenta bounce_time de 0.2 a 0.5
  • Monta el imán y el interruptor de láminas de forma más segura
  • Mantén los cables del sensor cortos o trenzados para reducir el ruido

La entrada nunca cambia

Verifica el estado del GPIO con:

python3 -c "from gpiozero import Button; from time import sleep; s=Button(17, pull_up=False); print(s.is_pressed); sleep(1)"

Resultado

Ahora tienes una alerta inteligente de apertura de buzón construida sobre una Raspberry Pi.
Cuando se abre la puerta del buzón, el interruptor de láminas cambia de estado, la Pi detecta el evento y se envía una alerta automáticamente.

Encuentra este producto y/o libros sobre este tema en Amazon

Ir a Amazon

Como afiliado de Amazon, gano con las compras que cumplan los requisitos. Si compras a través de este enlace, ayudas a mantener este proyecto.

Quiz rápido

Pregunta 1: ¿Qué evento detecta el monitor de buzón con Raspberry Pi descrito en el artículo?




Pregunta 2: ¿Para qué sirve la eliminación de rebote en este proyecto?




Pregunta 3: ¿Qué servicio se utiliza para enviar alertas al teléfono?




Pregunta 4: Según el artículo, ¿cómo suele ser la velocidad de las notificaciones en una conexión Wi‑Fi estable?




Pregunta 5: ¿Qué tipo de conexión se menciona como condición para notificaciones normalmente por debajo de 1 segundo?




Pregunta 6: ¿Qué componente se usa para detectar la apertura de la puerta del buzón?




Pregunta 7: ¿Qué información guarda el historial local de eventos?




Pregunta 8: ¿Qué consumo de CPU se indica como habitual para este sensor de automatización del hogar?




Pregunta 9: ¿Qué uso de GPU se menciona para este proyecto en una Raspberry Pi?




Pregunta 10: Además del buzón, ¿para cuál de estos casos puede reutilizarse el mismo patrón?




Carlos Núñez Zorrilla
Carlos Núñez Zorrilla
Electronics & Computer Engineer

Ingeniero Superior en Electrónica de Telecomunicaciones e Ingeniero en Informática (titulaciones oficiales en España).

Sígueme:


Caso práctico: monitor de fuente de laboratorio con Raspberry Pi

Caso práctico: lab power supply current monitor con — hero

Objetivo y caso de uso

Qué construirás: Un monitor de fuente de alimentación de laboratorio basado en Raspberry Pi que lee corriente, voltaje de bus y potencia desde un INA219 por I2C e imprime un flujo en vivo casi en tiempo real. También puedes registrar muestras en CSV para analizar después picos de carga, consumo en reposo y estabilidad de potencia.

Por qué importa / Casos de uso

  • Verificar cuánta corriente consume realmente una placa prototipo; por ejemplo, confirmar que un nodo sensor se mantiene cerca de 120–180 mA en lugar de superar un presupuesto de 250 mA.
  • Capturar eventos de arranque y transitorios mediante muestreo repetido por I2C, como cuando un motor o una ráfaga de radio empujan brevemente la corriente de 80 mA a 600 mA.
  • Estimar el consumo de potencia directamente a partir del voltaje y la corriente, útil para comprobar si una línea de 5 V está entregando alrededor de 2.5 W bajo carga.
  • Registrar lecturas en CSV para resolución de problemas, comparaciones entre versiones de firmware o documentación de pruebas de banco con latencia inferior a un segundo y carga muy baja de CPU/GPU en la Raspberry Pi.

Resultado esperado

  • Un script funcional de Raspberry Pi que lee mediciones del INA219 por I2C con una latencia de actualización típica de alrededor de 100–500 ms, según la configuración de muestreo y promediado.
  • Salida en consola en vivo que muestra corriente, voltaje y potencia; por ejemplo, 5.08 V, 0.42 A y 2.13 W.
  • Registros CSV opcionales que puedes abrir en una hoja de cálculo o graficar para analizar tendencias, picos y consumo en estado estable.
  • Funcionamiento ligero en la Pi: sin canalización de video, relevancia de 0 FPS y, normalmente, uso de GPU despreciable (~0% GPU) con baja sobrecarga general del sistema.

Audiencia: Makers, estudiantes y usuarios de laboratorio que monitorean proyectos DC de bajo voltaje; Nivel: Básico

Arquitectura/flujo: La salida de la fuente de alimentación de laboratorio pasa a través del shunt del INA219 hacia la carga; el INA219 mide la corriente del shunt y el voltaje de bus, la Raspberry Pi consulta el sensor por I2C, imprime valores en vivo y, opcionalmente, escribe filas con marca de tiempo en un archivo CSV.

Nota educativa de validación

Antes de publicar este caso, el contenido pasó la puerta automática de validación de Prometeo con estado PASS. El validador comprobó los bloques de código, la estructura del artículo, los comandos copiables y la coherencia con el catálogo de dispositivos soportados.

Evidencia de validación publicada

  • Resultado automático: PASS.
  • Estructura parseada: 3 apartados, 5 tablas y 9 bloques de código detectados antes de publicar.
  • Código comprobado: 2 Python/py_compile, 6 Bash/copy-paste checks.
  • Catálogo soportado: el texto se contrastó contra los perfiles de dispositivo validables de Prometeo y los stacks no soportados bloquean la publicación.
  • Hallazgos del informe: sin hallazgos bloqueantes.

Esta validación confirma compatibilidad sintáctica y de herramientas para el material publicado, pero no sustituye la prueba física sobre tu hardware, cableado y entorno exactos.

Nota educativa de seguridad

Este proyecto es un prototipo educativo, no un producto certificado. Antes de alimentar el montaje, verifica el pinout de la revisión exacta de tu placa ULX3S, mantén las señales de E/S de la FPGA a 3.3 V, nunca conectes 5 V directamente a los pines de E/S, desconecta la alimentación antes de cambiar el cableado y usa fuentes externas adecuadas para cargas, motores o servos, compartiendo tierra solo cuando el cableado lo requiera.


title: «Caso práctico: Monitor de corriente de fuente de alimentación de laboratorio con Raspberry Pi»
slug: «practical-case-raspberry-pi»
level: «Basic»
device: «Raspberry Pi»
objective: «Construir un monitor de corriente de fuente de alimentación de laboratorio con Raspberry Pi»


Monitor de corriente de fuente de alimentación de laboratorio con Raspberry Pi

Este caso práctico muestra cómo construir un monitor de corriente de fuente de alimentación de laboratorio con una Raspberry Pi y un sensor de corriente/potencia INA219. La Raspberry Pi lee corriente, voltaje de bus y potencia del sensor por I2C e imprime un flujo en vivo que también puede registrarse en un archivo CSV.

Nota de seguridad

Una fuente de alimentación de laboratorio puede entregar suficiente corriente como para sobrecalentar cables, dañar placas o provocar un incendio si se cablea mal. Apaga la fuente antes de cablear. Verifica la polaridad con un multímetro. Mantente dentro de las especificaciones del shunt y de voltaje del módulo INA219. Nunca conectes tensión de red directamente a una Raspberry Pi o a un breakout INA219.

Objetivo y caso de uso

Construir un monitor de corriente de fuente de alimentación de laboratorio que:

  • mida la corriente de alimentación
  • mida el voltaje de alimentación
  • estime la potencia
  • funcione en una Raspberry Pi
  • registre lecturas para análisis posterior

Lista de materiales

Elemento Cant. Notas
Raspberry Pi 3/4/5 o Pi Zero 2 W 1 Con Raspberry Pi OS
Módulo sensor de corriente I2C INA219 1 Breakout común compatible con 3.3 V
Fuente de alimentación de laboratorio 1 Fuente de banco DC de bajo voltaje
Carga bajo prueba 1 Ejemplo: carga resistiva, motor pequeño o placa de desarrollo
Cables jumper Varios Hembra-hembra o mixtos según sea necesario
Tarjeta MicroSD 1 Con Raspberry Pi OS instalado

Cómo funciona el monitor

El INA219 mide la caída de voltaje a través de su resistencia shunt integrada e informa:

  • Corriente en amperios
  • Voltaje de bus en voltios
  • Potencia en vatios

El monitor de corriente debe insertarse en serie con la salida positiva de la fuente de alimentación de laboratorio:

Fuente + -> INA219 VIN+ -> INA219 VIN- -> Carga +

La tierra de la carga vuelve directamente a la tierra de la fuente de alimentación. La Raspberry Pi se comunica con el INA219 solo mediante I2C.

Cableado

Raspberry Pi a INA219

Pin de Raspberry Pi Pin físico de la Pi Pin INA219
3.3V 1 VCC
GND 6 GND
GPIO 2 / SDA1 3 SDA
GPIO 3 / SCL1 5 SCL

Trayecto de potencia a través del sensor

Conexión Conectar a
Positivo (+) de la fuente de alimentación de laboratorio INA219 VIN+
INA219 VIN- Positivo (+) de la carga
Negativo (-) de la carga Negativo (-) de la fuente de alimentación de laboratorio

Habilitar I2C en Raspberry Pi

Ejecuta:

sudo raspi-config nonint do_i2c 0
sudo apt-get update
sudo apt-get install -y i2c-tools python3-pip

Reinicia:

sudo reboot

Después del reinicio, confirma que el sensor aparece en el bus I2C. El INA219 normalmente responde en 0x40:

i2cdetect -y 1

Evidencia esperada:

  • una tabla con 40 visible en la salida del escaneo
  • sin errores de cableado ni conflictos de dirección

Instalar la biblioteca de Python

Usa un controlador CircuitPython INA219 mantenido:

python3 -m pip install --user adafruit-circuitpython-ina219

Monitor de corriente en Python

Guarda esto como current_monitor.py:

#!/usr/bin/env python3
import csv
import sys
import time
from datetime import datetime

import board
import busio
from adafruit_ina219 import ADCResolution, BusVoltageRange, Gain, INA219


def create_sensor():
    i2c = busio.I2C(board.SCL, board.SDA)
    sensor = INA219(i2c)

    # Conservative configuration suitable for many low-voltage bench setups.
    sensor.bus_adc_resolution = ADCResolution.ADCRES_12BIT_32S
    sensor.shunt_adc_resolution = ADCResolution.ADCRES_12BIT_32S
    sensor.bus_voltage_range = BusVoltageRange.RANGE_16V
    sensor.gain = Gain.DIV_8_320MV
    return sensor


def open_csv(path):
    file_obj = open(path, "a", newline="", encoding="utf-8")
    writer = csv.writer(file_obj)
    if file_obj.tell() == 0:
        writer.writerow(
            ["timestamp", "bus_voltage_V", "shunt_voltage_mV", "current_A", "power_W"]
        )
        file_obj.flush()
    return file_obj, writer


def main():
    csv_path = sys.argv[1] if len(sys.argv) > 1 else "current_log.csv"
    interval_s = float(sys.argv[2]) if len(sys.argv) > 2 else 1.0

    sensor = create_sensor()
    csv_file, writer = open_csv(csv_path)

    print("Raspberry Pi lab power supply current monitor")
    print(f"Logging to: {csv_path}")
    print("Press Ctrl+C to stop.")
    print("timestamp,bus_voltage_V,shunt_voltage_mV,current_A,power_W")

    try:
        while True:
            timestamp = datetime.now().isoformat(timespec="seconds")
            bus_voltage = sensor.bus_voltage
            shunt_voltage_mv = sensor.shunt_voltage / 1000.0
            current_a = sensor.current / 1000.0
            power_w = sensor.power / 1000.0

            row = [
                timestamp,
                f"{bus_voltage:.3f}",
                f"{shunt_voltage_mv:.3f}",
                f"{current_a:.6f}",
                f"{power_w:.6f}",
            ]
            print(",".join(row))
            writer.writerow(row)
            csv_file.flush()
            time.sleep(interval_s)
    except KeyboardInterrupt:
        print("\nStopped.")
    finally:
        csv_file.close()


if __name__ == "__main__":
    main()

Hazlo ejecutable y ejecútalo:

chmod +x current_monitor.py
python3 current_monitor.py current_log.csv 1.0

Salida de ejemplo

Raspberry Pi lab power supply current monitor
Logging to: current_log.csv
Press Ctrl+C to stop.
timestamp,bus_voltage_V,shunt_voltage_mV,current_A,power_W
2026-06-27T10:15:01,5.018,12.400,0.124000,0.622000
2026-06-27T10:15:02,5.017,12.300,0.123000,0.617000
2026-06-27T10:15:03,5.018,12.500,0.125000,0.627000

Visualización opcional en terminal en vivo

Si quieres una lectura más clara en la terminal, guarda esto como live_display.py:

#!/usr/bin/env python3
import time

import board
import busio
from adafruit_ina219 import ADCResolution, BusVoltageRange, Gain, INA219


def main():
    i2c = busio.I2C(board.SCL, board.SDA)
    sensor = INA219(i2c)
    sensor.bus_adc_resolution = ADCResolution.ADCRES_12BIT_32S
    sensor.shunt_adc_resolution = ADCResolution.ADCRES_12BIT_32S
    sensor.bus_voltage_range = BusVoltageRange.RANGE_16V
    sensor.gain = Gain.DIV_8_320MV

    print("Live lab power supply current monitor. Press Ctrl+C to stop.")
    try:
        while True:
            bus_v = sensor.bus_voltage
            current_a = sensor.current / 1000.0
            power_w = sensor.power / 1000.0
            print(
                f"Voltage: {bus_v:6.3f} V | Current: {current_a:7.4f} A | Power: {power_w:7.4f} W",
                end="\r",
                flush=True,
            )
            time.sleep(0.5)
    except KeyboardInterrupt:
        print("\nStopped.")


if __name__ == "__main__":
    main()

Ejecútalo:

python3 live_display.py

Método de validación

Para respaldar las afirmaciones de precisión de la medición, valida el monitor de corriente frente a una referencia conocida.

Método

  1. Ajusta la fuente de alimentación de laboratorio a un voltaje DC seguro, como 5 V.
  2. Conecta una carga estable, por ejemplo una resistencia de potencia.
  3. Inserta un multímetro calibrado en serie con la carga.
  4. Inicia el monitor de corriente de la Raspberry Pi.
  5. Registra:
  6. lectura de corriente del INA219
  7. lectura de corriente del multímetro
  8. voltaje de alimentación
  9. Compara en varios niveles de carga.

Evidencia esperada

Punto de prueba Voltaje de alimentación Corriente del multímetro Monitor de corriente de Raspberry Pi Evidencia a guardar
Carga ligera alrededor de 5 V valor medido valor similar Foto o fila CSV
Carga media alrededor de 5 V valor medido valor similar Foto o fila CSV
Carga mayor dentro del límite del sensor alrededor de 5 V valor medido valor similar Foto o fila CSV

Un resultado razonable es que el monitor de Raspberry Pi siga de cerca al multímetro en todos los puntos de prueba. El error exacto permitido depende del módulo INA219, la tolerancia del shunt, el cableado y la calibración del medidor.

Resolución de problemas

Síntoma Causa probable Solución
i2cdetect no muestra 0x40 I2C deshabilitado o cableado incorrecto Vuelve a habilitar I2C y revisa SDA/SCL
La corriente permanece cerca de cero El sensor no está en serie con la carga Recablea: fuente + -> VIN+ -> VIN- -> carga +
Lecturas negativas o extrañas VIN+ y VIN- invertidos Intercambia los cables de potencia del lado alto
El script no logra importar el controlador Paquete de Python no instalado Vuelve a ejecutar python3 -m pip install --user adafruit-circuitpython-ina219
El voltaje se lee pero la corriente es incorrecta Fuera de rango o shunt/módulo inadecuado Mantente dentro de los límites del módulo y verifica el tipo de breakout

Resultado

Ahora tienes un monitor de corriente de fuente de alimentación de laboratorio con Raspberry Pi funcional que mide corriente de alimentación, voltaje y potencia, y registra lecturas en CSV para análisis posterior. Esta configuración es útil para pruebas de banco de dispositivos embebidos, verificar consumo de corriente en reposo y en pico, y documentar el consumo de potencia durante experimentos.

Encuentra este producto y/o libros sobre este tema en Amazon

Ir a Amazon

Como afiliado de Amazon, gano con las compras que cumplan los requisitos. Si compras a través de este enlace, ayudas a mantener este proyecto.

Quiz rápido

Pregunta 1: ¿Qué componente se usa en la Raspberry Pi para leer corriente, voltaje de bus y potencia?




Pregunta 2: ¿Cuál es uno de los objetivos principales del monitor descrito?




Pregunta 3: ¿Para qué sirve registrar muestras en CSV según el artículo?




Pregunta 4: ¿Qué rango de corriente se menciona como deseable para un nodo sensor de ejemplo?




Pregunta 5: ¿Qué evento transitorio se pone como ejemplo de aumento breve de corriente?




Pregunta 6: Si una línea de 5 V entrega alrededor de 2.5 W bajo carga, ¿qué se está estimando directamente?




Pregunta 7: ¿Qué interfaz de comunicación se utiliza para el sensor INA219?




Pregunta 8: ¿Qué magnitudes lee el monitor desde el INA219?




Pregunta 9: ¿Qué ventaja de rendimiento se destaca para la Raspberry Pi al usar este monitor?




Pregunta 10: ¿Para qué pueden servir los registros CSV además de la resolución de problemas?




Carlos Núñez Zorrilla
Carlos Núñez Zorrilla
Electronics & Computer Engineer

Ingeniero Superior en Electrónica de Telecomunicaciones e Ingeniero en Informática (titulaciones oficiales en España).

Sígueme:


Caso práctico: extractor por CO2 con Raspberry Pi

Caso práctico: co2 ventilation relay controlador con — hero

Objetivo y caso de uso

Lo que construirás: Un controlador con Raspberry Pi que lee la concentración de CO2 desde un sensor UART MH-Z19B y conmuta un relé para iniciar o detener un ventilador de ventilación según umbrales de ppm configurables. En una configuración típica, la Pi consulta el sensor cada 1–2 segundos, acciona el relé con un tiempo de respuesta GPIO inferior a 100 ms y usa recursos de cómputo insignificantes (<5% CPU, 0% GPU).

Por qué importa / Casos de uso

  • Automatizar el control de la calidad del aire en una oficina en casa, aula, taller o sala de reuniones cuando el CO2 supera niveles como 1000–1200 ppm.
  • Reducir el tiempo de funcionamiento innecesario del ventilador apagando la ventilación cuando el CO2 cae por debajo de un umbral inferior, por ejemplo 800 ppm, para evitar el traqueteo del relé y ahorrar energía.
  • Aprender de forma práctica la interacción de Raspberry Pi con sensores UART, el control de relés por GPIO, la lógica de umbrales y la automatización ambiental básica.
  • Crear una base para ampliaciones como registrar tendencias de ppm, añadir alertas o publicar datos en un panel.

Resultado esperado

  • Lecturas estables de CO2 desde el MH-Z19B por UART, normalmente actualizadas cada 1–2 segundos.
  • Conmutación fiable del relé cuando el CO2 cruza los umbrales definidos, con una latencia de activación GPIO normalmente inferior a 100 ms después de procesar una nueva lectura.
  • Un bucle de control simple basado en histéresis, por ejemplo relé ENCENDIDO por encima de 1000 ppm y APAGADO por debajo de 800 ppm, para evitar conmutaciones rápidas.
  • Un servicio ligero siempre activo adecuado para Raspberry Pi, que normalmente consume una carga mínima del sistema (<5% CPU, 0% GPU, sin requisito de FPS).

Público: principiantes de Raspberry Pi, makers y estudiantes que construyen automatización ambiental; Nivel: Básico

Arquitectura/flujo: Sensor de CO2 MH-Z19B → lectura UART en Raspberry Pi → lógica de umbral/histéresis → salida GPIO → módulo de relé aislado → ventilador de ventilación o carga de prueba de bajo voltaje

Nota educativa de validación

Antes de publicar este caso, el contenido pasó la puerta automática de validación de Prometeo con estado PASS. El validador comprobó los bloques de código, la estructura del artículo, los comandos copiables y la coherencia con el catálogo de dispositivos soportados.

Evidencia de validación publicada

  • Resultado automático: PASS.
  • Estructura parseada: 3 apartados, 3 tablas y 7 bloques de código detectados antes de publicar.
  • Código comprobado: 1 Python/py_compile, 6 Bash/copy-paste checks.
  • Catálogo soportado: el texto se contrastó contra los perfiles de dispositivo validables de Prometeo y los stacks no soportados bloquean la publicación.
  • Hallazgos del informe: sin hallazgos bloqueantes.

Esta validación confirma compatibilidad sintáctica y de herramientas para el material publicado, pero no sustituye la prueba física sobre tu hardware, cableado y entorno exactos.

Nota educativa de seguridad

Nota de seguridad

Este proyecto conmuta equipos de ventilación alimentados por la red eléctrica mediante un relé. Usa un módulo de relé con aislamiento adecuado, sigue las normas eléctricas locales y mantén el cableado de red físicamente separado del cableado de bajo voltaje de la Raspberry Pi. Si no estás cualificado para trabajar con corriente alterna de red, usa el relé solo para accionar una carga de prueba de bajo voltaje como un módulo LED o pide a un electricista cualificado que conecte el ventilador.


title: Caso práctico de Raspberry Pi: controlador de relé de ventilación basado en CO2
slug: practical-case-raspberry-pi
level: Básico
device: Raspberry Pi
objective: co2-ventilation-relay-controller


Controlador de relé de ventilación por CO2 con Raspberry Pi

Este caso práctico muestra cómo construir un controlador de relé de ventilación basado en CO2 en una Raspberry Pi. La Raspberry Pi lee la concentración de CO2 interior desde un sensor UART MH-Z19B y conmuta un relé para habilitar o deshabilitar un ventilador de ventilación cuando el valor medido cruza umbrales definidos.

Diagrama de bloques conceptual

Vista de alto nivel: qué entra, qué procesa cada bloque y qué sale del sistema.

Arquitectura funcional

Sensor de CO2 MH-Z19B

lectura UART en Raspberry Pi

lógica de umbral/histéresis

salida GPIO

módulo de relé aislado

ventilador de ventilación o carga de prue…

Flujo conceptual de señales y responsabilidades entre bloques del dispositivo.

Objetivo y caso de uso

Implementar un controlador de ventilación que:

  • Lea ppm de CO2
  • Encienda el relé de ventilación cuando el CO2 sea alto
  • Apague el relé de ventilación cuando el CO2 baje
  • Use histéresis para evitar el traqueteo del relé
  • Se ejecute continuamente como un script de servicio simple en Raspberry Pi

Hardware

  • Raspberry Pi con cabecera GPIO de 40 pines
  • Tarjeta microSD con Raspberry Pi OS
  • Sensor de CO2 MH-Z19B
  • Módulo de relé de 5 V, 1 canal, compatible con GPIO
  • Fuente externa de 5 V para el módulo de relé si la corriente del módulo lo requiere
  • Cables jumper
  • Opcional: lámpara de bajo voltaje o carga LED para pruebas seguras en banco

Cableado

Mapeo de pines

Función Pin del dispositivo Pin de Raspberry Pi Notas
5 V para el sensor MH-Z19B Vin Pin 2 (5V) El sensor requiere 5 V
Tierra para el sensor MH-Z19B GND Pin 6 (GND) Tierra común
TX del sensor MH-Z19B TX Pin 10 (GPIO15 / RXD) La Pi recibe datos del sensor
RX del sensor MH-Z19B RX Pin 8 (GPIO14 / TXD) Opcional para soporte de comandos
Entrada del relé Relay IN Pin 11 (GPIO17) Ejemplo activo en bajo en el software
VCC del relé Relay VCC Fuente de 5 V Comprueba la especificación del módulo
GND del relé Relay GND GND de la Pi Se requiere tierra común

Notas

  • Muchas placas de relé son activas en bajo. El software de abajo asume que llevar GPIO17 a LOW energiza el relé.
  • La interfaz UART del MH-Z19B es segura con lógica de 3.3 V en TX hacia RX de la Pi en placas breakout comunes. Verifica tu módulo antes de cablear.
  • En Raspberry Pi OS, la consola serie debe estar deshabilitada para que /dev/serial0 quede libre para el sensor.

Habilitar UART en Raspberry Pi

Ejecuta:

sudo raspi-config nonint do_serial_hw 0
sudo raspi-config nonint do_serial_cons 1
sudo reboot

Después de reiniciar, verifica que exista el dispositivo UART:

ls -l /dev/serial0

Instalar dependencias

sudo apt update
sudo apt install -y python3 python3-rpi.gpio

Programa del controlador

Guarda este archivo como co2_ventilation_controller.py.

#!/usr/bin/env python3
import time
import serial
import RPi.GPIO as GPIO

UART_DEVICE = "/dev/serial0"
UART_BAUD = 9600

RELAY_GPIO = 17
RELAY_ACTIVE_LOW = True

CO2_ON_THRESHOLD = 1000   # ppm: turn ventilation ON at or above this level
CO2_OFF_THRESHOLD = 800   # ppm: turn ventilation OFF at or below this level

POLL_INTERVAL_SECONDS = 5.0


def relay_write(enabled: bool) -> None:
    if RELAY_ACTIVE_LOW:
        GPIO.output(RELAY_GPIO, GPIO.LOW if enabled else GPIO.HIGH)
    else:
        GPIO.output(RELAY_GPIO, GPIO.HIGH if enabled else GPIO.LOW)


def mhz19_checksum(packet: bytes) -> int:
    checksum = 0xFF - (sum(packet[1:8]) % 256) + 1
    return checksum & 0xFF


def read_co2_ppm(ser: serial.Serial) -> int:
    command = bytes([0xFF, 0x01, 0x86, 0x00, 0x00, 0x00, 0x00, 0x00, 0x79])
    ser.reset_input_buffer()
    ser.write(command)
    response = ser.read(9)

    if len(response) != 9:
        raise RuntimeError(f"Incomplete response: got {len(response)} bytes")

    if response[0] != 0xFF or response[1] != 0x86:
        raise RuntimeError(f"Unexpected response header: {response.hex()}")

    if response[8] != mhz19_checksum(response):
        raise RuntimeError(f"Checksum error: {response.hex()}")

    co2_ppm = response[2] * 256 + response[3]
    return co2_ppm


def main() -> None:
    GPIO.setmode(GPIO.BCM)
    GPIO.setup(RELAY_GPIO, GPIO.OUT)
    relay_enabled = False
    relay_write(relay_enabled)

    print("Starting CO2 ventilation relay controller")
    print(f"ON threshold : {CO2_ON_THRESHOLD} ppm")
    print(f"OFF threshold: {CO2_OFF_THRESHOLD} ppm")

    try:
        with serial.Serial(UART_DEVICE, UART_BAUD, timeout=1.0) as ser:
            while True:
                try:
                    co2_ppm = read_co2_ppm(ser)

                    if not relay_enabled and co2_ppm >= CO2_ON_THRESHOLD:
                        relay_enabled = True
                        relay_write(relay_enabled)
                    elif relay_enabled and co2_ppm <= CO2_OFF_THRESHOLD:
                        relay_enabled = False
                        relay_write(relay_enabled)

                    state = "ON" if relay_enabled else "OFF"
                    print(f"CO2={co2_ppm} ppm, ventilation relay={state}")
                except RuntimeError as exc:
                    print(f"Read error: {exc}")

                time.sleep(POLL_INTERVAL_SECONDS)
    finally:
        relay_write(False)
        GPIO.cleanup()


if __name__ == "__main__":
    main()

Ejecutar el controlador

python3 co2_ventilation_controller.py

Salida esperada en consola:

  • CO2=650 ppm, ventilation relay=OFF
  • CO2=1100 ppm, ventilation relay=ON

Opcional: iniciar automáticamente al arrancar

Crea un archivo de unidad systemd:

sudo tee /etc/systemd/system/co2-ventilation.service >/dev/null <<'EOF'
[Unit]
Description=CO2 Ventilation Relay Controller
After=network.target

[Service]
Type=simple
User=pi
WorkingDirectory=/home/pi
ExecStart=/usr/bin/python3 /home/pi/co2_ventilation_controller.py
Restart=always
RestartSec=3

[Install]
WantedBy=multi-user.target
EOF

Habilítalo e inícialo:

sudo systemctl daemon-reload
sudo systemctl enable --now co2-ventilation.service
sudo systemctl status co2-ventilation.service --no-pager

Cómo funciona el control de ventilación

La Raspberry Pi implementa un controlador de ventilación por CO2 simple con histéresis:

Valor de CO2 Acción del relé Estado de la ventilación
>= 1000 ppm Energizar relé Ventilación ENCENDIDA
801 to 999 ppm Mantener el estado anterior Estable, sin traqueteo
<= 800 ppm Liberar relé Ventilación APAGADA

Esto evita conmutaciones rápidas cerca de un único umbral.

Método de validación

Para validar el comportamiento del controlador de relé de ventilación por CO2:

  1. Alimenta el sensor y el módulo de relé.
  2. Ejecuta el script Python.
  3. Observa la salida en vivo en la terminal.
  4. Expón el sensor a un nivel más alto de CO2, por ejemplo respirando cerca del sensor brevemente en una configuración de prueba ventilada.
  5. Confirma:
  6. El valor de CO2 impreso sube por encima de 1000 ppm
  7. El relé de ventilación cambia a ON
  8. Vuelve a colocar el sensor en aire fresco y espera a que la lectura baje.
  9. Confirma:
  10. El valor de CO2 impreso baja a 800 ppm o menos
  11. El relé de ventilación cambia a OFF

Evidencia esperada

  • Registros de terminal que muestren valores de CO2 cruzando ambos umbrales
  • Clics audibles del relé o cambio del indicador LED en la placa de relé
  • Comprobación opcional de continuidad con multímetro en los contactos del relé
  • Flujo de aire opcional o activación del ventilador cuando la salida de ventilación esté conectada

Solución de problemas

Síntoma Causa probable Solución
Incomplete response UART no habilitado o dispositivo serie incorrecto Vuelve a habilitar UART y comprueba /dev/serial0
Errores de checksum constantes Problema de cableado o desajuste de baudios Vuelve a comprobar TX/RX y usa 9600 baudios
Relé siempre ENCENDIDO El módulo es activo en bajo Mantén RELAY_ACTIVE_LOW = True
El relé nunca conmuta Pin GPIO incorrecto o sin tierra común Verifica el cableado de GPIO17 y GND
La lectura de CO2 no cambia Calentamiento del sensor o mala ubicación Deja que el sensor se caliente durante varios minutos

Resultado

Ahora tienes un controlador de relé de ventilación por CO2 para Raspberry Pi funcional que lee un sensor de CO2 y conmuta un relé para controlar la ventilación automáticamente.

Encuentra este producto y/o libros sobre este tema en Amazon

Ir a Amazon

Como afiliado de Amazon, gano con las compras que cumplan los requisitos. Si compras a través de este enlace, ayudas a mantener este proyecto.

Quiz rápido

Pregunta 1: ¿Qué sensor se utiliza para leer la concentración de CO2 en el proyecto descrito?




Pregunta 2: ¿A través de qué interfaz se comunica el sensor MH-Z19B con la Raspberry Pi en este caso?




Pregunta 3: ¿Qué dispositivo conmuta la Raspberry Pi para iniciar o detener el ventilador?




Pregunta 4: ¿Cada cuánto tiempo consulta normalmente la Raspberry Pi el sensor de CO2?




Pregunta 5: ¿Qué nivel de CO2 se menciona como ejemplo para activar la ventilación en algunos casos de uso?




Pregunta 6: ¿Qué umbral inferior se propone como ejemplo para apagar la ventilación y evitar traqueteo del relé?




Pregunta 7: ¿Qué técnica de control se menciona implícitamente al usar un umbral alto para encender y otro más bajo para apagar?




Pregunta 8: ¿Cuál es el tiempo de respuesta GPIO indicado para accionar el relé?




Pregunta 9: ¿Qué consumo de CPU se espera normalmente para este servicio en la Raspberry Pi?




Pregunta 10: ¿Cuál de las siguientes se menciona como posible ampliación futura del sistema?




Carlos Núñez Zorrilla
Carlos Núñez Zorrilla
Electronics & Computer Engineer

Ingeniero Superior en Electrónica de Telecomunicaciones e Ingeniero en Informática (titulaciones oficiales en España).

Sígueme:


Caso práctico: riego de maceta con Raspberry Pi

Caso práctico: plant irrigation pump controlador con — hero

Objetivo y caso de uso

Qué construirás: Un controlador de riego para plantas con Raspberry Pi que lee un sensor digital de humedad del suelo y activa una bomba de agua controlada por relé cuando la tierra está demasiado seca. El sistema realiza ciclos cortos de riego y luego hace una pausa antes de volver a comprobar para evitar el exceso de riego y el traqueteo del relé.

Por qué es importante / Casos de uso

  • Automatiza el riego de una planta de interior, una maceta de hierbas o una pequeña bandeja de plántulas sin necesidad de comprobaciones manuales constantes.
  • Ayuda a mantener condiciones del suelo más consistentes reaccionando en segundos ante una señal de estado seco en lugar de esperar horas o días a la intervención humana.
  • Ofrece una introducción sencilla al control GPIO, la conmutación por relé y la automatización basada en sensores en Raspberry Pi.
  • Útil para configuraciones interiores de bajo voltaje donde una bomba de 5 V puede funcionar en ráfagas cortas, como 2–10 segundos por ciclo.

Resultado esperado

  • Un controlador funcional basado en Python que consulta el sensor de humedad a intervalos temporizados, por ejemplo cada 30–60 segundos.
  • Activación automática de la bomba solo cuando el sensor informa suelo seco, con una ventana de riego controlada de 3–5 segundos.
  • Baja sobrecarga de cómputo en la Raspberry Pi, normalmente muy por debajo del 5% de CPU y sin carga significativa de GPU para esta tarea de automatización sin interfaz gráfica.
  • Un prototipo de bajo voltaje más seguro que mantiene la Pi a 5 V, usa un módulo de relé GPIO aislado y alimenta la bomba desde una fuente independiente adecuada.

Público: Principiantes, estudiantes y makers DIY que construyen su primer proyecto con sensores y actuadores; Nivel: Básico

Arquitectura/flujo: El sensor digital de humedad del suelo detecta estado seco/húmedo → Raspberry Pi GPIO lee la señal digital con umbral → el script de control decide si hace falta regar → la salida GPIO conmuta el relé → el relé alimenta una bomba externa durante un ciclo corto → el sistema espera un período de enfriamiento y luego vuelve a comprobar.

Nota educativa de validación

Antes de publicar este caso, el contenido pasó la puerta automática de validación de Prometeo con estado PASS. El validador comprobó los bloques de código, la estructura del artículo, los comandos copiables y la coherencia con el catálogo de dispositivos soportados.

Evidencia de validación publicada

  • Resultado automático: PASS.
  • Estructura parseada: 3 apartados, 3 tablas y 10 bloques de código detectados antes de publicar.
  • Código comprobado: 4 Python/py_compile, 6 Bash/copy-paste checks.
  • Catálogo soportado: el texto se contrastó contra los perfiles de dispositivo validables de Prometeo y los stacks no soportados bloquean la publicación.
  • Hallazgos del informe: sin hallazgos bloqueantes.

Esta validación confirma compatibilidad sintáctica y de herramientas para el material publicado, pero no sustituye la prueba física sobre tu hardware, cableado y entorno exactos.

Nota educativa de seguridad

Este proyecto es un prototipo educativo, no un producto certificado. Antes de alimentar el montaje, verifica el pinout de la revisión exacta de tu placa ULX3S, mantén las señales de E/S de FPGA a 3.3 V, nunca conectes 5 V directamente a los pines de E/S, desconecta la alimentación antes de cambiar el cableado y utiliza fuentes externas adecuadas para cargas, motores o servos, compartiendo tierra solo cuando el cableado lo requiera.


title: Caso práctico: Controlador de bomba de riego para plantas con Raspberry Pi
slug: practical-case-raspberry-pi
level: Basic


Controlador de bomba de riego para plantas con Raspberry Pi

Este caso práctico muestra cómo construir un controlador de bomba de riego para plantas con una Raspberry Pi. El controlador lee un sensor de humedad del suelo y conmuta una bomba de agua mediante un relé cuando la tierra está seca.

Nota de seguridad

Este es un proyecto educativo de bajo voltaje. Mantén la Raspberry Pi solo a 5 V y utiliza un módulo de relé diseñado para aislamiento GPIO de Raspberry Pi. No conectes tensión de red directamente al GPIO. Alimenta la bomba con su propia fuente adecuada, comparte tierra solo cuando lo requiera el diseño del relé y mantén el agua alejada de la electrónica.

Diagrama de bloques conceptual

Vista de alto nivel: qué entra, qué procesa cada bloque y qué sale del sistema.

Arquitectura funcional

El sensor digital de humedad del suelo de…

Raspberry Pi GPIO lee la señal digital co…

el script de control decide si hace falta…

la salida GPIO conmuta el relé

el relé alimenta una bomba externa durant…

el sistema espera un período de enfriamie…

Flujo conceptual de señales y responsabilidades entre bloques del dispositivo.

Objetivo y caso de uso

Construir un controlador basado en Raspberry Pi que:

  • mida la humedad del suelo,
  • decida si una planta necesita riego,
  • active una bomba durante un ciclo corto de riego,
  • espere antes de volver a comprobar.

Como una Raspberry Pi no tiene una entrada analógica integrada, este tutorial utiliza un módulo digital de humedad del suelo con umbral ajustable y salida digital.

Componentes

  • Raspberry Pi con Raspberry Pi OS
  • Tarjeta MicroSD
  • Módulo sensor digital de humedad del suelo con DO, VCC, GND
  • Módulo de relé de 1 canal y 5 V compatible con disparo GPIO de 3.3 V
  • Bomba de agua DC pequeña
  • Fuente de alimentación externa adecuada para la bomba
  • Cables jumper
  • Protoboard o terminales de tornillo
  • Tubo y recipiente de agua

Cableado

La Raspberry Pi lee la salida digital del sensor y controla la entrada del relé.

Función Pin del módulo Pin de Raspberry Pi BCM GPIO
Alimentación del sensor de suelo VCC Pin 1 3.3 V
Tierra del sensor de suelo GND Pin 6 GND
Salida digital del sensor de suelo DO Pin 11 GPIO17
Alimentación del relé VCC Pin 2 5 V
Tierra del relé GND Pin 9 GND
Entrada de control del relé IN Pin 13 GPIO27

Cableado del lado de la bomba

El relé conmuta la alimentación de la bomba, no el riel de alimentación de la Raspberry Pi.

Elemento del circuito de la bomba Conectar a
Positivo de la fuente de la bomba Relay COM
Relay NO Cable positivo de la bomba
Cable negativo de la bomba Negativo de la fuente de la bomba
Relay NC No usado

Usa NO (normalmente abierto) para que la bomba permanezca apagada cuando la Raspberry Pi esté arrancando o apagada.

Cómo funciona

Un módulo digital típico de humedad del suelo expone una salida de comparador:

  • DO = 0 o 1 según el diseño de la placa y el umbral del trimmer,
  • el trimmer establece el punto de conmutación entre seco/húmedo.

Esta guía asume:

  • GPIO17 == LOW significa suelo seco
  • GPIO17 == HIGH significa suelo húmedo

Si tu sensor se comporta de forma opuesta, el script de prueba de abajo lo mostrará claramente.

Habilitar acceso a GPIO

Actualiza los paquetes e instala la biblioteca GPIO:

sudo apt update
sudo apt install -y python3-gpiozero

Código 1: Prueba de cableado del sensor y del relé

Guarda como sensor_relay_test.py:

#!/usr/bin/env python3
from gpiozero import DigitalInputDevice, OutputDevice
from signal import pause
import time

SENSOR_PIN = 17
RELAY_PIN = 27

sensor = DigitalInputDevice(SENSOR_PIN, pull_up=False)
relay = OutputDevice(RELAY_PIN, active_high=False, initial_value=False)

def state_text() -> str:
    return "WET/HIGH" if sensor.value == 1 else "DRY/LOW"

print("Reading soil sensor for 10 seconds...")
for _ in range(10):
    print(f"Sensor raw state: {sensor.value} ({state_text()})")
    time.sleep(1)

print("Turning pump relay ON for 2 seconds...")
relay.on()
time.sleep(2)
print("Turning pump relay OFF")
relay.off()

Ejecútalo:

python3 sensor_relay_test.py

Resultado esperado

  • Cuando mueves el sensor entre suelo seco y húmedo, el estado impreso cambia.
  • El relé debería hacer clic una vez al encenderse y otra vez al apagarse.
  • Si el comportamiento del relé está invertido, probablemente la configuración active_high=False sea correcta para tu módulo de relé. Muchas placas de relé para Raspberry Pi son activas en bajo.

Código 2: Controlador de bomba de riego para plantas

Guarda como irrigation_controller.py:

#!/usr/bin/env python3
from gpiozero import DigitalInputDevice, OutputDevice
import time
from datetime import datetime

SENSOR_PIN = 17
RELAY_PIN = 27

CHECK_INTERVAL_SECONDS = 30
PUMP_ON_SECONDS = 5
POST_WATERING_DELAY_SECONDS = 60
MAX_CYCLES_PER_HOUR = 6

# Assumption for this tutorial:
# sensor.value == 0 means dry soil
# sensor.value == 1 means wet soil
DRY_SENSOR_VALUE = 0

sensor = DigitalInputDevice(SENSOR_PIN, pull_up=False)
relay = OutputDevice(RELAY_PIN, active_high=False, initial_value=False)

cycle_timestamps = []

def now_text() -> str:
    return datetime.now().strftime("%Y-%m-%d %H:%M:%S")

def is_dry() -> bool:
    return sensor.value == DRY_SENSOR_VALUE

def prune_old_cycles() -> None:
    global cycle_timestamps
    cutoff = time.time() - 3600
    cycle_timestamps = [t for t in cycle_timestamps if t >= cutoff]

def can_water() -> bool:
    prune_old_cycles()
    return len(cycle_timestamps) < MAX_CYCLES_PER_HOUR

def water_once() -> None:
    print(f"{now_text()} Pump ON for {PUMP_ON_SECONDS} s")
    relay.on()
    time.sleep(PUMP_ON_SECONDS)
    relay.off()
    cycle_timestamps.append(time.time())
    print(f"{now_text()} Pump OFF")

def main() -> None:
    print(f"{now_text()} Irrigation controller started")
    while True:
        dry = is_dry()
        print(f"{now_text()} Sensor value={sensor.value} dry={dry}")

        if dry:
            if can_water():
                water_once()
                print(f"{now_text()} Waiting {POST_WATERING_DELAY_SECONDS} s after watering")
                time.sleep(POST_WATERING_DELAY_SECONDS)
            else:
                print(f"{now_text()} Watering skipped: hourly cycle limit reached")
                time.sleep(CHECK_INTERVAL_SECONDS)
        else:
            time.sleep(CHECK_INTERVAL_SECONDS)

if __name__ == "__main__":
    try:
        main()
    except KeyboardInterrupt:
        relay.off()
        print(f"{now_text()} Stopped by user")

Ejecútalo:

python3 irrigation_controller.py

Opcional: Iniciar al arrancar con systemd

Copia el script a una ruta estable:

mkdir -p /home/pi/irrigation
cp irrigation_controller.py /home/pi/irrigation/
chmod +x /home/pi/irrigation/irrigation_controller.py

Crea el archivo de servicio:

sudo tee /etc/systemd/system/irrigation-controller.service >/dev/null <<'EOF'
[Unit]
Description=Raspberry Pi Plant Irrigation Pump Controller
After=multi-user.target

[Service]
Type=simple
User=pi
WorkingDirectory=/home/pi/irrigation
ExecStart=/usr/bin/python3 /home/pi/irrigation/irrigation_controller.py
Restart=on-failure
RestartSec=5

[Install]
WantedBy=multi-user.target
EOF

Habilítalo e inícialo:

sudo systemctl daemon-reload
sudo systemctl enable irrigation-controller.service
sudo systemctl start irrigation-controller.service
sudo systemctl status irrigation-controller.service --no-pager

Calibración

El módulo de humedad suele tener un pequeño potenciómetro.

  1. Coloca la sonda en la tierra a la profundidad que quieras supervisar.
  2. Ejecuta python3 sensor_relay_test.py.
  3. Gira el potenciómetro lentamente.
  4. Observa el punto en el que cambia la salida digital.
  5. Ajusta hasta que la salida cambie en el nivel de sequedad que debe activar el riego.

Método de validación

Para respaldar la afirmación de que este proyecto con Raspberry Pi implementa un controlador de bomba de riego para plantas funcional, valídalo con evidencia observable:

Comprobación Método Evidencia esperada
Detección del sensor Mueve la sonda entre suelo seco y suelo húmedo mientras ejecutas sensor_relay_test.py La salida de consola cambia entre estados seco y húmedo
Conmutación de la bomba Ejecuta sensor_relay_test.py Clic audible del relé y funcionamiento visible de la bomba durante 2 segundos
Riego automático Coloca la sonda en suelo seco y ejecuta irrigation_controller.py El registro con marca de tiempo muestra detección de seco, bomba encendida, bomba apagada
Recuperación tras el riego Humedece la tierra después de un ciclo de riego El controlador registra estado húmedo y deja de activar la bomba
Limitación de frecuencia Mantén el sensor seco de forma continua El registro finalmente muestra Watering skipped: hourly cycle limit reached

Solución de problemas

El sensor nunca cambia de estado

  • Comprueba el cableado de VCC, GND y DO.
  • Confirma que el módulo del sensor está alimentado con 3.3 V si su salida va directamente al GPIO de Raspberry Pi.
  • Recalibra el potenciómetro del umbral.

El relé hace clic pero la bomba no funciona

  • Comprueba la fuente de alimentación independiente de la bomba.
  • Confirma que la bomba está cableada a través de COM y NO.
  • Verifica que el voltaje de la bomba coincide con su fuente de alimentación.

La bomba funciona en el momento equivocado

  • La lógica de tu sensor puede estar invertida.
  • Cambia esta línea en irrigation_controller.py:
DRY_SENSOR_VALUE = 0

Si tu módulo informa seco como alto, cámbialo a:

DRY_SENSOR_VALUE = 1

Resultado

Ahora tienes un controlador de bomba de riego para plantas con Raspberry Pi que:

  • supervisa la humedad del suelo,
  • acciona una bomba mediante un relé,
  • riega solo cuando la planta necesita riego,
  • incluye un límite de seguridad simple para reducir bombeos repetidos.

Encuentra este producto y/o libros sobre este tema en Amazon

Ir a Amazon

Como afiliado de Amazon, gano con las compras que cumplan los requisitos. Si compras a través de este enlace, ayudas a mantener este proyecto.

Quiz rápido

Pregunta 1: ¿Qué dispositivo principal se utiliza para construir el controlador de riego descrito?




Pregunta 2: ¿Qué tipo de sensor lee el sistema para decidir si debe regar?




Pregunta 3: ¿Cuándo activa el sistema la bomba de agua?




Pregunta 4: ¿Qué componente controla la bomba de agua desde la Raspberry Pi?




Pregunta 5: ¿Por qué el sistema hace una pausa antes de volver a comprobar el sensor?




Pregunta 6: ¿Qué tipo de automatización ofrece este proyecto como introducción sencilla?




Pregunta 7: ¿Qué duración de riego por ciclo se menciona como útil para una bomba de 5 V?




Pregunta 8: ¿En qué tipo de configuraciones resulta especialmente útil este sistema?




Pregunta 9: ¿Qué ventaja aporta reaccionar en segundos ante una señal de suelo seco?




Pregunta 10: ¿Para qué uso doméstico se menciona este controlador de riego?




Carlos Núñez Zorrilla
Carlos Núñez Zorrilla
Electronics & Computer Engineer

Ingeniero Superior en Electrónica de Telecomunicaciones e Ingeniero en Informática (titulaciones oficiales en España).

Sígueme:


Caso práctico: monitor de congelador con Raspberry Pi

Caso práctico: monitor de congelador Raspberry Pi — hero

Objetivo y caso de uso

Lo que vas a construir: Un monitor de congelador con Raspberry Pi que lee un sensor impermeable DS18B20, sirve la temperatura actual en una página web local y activa una alarma visible cuando el congelador supera un límite seguro. También almacena lecturas con marca de tiempo de forma local para que puedas verificar después la deriva de temperatura, eventos de puerta abierta o fallos de refrigeración.

Por qué importa / Casos de uso

  • Comprobar el estado del congelador desde cualquier dispositivo de tu red local con cargas de página normalmente por debajo de 200 ms en una LAN doméstica.
  • Detectar calentamientos inseguros, por ejemplo cuando la temperatura sube por encima de -18 °C durante varios minutos después de que se deja una puerta abierta.
  • Mantener un registro local sencillo para confirmar si los alimentos permanecieron congelados durante cortes breves de energía o ciclos de descongelación.
  • Crear un servicio de monitorización práctico y de baja carga en Raspberry Pi con una demanda mínima de cómputo, normalmente muy por debajo del 5% de CPU y cerca del 0% de GPU.

Resultado esperado

  • Un lector de temperatura 1-Wire funcional conectado a un DS18B20 con muestreo periódico estable, por ejemplo cada 5-10 segundos.
  • Un pequeño panel en el navegador que muestre la temperatura actual, el estado de alarma y actualizaciones recientes casi en tiempo real.
  • Un comportamiento de alarma basado en umbral que cambie de estado cuando las lecturas superen el límite configurado para tu congelador.
  • Un registro local CSV o de texto que puedas revisar más tarde para medir tendencias de temperatura, duración de alarmas y latencia de respuesta del sensor.

Audiencia: Principiantes de Raspberry Pi, makers y usuarios de laboratorio casero que estén construyendo un monitor ambiental sencillo; Nivel: Básico

Arquitectura/flujo: Sensor DS18B20 → lectura 1-Wire en Raspberry Pi → script/servidor web local ligero → página de estado en navegador + registro local de temperatura + estado de alarma cuando se supera el umbral.

Nota educativa de validación

Antes de publicar este caso, el contenido pasó la puerta automática de validación de Prometeo con estado PASS. El validador comprobó los bloques de código, la estructura del artículo, los comandos copiables y la coherencia con el catálogo de dispositivos soportados.

Evidencia de validación publicada

  • Resultado automático: PASS.
  • Estructura parseada: 4 apartados, 3 tablas y 11 bloques de código detectados antes de publicar.
  • Código comprobado: 3 Python/py_compile, 7 Bash/copy-paste checks.
  • Catálogo soportado: el texto se contrastó contra los perfiles de dispositivo validables de Prometeo y los stacks no soportados bloquean la publicación.
  • Hallazgos del informe: sin hallazgos bloqueantes.

Esta validación confirma compatibilidad sintáctica y de herramientas para el material publicado, pero no sustituye la prueba física sobre tu hardware, cableado y entorno exactos.

Nota educativa de seguridad

Este proyecto es un prototipo educativo, no un producto certificado. Antes de alimentar el montaje, verifica el pinout de la revisión exacta de tu placa ULX3S, mantén las señales de E/S del FPGA a 3.3 V, nunca conectes 5 V directamente a los pines de E/S, desconecta la alimentación antes de cambiar el cableado y usa fuentes externas adecuadas para cargas, motores o servos, compartiendo tierra solo cuando el cableado lo requiera.


title: Alarma web de temperatura para congelador en Raspberry Pi
level: Básico
slug: practical-case-raspberry-pi


Alarma web de temperatura para congelador en Raspberry Pi

Este caso práctico muestra cómo construir una alarma web de temperatura para congelador con una Raspberry Pi. La Raspberry Pi lee un sensor de temperatura 1-Wire DS18B20 impermeable, sirve una pequeña página web local y activa una alarma cuando la temperatura del congelador supera un umbral seguro para alimentos congelados.

Nota educativa de seguridad

Este proyecto es solo para monitorización. No dependas de él como única protección para la seguridad alimentaria, medicamentos o almacenamiento comercial en frío. Mantén el cableado de red eléctrica alejado de la condensación, usa una fuente de alimentación adecuada de 5 V para Raspberry Pi y coloca la electrónica fuera del recinto del congelador.

Diagrama de bloques conceptual

Vista de alto nivel: qué entra, qué procesa cada bloque y qué sale del sistema.

Arquitectura funcional

Sensor DS18B20

lectura 1-Wire en Raspberry Pi

script/servidor web local ligero

página de estado en navegador + registro…

Flujo conceptual de señales y responsabilidades entre bloques del dispositivo.

Objetivo y caso de uso

Construir una alarma web de temperatura para congelador que:

  • mida la temperatura dentro de un congelador,
  • muestre la lectura actual en un navegador,
  • muestre un estado de alarma cuando el congelador se caliente por encima de un límite configurado,
  • registre las lecturas localmente para su verificación posterior.

Lista de materiales

  • Raspberry Pi con Raspberry Pi OS
  • Sensor de temperatura impermeable DS18B20
  • Resistencia de 4.7 kOhm
  • Protoboard o conexiones por terminal
  • Cables jumper
  • Acceso a red en la Raspberry Pi

Cableado

El DS18B20 usa el bus 1-Wire. Conéctalo a GPIO4.

Cable DS18B20 Función Pin de Raspberry Pi Notas
Rojo VDD 3.3 V, pin físico 1 No uses 5 V
Negro GND GND, pin físico 6 Tierra común
Amarillo/Blanco DATA GPIO4, pin físico 7 Datos 1-Wire
Resistencia de 4.7 kOhm Pull-up Entre 3.3 V y DATA Requerida para lecturas estables

Habilitar 1-Wire en Raspberry Pi

Edita /boot/firmware/config.txt en las versiones actuales de Raspberry Pi OS y habilita el overlay de 1-Wire.

sudo sh -c 'grep -q "^dtoverlay=w1-gpio" /boot/firmware/config.txt || echo "dtoverlay=w1-gpio" >> /boot/firmware/config.txt'
sudo reboot

Después de reiniciar, confirma que los módulos del kernel y la ruta del sensor están disponibles:

lsmod | grep w1
ls /sys/bus/w1/devices/

Deberías ver entradas similares a:

  • w1_bus_master1
  • 28-xxxxxxxxxxxx

Instalar software

Instala Flask para la interfaz web.

sudo apt update
sudo apt install -y python3-flask

Aplicación

Crea freezer_alarm.py:

#!/usr/bin/env python3
from __future__ import annotations

import csv
import glob
import os
import time
from datetime import datetime, timezone
from pathlib import Path

from flask import Flask, jsonify, render_template_string

# Alarm threshold in degrees Celsius.
# Example: alarm if freezer temperature rises above -12.0 C.
ALARM_THRESHOLD_C = -12.0

# Logging interval in seconds.
LOG_INTERVAL_S = 60

# CSV log file
LOG_FILE = Path("/home/pi/freezer_temperature_log.csv")

# DS18B20 sysfs base path
W1_BASE = "/sys/bus/w1/devices"

app = Flask(__name__)

HTML_TEMPLATE = """<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <meta http-equiv="refresh" content="15">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>Freezer Temperature Web Alarm</title>
  <style>
    body { font-family: Arial, sans-serif; margin: 2rem; background: #f5f7fa; color: #222; }
    .card { max-width: 36rem; padding: 1.5rem; border-radius: 12px; background: white; box-shadow: 0 2px 8px rgba(0,0,0,0.08); }
    .ok { color: #0a7d21; font-weight: bold; }
    .alarm { color: #b00020; font-weight: bold; }
    .value { font-size: 2rem; margin: 0.5rem 0; }
    code { background: #eef; padding: 0.1rem 0.3rem; border-radius: 4px; }
  </style>
</head>
<body>
  <div class="card">
    <h1>Freezer Temperature Web Alarm</h1>
    <p class="value">{{ temp_text }}</p>
    <p>Status:
      {% if alarm %}
        <span class="alarm">ALARM</span>
      {% else %}
        <span class="ok">OK</span>
      {% endif %}
    </p>
    <p>Alarm threshold: <code>{{ threshold }} C</code></p>
    <p>Last update: <code>{{ timestamp }}</code></p>
    <p>JSON endpoint: <code>/api/status</code></p>
  </div>
</body>
</html>
"""


def find_sensor_file() -> str:
    matches = glob.glob(os.path.join(W1_BASE, "28-*", "w1_slave"))
    if not matches:
        raise FileNotFoundError(
            "No DS18B20 sensor found under /sys/bus/w1/devices/. "
            "Check wiring and 1-Wire configuration."
        )
    return matches[0]


def read_temperature_c() -> float:
    sensor_file = find_sensor_file()
    with open(sensor_file, "r", encoding="ascii") as f:
        lines = f.read().strip().splitlines()

    if len(lines) != 2 or not lines[0].endswith("YES"):
        raise RuntimeError("Sensor CRC check failed")

    marker = "t="
    pos = lines[1].find(marker)
    if pos == -1:
        raise RuntimeError("Temperature value not found in sensor output")

    milli_c = int(lines[1][pos + len(marker):])
    return milli_c / 1000.0


def alarm_state(temp_c: float) -> bool:
    return temp_c > ALARM_THRESHOLD_C


def ensure_log_header() -> None:
    if not LOG_FILE.exists():
        LOG_FILE.parent.mkdir(parents=True, exist_ok=True)
        with open(LOG_FILE, "w", newline="", encoding="utf-8") as f:
            writer = csv.writer(f)
            writer.writerow(["timestamp_utc", "temperature_c", "alarm"])


def append_log_once() -> None:
    ensure_log_header()
    temp_c = read_temperature_c()
    state = alarm_state(temp_c)
    now = datetime.now(timezone.utc).isoformat()

    with open(LOG_FILE, "a", newline="", encoding="utf-8") as f:
        writer = csv.writer(f)
        writer.writerow([now, f"{temp_c:.3f}", int(state)])


@app.route("/")
def index():
    temp_c = read_temperature_c()
    state = alarm_state(temp_c)
    timestamp = datetime.now(timezone.utc).isoformat()

    return render_template_string(
        HTML_TEMPLATE,
        temp_text=f"{temp_c:.2f} C",
        alarm=state,
        threshold=f"{ALARM_THRESHOLD_C:.1f}",
        timestamp=timestamp,
    )


@app.route("/api/status")
def api_status():
    temp_c = read_temperature_c()
    state = alarm_state(temp_c)
    timestamp = datetime.now(timezone.utc).isoformat()
    return jsonify(
        {
            "device": "Raspberry Pi",
            "application": "freezer-temperature-web-alarm",
            "temperature_c": round(temp_c, 3),
            "alarm": state,
            "alarm_threshold_c": ALARM_THRESHOLD_C,
            "timestamp_utc": timestamp,
        }
    )


def main() -> None:
    append_log_once()
    app.run(host="0.0.0.0", port=8000, debug=False)


if __name__ == "__main__":
    main()

Hazlo ejecutable:

chmod +x freezer_alarm.py

Servicio de registro opcional

La aplicación web registra una vez al iniciarse. Para un registro continuo en segundo plano cada minuto, crea freezer_logger.py:

#!/usr/bin/env python3
from __future__ import annotations

import csv
import glob
import os
import time
from datetime import datetime, timezone
from pathlib import Path

ALARM_THRESHOLD_C = -12.0
LOG_INTERVAL_S = 60
LOG_FILE = Path("/home/pi/freezer_temperature_log.csv")
W1_BASE = "/sys/bus/w1/devices"


def find_sensor_file() -> str:
    matches = glob.glob(os.path.join(W1_BASE, "28-*", "w1_slave"))
    if not matches:
        raise FileNotFoundError("No DS18B20 sensor found")
    return matches[0]


def read_temperature_c() -> float:
    sensor_file = find_sensor_file()
    with open(sensor_file, "r", encoding="ascii") as f:
        lines = f.read().strip().splitlines()

    if len(lines) != 2 or not lines[0].endswith("YES"):
        raise RuntimeError("Sensor CRC check failed")

    pos = lines[1].find("t=")
    if pos == -1:
        raise RuntimeError("Temperature value not found")

    return int(lines[1][pos + 2:]) / 1000.0


def ensure_log_header() -> None:
    if not LOG_FILE.exists():
        LOG_FILE.parent.mkdir(parents=True, exist_ok=True)
        with open(LOG_FILE, "w", newline="", encoding="utf-8") as f:
            csv.writer(f).writerow(["timestamp_utc", "temperature_c", "alarm"])


def main() -> None:
    ensure_log_header()
    while True:
        now = datetime.now(timezone.utc).isoformat()
        temp_c = read_temperature_c()
        alarm = int(temp_c > ALARM_THRESHOLD_C)
        with open(LOG_FILE, "a", newline="", encoding="utf-8") as f:
            csv.writer(f).writerow([now, f"{temp_c:.3f}", alarm])
        time.sleep(LOG_INTERVAL_S)


if __name__ == "__main__":
    main()

Ejecuta la aplicación web:

python3 freezer_alarm.py

En otra terminal, ejecuta el registrador:

python3 freezer_logger.py

Abre la página de estado desde otro dispositivo en la misma red:

hostname -I

Luego navega a:

http://<raspberry-pi-ip>:8000/

Cómo funciona la alarma

Esta alarma web de temperatura para congelador informa:

  • OK cuando la temperatura del congelador es menor o igual que -12.0 C
  • ALARM cuando la temperatura del congelador supera -12.0 C

Puedes cambiar el límite en ambos archivos Python editando:

ALARM_THRESHOLD_C = -12.0

Método de validación

No afirmes precisión ni fiabilidad sin comprobarlas. Un método de validación sencillo es:

Comprobación Método Evidencia esperada
Detección del sensor ls /sys/bus/w1/devices/ Existe un directorio de dispositivo 28-...
Lectura de temperatura en vivo Abrir /api/status El JSON incluye temperature_c y alarm
Umbral de alarma Calienta ligeramente el sensor con la mano o mueve la sonda hacia el aire ambiente para una prueba breve alarm cambia de false a true cuando la temperatura medida cruza el umbral
Registro Espera al menos 2 minutos /home/pi/freezer_temperature_log.csv contiene varias filas con marca de tiempo

Solución de problemas

Síntoma Causa Solución
No existe la ruta del sensor 28-... 1-Wire no habilitado o error de cableado Vuelve a comprobar dtoverlay=w1-gpio, el cableado y reinicia
La comprobación CRC falló Conexión débil o ruido Comprueba la colocación de la resistencia y las uniones del cable
La página web no es accesible La aplicación no se está ejecutando o hay un problema de firewall/red Inicia python3 freezer_alarm.py y verifica la dirección IP de la Pi
La temperatura parece incorrecta La sonda no está colocada completamente en el área objetivo Reubica el sensor y compáralo con un termómetro conocido

Resultado

Ahora tienes una alarma web de temperatura para congelador en Raspberry Pi que lee la temperatura desde un sensor DS18B20, expone una página en el navegador y un endpoint de estado JSON, y registra mediciones para su verificación.

Encuentra este producto y/o libros sobre este tema en Amazon

Ir a Amazon

Como afiliado de Amazon, gano con las compras que cumplan los requisitos. Si compras a través de este enlace, ayudas a mantener este proyecto.

Quiz rápido

Pregunta 1: ¿Qué sensor impermeable se utiliza en el monitor de congelador descrito?




Pregunta 2: ¿Cuál es una de las funciones principales del sistema construido con Raspberry Pi?




Pregunta 3: ¿Qué ocurre cuando el congelador supera un límite seguro de temperatura?




Pregunta 4: ¿Para qué se almacenan lecturas con marca de tiempo de forma local?




Pregunta 5: ¿Desde dónde se puede comprobar el estado del congelador según el artículo?




Pregunta 6: ¿Qué temperatura se menciona como ejemplo de calentamiento inseguro?




Pregunta 7: ¿Qué nivel de carga de CPU suele requerir este servicio de monitorización?




Pregunta 8: ¿Qué uso de GPU se menciona para este servicio?




Pregunta 9: ¿Qué tipo de servicio se pretende crear con la Raspberry Pi?




Pregunta 10: ¿Qué situación puede confirmar el registro local además de la deriva de temperatura?




Carlos Núñez Zorrilla
Carlos Núñez Zorrilla
Electronics & Computer Engineer

Ingeniero Superior en Electrónica de Telecomunicaciones e Ingeniero en Informática (titulaciones oficiales en España).

Sígueme: