📑 Monitorizar o portão de duas folhas


(Ricardo Silva) #1

Aqui deixo um projecto que te permite com um nodemcu/wemos, uma placa de relé, um reed switch e um sensor de temperatura, controlares um portão de duas folhas, como monotorizares o portão sabendo o seu estado e a temperatura ambiente dentro da garagem.

O que é necessário para executares este projecto?

Lista de Material:

  • 1x wemos D1 mini ou Nodemcu
  • 1 relé wemos ou uma placa de relé (ligado ao interruptor do motor que permite abrir - parar - fechar o
  • portão)
  • 1 sensor dht22 com placa assim já vem pronto a ligar (Sensor de temperatura e humidade da garagem)
  • 1 par de reed switch para saber a posição do portão (aberto - fechado)
  • 1 Transformador 220vac - 5vdc. No esquema esta um HLK-PM01 mas podem usar um carregador de telemóvel.

Nota:
Não foram deixados nenhuns links devido a que podem deixar de estar a funcionar, mas este material encontras facilmente em lojas online da china, seja Alixpress, Bangood, dealextreme etc,

Abaixo deixo o código para flashares no teu wemos ou Nodemcu com o software arduino IDE:

Não te esqueças de mudar os teus dados:
Nome da tua Rede como a tua password da rede, Ip do servidor do teu broker mqtt tal como o username e password do broker.

//#include <Timing.h>
//MQTT
#include <PubSubClient.h>
//ESP
#include <ESP8266WiFi.h>
#include <ESP8266WebServer.h>
#include <ESP8266mDNS.h>
#include <ESP8266HTTPUpdateServer.h>
#include <Bounce2.h> //elimina ruido no botão manual https://github.com/thomasfredericks/Bounce-Arduino-Wiring
#include "RemoteDebug.h"
#include <DHT.h>
#include <Adafruit_Sensor.h>

//para o botão touch ou neste caso tambem para os 2 botões do interruptor
// o I/O aceitam 5v mas vou por 3.3v

//aqui é o pin do wemos para o relay do meu portão
#define door D1
#define sensor_door_close D2
#define DHTPIN D3

//constant
//wifi
const char* ssid = "";
const char* password = "";
#define HOST_NAME "portao"
#define DHTTYPE DHT22

//mqtt
const char* mqtt_server = "";
const char* mqtt_username = "portao";
const char* mqtt_password = "";
const char* mqtt_id = mqtt_username;
const int mqtt_port = 1883;

//ha
const char* ha_command_door = "ha/portao/door/set";
const char* ha_state_door = "ha/portao/door/status";
const char* ha_availability = "ha/portao/door/lwt";
const char* ha_reboot_esp = "ha/portao/door/reboot";
const char* ha_temperature = "ha/portao/temperature/value";
const char* ha_humidity = "ha/portao/humidity/value";

//aqui vou ter que ter OPEN CLOSE STOP no que vem o mqtt
const char* payload_open = "OPEN";
const char* payload_close = "CLOSE";
const char* payload_stop = "STOP";
const char* payload_available = "ONLINE";
const char* payload_not_available = "OFFLINE";
const char* ota_estado = "OTA ONLINE";
const char* ota_topico = strcat("ota/",mqtt_username);
const char* reboot_esp = "RESTART";

//outros
const int SERIAL_BAUDRATE = 115200;
const int port_webserver = 80;

//class
ESP8266WebServer httpServer(port_webserver);
ESP8266HTTPUpdateServer httpUpdater;
WiFiClient espwifiClient;
PubSubClient client(mqtt_server, mqtt_port,espwifiClient);
RemoteDebug Debug;
DHT dht(DHTPIN, DHTTYPE);

//debouncer para o ruido nos botões
Bounce debouncerClose_door = Bounce();

//variaveis
String lastStateNotified_door = "NONE";
int door_laststatesensor_close = 5;
int timeSinceLastRead = 0;

void callback(char* topic, byte* payload, unsigned int length) {
	
		payload[length] = '\0';
		String strTopic = String((char*)topic);
		if(strTopic == ha_command_door)
		{
			String infomqtt = String((char*)payload);
			if(infomqtt.equals(payload_open))
			{
				Debug.println("vai para o metodo opengate()");
				openGate();
			}else if (infomqtt.equals(payload_close))
			{
				Debug.println("vai para o metodo closegate()");
				closeGate();
			}else if (infomqtt.equals(payload_stop))
			{
				Debug.println("vai para o metodo stopgate()");
				stopGate();
			}   
		}else if(strTopic == ha_reboot_esp){
			Debug.println("ESP Restart");
			ESP.restart();
		}
	
} 

bool checkMqttConnection() {
  while (!client.connected()) {
    Serial.print("Attempting MQTT connection...");
    Debug.println("Attempting MQTT connection...");
	//aqui i false ou true é importante
	// true: volta ao estado anterior mas para a garagem não é util porque tenho o estado pelo sensores
	//no caso de persianas pode ser true para continuar o que estava a fazer
    if (client.connect(mqtt_id, mqtt_username, mqtt_password, ha_availability, 0, true, payload_not_available )) {
		Serial.println("connected");
		Debug.println("connected");
		client.publish(ota_topico, ota_estado, true);      
		client.publish(ota_topico, (const char*)"connected", true);
		client.publish(ha_availability, payload_available, true);
		client.subscribe(ha_command_door);			
		client.subscribe(ha_reboot_esp);			
    } else {
		Serial.print("failed, rc=");
		Debug.print("failed, rc=");
		Serial.print(client.state());
		Debug.print(client.state());
		Serial.println(" try again in 5 seconds");
		Debug.println(" try again in 5 seconds");
		delay(5000);
    }
  }
  return true;
}

void setup_wifi() {
  delay(100);
  //debug
  Serial.println();
  Serial.print("Connecting to ");
  Serial.println(ssid);
  //ota add isso
  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, password);
  int restartesp = 0;
  while (WiFi.status() != WL_CONNECTED) 
  {
    delay(1000);
    Serial.print("Connecting to WiFi.." + String(restartesp) + " ");
    restartesp++;
    if(restartesp > 9)
    {
      ESP.restart();
    }
  }
  MDNS.begin(HOST_NAME);
  httpUpdater.setup(&httpServer);
  httpServer.begin();
  MDNS.addService("http", "tcp", port_webserver);
  Serial.println("");
  Serial.println("WiFi connected");
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP());
}

void setup() {
  
  Serial.begin(SERIAL_BAUDRATE);
  setup_wifi(); 
  //modo debug por telnet
  Debug.begin(HOST_NAME);
  Debug.setResetCmdEnabled(true);
  Debug.showTime(true);
  Debug.showProfiler(true); // Profiler
  //client.setServer(mqtt_server, mqtt_port);
  client.setCallback(callback);
  //aqui é para o relay da minha porta. O relay simula o interruptor que faz abrir/stop/fechar	
  digitalWrite(door, LOW);
  pinMode(door, OUTPUT);  
  //sensores da minha porta
  //para contornar o problema se o esp8266 aceita 5V ou 3.3, vou por o pin 
  //com saida up e passa a 0 com contacto fechado
  pinMode(sensor_door_close, INPUT_PULLUP);
  //associar ao debouncer
  debouncerClose_door.attach(sensor_door_close);
  debouncerClose_door.interval(5);//DELAY
	  
}

void openGate(){  
	if(!lastStateNotified_door.equals(payload_open)){
		digitalWrite(door,HIGH);
		delay(400);
		digitalWrite(door,LOW);
		lastStateNotified_door = payload_open;
		Serial.println("OPEN");
		Debug.println("OPEN");
	}  
}

void closeGate(){
	if(!lastStateNotified_door.equals(payload_close)){
	  digitalWrite(door,HIGH);
		delay(400);
		digitalWrite(door,LOW);
		lastStateNotified_door = payload_close;
		Serial.println("CLOSE");   
		Debug.println("CLOSE");   
  } 
}

void stopGate(){
	if(!lastStateNotified_door.equals(payload_stop)){
		 digitalWrite(door,HIGH);
		delay(400);
		digitalWrite(door,LOW);
		lastStateNotified_door = payload_stop;
		client.publish(ha_state_door,payload_stop,true);
		Serial.println("STOP");
		Debug.println("STOP");
	}  
}

//permite verificar o estado da porta com os sensores
//assim se a porta for aberta com o comando ou pelo interruptor já o sabemos
void check_door_status() {

	//atualizar estado dos sensores
	debouncerClose_door.update();
	int currentStateClose = debouncerClose_door.read();
	
	if(door_laststatesensor_close == 5){
		
		door_laststatesensor_close = currentStateClose;		
		Debug.println("Primeiro if para o estado dos sensores");
		
	}else if(currentStateClose != door_laststatesensor_close){
		
		if(currentStateClose == 1){
			publish_door_status("Aberto");
			Serial.println("Aberto");
			Debug.println("Aberto");
		}else {
			publish_door_status("Fechado");
			Serial.println("Fechado");
			Debug.println("Fechado");
		}
		door_laststatesensor_close = currentStateClose;		
		
	}
}

void publish_door_status(String message)
{
	if(message == "Fechado")	{
		lastStateNotified_door = payload_close;
		client.publish(ha_state_door,payload_close,true);
	}else if(message == "Aberto"){
		lastStateNotified_door = payload_open;
		client.publish(ha_state_door,payload_open,true);
	}
}

void loop() {
  
  if (WiFi.status() == WL_CONNECTED) 
  {
    if (checkMqttConnection())
		{
			httpServer.handleClient();
			client.loop(); 
			check_door_status();
			Debug.handle();
			//sensor DHT
			if(timeSinceLastRead > 30000) 
			{
				float h = dht.readHumidity();
				// Read temperature as Celsius (the default)
				float t = dht.readTemperature();
				// Check if any reads failed and exit early (to try again).
				if (isnan(h) || isnan(t)) {
					 Serial.println("Failed to read from DHT sensor!");
					 Debug.println("Failed to read from DHT sensor!");
					 timeSinceLastRead = 0;
					 return;
				}		
				
				 const int VAL_MAX = 16;
				 char val[VAL_MAX];
				 timeSinceLastRead = 0;
				 client.publish(ha_humidity, dtostrf(h, 1, 2, val),true);
				 client.publish(ha_temperature, dtostrf(t, 1, 2, val),true);
				 Debug.printf("Temperature: %s\n", dtostrf(t, 1, 2, val));
				 Debug.printf("Humidade: %s\n", dtostrf(h, 1, 2, val));
			}
			delay(100);
			timeSinceLastRead += 100;
    }
  }else{
		Debug.println("ESP Restart");
		ESP.restart();
  }	
}

Do lado do home assistant:

cover.yaml:

- platform: mqtt
  name: "Portao"
  command_topic: "ha/portao/door/set"
  state_topic: "ha/portao/door/status"
  availability_topic: "ha/portao/door/lwt"
  qos: 0
  retain: false
  payload_open: "OPEN"
  payload_close: "CLOSE"
  payload_stop: "STOP"
  payload_available: "ONLINE"
  payload_not_available: "OFFLINE"
  state_open: "OPEN"
  state_closed: "CLOSE"
  optimistic: false

sensors.yaml:

- platform: mqtt
  state_topic: 'ha/portao/temperature/value'
  name: 'Temperatura Portão'
  unit_of_measurement: °C
  icon: mdi:thermometer
  availability_topic: "ha/portao/door/lwt"
  payload_available: "ONLINE"
  payload_not_available: "OFFLINE"
  
- platform: mqtt
  state_topic: 'ha/portao/humidity/value'
  name: 'Humidade Portão' 
  icon: mdi:water-percent
  availability_topic: "ha/portao/door/lwt"
  unit_of_measurement: '%'      
  payload_available: "ONLINE"
  payload_not_available: "OFFLINE"

Ligações:

Segue as fotos de como ficou. No meu caso é um portão de aluminio no qual retirei a fechadura e meti no lugar os sensores reed. O cabo branco é que liga ao sensor reed.


(Jorge Assunção) #2