Arduino per controllare sistema di allarme da Home Assistant

Salve,
Premetto che sono totalmente nuovo all’arduino e che non conosco linguaggi di programmazione pur avendo una conoscenza di base della struttura di un linguaggio di programmazione. Sono un ingegnere elettrico.
Da un po’ mi sono cimentato con Home Assistant per l’automazione domotica e devo dire che sono riuscito ad arrivare ad un livello decente di comprensione del sistema. Adesso sto cercando di interfacciare il mio vecchio sistema di allarme con Home Assistant.

Poiché avevo a disposizione gratuitamente un Arduino Uno originale con Ethernet Shield ho provato ad utilizzare questo sistema.
Sono riuscito ad ottenere l’automazione che mi ero preposto usando la libreria aREST. Cosa molto semplice in quanto posso programmare i pin di arduino tramite ethernet direttamente da Home Assistant (come sensori o come switches). Per la parte elettrica non è stato un problema.
Il problema che ho con aRESt e’ che mentre il controllo dei pin in output è immediato, la lettura dei PIN di input è molto lenta (credo perché aREST usi una modalità polling quindi intervallata da tempi di controllo predefiniti dello stato del pin, fino anche a 45 secondi per aggiornare lo stato).

Leggendo un po’ su internet credo che il sistema sarebbe molto più veloce in lettura utilizzando la piattaforma MQTT dove il cambio di stato del PIN andrebbe ad aggiornare rapidamente il relativo Topic, quindi cambiando lo stato del sensore in Home Assistant).
Ho passato un paio di giorni a esaminare sketches pensando di poter modificare a piacimento uno esistente, ma a causa della mia ignoranza sul linguaggio di programmazione non riesco a fare passi in avanti.

Ho bisogno solo di informazioni binarie (On e off per intenderci sia per input che per output)
La logica di cui ho bisogno è molto semplice: quando un pin (esempio pin 1) impostato come input legge uno stato basso allora pubblica sul broker arduino/PIN1/’off’, quando legge alto pubblica arduino/PIN1/’on’.

Nel caso di un pin impostato come output (esempio pin 2) allora se viene pubblicato sul broker arduino/pin2/’off’ il pin 2 si imposta su in livello LOW se invece viene pubblicato arduino/pin2/’on’ allora pin 2 viene impostato su livello HIGH.
Con questa semplice logica sono in grado di controllare tutti gli aspetti del mio sistema di allarme da Home Assistant e ricevere messaggi dal bot di telegram.

Ho trovato uno sketch che è simile a quello di cui ho bisogno con ethernet (non wifi), ma utilizza la libreria bounce.h che non so come è fatta e non vorrei avere gli stessi problemi che ho con aREST e poi vorrei mantenere lo sketch più semplice possibile. È la prima volta che scrivo su una community per cui spero di non aver infranto le regole scritte e non. Grazie per ogni aiuto che mi potrete dare.

Buongiorno, :slight_smile:
essendo il tuo primo post, nel rispetto del regolamento della sezione Italiana del forum (… punto 13, primo capoverso), ti chiedo cortesemente di presentarti IN QUESTO THREAD (spiegando bene quali conoscenze hai di elettronica e di programmazione ... possibilmente evitando di scrivere solo una riga di saluto) e di leggere con molta attenzione tutto il su citato REGOLAMENTO ... Grazie. :slight_smile:

Guglielmo

P.S.: Ti ricordo che, purtroppo, fino a quando non sarà fatta la presentazione nell’apposito thread, nessuno ti potrà rispondere, quindi ti consiglio di farla al più presto. :wink:

Salve Guglielmo. Grazie molte per la comunicazione (o heads up come diciamo in inglese!). Ho fatto presentazione, spero vada bene. Adesso do' un occhiata al regolamento.

tore71:
... ma utilizza la libreria bounce.h che non so come è fatta e ...

Mah, da quanto ne so, quella libreria dovrebbe sevire per gestire il "debouncing" di un pulsante ... a te serve farlo o sul pin hai un segnale digitale pulito ?

Guglielmo

Ho un segnale digitale pulito. L'ho testato e i valori sono molto stabili.

... quindi la "bounce.h" a te non serve a nulla, puoi tranquillamente eliminarla e leggere direttammente il pin digitale in INPUT. :slight_smile:

Guglielmo

si credo di si, ma il problema arriva nello scrivere o modifcare il codice che comunica con il broker MQTT attraverso ethernet.
Posso provare a postare quello che avevo trovato e veder cosa si puo’ fare.

(PS: Mi sono ricordato che in ingresso ho anche uno di quei schedine con rele’ che se fossero fatte bene dovrebbero avere un RC in uscita per ridurre il bounce. A occhio direi che non dovrei avere problemi)

/*
Example MQTT-switch-relay-node with 4 sensors and 4 switchs 

 - connects to an MQTT server
 - publishes "hello world" to the topic "switch"
 - subscribes to the topic "switch"
 - controls 4 switchs on pins 2,3,5 and 6 - switchs can be replaced with relays
 - reads 4 sensor on pins 7,8,9 and 10
 - turns on/off a specific switch when it receives a specific "on"/"off" from the "switch" topic
 - sends a specific "on"/"off" to the "switch" topic a specific sensor is pressed
 - multiple arduino's with same generic sketch can run parallel to each other
 - multiple arduino's need each to have a unique ip-addres, unique mac address and unique MQTT client-ID

 - tested on arduino-uno with W5100 ethernet shield
 - Ethernet Shield W5100 uses pins 4,10,11,12,13
 - availbale digital pins: 1,2,3,5,6,7,8,9,10 
*/

//------------------------------------------------------------------------------

#include <SPI.h>
#include <Ethernet.h>
#include <PubSubClient.h>
#include <Bounce2.h>

// Set switch variables to Arduino digital pins
int switch1 = 2;
int switch2 = 3;
int switch3 = 5;                             // pin 4 used by ethernet shield
int switch4 = 6;


// Set sensor variables to Arduino digital pins
int sensor1 = 7;
int sensor2 = 8;
int sensor3 = 9;
int sensor4 = 10;                         // pins 11,12,13 used by ethernetshield

// Set variables to act as virtual switches
// Set variable values initially to LOW (and not HIGH)
int switch1Value = LOW;             
int switch2Value = LOW;
int switch3Value = LOW;
int switch4Value = LOW;


//---------------------------------------------------------------------------

// Arduino MAC address is on a sticker on your Ethernet shield
// must be unique for every node in same network
// To make a new unique address change last letter

byte mac[]    = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xEE };  

// Unique static IP address of this Arduino - change to adapt to your network
IPAddress ip(192,168,1,7);

// IP Address of your MQTT broker - change to adapt to your network
byte server[] = { 192, 168, 1, 20 };

// Handle and convert incoming MQTT messages ----------------------------------------

void callback(char* topic, byte* payload, unsigned int length) {
 // handle message arrived
 String content="";
 char character;
 for (int num=0;num<length;num++) {
     character = payload[num];
     content.concat(character);
 }   
 Serial.println(topic);
 Serial.println(content); // message sent out by sensor actions is returned from broker and serial printed


// Set specific virtual switches on basis of specific incoming messages ----------------------------
 
 if (content == "1on") {
   switch1Value = HIGH;
 }
 
 if (content == "1off") {
   switch1Value = LOW;
 }
 
 if (content == "2on") {
   switch2Value = HIGH;
 }
 
 if (content == "2off") {
   switch2Value = LOW;
 }

 
 if (content == "3on") {
   switch3Value = HIGH;
 }
 
 if (content == "3off") {
   switch3Value = LOW;
 }
 
 if (content == "4on") {
   switch4Value = HIGH;
 }
 
 if (content == "4off") {
   switch4Value = LOW;
 }
 
   
 // Set digital pin states according to virtual switch settings
   
 digitalWrite(switch1,switch1Value);
 digitalWrite(switch2,switch2Value);
 digitalWrite(switch3,switch3Value);
 digitalWrite(switch4,switch4Value);

}

// Initiate instances -----------------------------------

EthernetClient ethClient;
PubSubClient client(server, 1883, callback, ethClient);

// Initiate a bouncer instance for each sensor
Bounce bouncer1 = Bounce();
Bounce bouncer2 = Bounce();
Bounce bouncer3 = Bounce();
Bounce bouncer4 = Bounce();

//-------------------------------------------------------

void setup()

{

 // setup switch, sensor, bouncer 1 -----------------------
 pinMode(switch1, OUTPUT);
 pinMode(sensor1,INPUT);
 digitalWrite(sensor1,HIGH);
 bouncer1 .attach(sensor1);
 bouncer1 .interval(5);

 // setup switch, sensor, bouncer 2 -----------------------
 pinMode(switch2, OUTPUT);
 pinMode(sensor2,INPUT);
 digitalWrite(sensor2,HIGH);
 bouncer2 .attach(sensor2);
 bouncer2 .interval(5);

 // setup switch, sensor, bouncer 3 -----------------------
 pinMode(switch3, OUTPUT);
 pinMode(sensor3,INPUT);
 digitalWrite(sensor3,HIGH);
 bouncer3 .attach(sensor3);
 bouncer3 .interval(5);

 // setup switch, sensor, bouncer 4 -----------------------
 pinMode(switch4, OUTPUT);
 pinMode(sensor4,INPUT);
 digitalWrite(sensor4,HIGH);
 bouncer4 .attach(sensor4);
 bouncer4 .interval(5);

 // setup serial and ethernet communications -------------------------------

 // Setup serial connection
 Serial.begin(9600);

 // Setup ethernet connection to MQTT broker
 Ethernet.begin(mac);
 if (client.connect("arduino")) {   // change as desired - clientname must be unique for MQTT broker
   client.publish("switch","hello world - here arduino");
   Serial.println("connected");
   client.subscribe("switch"); // subscribe to topic "switch"
 }
}

//----------------------------------------------

void loop()
{

// Listen for sensor interactions and take actions ----------------------------------------  
// Note: sensor actions do send MQTT message AND do set switch(x)Value to HIGH or LOW

 if (bouncer1.update()) {
   if (bouncer1.read() == HIGH) {
     if (switch1Value == LOW) {
       switch1Value = HIGH;
       client.publish("switch","1on"); 
     } else {
       switch1Value = LOW;
       client.publish("switch","1off");
     }
   }
 }  

//-----------------------------------------------
 
 if (bouncer2.update()) {
   if (bouncer2.read() == HIGH) {
     if (switch2Value == LOW) {
       switch2Value = HIGH;
       client.publish("switch","2on");
     } else {
       switch2Value = LOW;
       client.publish("switch","2off");
     }
   }
 }  
 
//------------------------------------------------  

 if (bouncer3.update()) {
   if (bouncer3.read() == HIGH) {
     if (switch3Value == LOW) {
       switch3Value = HIGH;
       client.publish("switch","3on");
     } else {
       switch3Value = LOW;
       client.publish("switch","3off");
     }
   }
 }  

//-----------------------------------------------
 
 if (bouncer4.update()) {
   if (bouncer4.read() == HIGH) {
     if (switch4Value == LOW) {
       switch4Value = HIGH;
       client.publish("switch","4on");
     } else {
       switch4Value = LOW;
       client.publish("switch","4off");
     }
   }
 }  
 
//------------------------------------------------  
 
 client.loop();
}

// End of sketch ---------------------------------

Sono riuscito a fare dei progressi.
Innanzi tutto ho testato il Bounce2 e funziona bene.

Lo sketch non mi da errori si conentte al broker e riesce a fare subscribe e publish.

Ho invece un problema nella parte con della condizione “if” subito dopo il “callback”

(qui sotto posto lo sketch e sotto ancora posto la parte dove ho problemi)

/*
 Example MQTT-switch-relay-node with 4 sensors and 4 switchs 
 
  - connects to an MQTT server
  - publishes "hello world" to the topic "switch"
  - subscribes to the topic "switch"
  - controls 4 switchs on pins 2,3,5 and 6 - switchs can be replaced with relays
  - reads 4 sensor on pins 7,8,9 and 10
  - turns on/off a specific switch when it receives a specific "on"/"off" from the "switch" topic
  - senses an HIGH/LOW on sensors and publishes a payload to the MQTT broker.
  - multiple arduino's with same generic sketch can run parallel to each other
  - multiple arduino's need each to have a unique ip-addres, unique mac address and unique MQTT client-ID

  - tested on arduino-uno with W5100 ethernet shield
  - Ethernet Shield W5100 uses pins 4,10,11,12,13
  - availbale digital pins: 1,2,3,5,6,7,8,9,10 
*/

//------------------------------------------------------------------------------

#include <SPI.h>
#include <Ethernet.h>
#include <PubSubClient.h>
#include <Bounce2.h>

// Set switch variables to Arduino digital pins
int switch1 = 2;
int switch2 = 3;
int switch3 = 5;                             // pin 4 used by ethernet shield
int switch4 = 6;


// Set sensor variables to Arduino digital pins
int sensor1 = 7;
int sensor2 = 8;
int sensor3 = 9;
int sensor4 = 10;                         // pins 11,12,13 used by ethernetshield

// Set variables to act as virtual switches

//---------------------------------------------------------------------------

// Arduino MAC address is on a sticker on your Ethernet shield
// must be unique for every node in same network
// To make a new unique address change last letter

byte mac[]    = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };  

// Unique static IP address of this Arduino - change to adapt to your network
IPAddress ip(192,168,1,7);
IPAddress gateway(192, 168, 1, 100);
IPAddress subnet(255, 255, 255, 0);

// IP Address of your MQTT broker - change to adapt to your network
byte server[] = { 192, 168, 1, 20 };

// Prototype function added
void callback(char* topic, byte* payload, unsigned int length);

// Start Ethernet and MQTT Server

EthernetClient ethClient;
PubSubClient client(server, 1883, callback, ethClient);


// Handle and convert incoming MQTT messages ----------------------------------------

void callback(char* topic, byte* payload, unsigned int length) {
  // handle message arrived
  String content="";
  char character;
  for (int num=0;num<length;num++) {
      character = payload[num];
      content.concat(character);
  }   
  Serial.println(topic);
  Serial.println(content); // message sent out by sensor actions is returned from broker and serial printed
  // client.publish("Test", "ON"); // message to test publishing on MQTT
  
// Set specific virtual switches on basis of specific incoming messages ----------------------------
  
  if (topic == "arduino/cmd/switch1") {
    if (content == "ON") {
     client.publish("arduino/stat/switch1", "ON");
     digitalWrite(switch1,HIGH);   // Set digital pin states according to virtual switch settings
    }
  }
  
  if (topic == "arduino/cmd/switch1") {
    if (content == "OFF") {
     client.publish("arduino/stat/switch1", "OFF");
     digitalWrite(switch1,LOW);   // Set digital pin states according to virtual switch settings
    }
  }
  
  if (topic == "arduino/cmd/switch2") {
    if (content == "ON") {
     client.publish("arduino/stat/switch2", "ON");
     digitalWrite(switch2,HIGH);   // Set digital pin states according to virtual switch settings
    }
  }
  
  if (topic == "arduino/cmd/switch2") {
    if (content == "OFF") {
     client.publish("arduino/stat/switch2", "OFF");
     digitalWrite(switch2,LOW);   // Set digital pin states according to virtual switch settings
    }
  }

   if (topic == "arduino/cmd/switch3") {
    if (content == "ON") {
     client.publish("arduino/stat/switch3", "ON");
     digitalWrite(switch2,HIGH);   // Set digital pin states according to virtual switch settings
    }
  }
  
  if (topic == "arduino/cmd/switch3") {
    if (content == "OFF") {
     client.publish("arduino/stat/switch3", "OFF");
     digitalWrite(switch2,LOW);   // Set digital pin states according to virtual switch settings
    }
  }
  
  if (topic == "arduino/cmd/switch4") {
    if (content == "ON") {
     client.publish("arduino/stat/switch4", "ON");
     digitalWrite(switch2,HIGH);   // Set digital pin states according to virtual switch settings
    }
  }
  
  if (topic == "arduino/cmd/switch4") {
    if (content == "OFF") {
     client.publish("arduino/stat/switch4", "OFF");
     digitalWrite(switch2,LOW);   // Set digital pin states according to virtual switch settings
    }
  }
}

// Initiate a bouncer instance for each sensor
Bounce bouncer1 = Bounce();
Bounce bouncer2 = Bounce();
Bounce bouncer3 = Bounce();
Bounce bouncer4 = Bounce();

//-------------------------------------------------------

void setup()

{

  // setup switch, sensor, bouncer 1 -----------------------
  pinMode(switch1, OUTPUT);
  pinMode(sensor1,INPUT);
  digitalWrite(sensor1,LOW);
  bouncer1 .attach(sensor1);
  bouncer1 .interval(25);

  // setup switch, sensor, bouncer 2 -----------------------
  pinMode(switch2, OUTPUT);
  pinMode(sensor2,INPUT);
  digitalWrite(sensor2,LOW);
  bouncer2 .attach(sensor2);
  bouncer2 .interval(25);

  // setup switch, sensor, bouncer 3 -----------------------
  pinMode(switch3, OUTPUT);
  pinMode(sensor3,INPUT);
  digitalWrite(sensor3,LOW);
  bouncer3 .attach(sensor3);
  bouncer3 .interval(25);

  // setup switch, sensor, bouncer 4 -----------------------
  pinMode(switch4, OUTPUT);
  pinMode(sensor4,INPUT);
  digitalWrite(sensor4,LOW);
  bouncer4 .attach(sensor4);
  bouncer4 .interval(25);

  // setup serial and ethernet communications -------------------------------

  // Setup serial connection
  Serial.begin(9600);

  // Setup ethernet connection to MQTT broker
  Ethernet.begin(mac);
  if (client.connect("arduino", "YYYY", "XXXX")) {                // change as desired - clientname must be unique for MQTT broker
    client.publish("arduino/","hello world - here arduino");
    Serial.println("connected");
    client.subscribe("arduino/#");                    // subscribe to topic "aruino/" list of topics
    } else {
    Serial.println("Not Connected");
  }
}

//----------------------------------------------

void loop()
{

// Listen for sensor interactions and take actions ----------------------------------------  
// Note: sensor actions do send MQTT message AND do set switch(x)Value to HIGH or LOW

  if (bouncer1.update()) {
    if (bouncer1.read() == HIGH) {
        client.publish("arduino/stat/sensor1","ON");                
        } else {
        client.publish("arduino/stat/sensor1","OFF");
    }
  }  

//-----------------------------------------------
  
  if (bouncer1.update()) {
    if (bouncer2.read() == HIGH) {
        client.publish("arduino/stat/sensor2","ON");                
        } else {
        client.publish("arduino/stat/sensor2","OFF");
    }
  }  
  
//------------------------------------------------  

  if (bouncer1.update()) {
    if (bouncer3.read() == HIGH) {
        client.publish("arduino/stat/sensor3","ON");                
        } else {
        client.publish("arduino/stat/sensor3","OFF");
    }
  }  

//-----------------------------------------------
  
  if (bouncer1.update()) {
    if (bouncer4.read() == HIGH) {
        client.publish("arduino/stat/sensor4","ON");                
        } else {
        client.publish("arduino/stat/sensor4","OFF");
    }
  }  
  
//------------------------------------------------  
  
  client.loop();
}

// End of sketch ---------------------------------
void callback(char* topic, byte* payload, unsigned int length) {
  // handle message arrived
  String content="";
  char character;
  for (int num=0;num<length;num++) {
      character = payload[num];
      content.concat(character);
  }   
  Serial.println(topic);
  Serial.println(content); // message sent out by sensor actions is returned from broker and serial printed

se pubblico sul topic “arduino/cmd/switch1” il payload “ON” con MQTT.fx, riesco a leggerli correttamente entrambi sulla seriale di arduino.

Questo vuol dire che le condizioni seguenti sono true,

if (topic == "arduino/cmd/switch1") {
    if (content == "ON") {
     client.publish("arduino/stat/switch1", "ON");
     digitalWrite(switch1,HIGH);   // Set digital pin states according to virtual switch settings
    }
  }

Mi aspetterei di vedere pubblicato “ON” sul topic “arduino/stat/switch1” del broker e il pin “switch1” andare HIGH.

Ma questo non succede.

Dove sta l’errore?

Ringrazio chiunque mi possa aiutare

Salve,

Non riesco proprio a risolvere questo problema.
Mi chiedevo se ci fosse qualcuno che mi possa dare una mano a capire perche' questo sketch non funziona bene.
Fatemi sapere se non sono stato chiaro e/o se devo fornire piu' informazioni o formularle in modo diverso.
Grazie.

Purtroppo non so quanti utenti siano utilizzatori di MQTT con Arduino ... potresti dover attendere parecchio ... :confused:

Guglielmo

Allora ho risolto cambiando la callback come segue:

void callback(char* topic, byte* payload, unsigned int length) {

  payload[length] = '\0'; // Null terminator used to terminate the char array
  String message = (char*)payload;
  String strTopic = String((char*)topic);
  client.publish("allarme/","online");

  Serial.println(strTopic);
  Serial.println(message); // message sent out by sensor actions is returned from broker and serial printed

Dopo questo cambiamento riesco a controllare i pin e a leggere i sensori sul broker MQTT e quindi da Home Assistant.

Direi che il problema e' risolto.