Bom dia a todos, tudo bem com vocês? Meu nome é José Pétri e estou querendo desenvolver um sistema super robusto e confiável para automatizar a nossa casa. Não só isso, mas também para coletar dados (isso vai ficar para um próximo post).
No caso, até o momento, já montei um sistema com Hassio e ESP8266 que liga e apaga as luzes, que possui funções, que verifica se há ou não energia na rede (se não houver energia a lampada tem de estar apagada então se o botão no mqtt estiver como ON é mudado para OFF) enfim, segue um vídeo abaixo para melhor visualização =]
Então o sistema já esta funcionando e rodando bem. Dá para ser utilizado já, mas desejo melhorar mais. Por exemplo, se não houver internet o ESP8266 não se conecta a nada e não funciona mais. Quero criar uma rede mesh independente e permitir que esta rede conecte-se ao ESP8266. Como estou usando o Raspberry acredito que possa colocar dois adaptadores de rede USB e usar um para receber a internet e outro para enviar o MQTT por outra rede. Assim, se algo acontecer com o roteador a rede fica independente. Não sei, ainda estou amadurecendo a ideia.
Se gostarem do código ou se verem alguma parte que possa ser melhorada, qualquer que seja, por favor, estou ansioso para receber alguma critica ou conselho =]
//---------------------------------------------------------------------------------------------------------- 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);
}
Aqui tenho uma lista de reprodução com o projeto, podem pular para o último video que é o do codigo acima.
Obrigado pela atenção.