Gestão Domótica
Gostaria de reagir a esta mensagem? Crie uma conta em poucos cliques ou inicie sessão para continuar.

Ir para baixo
avatar
Admin
Admin
Mensagens : 5
Data de inscrição : 30/10/2018
https://gestaodomotica.forumeiros.com

Interruptor para até 8 lampadas, com funções - Versão 2.1 Alpha Empty Interruptor para até 8 lampadas, com funções - Versão 2.1 Alpha

Dom Nov 04, 2018 9:12 am
Olá a todos! Durante esta semana fiz algumas modificações a alguns avanços! Cada vez mais próximo da conclusão deste primeiro projeto =]

Estou querendo montar um sistema que seja o mais próximo possível da perfeição. Quero prever o maior numero de erros e situações que tragam qualquer sentimento de insatisfação para o usuário por exemplo - Se você desligou a luz no aplicativo e deseja ligar ela no interruptor tem de pressionar o botão uma vez para baixo e depois para cima - Este caso não é algo que vá trazer qualquer prejuízo para o usuário, mas traz uma mudança brusca de rotina! A vida inteira foi acostumando a pressionar o botão e acender ou apagar a luz, a unica situação em que isso não ocorria era quando havia um problema (falta de luz ou lampada queimada) e este é um sentimento que quero longe do projeto, quero satisfação ao acionamento de cada botão =]

Então neste semana (mesmo com muito trabalho e provas) fiz algumas modificações, organizei melhor a forma como inserimos os botões, coloquei alguns códigos para verificar se o botão esta realmente ativado ou não, e algumas funções como acender e apagar todas as luzes.) O código segue abaixo e irei documentar melhor na versão final, mas qualquer duvida responderei o mais rápido possível.

- Adição de novos botões no Hassio usando o endereço hierárquico do sistema (podemos adicionar botões nos cômodos e quando integrar com o Google assistant irá organizar os botões automaticamente.)
- Função de leitura de botões push buttons para compactar o projeto e permitir customização de funções, embora isso represente um risco caso a fonte ou o esp8266 apresentem algum problema.
- Criação de rotinas de verificação de estado do botão e atualização do comando dos botões, integração total da parte local com o servidor hassio.

Abaixo segue o código usado no teste.

Código:
//---------------------------------------------------------------------------------------------------------- BIBLIOTECAS ----- ||
  #include <ESP8266WiFi.h> //lib do wifi para o ESP8266
  #include <ESP8266mDNS.h>
  #include <WiFiUdp.h>
  #include <ArduinoOTA.h> //lib do ArduinoOTA
  #include <PubSubClient.h>
  #include <ESP8266WebServer.h>
  #include <WiFiManager.h>
  #include <Ticker.h>// Watcdog bibl

//-------------------------------------------------------------------------------------------------------- IP FIXO TELNET -----||
  IPAddress ip(192,168,0,XXX);//no lugar no XXX coloque o IP
  IPAddress geteway(192,168,0,XXX); //no lugar no XXX coloque o IP do router
  IPAddress subnet(255,255,255,0);
  WiFiServer TelnetServer(23);
  WiFiClient Telnet;

  void handleTelnet(){
    if(TelnetServer.hasClient()){
      //Cliente esta conectado
      if(!Telnet || !Telnet.connected()){
        if(Telnet) Telnet.stop();
        Telnet = TelnetServer.available();
      }else{
        TelnetServer.available().stop();
      }
    }
  }

// -----------------------------------------------------------------------------------------------------------------  MQTT ----||
  #define MQTT_AUTH true  //Ativa a autenticação
  #define MQTT_USERNAME "@@@@@" // Login do MQTT aqui colocamos o login no lugar do @@@
  #define MQTT_PASSWORD "XXXXXXXXX" // Senha do MQTT aqui colocamos a senha do MQTT
  const String HOSTNAME  = "TANTO FAZ"; // Nome do dispositivo, este nome tambem é utilizado para criar o Access Point para configuração
  const char* servidorMQTT = "192.168.0.XXX"; //IP ou DNS do servidor, neste caso do HassIO

// ----------------------------------------------------------------------------------------------------------------- WIFI -----||
  const char* ssid = "@@@@@@@"; //nome da rede
  const char* password = "XXXXXXXXXXXXX"; //senha da rede
  WiFiClient wclient;
  PubSubClient client(servidorMQTT,1883,wclient);

//--------------------------------------------------------------------------------- MULTIPLICADOR DE ENTRADAS ANALOGICAS ----- ||

  int MUXPinS0 = D3;
  int MUXPinS1 = D4;
  int MUXPinS2 = D5;
  int MUXPinS3 = D6;

//------------------------------------------------------------------------------------- MULTIPLICADOR DE SAIDAS DIGITAIS ----- ||
  #define pinSH_CP D0   //Pino Clock
  #define pinST_CP D1  //Pino Latch
  #define pinDS    D2  //Pino Data
  #define qtdeCI   1


//------------------------------------------------------------------------------- VARIAVEIS DOS BOTÕES, RELES E SENSORES ----- ||
  int const quantidaDeBotao = 4;

  int pinLDR = 0; //luz apagada valor baixo, luz acesa valor alto
  int C1 = 0;
  int X = 0;
  unsigned long delayLamp = 0;
  int temporizador = 0;
  String MQTT_STATE_TOPIC = ""; //Topico onde o dispositivo publica (por exemplo o estado da lâmpada ON ou OFF)
  String MQTT_COMMAND_TOPIC = ""; //Topico onde o dispositivo subscreve (por exemplo controlar uma lâmpada)
  const char * mqttState = "";
  const char * mqttSet = "";
  
  struct Rele{ //Structure dos botões (até o limite de hardware)
    char nome[20];
    int Pino;
    bool estadoDaLuz;
    bool estado;
    int tensao;
    int acionamento = 0;
    int funcao;
    unsigned long Delay = millis();
  };

  struct Rele Botao[4];


//============================================================================================================================
// ------------------------------------------------< VOID SETUP >-------------------------------------------------------------
//============================================================================================================================
void setup(){
Serial.begin(115200);

//--------------------------------------------------------------------------------- MULTIPLICADOR DE ENTRADAS ANALOGICAS ----- ||
  pinMode(MUXPinS0, OUTPUT);
  pinMode(MUXPinS1, OUTPUT);
  pinMode(MUXPinS2, OUTPUT);
  pinMode(MUXPinS3, OUTPUT);
  
//------------------------------------------------------------------------------------- MULTIPLICADOR DE SAIDAS DIGITAIS ----- ||
   pinMode(pinSH_CP, OUTPUT);
   pinMode(pinST_CP, OUTPUT);
   pinMode(pinDS, OUTPUT);

  WiFiManager wifiManager;
  //wifiManager.resetSettings(); //Limpa a configuração anterior do Wi-Fi SSID e Password, procedimento, 1º descomentar a linha, 2º Fazer Upload do código para o ESP e deixar o ESP arrancar, 3º Voltar a comentar a linha e enviar novamente o código para o ESP
  /*define o tempo limite até o portal de configuração ficar novamente inátivo,
   útil para quando alteramos a password do AP*/
  wifiManager.setTimeout(180);
  wifiManager.autoConnect(HOSTNAME.c_str());
  client.setCallback(callback); //Registo da função que vai responder ás mensagens vindos do MQTT

//----------------------------------------------------------------------------------------- INICIANDO SERVIDOR TELNET ---------||
   TelnetServer.begin();
   TelnetServer.setNoDelay(true);





  
  
    
  
   WiFi.mode(WIFI_STA);
   WiFi.begin(ssid, password);
  
  
  while (WiFi.waitForConnectResult() != WL_CONNECTED) {
    delay(5000);
    ESP.restart();
  }


  // Identificação do
  ArduinoOTA.setHostname("interruptor");

  // Senha para conexão via OTA
  ArduinoOTA.setPassword("32342415");


  //define o que será executado quando o ArduinoOTA iniciar
  
  ArduinoOTA.onStart([]() {
    String type;
    if (ArduinoOTA.getCommand() == U_FLASH) {
      type = "sketch";
    } else { // U_SPIFFS
      type = "filesystem";
    }

  });//startOTA é uma função criada para simplificar o código

  //define o que será executado quando o ArduinoOTA terminar
  ArduinoOTA.onEnd([]() {
    //Serial.println("\nEnd");
  }); //endOTA é uma função criada para simplificar o código

  //define o que será executado quando o ArduinoOTA estiver gravando
  ArduinoOTA.onProgress([](unsigned int progress, unsigned int total) {
    //Serial.printf("Progress: %u%%\r", (progress / (total / 100)));
  });//progressOTA é uma função criada para simplificar o código

  //define o que será executado quando o ArduinoOTA encontrar um erro
  ArduinoOTA.onError([](ota_error_t error) {
    //Serial.printf("Error[%u]: ", error);
    if (error == OTA_AUTH_ERROR) {
      //Serial.println("Auth Failed");
    } else if (error == OTA_BEGIN_ERROR) {
      //Serial.println("Begin Failed");
    } else if (error == OTA_CONNECT_ERROR) {
      //Serial.println("Connect Failed");
    } else if (error == OTA_RECEIVE_ERROR) {
      //Serial.println("Receive Failed");
    } else if (error == OTA_END_ERROR) {
      //Serial.println("End Failed");
    }
  });//errorOTA é uma função criada para simplificar o código
  
  //inicializa ArduinoOTA
    ArduinoOTA.begin();


  
  
}
//============================================================================================================================
// ------------------------------------------------> VOID SETUP <-------------------------------------------------------------
//============================================================================================================================






//--------------------------- LEITURA DOS VALORES ANALOGICOS DA PLACA 16 CANAIS -------------------||
double getAnalog(int MUXyPin) {
  //MUXyPin must be 0 to 15 representing the analog pin you want to read
  //MUXPinS3 to MUXPinS0 are the Arduino pins connected to the selector pins of this board.
  digitalWrite(MUXPinS3, HIGH && (MUXyPin & B00001000));
  digitalWrite(MUXPinS2, HIGH && (MUXyPin & B00000100));
  digitalWrite(MUXPinS1, HIGH && (MUXyPin & B00000010));
  digitalWrite(MUXPinS0, HIGH && (MUXyPin & B00000001));
  return (double)analogRead(A0);
}

String mqttAState(int S){
  switch (S){
          case 0:
            return "casa/sala/central/state";
            break;
          case 1:
            return "casa/sala/tv/state";
            break;
          case 2:
            return "casa/sala/led/state";
            break;
          case 3:
            return "casa/sala/corredor/state";
            break;    
          default  :
            return "default default default default ";    
  }
}

String mqttASet(int S){
  switch (S){
          case 0:
            return "casa/sala/central/set";
            break;
          case 1:
            return "casa/sala/tv/set";
            break;
          case 2:
            return "casa/sala/led/set";
            break;    
          case 3:
            return "casa/sala/corredor/set";
            break;  
          default  :
            return "default default default default ";  
  }
}









void ci74HC595Write(byte pino, bool estado) {
static byte ciBuffer[qtdeCI];

bitWrite(ciBuffer[pino / 8], pino % 8, estado);

digitalWrite(pinST_CP, LOW); //Inicia a Transmissão

digitalWrite(pinDS, LOW);    //Apaga Tudo para Preparar Transmissão
digitalWrite(pinSH_CP, LOW);

for (int nC = qtdeCI-1; nC >= 0; nC--) {
    for (int nB = 7; nB >= 0; nB--) {

        digitalWrite(pinSH_CP, LOW);  //Baixa o Clock      
        
        digitalWrite(pinDS,  bitRead(ciBuffer[nC], nB) );     //Escreve o BIT
        
        digitalWrite(pinSH_CP, HIGH); //Eleva o Clock
        digitalWrite(pinDS, LOW);     //Baixa o Data para Previnir Vazamento      
    }  
}

digitalWrite(pinST_CP, HIGH);  //Finaliza a Transmissão

}


//--------------------------------------------------------------------------------------- FUNÇÕES MQTT -------------------------
//Chamada de recepção de mensagem


void callback(char* topic, byte* payload, unsigned int length) { //Padrão de recebimento do MQTT
  //Primeiro recebe o Topico, Mensagem do programa, tamanho da mensagem



  String payloadStr = "";
  for (int i=0; i<length; i++) { //Abre a mensagem recebida de acordo com o tamanho informado.
    payloadStr += (char)payload[i];
  }


  
   String topicStr = String(topic);
   /*for (int i=0; i<length; i++) { //Abre a mensagem recebida de acordo com o tamanho informado.
    payloadStr += (char)topic[i];
  }
 */
  
  
  
 Serial.println(topicStr);


  for(int i=0;i<quantidaDeBotao;i++){
    if(topicStr == mqttAState(i)){
      X=i;
    }
    if(topicStr == mqttASet(i)){
      X=i;
    }
  }

  Serial.println(X);
Botao[X].Pino = X;
MQTT_STATE_TOPIC = mqttAState(X);
MQTT_COMMAND_TOPIC = mqttASet(X);
mqttState = MQTT_STATE_TOPIC.c_str();
mqttSet = MQTT_COMMAND_TOPIC.c_str();


  if(topicStr.equals(mqttSet)){
    if(payloadStr.equals("ON")){
      ci74HC595Write(X, LOW);
      Botao[X].estadoDaLuz = true; //controle interno da luz, true acesa, false apagada.
      Botao[X].estado = true;
      Botao[X].Delay = millis();//Espera para que a aplicação seja aplicada no circuito e ele não reporte um falso positivo para o acionamento do interruptor.
      client.publish(mqttState,"ON",true);
    }else if(payloadStr.equals("OFF")){
      ci74HC595Write(X, HIGH);
      client.publish(mqttState,"OFF",true);
      Botao[X].estadoDaLuz = false; //controle interno da luz, true acesa, false apagada.
      Botao[X].estado = false;
      Botao[X].Delay = millis();//Espera para que a aplicação seja aplicada no circuito e ele não reporte um falso positivo para o acionamento do interruptor.
    }
  }
}
 

//Verifica se o estado da ligação está ativa e se não estiver tenta conectar-se
bool checkMqttConnection(){
  
//for(int B=0;B<quantidaDeBotao;B++){





  if (!client.connected()) {
    if (MQTT_AUTH ? client.connect(HOSTNAME.c_str(),MQTT_USERNAME, MQTT_PASSWORD) : client.connect(HOSTNAME.c_str())) {
      //SUBSCRIÇÃO DE TOPICOS

      
  for(int i=0;i<quantidaDeBotao;i++){
      MQTT_COMMAND_TOPIC = mqttASet(i);
      mqttSet = MQTT_COMMAND_TOPIC.c_str();
      client.subscribe(mqttSet);
  }
    }
  }
  return client.connected();
}


void desligaTudo(){

for(int i = 0; i<quantidaDeBotao; i++){
ci74HC595Write(i, LOW);
MQTT_STATE_TOPIC = mqttAState(i);
mqttState = MQTT_STATE_TOPIC.c_str();
        client.publish(mqttState,"OFF",true);
        Botao[i].estadoDaLuz = false;
        Botao[i].estado = false;
    }
}

void ligaTudo(){

for(int i = 0; i<quantidaDeBotao; i++){
ci74HC595Write(i, HIGH);
MQTT_STATE_TOPIC = mqttAState(i);
mqttState = MQTT_STATE_TOPIC.c_str();
        client.publish(mqttState,"ON",true);
        Botao[i].estadoDaLuz = true;
        Botao[i].estado = true;
    }
}


//============================================================================================================================
// ------------------------------------------------( VOID LOOP )--------------------------------------------------------------
//============================================================================================================================
void loop(){


//----------------- medidor de tensão-------------------------------------------------------------------

for(int i=0;i<quantidaDeBotao;i++){
  
    
    int estadobutton = getAnalog(i+6);
    
    if(Botao[i].acionamento == 0 && estadobutton>=600){
    Botao[i].Delay = millis();
    Botao[i].acionamento = 1;
    }

    
    if(Botao[i].acionamento == 1 && estadobutton<=400){
      if((millis() - Botao[i].Delay) <= 500){
        Botao[i].estado = !Botao[i].estado;
        Botao[i].acionamento = 0;
        Serial.printf("O botão %d esta no estado %s\nPressionado rapidamenten\n\n",i,Botao[i].estado?"true":"false");
        }
       if((millis() - Botao[i].Delay) >= 500){
          
          
          switch (i){
          case 0:
            ligaTudo();
            break;
          case 1:
            desligaTudo();
            break;
          case 2:
            
            break;    
          case 3:
            
            break;  
          default  :
              ;
  }

        Botao[i].acionamento = 0;
        Serial.printf("O botão %d esta no estado %s\nPressionado devagar\n\n",i,Botao[i].estado?"true":"false");
        }
        
    }

    
    

}
  
Telnet.printf("Estado da Lampada = %d", Botao[0].tensao);




//---------------------------------------------------------------------------------------
for(int i = 0; i<quantidaDeBotao; i++){

MQTT_STATE_TOPIC = mqttAState(i);
mqttState = MQTT_STATE_TOPIC.c_str();

    if(Botao[i].estado == false && Botao[i].estadoDaLuz == true) {
        client.publish(mqttState,"OFF",true);
        Botao[i].estadoDaLuz = false;
        ci74HC595Write(i, LOW);
    }
    if(Botao[i].estado == true && Botao[i].estadoDaLuz == false){
        client.publish(mqttState,"ON",true);
        Botao[i].estadoDaLuz = true;
        ci74HC595Write(i, HIGH);
    }
}


//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++



Telnet.println("");

if(temporizador>0){
  temporizador--;
}






int valorLDR = getAnalog(pinLDR);

if(valorLDR<=400 && C1>= 800){
Telnet.printf("Lampada queimada!!!");
}else{
Telnet.printf("Intensidade da luz: %d", valorLDR);Telnet.println("");Telnet.println("");
}
C1=0;





// -------------------------------------------------------------------------------------------------------- CONEXÃO MQTT -----
  if (WiFi.status() == WL_CONNECTED) {
      if (checkMqttConnection()){
          client.loop();
      }
  }
// ------------------------------------------------------------------------------------------------------ CONEXÃO TELNET -----
handleTelnet();

  ArduinoOTA.handle();


  delay(100);
}

  


Abaixo um pequeno vídeo demonstrando a funcionalidade do código.



Código antigo desatualizado, agora não é mais carregado o botão pelo comando ON / OFF



Aqui demonstrando a versatilidade do projeto, podendo ser comando por interruptor físico, rede local ou fora de casa.






Outros videos do mesmo projeto no link abaixo:

Clique aqui para ver a lista de videos do projeto
Ir para o topo
Permissões neste sub-fórum
Não podes responder a tópicos