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
Flujo conceptual de señales y responsabilidades entre bloques del dispositivo.
Ruta de validación
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:
- lea una entrada de pulsos en un pin GPIO de Raspberry Pi
- elimine el rebote de la señal
- almacene eventos de pulsos en un archivo CSV
- 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.txtalmacena 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
- 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.0UNIT_NAME = "litre"- contador eléctrico con
1000 pulses/kWh: PULSES_PER_UNIT = 1000.0UNIT_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
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.




