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.