Domotica con arduino.

Salve, vorrei condividere con tutti voi il progetto realizzato a casa mia. Sono assiduo lettore di questo forum, oramai è da 5 anni che uso arduino, anche per la realizzazione di progetti impegnativi: robot radiocomandato tagliaerba, contagiri, strumenti particolari per la nautica,ecc.
In totale ho una ventina di arduino pro mini installati in tutta casa, alcuni comandano relè altri dei pulsanti touch (anche loro creati da me). Ho più di 100 metri lineari di rete rs485 che corre per tutta la casa. Come libreria ho utilizzato la mitica RS485 non blocking di Gammon. Il protocollo (creato da me) è semplicissimo ma molto robusto, ogni volta che premo un pulsante invio in rete 2 byte (comando+stato); tutti gli arduino in rete sono sempre in ascolto, appena ricevono un comando da loro gestibile lo eseguono e si rimettono subito in ascolto. Questa in linea di massima il funzionamento.
Tutto questo per chi fosse interessato a confronti, idee, miglioramenti o aiuto in genere.
Grazie ancora a tutto il forum.

io posso solo farti i complimenti

io idem ( i complimenti )

E se ti va' di pubblicare il progetto completo, qui ne faresti felici molti

Grazie ragazzi. Ho 20 diversi scketch, ovviamente ogni arduino ha il suo anche se di base sono tutti uguali (a parte quello che gestisce anche il modulo bluetooth che interpreta tutti i comandi proveniente dallo smartphone). La particolarità della mia rete è che non c'è un master e svariati slave, ma ogni arduino al momento opportuno (appena sfioro un pulsante per esempio) occupa il bus e invia il comando ovviamente prima controlla che non ci siano altri arduini già in trasmissione. :wink:

Quello che segue è l'arduino a cui è attaccato il modulo bluetooth (su seriale hardware perche la seriale software già la uso per l'rs485) e inoltre sono attaccati 2 pulsianti touch che mi comandano in remoto su un'altra scheda 2 relay per le luci della cucina (led strip e plafoniera centrale).

// CucinaDisimpegno comanda 2 relè tramite comandi remoti. cucinacentrale msg=2  cucinastrip msg=1


#include <RS485_non_blocking.h>
#include <SoftwareSerial.h>

SoftwareSerial rs485 (9, 6);

size_t fWrite (const byte what)
{
  return rs485.write (what);
}
int fAvailable ()
{
  return rs485.available ();
}

int fRead ()
{
  return rs485.read ();
}

RS485 myChannel (fRead, fAvailable, fWrite, 2);


const int pincucinacentrale = 2;
const int pincucinastrip = 4;
const int buttonPin1 = 14; //comando luce cucinacentrale A0
const int buttonPin2 = 15; //comando luce cucinastrip A1
const int ledPin = 5;   //luce cucinacentrale led
const int ledPin2 = 3;   //luce cucinastrip led
byte value1, value2 ;
int periode1 = 4000;
byte molt1 = 127;
int periode2 = 4000;
int debounceDelay1 = 300;
int debounceDelay2 = 300;
byte molt2 = 127;
boolean cucinacentrale = LOW, cucinastrip = LOW, invia1, invia2 = LOW,
lastButtonState1 = LOW, buttonState1, blocca1 = LOW,
lastButtonState2 = LOW, buttonState2, blocca2 = LOW, errore;
unsigned int time, lastDebounceTime1, lastDebounceTime2;
void setup()
{
  rs485.begin (28800);
  Serial.begin(9600);
   pinMode(7, OUTPUT);//comando invio
  pinMode(8, OUTPUT);//comando invio
  pinMode(pincucinacentrale, OUTPUT); //cucinacentrale
  pinMode(pincucinastrip, OUTPUT);//cucinastrip
  pinMode(ledPin, OUTPUT); //led
  pinMode(ledPin2, OUTPUT);//led
  pinMode(buttonPin1, INPUT);
  pinMode(buttonPin2, INPUT);
  myChannel.begin ();
}

void loop() {
  time=millis();
  if (Serial.available() > 2 || errore){
    errore=1;
    byte a = Serial.read();
  }
  if (Serial.available() ==0) errore=0;  
  if (Serial.available() == 2 and !errore) {
    byte msg [2];
    msg[0] = Serial.read();
    msg[1] = Serial.read();
    if (msg[0] == 2) {
      if (msg[1] == 0) {
        cucinacentrale = 0;  //stato cucinacentrale
      }
      if (msg[1] == 1) {
        cucinacentrale = 1;
      }
    }
    if (msg[0] == 1) {
      if (msg[1] == 0) {
        cucinastrip = 0;  //stato cucinastrip
      }
      if (msg[1] == 1) {
        cucinastrip = 1;
      }
    }
    errore=0;
    digitalWrite(7, HIGH);
    digitalWrite(8, HIGH);
    myChannel.sendMsg (msg, 2);
    digitalWrite(7, LOW);
    digitalWrite(8, LOW);
    if (msg[1]!=255){
      Serial.print(msg[0],HEX);
      Serial.print(msg[1],HEX);
    }
  }
  if (myChannel.update ())
  {
    byte msg [2];
    memcpy (msg, myChannel.getData (), 2);
      if (msg[1]!=255){
      Serial.print(msg[0],HEX);
      Serial.print(msg[1],HEX);
      }
    myChannel.reset ();
    if (msg[0] == 2) {
      if (msg[1] == 0) {
        cucinacentrale = 0;  //stato cucinacentrale
      }
      if (msg[1] == 1) {
        cucinacentrale = 1;
      }
    }
    if (msg[0] == 1) {
      if (msg[1] == 0) {
        cucinastrip = 0;  //stato cucinastrip
      }
      if (msg[1] == 1) {
        cucinastrip = 1;
      }
    }
  }

  int reading1 = digitalRead(buttonPin1);
  int reading2 = digitalRead(buttonPin2);


  if (reading1 != lastButtonState1) {
    lastDebounceTime1 = time;
    blocca1 = 0;
  }

  if ((time - lastDebounceTime1) > debounceDelay1) {
    if (reading1 != buttonState1) {
      buttonState1 = reading1;
      if (buttonState1 == LOW) {
        cucinacentrale = !cucinacentrale;
        blocca1 = 1;
        invia1 = 1;
      }
    }
  }

  lastButtonState1 = reading1;

  if (cucinacentrale) {
    periode1 = 1;
    molt1 = 127;
    if (reading1 == 0 && !blocca1) {
      periode1 = 100;
      molt1 = 127;
    }
  }

  if (!cucinacentrale) {
    periode1 = 4000;
    molt1 = 16;
    if (reading1 == 0 && !blocca1) {
      periode1 = 100;
      molt1 = 127;
    }
  }


  if (reading2 != lastButtonState2) {
    lastDebounceTime2 = time;
    blocca2 = 0;
  }

  if ((time - lastDebounceTime2) > debounceDelay2) {
    if (reading2 != buttonState2) {
      buttonState2 = reading2;
      if (buttonState2 == LOW) {
        cucinastrip = !cucinastrip;
        blocca2 = 1;
        invia2 = 1;
      }
    }
  }

  lastButtonState2 = reading2;

  if (cucinastrip) {
    periode2 = 1;
    molt2 = 127;
    if (reading2 == 0 && !blocca2) {
      periode2 = 100;
      molt2 = 127;
    }
  }

  if (!cucinastrip) {
    periode2 = 4000;
    molt2 = 16;
    if (reading2 == 0 && !blocca2) {
      periode2 = 100;
      molt2 = 127;
    }
  }

  value1 = molt1 + (molt1 - 1) * cos(2 * PI / periode1 * time);
  value2 = molt2 + (molt2 - 1) * cos(2 * PI / periode2 * time);

  analogWrite(ledPin, value1); //Lampeggio led 
  analogWrite(ledPin2, value2); //Lampeggio led 

  if (invia1 && !myChannel.isPacketStarted ()) { //invia messaggio stato cucinacentrale
    byte msg [2];
    msg[0] = 2;
    msg[1] = cucinacentrale;
    digitalWrite(7, HIGH);
    digitalWrite(8, HIGH);
    myChannel.sendMsg (msg, 2);
    Serial.print(msg[0],HEX);
    Serial.print(msg[1],HEX);
    digitalWrite(7, LOW);
    digitalWrite(8, LOW);
    invia1 = 0;
  }

  if (invia2 && !myChannel.isPacketStarted ()) { //invia messaggio stato cucinastrip
    byte msg [2];
    msg[0] = 1;
    msg[1] = cucinastrip;
    digitalWrite(7, HIGH);
    digitalWrite(8, HIGH);
    myChannel.sendMsg (msg, 2);
    Serial.print(msg[0],HEX);
    Serial.print(msg[1],HEX);
    digitalWrite(7, LOW);
    digitalWrite(8, LOW);
    invia2 = 0;
  }

}

La libreria che usi è questa?
--> Gammon Forum : Electronics : Microprocessors : RS485 communications

La variabili che gestiscono i millis è meglio dichiararle come unsigned long e non come unsigned int.

Sì la libreria è proprio quella, la versione non blocking. Perché dovrei usare delle Long? La variabile time mi gestisce il fading dei led attaccati ai pulsanti, come vedi calcolo il seno di time e periodo per avere un fade visivamente gradevole, usando la Long dopo 1 giorno quel calcolo diventava mostruosamente lento e mi dava problemi sia alla ricezione dei dati che al fade. Usando un semplice int dopo un minuto e qualche secondo quella variabile si azzera automaticamente e ho risolto alla grande il problema dei rallentamenti. Ci ho sbattuto la testa 3 mesi per capire da dove venisse il problema. Più tardi pubblico un video per mostrarvi visivamente l'effetto che fa.

Solo per una questione di reset della variabile. Ma se è voluto, va bene.

Ecco il video Luci touch arduino - YouTube

mi piacerebbe usare Arduino per creare un dispositivo KNX (conosci la tecnologia?). Credo che tu sia già ad un buon 90% della strada!

gian_marco:
mi piacerebbe usare Arduino per creare un dispositivo KNX (conosci la tecnologia?). Credo che tu sia già ad un buon 90% della strada!

Non conoscevo la tecnologia, mi sono documentato superficialmente. Più o meno il mio progetto riprende un po tutto del knx. La parte cablata è stata implementata tramite rs485, molto robusto ed immune ai rumori visto che usa un segnale differenziale. Vengo dal mondo del Plc ed adesso lavoro prevalentemente con la nautica. La mia rete, oltre a essere interfacciata tramite bluetooth è accessibile da internet grazie ad un modulo wifi. Ho anche installato un lettore di badge rfid per l'accensione delle luci scale e apertura portoncino di ingresso, sensore gpl metano, vari sensori pir, led strip pilotate in pwm, e poi la chicca delle chicche.....un display da 2 pollici oled che mi visualizza il consumo istantaneo tramite lettura dei lampeggiante del contatore enel, tutto questo lo ho fatto perché ho un contratto da 3kw e ho installato un piano a induzione per cucinare.

Ottimo progetto.
Puoi indicare come hai gestito l'alimentazione dei moduli ?
Che interfaccia e con che cavo hai gestito il protocollo 485 ?

Come accennavo all'inizio, ho circa 100mt lineari di cavo (cavo tipo allarme con all'interno 2 conduttori con sezione maggiore utilizzati per i 5v e 4 fili più sottili utilizzati per la rete più calza schermo). Alimento il tutto tramite uno switching 230V/5V da 5 ampere. Il cavo è tipo questo
L'interfaccia hardware rs485 è tipo questa:
ho rimosso le resistenze R7 da 120ohm su tutti i moduli eccetto i 2 di testa. Considera che la mia rete viaggia nelle stesse canalette dei cavi a 230v in un lungo tratto da 10mt mi dava qualche distrubo causato dal piano a induzione ho risolto aggiungendo una resistenza da 100ohm in parallelo ai morsetti A e B dell'interfaccia che si trova più o meno a metà rete. Piu avanti penso di rimuovere anche il piccolo led rosso solo per una questione estetica (la lucina rossa filtra tra gli spazi dei pulsanti).

Update....ho installato anche un arduino mini dentro al citofono, adesso riesco anche ad aprire il portoncino tramite badge rfid.

Ma sei proprio un mito ! :smiley:
E' un po' la mania di noi smanettatori avere la casa più o meno domotica, quindi ti faccio i miei complimenti.

Ho visto che vieni dal mondo PLC come me (uso Mitsubishi FX e per piccole cosine uso gli AlfaXL) e con Arduino Nano io ci ho fatto il mio PLC personale che ora uso in sostituzione dell'Alfa Mitsubishi. Almeno il mio display 20x4 è più leggibile del misero 16x4 grande la metà. Poi con I2C faccio un po' di tutto.

Complimenti ancora!

steve-cr:
Ma sei proprio un mito ! :smiley:
E' un po' la mania di noi smanettatori avere la casa più o meno domotica, quindi ti faccio i miei complimenti.

Ho visto che vieni dal mondo PLC come me (uso Mitsubishi FX e per piccole cosine uso gli AlfaXL) e con Arduino Nano io ci ho fatto il mio PLC personale che ora uso in sostituzione dell'Alfa Mitsubishi. Almeno il mio display 20x4 è più leggibile del misero 16x4 grande la metà. Poi con I2C faccio un po' di tutto.

Complimenti ancora!

Grazie. Si ho lavorato con i Siemens principalmente. Ancora devo completare il sistema di allarme e il display che mi visualizza in real time i watt consumati.

Ti faccio i miei complimenti , mi iscrivo.

Io lo sto progettando e sto facendo delle prove, per iniziare voglio mettere solo sensori di temperatura e umidità per ogni stanza, inoltre dovrei sentire la bussata della porta , del citofono poi i consumi di corrente con i moduli quelli non invasivi a pinza amperometrica per interderci, controllo rack server presente in garage con sensori di temperatura , allagamento, fuoco , mancanza corrente (con invio sms e email).
Il tutto gestibile con un pannello tft sempre con arduino per le visualizzazioni e l'abilitazione del router wifi,
a me non piace avere il wireless attivato 24/24,
Per il salvataggio dati per le statistiche potrei o utilizzare quelli online tipo xively, oppure tenermeli io ho nel server principale o nel raspberry che già utilizzo come centralino voip .

Utilizzo lo stesso protocollo di Gammon quello normale, penso che utilizzerò il non blocking ed anche i stessi moduli rs485 .

Per ora intenzionalmente e per ovvie ragioni NON utilizzerò la 220v per accendere lampade ecc., sarà tutto a bassa tensione e con controlli di assorbimento.

Mi unisco ai complimenti.
Realizzare quello che tu hai fatto sarebbe il mio sogno

pines:
Ti faccio i miei complimenti , mi iscrivo.

Io lo sto progettando e sto facendo delle prove, per iniziare voglio mettere solo sensori di temperatura e umidità per ogni stanza, inoltre dovrei sentire la bussata della porta , del citofono poi i consumi di corrente con i moduli quelli non invasivi a pinza amperometrica per interderci, controllo rack server presente in garage con sensori di temperatura , allagamento, fuoco , mancanza corrente (con invio sms e email).
Il tutto gestibile con un pannello tft sempre con arduino per le visualizzazioni e l'abilitazione del router wifi,
a me non piace avere il wireless attivato 24/24,
Per il salvataggio dati per le statistiche potrei o utilizzare quelli online tipo xively, oppure tenermeli io ho nel server principale o nel raspberry che già utilizzo come centralino voip .

Utilizzo lo stesso protocollo di Gammon quello normale, penso che utilizzerò il non blocking ed anche i stessi moduli rs485 .

Per ora intenzionalmente e per ovvie ragioni NON utilizzerò la 220v per accendere lampade ecc., sarà tutto a bassa tensione e con controlli di assorbimento.

Grazie per i complimenti. Oramai sono a quasi l'80% del lavoro totale, anche se ogni giorno mi vengono nuove idee da implementare. Quello che posso consigliarti è di usare la versione non blocking della libreria e soprattutto di crearti un protocollo ultra semplice. La mia scelta è ricaduta su una versione senza master, tutti possono ascoltare e tutti possono trasmettere al momento opportuno. L'unica accortezza è stare attenti che non ci siano altre trasmissioni in corso mentre tenti di trasmettere. Non ho implementato ack o robe del genere. Fino ad oggi non sgarra di un colpo e non ho avuto collisioni. Domani metterò sù il sensore lampeggi contatore, anche lui connesso in rete. Il display sarà piazzato in casa al secondo piano. Ho scelto di trasmettere 3byte ad ogni lampeggio o comunque al massimo ogni 2 secondi anche se il lampeggio non è avvenuto. Quando gli assorbimenti saranno al massimo (4kWh) avrò più di un lampeggio al secondo, quindi il bus sarà abbastanza occupato (anche se trasmetto a 28.800bps). Questa sarà la vera prova del nove della mia rete.

Per la rilevazione dei consumi non ho scelto quella del sensore di lampeggio solo perchè sono in condominio ed il contatore o meglio i contatori stanno tutti insieme, certo se lo avevo in casa allora optavo per il sensore di lampeggio .
Debbo fare ancora delle prove con il sensore non invasivo SCT-013-030 è fino a 30A poi cè anche SCT-013-000 che arriva max a 100A certamente hanno una % di errore ma da quello che ho letto chi li usa sono abbastanza affidabili .

Per il protocollo io invece stavo optando per il master/slave penso che sia più preciso. Mi spiego ho intenzione di mandare un comando con il master per la sincronizzazione degli slave, cioè quando gli arriva il comando di sincronismo i contatore degli slave partono da 0 e sanno che ogni 60 secondi saranno interrogati.
Il problema può nascere ad esempio se suona il campanello che lo slave deve informare il master che il campanello è stato pigiato , pero gli slave lo sanno grazie al contatore quando saranno interrogati, un ulteriore problema potrebbe essere se più di uno slave devono comunicare qualcosa che non sia ciclico, allora o si cerca di avere solo 1 slave raggruppa questa esigenza oppure si fa una ulteriore temporizzazione di slave.
Devo sperimentare una temporizzazione di slave in base anche al numero che ho. Mi spiego .
Avendo 5 slave e mettendo una temporizzazione di 200ms posso interrogarli 1 volta al secondo il che è ottimo nel mio caso, poi naturalmente il master deve prendersi il suo tempo per fare le scritture,
penso di metterne :
1 mega master con Shield TFT , Ethernet e GSM
1 nano slave per consumi corrente e rilevamento bussata citofono e porta inserito nel quadro elettrico con scatoletta din
1 mega slave per rack server
1 (forse 2) nano slave per sensori vari (temperature , umidità , luce , rumori)
1 nano slave per monitoraggio antifurto
1 nano per stazione meteo esterna e sensore di pioggia .
1 mega o nano come master di riserva o supplementare (in fase di studio) magari lui riceve solo e scrive i dati su server locale o remoto

Il problema è il mega master che ha lo shield gsm che utilizza la softserial la stessa che usa la rs485 quindi va in conflitto , ho fatto qualche prova ma debbo approfondire meglio.
Il master alimenta tutti gli slave con rele o un transistor polarizzato opportunamente, cosi da resettarlo se non ottiene risposte dallo slave e segnalarlo sul TFT.
Con il gsm posso tranquillamente pilotare o sapere lo stato di sensori con un sms .

Tienici informato ...

allego schema

Io ho optato per la software serial riguardo all'RS485, così ho la seriale hardware disponibile per il debug o per attaccarsi hc05 oppure la seriale wireless. Io ho circa 20 arduini pro mini, mi sarebbe stato molto complicato gestirli tutti attraverso un master pertanto ho optato per la soluzione senza master.
Complimenti anche a te, bellissimo progetto.