Monitor de voltaje de termopar para piloto de calentador de agua: alertas seguras por email y SMS
Componentes y suministros
| Adafruit Raspberry Pi Zero WH | × | 1 |
| Arduino Nano R3 | × | 1 |
Sobre el proyecto
Sistema de monitorización de la llama piloto del calentador de agua a gas
Los calentadores de agua a gas tradicionales mantienen una llama piloto 24/7. Esta llama calienta un termopar que genera un pequeño voltaje (hasta 30 milivoltios). Este voltaje es usado por el termostato del calentador para mantener abierta una válvula de gas. Si la llama piloto se apaga, el voltaje cesa y la válvula de gas se cierra automáticamente.
En mi calentador, la llama piloto se apaga ocasionalmente. Como solo ocurre unas 3 veces al año, no quiero reemplazar el costoso calentador. Intenté cambiar el termopar, pero no solucionó el problema.
Mi solución: monitorizar el voltaje generado por el termopar. Si cae a cero, envío mensajes de texto y emails para poder reencender la llama piloto. Recuerda, no hay peligro de fuga de gas, porque la válvula se cierra siempre que el voltaje del termopar cae a cero.
Visión general
Se usa una Raspberry Pi Zero WH para enviar emails y SMS cuando la llama piloto se apaga. Como la Raspberry Pi no tiene forma de medir voltaje, se usa un Arduino Nano para monitorizar el voltaje del termopar.
Los Arduino tienen convertidores analógico-digitales (ADC) que leen un voltaje y lo convierten en un número entre 0 y 1023. En este proyecto, el Arduino lee el voltaje del termopar y comunica este valor a la Raspberry Pi. La Raspberry Pi recibe la lectura e la interpreta. Si el valor es demasiado bajo, asumimos que la llama piloto se ha apagado y enviamos notificaciones.
Paso 1: Preparar tu Raspberry Pi
Pon la Raspberry Pi en marcha en tu red (puedes consultar mi otro proyecto para instrucciones).
Crea un programa Python que reciba lecturas de voltaje del Arduino. El programa hará un bucle y enviará notificaciones cuando la lectura de voltaje sea demasiado baja. El código fuente está adjunto.
Paso 2: Preparar tu Arduino
Compré Arduinos Nano chinos baratos, así que me costó algo de prueba y error hacerlos funcionar con mi Windows 10.
Carga en el Arduino un sketch que mida el voltaje en su pin de entrada cada 30 segundos. El Arduino puede medir voltaje entre 0 y un voltaje de referencia. Se puede seleccionar 1,1V o 5V como referencia. Como el termopar solo entrega como máximo 30 mV, usaremos la referencia de 1,1V para mayor resolución. El ADC del Arduino da 0 para 0V y 1023 para 1,1V. El termopar entrega máx. 30 mV, así que la lectura será 28 o menos.
Paso 3: Conectar el Arduino a la fuente de voltaje
El termopar envía voltaje al termostato del calentador mediante un cable coaxial. El exterior del cable es el positivo.

Corta el cable a unos 13 cm (5 pulgadas) del termostato del calentador. Retrocede un poco el aislamiento exterior del cable coaxial para acceder al cable central. No destruyas el aislamiento pintado del cable central; no queremos que haga cortocircuito con el exterior del coaxial.

Conecta el cable de modo que suministre el voltaje positivo al termostato del calentador y al pin de entrada del Arduino (usé pin A0). El lado negativo de la fuente de voltaje debe ir conectado a la masa del Arduino, así como al negativo del termostato del calentador.
Usé cables de 30 cm con pinzas de cocodrilo en los extremos para hacer las conexiones.

Paso 4: Conectar el Arduino a la Raspberry Pi
Nuestro sketch en el Arduino transmitirá el número del ADC a la Raspberry Pi. El Arduino enviará la señal como salida desde su pin digital 9.
Los Arduino envían señales a +5V. La Raspberry Pi solo acepta entradas de 3V. Por tanto, entre el Arduino y la Raspberry Pi debe haber un divisor de voltaje. Esto reduce el voltaje de 5V a unos 2,8V.
Un divisor de voltaje es un sistema de resistencias que reduce el voltaje de entrada.

El voltaje de salida se determina por la relación del divisor.

No se puede usar una sola resistencia para reducir el voltaje porque cuando no fluye corriente, el voltaje en ambos lados de la resistencia será Vin (5V). Usar un divisor reduce el voltaje incluso sin corriente.
Las masas de todo deben estar conectadas. Ver diagrama de conexiones.
Paso 5: El Arduino transmite la medición de voltaje
Cada 30 segundos el sketch del Arduino obtiene la medición del ADC y transmite el número a la Raspberry Pi. Decidí usar un sistema de señalización primitivo de un solo hilo desde el pin 9 del Arduino al pin 16 de la Raspberry Pi.
Paso 6: La Raspberry Pi recibe la medición
La Raspberry Pi usa un programa Python con un bucle infinito para escuchar flancos de subida en el pin 16. Cuando se detecta un flanco de subida, se asume que el Arduino ha comenzado a transmitir un número.
Sistema de señalización
Transmite un número de dos dígitos (ej: «12»). Cada dígito va precedido por un pulso positivo recibido en el pin 16. Pulsos positivos subsiguientes separados por menos de 20 ms incrementan el valor de ese dígito. Una pausa superior a 40 ms indica que el dígito ha terminado y comienza el siguiente. Otra pausa superior a 40 ms indica que el segundo dígito ha terminado. El número completo de dos dígitos está listo.
En el código Python de la Raspberry Pi, el número recibido del Arduino es devuelto por el método que interpreta las señales. Otro código Python decide si se debe enviar notificación. Luego el código vuelve a esperar el siguiente flanco de subida en el pin 16.
Paso 7: Enviar la notificación
Si el voltaje es demasiado bajo, incrementa el contador de lecturas bajas. Se mantiene un contador para evitar falsas alarmas. Si el contador llega a 5, el voltaje ha estado bajo durante 5 mediciones (cada una a 30 segundos). Envía la notificación y reinicia el contador. Las notificaciones se envían usando smtplib y una cuenta de Gmail. Se guarda una marca de tiempo cuando se envía la notificación. La siguiente notificación no se enviará hasta pasadas 6 horas.
Para alertas por SMS, usé una función que ofrecen la mayoría de operadores: la capacidad de enviar un email que llega como SMS. Ej: para Verizon: 5555555555@vtext.com envía un SMS a ese número.
Gmail
Creé una nueva cuenta Gmail para enviar notificaciones. Al principio configuré la seguridad para permitir acceso «menos seguro» para que el código Python pudiera enviar emails. Pero tras unos meses, Gmail puede deshabilitar este acceso. Descubrí que Gmail prefiere el uso de contraseñas de aplicación.
Configuración de contraseña de aplicación: https://support.google.com/accounts/answer/185833
Paso 8: Conectar todo
Conecta el Arduino al cable del termopar del calentador y a la Raspberry Pi mediante el divisor de voltaje. (La parte superior de mi divisor usa dos resistencias que suman 550 ohmios, porque eran las que tenía a mano). Alimenta el Arduino y comenzará a medir el voltaje y enviar señales a la Raspberry Pi cada 30 segundos.

Paso 9: Ejecutar el programa Python
- Crea un script que lance tu programa Python.
- Edita el crontab de root para ejecutar automáticamente tu script al arrancar. Ajusta las rutas según tu Raspberry Pi y donde guardes el programa Python.
- Para editar el crontab:
sudo crontab -e - Añade una línea para ejecutar tu script de arranque al reiniciar la Pi:
@reboot sh /home/pi/hotwater/run_HotWaterNotifier.sh >> /home/pi/hotwater/logs/HotWaterNotifier.log 2>&1 - Para ejecutar manualmente (antes de configurar crontab):
Primero ejecuta el proceso (ejecuta tu script run_HotWaterNotifier.sh)
Luego tecleactrl-Zpara suspender el proceso
Luego tecleabguna o dos veces para enviar el proceso a segundo plano
Teleadisown, esto permite que el proceso siga corriendo tras cerrar sesión - Para ver si el proceso sigue corriendo:
ps aux | grep -i HotWater

Código
Código Arduino Arduino
Lee el voltaje cada 30 segundos y envía señales a la Raspberry Pi.
/****************************************************************************** HotWaterHeater Mide el voltaje del termopar del calentador de agua. Usa señalización para enviar esta medición a la Raspberry Pi. ****************************************************************************/
// double ReferenceVoltage = 5.0; // referencia no usada
double ReferenceVoltage = 1.1;
int OUTPUT_PIN = 9;
int INTRA_DIGIT_WAIT = 20;
int BETWEEN_DIGIT_WAIT = 50;
void setup() {
pinMode(LED_BUILTIN, OUTPUT);
pinMode(OUTPUT_PIN, OUTPUT);
analogReference(INTERNAL);
Serial.begin(9600);
}
void loop() {
int pinInput;
double voltage;
pinInput = analogRead(A0);
Serial.print("PinInputA0="); Serial.print(pinInput);
voltage = (pinInput * ReferenceVoltage) / 1023;
Serial.print(", voltageA0="); Serial.println(voltage);
// Nota: lectura 5 = 5.38 mV
sendNumberSignal(pinInput, OUTPUT_PIN, INTRA_DIGIT_WAIT, BETWEEN_DIGIT_WAIT);
delay(30000);
}
void sendNumberSignal(int number, int pin, int intraDigitWait, int betweenDigitWait) {
int tens = number / 10;
int ones = number % 10;
Serial.print("Signaling: "); Serial.println(number);
// Envía decenas
sendPulse(pin, intraDigitWait);
for (int i = 0; i < tens; i++) sendPulse(pin, intraDigitWait);
delay(betweenDigitWait);
// Envía unidades
sendPulse(pin, intraDigitWait);
for (int i = 0; i < ones; i++) sendPulse(pin, intraDigitWait);
delay(betweenDigitWait);
}
void sendPulse(int pin, int intraDigitWait) {
digitalWrite(pin, HIGH);
delay(intraDigitWait);
digitalWrite(pin, LOW);
delay(intraDigitWait);
}
Código Python Python
Recibe señales del Arduino, las interpreta en lectura de voltaje, decide si es demasiado bajo y envía emails/SMS.
###############################################################################
# HotWaterNotifier.py
# Monitoriza pin de entrada y recibe señales de un Arduino.
# Decodifica señales en mediciones numéricas de voltaje.
# Cuando la lectura recibida es demasiado baja, indica que la llama piloto está apagada.
# Si ocurre durante 5 mediciones seguidas, asume que realmente está apagada.
# Envía emails/SMS y registra la hora. Solo envía email/SMS cada 6 horas.
# Escrito para Python 2.7. Cambios menores para Python 3.
###############################################################################
import smtplib
import RPi.GPIO as GPIO
import os, os.path, time, datetime, string, logging, sys
GPIO_Alert = 16
emailWaitHours = 6
lowSensorReading = 1
maxLowVoltageCount = 5
GPIO.setmode(GPIO.BCM)
GPIO.setup(GPIO_Alert, GPIO.IN, pull_up_down=GPIO.PUD_DOWN)
lastEmailSentTime = datetime.datetime(2000,1,1,0,0,0,0)
def setup_custom_logger(name):
formatter = logging.Formatter(fmt='%(asctime)s %(levelname)-8s %(message)s', datefmt='%Y-%m-%d %H:%M:%S')
handler = logging.FileHandler('HotWaterLog.txt', mode='a')
handler.setFormatter(formatter)
screen_handler = logging.StreamHandler(stream=sys.stdout)
screen_handler.setFormatter(formatter)
logger = logging.getLogger(name)
logger.setLevel(logging.DEBUG)
logger.addHandler(handler)
logger.addHandler(screen_handler)
return logger
def send_email_alert():
global lastEmailSentTime
nowTime = datetime.datetime.now()
emailWaitDelta = datetime.timedelta(hours=emailWaitHours)
limitTime = nowTime - emailWaitDelta
if lastEmailSentTime is None or limitTime > lastEmailSentTime:
logger.info('Sending email alert...')
HOST = "smtp.gmail.com"
PORT = 587
SUBJECT = "Hot Water Heater Alert"
TO = ["XXXXXXXXXXXXXX@gmail.com", "5555555555@vtext.com"]
FROM = "XXXXXXXXXXXXXX@gmail.com"
PWD = "XXXXXXXXXXXXXX"
text = "Low Voltage Measured on the Hot Water Heater"
BODY = "\r\n".join(["from: %s" % FROM, "to: %s" % ", ".join(TO), "Subject: %s" % SUBJECT, "", text])
try:
s = smtplib.SMTP(HOST, PORT)
s.set_debuglevel(1)
s.ehlo()
s.starttls()
s.login(FROM, PWD)
s.sendmail(FROM, TO, BODY)
s.quit()
except Exception as e:
logger.exception('Exception caught file sending email. Trying again in 6 hours')
lastEmailSentTime = nowTime
else:
logger.info('Not sending email. Last email sent at: ' + lastEmailSentTime.strftime("%Y-%m-%d %H:%M:%S"))
def waitReceiveNumber(GPIO_Alert):
lastSignalTime = datetime.datetime(2000,1,1,0,0,0,0)
isTens = True
isFirstIteration = True
tensValue = 0
onesValue = 0
receivedEdge = None
singleDigitMilliseconds = datetime.timedelta(milliseconds=70)
wholeNumberWaitTime = 200
while True:
if isFirstIteration:
receivedEdge = GPIO.wait_for_edge(GPIO_Alert, GPIO.RISING, timeout=-1)
else:
receivedEdge = GPIO.wait_for_edge(GPIO_Alert, GPIO.RISING, timeout=wholeNumberWaitTime)
signalTime = datetime.datetime.now()
signalInterval = signalTime - lastSignalTime
lastSignalTime = signalTime
logger.info('signalInterval: ' + str(signalInterval.total_seconds() * 1000))
if (signalInterval < singleDigitMilliseconds) or isFirstIteration:
isFirstIteration = False
if isTens:
tensValue += 1
else:
onesValue += 1
elif receivedEdge is not None:
if isTens:
isTens = False
onesValue += 1
else:
return ((tensValue - 1) * 10) + (onesValue - 1)
else:
return ((tensValue - 1) * 10) + (onesValue - 1)
def main():
logger.info('Starting HotWaterNotifier')
referenceVoltage = 1.1
lowVoltageCount = 0
try:
while True:
sensorReading = waitReceiveNumber(GPIO_Alert)
voltage = (sensorReading * referenceVoltage) / 1023
logger.info('sensorReading: ' + str(sensorReading) + ', voltage: ' + str(voltage))
if sensorReading <= lowSensorReading:
lowVoltageCount += 1
if lowVoltageCount >= maxLowVoltageCount:
logger.info('Low voltage alert')
send_email_alert()
lowVoltageCount = 0
else:
lowVoltageCount = 0
except KeyboardInterrupt:
logger.info('Keyboard interrupt received')
GPIO.cleanup()
GPIO.cleanup()
def testEmail():
logger.info('Starting HotWaterNotifier')
referenceVoltage = 1.1
lowVoltageCount = 0
try:
send_email_alert()
except KeyboardInterrupt:
logger.info('Keyboard interrupt received')
GPIO.cleanup()
GPIO.cleanup()
logger = setup_custom_logger('HotWaterNotifier')
if __name__ == "__main__":
main()
Script para iniciar el código Python SH
Este es el script que crontab llama para iniciar el código Python.
#!/bin/bash # run_HotWaterNotifier.sh # Lanza el notificador cd /home/pi/hotwater sudo python HotWaterNotifier.py
Proceso de manufactura
- Centro de Energía Doméstica: Monitorización de paneles solares fotovoltaicos, térmicos y temperaturas con Raspberry Pi y Moteino
- Crea un Impresionante Sistema Ambilight para Monitor con Arduino
- Monitorización en Tiempo Real de Panel Solar con Arduino: Sistema de Adquisición de Datos de Bajo Coste
- Captura Gotas de Agua en Acción con Arduino Nano: Fotografía de Alta Velocidad DIY
- Construye un Monitor de Energía y Registrador de Datos Fiable con Arduino – Guía Paso a Paso
- Monitor de Frecuencia Cardíaca IoT en Tiempo Real con Arduino y MAX30100
- Monitor de Temperatura y Reloj en Tiempo Real con Arduino Due y Pantalla TFT 3.2"
- Construye un Contador Geiger-Müller Personalizado con Arduino, Elevador de Alta Tensión y Pantalla LCD 20x4
- Calentador de Agua por Bomba de Calor Óptimo: Soluciones Eficientes de Agua Caliente
- Cómo Elegir la Mejor Bomba de Agua Caliente Doméstica: Consejos y Guía de Expertos
- Conceptos básicos de bombas de agua caliente: funcionamiento e importancia