Riprogrammare sonoff con arduino.

Salve a tutti. Vorrei riprogrammare un dispositivo sonoff a 4 canali come il seguente:

Sonoff

A questo punto, ho scritto un nuovo firmware che posto di seguito:

#include <ESP8266WiFi.h>
#include <Wire.h> 


const char* ssid     = "MLDA";
const char* password = "ddddddd";

//rele
const int relayD1 = 12;
const int relayD2 = 5;
const int relayD3 = 4;
const int relayD4 = 15;
//switch button
const int switch4 = 14;
const int switch3 = 10;
const int switch2 = 9;
const int switch1 = 0;

//tipo di button
const int tipoSwitch1 = 1; //rele
const int tipoSwitch2 = 0; //interruttore
const int tipoSwitch3 = 0; //interruttore
const int tipoSwitch4 = 0; //interruttore
//stato button
int stateSwitch1 = 0;
int stateSwitch2 = 0;
int stateSwitch3 = 0;
int stateSwitch4 = 0;

//led segnale wifi
int gpio_13_led = 13;
// Set web server port number to 80
WiFiServer server(80);
// Variable to store the HTTP request
String header;
//STATO RELE
int SPENTO = 0;
int ACCESO = 1;

void setup() {

  Serial.begin(115200);
  pinMode(gpio_13_led, OUTPUT);
  delay(200);  
  digitalWrite(gpio_13_led, ACCESO);
  delay(2000);  
  
  ConnectWiFi();
  
  delay(2000);  
  
  pinMode(relayD1, OUTPUT);
  pinMode(relayD2, OUTPUT);
  pinMode(relayD3, OUTPUT);  
  pinMode(relayD4, OUTPUT);

  pinMode(switch4, INPUT);
  pinMode(switch3, INPUT);
  pinMode(switch2, INPUT);
  //pinMode(switch1, INPUT);
  
  digitalWrite(relayD1, SPENTO);
  delay(100);
  digitalWrite(relayD2, SPENTO);
  delay(100);
  digitalWrite(relayD3, SPENTO);
  delay(100);
  digitalWrite(relayD4, SPENTO);
  delay(100);

  Serial.println("Setup PIN terminato");
  delay(200);

  digitalWrite(gpio_13_led, SPENTO);
  delay(200);  
  delay(1000);
 
  Serial.println(WiFi.localIP());
  server.begin();
}

void loop(){
  delay(100);
  if(digitalRead(switch4) == LOW){
     if(tipoSwitch4 == 1){
    //  Serial.println("ATTIVO RELE");
      activateRele(relayD4);
      delay(300);
    }else if(tipoSwitch4 == 0){
	  activateSwitch(relayD4,&stateSwitch4);
      delay(300);
    }
  }

  if(digitalRead(switch3) == LOW){
     if(tipoSwitch3 == 1){
      //Serial.println("ATTIVO RELE");
      activateRele(relayD3);
      delay(300);
    }else if(tipoSwitch3 == 0){
      activateSwitch(relayD3,&stateSwitch3);
      delay(300);
    }
  }

  if(digitalRead(switch2) == LOW){
     if(tipoSwitch2 == 1){
     //Serial.println("ATTIVO RELE");
      activateRele(relayD2);
      delay(300);
    }else if(tipoSwitch2 == 0){
      activateSwitch(relayD2,&stateSwitch2);
      delay(300);
    }
  }

  if(digitalRead(switch1) == LOW){
     if(tipoSwitch1 == 1){
   //   Serial.println("ATTIVO RELE");
      activateRele(relayD1);
      delay(300);
    }else if(tipoSwitch1 == 0){
      activateSwitch(relayD1,&stateSwitch1);
      delay(300);
    }
  }
 
  
  if (WiFi.status() != WL_CONNECTED){
     Serial.println(WiFi.status());
     Serial.println("riconnessione in corso");
     digitalWrite(gpio_13_led, ACCESO);
     delay(200);  
     ConnectWiFi();
     delay(1000);
  }
  WiFiClient client = server.available();   // Listen for incoming clients
 if (client) {  
    sendPageHtml(client);// If a new client connects,
   // Serial.println("New Client.");          // print a message out in the serial port
    String currentLine = "";                // make a String to hold incoming data from the client
    while (client.connected()) {            // loop while the client's connected
      if (client.available()) {             // if there's bytes to read from the client,
        char c = client.read();             // read a byte, then
        Serial.write(c);                    // print it out the serial monitor
        header += c;
        if (c == '\n') {                    // if the byte is a newline character
          // if the current line is blank, you got two newline characters in a row.
          // that's the end of the client HTTP request, so send a response:
          if (currentLine.length() == 0) {

            closeConnection(client);
            

            String readString = getValue(header, ' ', 1);
           
            
            if (header.indexOf("ON") >= 0) {
              String _PIN = readString.substring(4);
              int pinOn =  getPinToMove(_PIN.toInt());
              digitalWrite(pinOn, ACCESO);
            } else if (header.indexOf("OFF") >= 0) {
              String _PIN = readString.substring(5);
              int pinOn =  getPinToMove(_PIN.toInt());
              digitalWrite(pinOn, SPENTO); 
            }else if (header.indexOf("RELE") >= 0) {
              //RECUPERO LA CORRENTE PASSATA DAL PIN
             String _PIN = readString.substring(6);
             int pinOn = getPinToMove(_PIN.toInt());
             activateRele(pinOn);
            }
            break;
          }
        } else if (c != '\r') {  // if you got anything else but a carriage return character,
          currentLine += c;      // add it to the end of the currentLine
        }
      }
    }
    // Clear the header variable
    header = "";
    // Close the connection
    client.stop();
  }
}

void activateRele(int pinToActivate){
  digitalWrite(pinToActivate, ACCESO); 
  delay(250);   
  digitalWrite(pinToActivate, SPENTO); 
  delay(50);
}
//l asterisco fa si che la variabile, viene passata per riferimento e non per valore
void activateSwitch(int pinToActivate, int* statePin){
 if(*statePin == 0){
    *statePin = 1;
    digitalWrite(pinToActivate, ACCESO); 
  }else{
    *statePin = 0;
    digitalWrite(pinToActivate, SPENTO); 
  }
  
}

void sendPageHtml(WiFiClient client)
{
  client.println("<!DOCTYPE html><html>");
  client.println("</html>");
  client.println();
}


void closeConnection(WiFiClient client){
  client.println("HTTP/1.1 200 OK");
  client.println("Content-type:text/html");
  client.println("Connection: close");
  client.println();  
}


bool ConnectWiFi() {
  // Serial.println("testo lcd" +testo);
  WiFi.setSleepMode(WIFI_NONE_SLEEP);
  WiFi.begin(ssid, password);
  WiFi.config(ip, gateway, subnet);
  digitalWrite(gpio_13_led, SPENTO);
  delay(200);  
  digitalWrite(gpio_13_led, ACCESO);
  delay(200);
  delay(10000);
 
  while (WiFi.waitForConnectResult() != WL_CONNECTED) {
    digitalWrite(gpio_13_led, SPENTO);
    delay(200);
    digitalWrite(gpio_13_led, ACCESO);
    delay(200);
    Serial.println(WiFi.status());
    Serial.println(WL_CONNECTED);
    WiFi.disconnect();
    delay(5000);
    WiFi.begin(ssid, password);
    WiFi.mode(WIFI_STA);
      
   // WiFi.config(ip, gateway, subnet);
    delay(10000);
  }
   digitalWrite(gpio_13_led, SPENTO);
  delay(200);
  Serial.println ("WiFi connected ");
  return true;
}

String getValue(String data, char separator, int index)
  {
    int found = 0;
    int strIndex[] = {0, -1};
    int maxIndex = data.length()-1;
  
    for(int i=0; i<=maxIndex && found<=index; i++){
      if(data.charAt(i)==separator || i==maxIndex){
          found++;
          strIndex[0] = strIndex[1]+1;
          strIndex[1] = (i == maxIndex) ? i+1 : i;
      }
    }
  
    return found>index ? data.substring(strIndex[0], strIndex[1]) : "";
  }//fine metodo getvalue

  int getPinToMove(int idPin)
  {
    switch (idPin) {
      case 1: return 12;
      case 2: return 5;
      case 3: return 4;
      case 4: return 15;
        // Qui sai che x è > 0 && < 4
        break;
  }
}

Ora vi espongo il mio problema. Questo tipo di dispositivo, ha sia la possibilità di attivare i RELE tramite richiesta HTTP, che tramite l'utilizzo dei pulsanti. Per ognuno dei 4 relè c'è un pulsante.

Ho implementato anche i codice per attivare o meno un relè utilizzando I pulsanti presenti, la cosa che vorrei ottimizzare consiste nel fatto che con questo codice, se per qualsiasi problema, la centralina perde il segnale WiFi, anche l'utilizzo dei pulsanti fisici, è compromesso.

Si può ottimizzare il codice facendo si che i pulsanti continuino il loro corretto funzionamento anche senza WiFi attivo?

IL problema è la funzione di connessione che è bloccante e monopolizza tutto il tempo a colpi di delay da dieci secondi ciascuno.

La soluzione completa sarebbe ripensare tutto sotto forma di macchina a stati che conta il tempo con millis (anche se durante la connessione l'ESP8266 sballa i valori di millis).

La soluzione semplice è evitare del tutto quella funzione, tanto la connessione torna in piedi da sola, basta un WiFi.begin nel setup.

E se proprio si vuole controllare lo stato della connessione:

if (WiFi.status() == WL_CONNECTED) {
    WiFiClient client = server.available();   // Listen for incoming clients
    if (client) { 
        ....
    }
}

Ciao ti ringrazio per il tuo supporto. HO application una modifica al codice.

Adesso il codice nel loop è il seguente:

void loop(){
  delay(100);
  if(digitalRead(switch4) == LOW){
     if(tipoSwitch4 == 1){
      Serial.println("ATTIVO RELE");
      activateRele(relayD4);
      delay(300);
    }else if(tipoSwitch4 == 0){
      Serial.println("tiposwitch4");
      activateSwitch(relayD4,&stateSwitch4);
      delay(300);
    }
  }else{
    Serial.println("SWITCH4 NON LOW");
    digitalRead(switch4);
  }

  if(digitalRead(switch3) == LOW){
    Serial.println("RELE 3");
    Serial.println(digitalRead(switch3));
     if(tipoSwitch3 == 1){
      //Serial.println("ATTIVO RELE");
      activateRele(relayD3);
      delay(300);
    }else if(tipoSwitch3 == 0){
      activateSwitch(relayD3,&stateSwitch3);
      delay(300);
    }
  }

  if(digitalRead(switch2) == LOW){
     if(tipoSwitch2 == 1){
     //Serial.println("ATTIVO RELE");
      activateRele(relayD2);
      delay(300);
    }else if(tipoSwitch2 == 0){
      activateSwitch(relayD2,&stateSwitch2);
      delay(300);
    }
  }

  if(digitalRead(switch1) == LOW){
     if(tipoSwitch1 == 1){
   //   Serial.println("ATTIVO RELE");
      activateRele(relayD1);
      delay(300);
    }else if(tipoSwitch1 == 0){
      activateSwitch(relayD1,&stateSwitch1);
      delay(300);
    }
  }
 
  
 if (WiFi.status() == WL_CONNECTED) {
    WiFiClient client = server.available();   // Listen for incoming clients
 if (client) {  
    sendPageHtml(client, -1);// If a new client connects,
   // Serial.println("New Client.");          // print a message out in the serial port
    String currentLine = "";                // make a String to hold incoming data from the client
    while (client.connected()) {            // loop while the client's connected
      if (client.available()) {             // if there's bytes to read from the client,
        char c = client.read();             // read a byte, then
        Serial.write(c);                    // print it out the serial monitor
        header += c;
        if (c == '\n') {                    // if the byte is a newline character
          // if the current line is blank, you got two newline characters in a row.
          // that's the end of the client HTTP request, so send a response:
          if (currentLine.length() == 0) {

            closeConnection(client);
            
            String readString = getValue(header, ' ', 1);
            Serial.println("+++++++++++++++");
            Serial.println(readString);
            Serial.println("+++++++++++++++");
            
            if (header.indexOf("ON") >= 0) {
              String _PIN = readString.substring(4);
              int pinOn =  getPinToMove(_PIN.toInt());
              digitalWrite(pinOn, ACCESO);
              //Serial.println("LUCE ACCESA PIN " +pinOn);
            
            } else if (header.indexOf("OFF") >= 0) {
              String _PIN = readString.substring(5);
              int pinOn =  getPinToMove(_PIN.toInt());
              digitalWrite(pinOn, SPENTO); 
              //Serial.print("LUCE SPENTA "+pinOn);
          
            }else if (header.indexOf("RELE") >= 0) {
              //RECUPERO LA CORRENTE PASSATA DAL PIN
             String _PIN = readString.substring(6);
             int pinOn = getPinToMove(_PIN.toInt());
             activateRele(pinOn);
             /*digitalWrite(pinOn, ACCESO); 
             //Serial.println("RELE ACCESA "+pinOn);
             //ATTENDO DUE SECONDI, POI SPENGO IL PIN
             delay(250);   
             digitalWrite(pinOn, SPENTO); 
            delay(50);*/
            }else if (header.indexOf("STATUS") >= 0) {
               String _PIN = readString.substring(8);
               Serial.println("PIN PER STATUS "+_PIN);
               sendPageHtml(client,_PIN.toInt()); 
            }
            // Break out of the while loop
            break;
          } else { // if you got a newline, then clear currentLine
            currentLine = "";
          }
        } else if (c != '\r') {  // if you got anything else but a carriage return character,
          currentLine += c;      // add it to the end of the currentLine
        }
      }
    }
    // Clear the header variable
    header = "";
    // Close the connection
    client.stop();
   // Serial.println("Client disconnected.");
   // Serial.println("");
  }
}
  
}

Il problema che si verifica adesso è che ogni tanto i pulsanti non vengono riconosciuti. Non viene riconosciuto lo stato a LOW.

Cioè che vedo nella finestra "Monitor seriale" di arduiono è

SWITCH4 NON LOW. (QUesto di continuo), è come se si incanta il pulsante.

Non penso sia un problema hardware in quanto capita anche con gli altri 3 switch button.
Mi sapreste aiutare ?

Oltre al fatto che se tieni un pulsante premuto ti spara tre comandi al secondo, e che se lo premi per meno di 100ms probabilmente non viene sentito, non mi sembra ci siano inghippi. Per averne la certezza disabilita tutto il blocco di gestione della comunicazione lasciando solo quelli dei pulsanti. Cosa succede?

Ho fatto la prova che tu dici funziona per un po’ dopo rimane incantato uno dei 4 switch, il problema è che non è sempre lo stesso. Quindi dubito che il problema sia
Hardware.

Inoltre volevo sapere se vi fosse un modo più efficiente
Per gestire questi pulsanti

bircastri:
funziona per un po’ dopo rimane incantato uno dei 4 switch, il problema è che non è sempre lo stesso.

Hai provato a settarli come INPUT_PULLUP invece che solo INPUT? (sempre che sugli ESP8266 si possa fare...)

bircastri:
Ho fatto la prova che tu dici funziona per un po’ dopo rimane incantato uno dei 4 switch, il problema è che non è sempre lo stesso. Quindi dubito che il problema sia Hardware.

In ogni caso se non ci dai indicazioni sulle connessioni dei pulsanti (ad esempio vedo che testi per LOW, come hai collegato i pulsanti? E hai messo delle resistenze di pullup? Se non lo hei messe, il problema può essere quello!) e non ci mostri l'intero codice (quantomeno la setup) diventa un "andare per tentativi"...

@docdoc, l'intero codice è nel primo post, compreso il metodo setup().

bircastri:
@docdoc, l'intero codice è nel primo post, compreso il metodo setup().

Si, hai ragione, scusa, ero rimasto al tuo post #2 dove hai messo solo la loop().

Per le altre mie domande invece?