Progetto Domotica Parte Gestione Luci

Ciao a tutti
mi chiamo Andrea
e sto tentando di fare un progetto per la domotica della mia casa che sto ristuttrurando, sfruttando uno o più arduini.
Al momento sono alle prese con la gestione luci, il mio impianto è gestito da dei pulsanti che comandano dei RELE passo passo con 2 uscite (2 NO) ad una è collegata l'utenza (Lampade di illuminazione + una spia di segnalazione a 220V) ed il secondo contatto lo utilizzo per far capire all'arduino lo stato del Rele passo passo (collego il +5VDC che va ad una resistenza all'ingresso del INPUT dell'arduino).
il mio scopo per ora è far si che il sistema dopo aver premuto un tasto che chiamo ALLOFF deve spegnere solo le luci attualmente accese.
in pratica leggo tutti gli stati del rele passo passo li do in pasto all'arduino e se premo il tasto ALLOFF allora attiva dei rele in parallelo alla bombina del passo passo per far si che cambi di stato
ho compilato il codice e funziona ma se accendo e a caso le luci per fare delle prove tipo 2 assieme e poi una subito dopo l'arduino impazzisce e comanda a caso qualche rele.
qualcuno sa darmi qualche dritta al riguardo?
di seguito posto il mio codice spero sia comprensibile, lo so mi sarò complicato sicuramente la vita ma non sono un genio in programmaziona anzi...

#define OCORR 22          // LUCE CORRIDIO collegato al pin digitale 22
#define OCUCINA 24
#define OSALA 26
#define OBAGNOP 28
#define OBAGNOG 30
#define OCBIMBO 32
#define OCSTUDIO 34
#define OCMATR 36
#define OBALCONE 38
#define ALLOFF 7        //INPUT all off
#define ICORR 23          //INPUT di stato
#define ICUCINA 25
#define ISALA 27
#define IBAGNOP 29
#define IBAGNOG 31
#define ICBIMBO 33
#define ICSTUDIO 35
#define ICMATR 37
#define IBALCONE 39

int  valalloff = 0;          // conservo i valori  
int SCORR = 0;
int SCUCINA = 0;
int SSALA = 0;
int SBAGNOP = 0;
int SBAGNOG = 0;
int SCBIMBO = 0;
int SCSTUDIO = 0;
int SCMATR = 0;
int SBALCONE = 0;
  
void setup() {

  Serial.begin(9600);
  pinMode(OCORR, OUTPUT);       // impostazioni pin in-out
  pinMode(OCUCINA, OUTPUT);
  pinMode(OSALA, OUTPUT);
  pinMode(OBAGNOP, OUTPUT);
  pinMode(OBAGNOG, OUTPUT);
  pinMode(OCBIMBO, OUTPUT);
  pinMode(OCSTUDIO, OUTPUT);
  pinMode(OCMATR, OUTPUT);
  pinMode(OBALCONE, OUTPUT);
  pinMode(ALLOFF, INPUT);
  pinMode(ICORR, INPUT);
  pinMode(ICUCINA, INPUT);
  pinMode(ISALA, INPUT);
  pinMode(ICBIMBO, INPUT);
  pinMode(IBAGNOP, INPUT);
  pinMode(IBAGNOG, INPUT);
  pinMode(ICSTUDIO, INPUT);
  pinMode(ICMATR, INPUT);
  pinMode(IBALCONE, INPUT);
  
  
  digitalWrite(OCORR, HIGH);
  digitalWrite(OCUCINA,HIGH);
  digitalWrite(OSALA,HIGH);
  digitalWrite(OBAGNOG,HIGH);
  digitalWrite(OBAGNOP,HIGH);
  digitalWrite(OCBIMBO,HIGH);
  digitalWrite(OCSTUDIO,HIGH);
  digitalWrite(OCMATR,HIGH);
  digitalWrite(OBALCONE,HIGH);
  

  
}  
  
void loop() {  
  valalloff = digitalRead(ALLOFF);  // legge il valore dell'input e lo conserva  
  SCORR  = digitalRead(ICORR);
  SCUCINA = digitalRead(ICUCINA);
  SSALA = digitalRead(ISALA);
  SBAGNOP = digitalRead(IBAGNOP);
  SBAGNOG = digitalRead(IBAGNOG);
  SCBIMBO = digitalRead(ICBIMBO);
  SCSTUDIO = digitalRead(ICSTUDIO);
  SCMATR = digitalRead(ICMATR);
  SBALCONE = digitalRead(IBALCONE);

     
     
  // controlla che l'input ALL OFF sia HIGH (pulsante premuto)  
  if (valalloff == HIGH) {  
    delay(100);    
    if (SCORR == HIGH) { 
    digitalWrite(OCORR, LOW);  
    delay(300);
    digitalWrite(OCORR, HIGH);
    delay(100);
    Serial.println("Luce Corridoio");
    }
        if (SCUCINA == HIGH) { 
    delay(100);
    digitalWrite(OCUCINA, LOW);  
    delay(300);
    digitalWrite(OCUCINA, HIGH);
    Serial.println("Luce Cucina");
    delay(100);
    }
        if (SSALA == HIGH) { 
          delay(100);
    digitalWrite(OSALA, LOW);  
    delay(300);
    digitalWrite(OSALA, HIGH);
    Serial.println("Luce Sala");
    delay(100);
    }
        if (SBAGNOP == HIGH) { 
          delay(100);
    digitalWrite(OBAGNOP, LOW);  
    delay(300);
    digitalWrite(OBAGNOP, HIGH);
    Serial.println("Luce Bagno Piccolo");
    delay(100);
    }
        if (SBAGNOG == HIGH) { 
          delay(100);
    digitalWrite(OBAGNOG, LOW);  
    delay(300);
    digitalWrite(OBAGNOG, HIGH);
    Serial.println("Luce Bagno Grande");
    delay(100);
    }
        if (SCBIMBO == HIGH) { 
          delay(100);
    digitalWrite(OCBIMBO, LOW);  
    delay(300);
    digitalWrite(OCBIMBO, HIGH);
    Serial.println("Luce Camera Bambino");
    delay(100);
    }
         if (SCSTUDIO == HIGH) { 
           delay(100);
    digitalWrite(OCSTUDIO, LOW);  
    delay(500);
    digitalWrite(OCSTUDIO, HIGH);
    Serial.println("Luce Studio");
    delay(200);
    }
        if (SCMATR == HIGH) { 
    digitalWrite(OCMATR, LOW);  
    delay(500);
    digitalWrite(OCMATR, HIGH);
    Serial.println("Luce Camera Matrimoniale");
    delay(200);
    }
        if (SBALCONE == HIGH) { 
          delay(100);
    digitalWrite(OBALCONE, LOW);  
    delay(500);
    digitalWrite(OBALCONE, HIGH);
    Serial.println("Luce Balcone");
    delay(200);
    }
  }  
   
}

Il programma non l'ho guardato, perchè scusami se te lo dico ma andrebbe rivisto un po' :slight_smile: :slight_smile:
Comunque non è un problema di software, ma di hardware ti sei risposto da solo

ho compilato il codice e funziona ma se accendo a caso le luci per fare delle prove tipo 2 assieme e poi una subito dopo l'arduino impazzisce e comanda a caso qualche rele.

Potenza inufficiente di alimentazione arduino o disturbi sulla rete, cerca bene su google e troverai molti argomenti. Manca principalmente un debug per vedere cosa accade, questo è il primo aiuto che ti può dare il micro stesso.

ciao

Ps: Non cercate di imparare ad usare arduino nei due mesi di ristrutturazione, cercate di incominciare molto prima, per fare una cosa seria ed efficiente ci vuole almeno un anno di studio, letture e prove.
Io dopo 9 anni che uso i micro imparo ancora trucchi SW e HD tutti i giorni.

ma se accendo e a caso le luci per fare delle prove tipo 2 assieme e poi una subito dopo l'arduino impazzisce e comanda a caso qualche rele

Direi cablaggio che capta disturbi più mancanza di debounching (hardware e/o software) sugli ingressi.

Come minimo una volta trovato ALLOFF alto bisogna aspettare un 40..80 millisecondi e controllare se è ancora alto, altrimenti ignorare il falso comando.

In realtà questa operazione sarebbe da fare per tutti gli ingressi, potrebbe anche essere che il solo debounching software "risolva" il malfunzionamento mascherando i disturbi introdotti dal cablaggio (che se ci fossero resterebbero comunque tali).

Bisognerebbe quindi vedere esattamente come quei contatti di sense sono collegati agli ingressi, ad esempio se la resistenza di pull-up è troppo alta. Il minimo sindacale per leggere un contatto remoto senza usare fotoaccoppiatori è qualcosa come questo (che però ancora non protegge da disturbi "captati" dalla massa):

Sarebbe interessante provare separatamente entrambe le cose (debounch software e filtro hardware) per vedere quale da i risultati migliori... e poi usarle assieme :wink:

Grazie mille per le info inizierò a vedere come migliorare il codice ed ad assemblare l'Hardware e vediamo che ne esce.

Ciao a tutti
Prendendo spunto dai vostri consigli ho guardato sul web i possibili modi per implementare l antirimbalzo sia software che hardware ed ho visto diverse strade.
Parlando di hardware la soluzione semplice è quella che mi avete disegnato sopra ma secondo la vostra esperienza quale sarebbe il metodo migliore?( Se si parla di saldare non ho aalcuna difficolta )Avreste voglia di mettere giù un ipotetico schema di un singolo ingresso?
Al momento io uso solo il sistema pull-down con solo 2 resistenza.
Sono disposto ad aggiungere sia integrato che altre cose accetto consigli.
Per il software ho molta più difficoltà come avete visto la mia esperienza è molto maolro bassa, ho visto che vi sono possibilità di usare funzioni, ritardi o addirittura librerie voi cosa userete?
Mi servirebbe un modo semplice ma efficace magari se avete modo di mettere giù un esempio sarebbe il top.
Ci ringrazio in anticipo per le info e la disponibilità

Esempio software con processi a stati finiti che controlla pulsante ialloff e le luci cucina e sala secondo la tua logica. Per ogni altro punto luce basta aggiungere le due righe nel mainloop e la variabile struttura di tipo 'unita_t' con i cinque byte dati all'inizio del programma (...è più facile rispondere a domande specifiche che spiegare da zero :cold_sweat: ):

#define IALLOFF 7
#define ISALA 27
#define ICUCINA 25
#define OSALA 26
#define OCUCINA 24
#define TRESOLUTION 15     // risoluzione temporale mainloop
//-----------------------------------------------------------------------------

typedef struct {
    uint8_t  stato;         // stato ingresso filtrato
    uint8_t  i_stat;        // stato debouncher
    uint8_t  i_count;       // contatore debouncher
    uint8_t  o_stat;        // stato controllo output
    uint8_t  o_count;       // contatore controllo output
} unita_t;


unita_t palloff = {LOW, 0, 0, 0, 0};
unita_t cucina = {LOW, 0, 0, 0, 0};
unita_t sala = {LOW, 0, 0, 0, 0};


uint16_t timeloop;          // contatore base tempi programma
//-----------------------------------------------------------------------------
void setup()
{
    pinMode(IALLOFF, INPUT);

    pinMode(ICUCINA, INPUT);
    pinMode(OCUCINA, OUTPUT);
    digitalWrite(OCUCINA, HIGH);

    pinMode(ISALA, INPUT);
    pinMode(OSALA, OUTPUT);
    digitalWrite(OSALA, HIGH);

    timeloop = millis();
}  
//-----------------------------------------------------------------------------
// Processo debounch ingresso 'in'
//-----------------------------------------------------------------------------
uint8_t debounch(uint8_t in, ::unita_t* unita)
{
    uint8_t rd = digitalRead(in);
    switch (unita->i_stat)
    {
        case 0: // stato low, attesa ingresso high
            if (rd == HIGH)
                { unita->i_stat = 1; unita->i_count = 60 / TRESOLUTION; }
            break;

        case 1: // stato low, conteggio tempo high
            if (rd == LOW)
                { unita->i_stat = 0; break; }
            unita->i_count -= 1;
            if (unita->i_count == 0)
                { unita->i_stat = 2; unita->stato = HIGH; }
            break;

        case 2: // stato high, attesa ingresso low
            if (rd == LOW)
                { unita->i_stat = 3; unita->i_count = 60 / TRESOLUTION; }
            break;

        case 3: // stato high, conteggio tempo low
            if (rd == HIGH)
                { unita->i_stat = 2; break; }
            unita->i_count -= 1;
            if (unita->i_count == 0)
                { unita->i_stat = 0; unita->stato = LOW; }
    }
}
//-----------------------------------------------------------------------------
// Processo comando uscita 'out' con tempi t1 t2 t3
//-----------------------------------------------------------------------------
void gest_out(uint8_t out, ::unita_t* unita, uint8_t t1, uint8_t t2, uint8_t t3)
{
    switch (unita->o_stat)
    {
        case 0: // attesa comando spegnimento (uscita HIGH)
            if (palloff.stato == HIGH  &&  unita->stato == HIGH)
            {
                unita->o_stat = 1; 
                unita->o_count = t1 / TRESOLUTION;
            }
            break;

        case 1: // conteggio tempo t1 (uscita HIGH)
            unita->o_count -= 1;
            if (unita->o_count == 0)
            {
                unita->o_stat = 2; 
                digitalWrite(out, LOW); 
                unita->o_count = t2 / TRESOLUTION; 
            }
            break;

        case 2: // conteggio tempo t2 (uscita LOW)
            unita->o_count -= 1;
            if (unita->o_count == 0)
            {
                unita->o_stat = 3; 
                digitalWrite(out, HIGH); 
                unita->o_count = t3 / TRESOLUTION;
            }
            break;

        case 3: // conteggio tempo t3 (uscita HIGH)
            unita->o_count -= 1;
            if (unita->o_count == 0)
                unita->o_stat = 0;
    }
}
//-----------------------------------------------------------------------------
void loop()
{ 
    if (millis() - timeloop >= TRESOLUTION)
    {
        timeloop += TRESOLUTION;

        // operazioni eseguite ogni TRESOLUTION millisecondi
        debounch(IALLOFF, &palloff);
        debounch(ICUCINA, &cucina);
        debounch(ISALA, &sala);
        gest_out(OCUCINA, &cucina, 105, 300, 105);
        gest_out(OSALA, &sala, 105, 300, 105);
    }
}
//-----------------------------------------------------------------------------

Per quanto riguarda l'hardware il "meglio" è sempre l'optoisolato.