Aqui deixo um projecto que te permite com um nodemcu/wemos uma placa de relé dois par de reed switch e um sensor de temperatura, controlares o portão da tua garagem, 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 (Sensor de temperatura e humidade da garagem)
- 2 pares de reed switch para saber a posição do portão (fechado - abrindo - aberto - fechando - parado)
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>
//aqui é o pin do wemos para o relay do meu portão
#define door1 D1
#define sensor_door1_open D2
#define sensor_door1_close D5
#define DHTPIN D3
//constant
//wifi
const char* ssid = "";
const char* password = "";
#define HOST_NAME "garagem"
#define DHTTYPE DHT22
//mqtt
const char* mqtt_server = "";
const char* mqtt_username = "";
const char* mqtt_password = "";
const char* mqtt_id = mqtt_username;
const int mqtt_port = 1883;
//ha
const char* ha_command_door1 = "ha/garagem/door1/set";
const char* ha_state_door1 = "ha/garagem/door1/status";
const char* ha_availability = "ha/garagem/door1/lwt";
const char* ha_sensor_door1 = "ha/garagem/door1/position";
const char* ha_reboot_esp = "ha/garagem/door1/reboot";
const char* ha_temperature = "ha/garagem/temperature/value";
const char* ha_humidity = "ha/garagem/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 debouncerOpen_door1 = Bounce();
Bounce debouncerClose_door1 = Bounce();
//variaveis
String lastStateNotified_door1 = "NONE";
int door1_laststatesensor_open = 5;
int door1_laststatesensor_close = 5;
bool firststart = true;
int timeSinceLastRead = 0;
void callback(char* topic, byte* payload, unsigned int length) {
if(!firststart)
{
payload[length] = '\0';
String strTopic = String((char*)topic);
if(strTopic == ha_command_door1)
{
String infomqtt = String((char*)payload);
if(infomqtt.equals(payload_open))
{
Debug.println("vai para o metodo opencover()");
openCover();
}else if (infomqtt.equals(payload_close))
{
Debug.println("vai para o metodo closecover()");
closeCover();
}else if (infomqtt.equals(payload_stop))
{
Debug.println("vai para o metodo stopCover()");
stopCover();
}
}else if(strTopic == ha_reboot_esp){
Debug.println("ESP Restart");
ESP.restart();
}
}else{
firststart = false;
}
}
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");
firststart = true;
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_door1);
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_AP_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(door1, LOW);
pinMode(door1, 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_door1_open, INPUT_PULLUP);
pinMode(sensor_door1_close, INPUT_PULLUP);
//associar ao debouncer
debouncerOpen_door1.attach(sensor_door1_open);
debouncerOpen_door1.interval(5);//DELAY
debouncerClose_door1.attach(sensor_door1_close);
debouncerClose_door1.interval(5);//DELAY
}
void openCover(){
if(!lastStateNotified_door1.equals(payload_open)){
digitalWrite(door1,HIGH);
delay(400);
digitalWrite(door1,LOW);
lastStateNotified_door1 = payload_open;
Serial.println("OPEN");
Debug.println("OPEN");
}
}
void closeCover(){
if(!lastStateNotified_door1.equals(payload_close)){
digitalWrite(door1,HIGH);
delay(400);
digitalWrite(door1,LOW);
lastStateNotified_door1 = payload_close;
Serial.println("CLOSE");
Debug.println("CLOSE");
}
}
void stopCover(){
if(!lastStateNotified_door1.equals(payload_stop)){
digitalWrite(door1,HIGH);
delay(400);
digitalWrite(door1,LOW);
lastStateNotified_door1 = payload_stop;
client.publish(ha_state_door1,payload_stop,true);
client.publish(ha_sensor_door1,"Parada",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_door1_status() {
//atualizar estado dos sensores
debouncerOpen_door1.update();
debouncerClose_door1.update();
int currentStateOpen = debouncerOpen_door1.read();
int currentStateClose = debouncerClose_door1.read();
if(door1_laststatesensor_close == 5 && door1_laststatesensor_open == 5){
door1_laststatesensor_close = currentStateClose;
door1_laststatesensor_open = currentStateOpen;
Debug.println("Primeiro if para o estado dos sensores");
}else if(currentStateClose != door1_laststatesensor_close && currentStateOpen == door1_laststatesensor_open){
if(currentStateClose == 1 && door1_laststatesensor_close == 0){
publish_door1_status("Abrindo");
Serial.println("Abrindo");
Debug.println("Abrindo");
}else {
publish_door1_status("Fechado");
Serial.println("Fechado");
Debug.println("Fechado");
}
door1_laststatesensor_close = currentStateClose;
}else if (currentStateClose == door1_laststatesensor_close && currentStateOpen != door1_laststatesensor_open){
if(currentStateOpen == 1 && door1_laststatesensor_open == 0){
publish_door1_status("Fechando");
Serial.println("Fechando");
Debug.println("Fechando");
}else {
publish_door1_status("Aberto");
Serial.println("Aberto");
Debug.println("Aberto");
}
door1_laststatesensor_open = currentStateOpen;
}else if (currentStateClose != door1_laststatesensor_close && currentStateOpen != door1_laststatesensor_open){
door1_laststatesensor_close = currentStateClose;
door1_laststatesensor_open = currentStateOpen;
publish_door1_status("error");
Serial.println("Problema nos sensores");
Debug.println("Problema nos sensores");
}
}
void publish_door1_status(String message)
{
if(message == "Fechado") {
lastStateNotified_door1 = payload_close;
client.publish(ha_state_door1,payload_close,true);
client.publish(ha_sensor_door1, "Fechado", true);
}else if(message == "Aberto"){
lastStateNotified_door1 = payload_open;
client.publish(ha_state_door1,payload_open,true);
client.publish(ha_sensor_door1, "Aberto", true);
}else if(message == "error"){
client.publish(ha_sensor_door1, "Problema nos sensores", true);
}else if(message == "Fechando"){
client.publish(ha_sensor_door1,"Fechando",true);
}else if(message == "Abrindo"){
client.publish(ha_sensor_door1,"Abrindo",true);
}
}
void loop() {
if (WiFi.status() == WL_CONNECTED)
{
if (checkMqttConnection())
{
httpServer.handleClient();
client.loop();
check_door1_status();
Debug.handle();
//sensor DHT
// Report every 2 seconds.
if(timeSinceLastRead > 30000)
{
// Reading temperature or humidity takes about 250 milliseconds!
// Sensor readings may also be up to 2 seconds 'old' (its a very slow sensor)
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));
client.publish(ha_temperature, dtostrf(t, 1, 2, val));
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();
}
}
Com esse codigo tem o estado do portão: fechado - abrindo - aberto - fechando - parado + temperatura e humidade + debug do wemos (telnet porta 23)
Do lado do home Assistant no ficheiro configuration.yaml
colocas:
cover:
- platform: mqtt
name: "Garagem"
command_topic: "ha/garagem/door1/set"
state_topic: "ha/garagem/door1/status"
availability_topic: "ha/garagem/door1/lwt"
qos: 0
retain: true
payload_open: "OPEN"
payload_close: "CLOSE"
payload_stop: "STOP"
payload_available: "ONLINE"
payload_not_available: "OFFLINE"
state_open: "OPEN"
state_closed: "CLOSE"
optimistic: false
sensor:
- platform: mqtt
state_topic: 'ha/garagem/door1/position'
name: 'garagem_estado_minhaporta'
qos: 0
retain: true
customize:
sensor.garagem_estado_minhaporta:
friendly_name: Estado
show_last_changed: true
templates:
icon_color: >
if (state === 'Fechando' || state === 'Abrindo') return 'yellow';
else if (state === 'Problema nos sensores') return 'red';
else if (state === 'Parada') return 'orange';
return 'rgb(54, 95, 140)';
icon: >
if (state === 'Fechando') return 'mdi:garage';
else if (state === 'Abrindo') return 'mdi:garage-open';
else if (state === 'Aberto') return 'mdi:garage-open';
else if (state === 'Fechado') return 'mdi:garage';
else if (state === 'Problema nos sensores') return 'mdi:garage-alert';
else if (state === 'Parada') return 'mdi:garage-alert';
Video: