Haciendo unas reformas en casa me doy cuenta que la sirena inalámbrica instalada con el sistema de alarma no tiene el alcance con la señal de radio para llegar el sitio donde será instalada.
Viendo que tengo una sirena clásica cableada que nunca instalé por lo incomodo de colocar tantos metros de cable decidí convertirla en inalámbrica mediante dos enlaces de Radio controlados con Arduinos Nano.
En la siguiente imagen se puede ver la sirena con el receptor ya instalado en su interior.

Para activar la sirena remota uso la señal de activación que la propia alarma publica para activar una sirena interna (+12V), esta señal de 12 voltios se conecta a un opto-acoplador PC817 que dispara una interrupción en el Arduino Nano.
Una vez se detecta la interrupción se envía un comando de activación a la sirena remota.
El siguiente es el diagrama electrónico del emisor.
El siguiente es el programa para el emisor, se puede ver que en la rutina de interrupción se envía el comando para activar la sirena remota también se puede ver el uso de un delay() en la rutina de la interrupción lo que se puede entender como una interrupción anidada situación prohibida en Arduino sin embargo en este caso y debido a la forma en que el código ha sido diagramado esto es funcional.
Si se detecta que los 12 voltios de la sirena interna desaparecen se entiende que la alarma se ha desactivado y se envía el comando para apagar la sirena remota y todo el sistema pasa a bajo consumo deteniendo la CPU hasta que una nueva interrupción lo despierte.
/**********************************************************************
** Descripción : Control de una sirena por enlace de Radio
** Envia el 5 veces el comando activación a la sirena.
**
** Target : Arduino NANO
** ToolChain : Arduino IDE 1.8.1´9 bajo Linux Debian
** Daniel Schmidt
**********************************************************************/
#include <avr/sleep.h>
#define alarma 3 // IRQ_1 Detecta el disparo de la alarma
volatile unsigned char bandera_1 = 0;
unsigned char control_1 = 0;
unsigned char control_2 = 0;
void setup() {
Serial.begin(9600);
while (!Serial) {
; // Espera que se establezca la conexion
}
pinMode(3,INPUT_PULLUP); // Pin que detecta el disparo de la alarma
}
void loop() {
// Si el pin 3 esta a nivel alto enviar comando APAGAR SIRENA
if (digitalRead(alarma) == HIGH && control_2 <=4){// Envía el comando 5 veces
do{
Serial.write('B'); // Envía el comando stop (Sirena desactivada)
control_2++; // Incrementa el contador de muestras
control_1 = 0;
delay(1000); // Espera un segundo en cada envío de comando
}while(control_2 <=4);
}
sleep_enable(); // Activar el modo sleep
attachInterrupt( 1, ISR_Alarma_SI, LOW); // Define que ISR lo despierta
set_sleep_mode(SLEEP_MODE_PWR_DOWN); // Modo en que entra al sleep
sleep_cpu(); // Detiene la CPU
}
/*************************************************
Rutina para detectar el disparo de la alarma
*************************************************/
void ISR_Alarma_SI(){
sleep_disable();
delay(2000); // IMPORTANTE: Tiempo de espera para que toda
// la electrónica se active.
// Si el pin esta bajo luego de dos segundo enviar comando ACTIVAR SIRENA
if(digitalRead(alarma) == LOW && control_1 <=4){ // Envía el comando 5 veces
do{
Serial.write('A'); // Envía el comando de disparo (Sirena activada)
control_1++; // Incrementa el contador de muestras
control_2 = 0;
delay(1000);
}while(control_1 <=4);
}
}
El diagrama electrónico del receptor que controla la sirena remota es el siguiente.

El receptor es quien activa la sirena remota al recibir el comando 'A', en este caso la mantiene activa durante un minuto y pasa en modo bajo consumo al recibir el comando 'B' que indica que la alarma ha sido desactivada.
En este ejemplo se uso un enlace de radio lora simplemente por la distancia a cubrir pero evidentemente cualquier enlace funcionará ya que esto es solo el medio de transporte del protocolo de comunicación que hace que todo funcione.
El siguiente es el código del receptor.
/*************************************************************************************
** Descripción : Control de una sirena por enlace Lora
** La sirena se activa con el comando A y se desactiva
** con el comando B o transcurridos 1 minuto de estar activada.
** NOTA : Recordar que el contador interno de millis es de 32 bits es decir
** que va desde 0 a 4294967296 milisegundos.
** Target : Arduino NANO
** ToolChain : Arduino IDE 1.8.19 bajo Linux Debian
** Daniel Schmidt
**************************************************************************************/
#include <avr/sleep.h>
#define pin_ISR 2 // Pin IRQ para ATmega 328
#define sirena 9
unsigned long milisegundos = 0;
volatile char dato;
unsigned int segundos = 0;
unsigned char bandera = 0;
unsigned char bandera_timer = 0;
volatile char tmp;
void sleep(void);
void ISR_Sirena_SI(){ // Esta ISR se ejecuta primero que la UART (Vector 2)
sleep_disable();
dato = '0';
}
void setup() {
Serial.begin(9600);
while (!Serial) {
; // Espera que se establezca la conexión
}
milisegundos = millis();
pinMode(sirena, OUTPUT);
digitalWrite(sirena, LOW); // Sirena en silencio
sleep_enable(); // Modo sleep habilitado
attachInterrupt( 0, ISR_Sirena_SI, LOW); // ISR para salir del sleep
set_sleep_mode(SLEEP_MODE_PWR_DOWN); // Modo del sleep agresivo
sleep_cpu(); // CPU pasa al modo sleep
}
void loop() {
while (Serial.available()>0){ // Usar Inte_Vector 19
dato = Serial.read();
}
if((dato == 'A') || (dato == 'B')){
if(dato == 'A' && bandera == 0 ){// Control para activar
digitalWrite(sirena, HIGH); // Sirena ACTIVADA!!
bandera = 1;
dato = '0';
segundos = 0;
}
if(dato == 'B'){
digitalWrite(sirena, LOW); // Sirena DESACTIVADA con B!!
segundos = 0;
bandera = 0;
dato = '0';
bandera_timer = 0;
sleep(); // Nuevamente sleep solo si la alarma envía el comando B
}
if(dato == 'A' && bandera_timer == 0 ){
if ( millis() - milisegundos >= 1000 ) { // Ya pasaron 1000 milisegundos (Un segundo)?
segundos++;
milisegundos = millis(); // Actualiza el valor actual de millis
if(segundos >= 60){ // Si pasaron 60 segundos desactivar sirena
digitalWrite(sirena, LOW);
segundos = 0;
bandera_timer = 1;
}
}
}
}
// ############ Por si acaso el programa llega hasta este punto pasar a sleep #########
// ############ (El programa NO debería de llegar hasta este punto) #########
if(segundos == 120){ // Si pasaron 120 segundos pasar a sleep nuvamente
digitalWrite(sirena, LOW);
segundos = 0;
bandera = 0;
bandera_timer = 0;
sleep();
}
}
void sleep()
{
while (Serial.available()>0)
tmp = Serial.read(); // Limpiar buffer de RX
digitalWrite(sirena, LOW);
segundos = 0;
bandera = 0;
bandera_timer = 0;
delay(100);
sleep_enable(); // Activar el modo sleep
attachInterrupt( 0, ISR_Sirena_SI, LOW); // ISR que lo hace despertarí
set_sleep_mode(SLEEP_MODE_PWR_DOWN); // Modo en que entra al sleep
sleep_cpu(); // Detiene la CPU
}