"Smart" Garage Door: easy and cheap. HA + MQTT + ESP8266

This was a fun and super useful project. $15-20 and maybe a couple hours work.
We can check on our garage doors, and open or close them from anywhere.
Best part was setting the automation to check on them at night and if they’re open it closes them.

1 Like

Nice project I Saw u also used the mqtt led project … can u maybe send me your wiring Schema ? My setup breaks After each x days. I have to admit that I didn’t make it waterproof enough and I wanna build it again from scratch … which components did u exactly use?

Nice video btw :+1:

Thanks! Glad you like the video.

Here’s links to everything I used for my lights.
Product Links-
LEDs: http://amzn.to/2wZFMMP
Power Supply: http://amzn.to/2y5u97p
Water Proof Box: http://amzn.to/2fm890j
Raspberry Pi: http://amzn.to/2x0q5VQ
Wifi Controller Board: http://amzn.to/2x15n9Q
Extra Wire: http://amzn.to/2f5z7MD
Bread Board and Jumpers: http://amzn.to/2y669kt
J-Channel: https://www.lowes.com/pd/Georgia-Paci

And the wiring diagram: https://github.com/Snipercaine/Holiday-LED-files

The diagram isn’t my best work. Let me know if you have specific questions. I’ll sure do my best to help you.
Good luck!

I’m having issues with this.
I am now connecting to the mqtt broker and can see that a service is being called “service cover/open_cover called” , but no action is getting to the relay. I can’t tell if it is the .yaml files not setup correctly causing no topic to be published (or the wrong topic) or if the Wemos code is preventing from sending the signal. I’ve tried changing to both pins 5 & 6 with no luck. I used Drzzs github file called [Update HA_Garage_Public_w_wifi_pw.ino]
[https://github.com/Snipercaine/HA_Garage_Doors/commit/53bec0c44f914ca10b5cd3452ea3a95b394009b6](http://Here’s the ino file from his github)

Here is the code for the wemos I’m using:
#include <ESP8266SSDP.h>

#include <ESP8266WiFi.h>          //ESP8266 Core WiFi Library
#include <PubSubClient.h>         //MQTT
 
////**********START CUSTOM PARAMS******************//
 
////Define parameters for the http firmware update // which we aren't using 
const char* host = "Garage1ESP2";
const char* ssid = "dd-wrt";
const char* password = "*************";
 
//Define the pins
#define RELAY_PIN 6
#define DOOR_PIN 15 //just another name for D8 pin
 
//Define your own MQTT 
#define mqtt_server "192.168.1.144"  //This is what you set up in HA. 
#define door_topic "sensor/garage/state1" //you can change this name, but make sure you "replace all"
#define button_topic "sensor/garage/action1" //you can change this name, but make sure you "replace all"
const char* mqtt_user = "gg"; //This is what you set up in HA. 
const char* mqtt_pass = "gg"; //This is what you set up in HA. 
 
//************END CUSTOM PARAMS********************//
//This can be used to output the date the code was compiled
const char compile_date[] = __DATE__ " " __TIME__;
 
WiFiClient espCgarage1;
 
//Initialize MQTT
PubSubClient client(espCgarage1);
 
//Setup Variables
String switch1;
String strTopic;
String strPayload;
char* door_state = "UNDEFINED";
char* last_state = "";
 
void setup() {
  //Set Relay(output) and Door(input) pins
  digitalWrite(RELAY_PIN, OUTPUT);
  digitalWrite(RELAY_PIN, LOW);
  digitalWrite(DOOR_PIN, INPUT);
 
  Serial.begin(115200);

  setup_wifi();


  client.setServer(mqtt_server, 1883); //1883 is the port number you have forwared for mqtt messages. You will need to change this if you've used a different port 
  client.setCallback(callback); //callback is the function that gets called for a topic sub
}


void loop() {
  //If MQTT client can't connect to broker, then reconnect
  if (!client.connected()) {
    reconnect();
  }
  checkDoorState();
  client.loop(); //the mqtt function that processes MQTT messages
  
}
 
void callback(char* topic, byte* payload, unsigned int length) {
  //if the 'garage/action1' topic has a payload "OPEN", then 'click' the relay
  payload[length] = '\0';
  strTopic = String((char*)topic);
  if (strTopic == button_topic)
  {
    switch1 = String((char*)payload);
    Serial.println(switch1);            //   I TRIED CHANGING THIS LINE OF CODE -- I X'ED IT OUT
    if (switch1 == "OPEN")
    {
      //'click' the relay
      Serial.println("ON");
      digitalWrite(RELAY_PIN, HIGH);
      delay(900);
      digitalWrite(RELAY_PIN, LOW);
    }
  }
}



void setup_wifi() {

  delay(10);
  Serial.println();
  Serial.print("Connecting to ");
  Serial.println(ssid);

  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, password);

  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }

  Serial.println("");
  Serial.println("WiFi connected");
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP());
}



void checkDoorState() {
  //Checks if the door state has changed, and MQTT pub the change
  last_state = door_state; //get previous state of door
  if (digitalRead(DOOR_PIN) == 0) // get new state of door
    door_state = "closed";
  else if (digitalRead(DOOR_PIN) == 1)
    door_state = "open";  
  if (last_state != door_state) { // if the state has changed then publish the change
    client.publish(door_topic, door_state);
    Serial.println(door_state);
  }
}
 
void reconnect() {
  //Reconnect to Wifi and to MQTT. If Wifi is already connected, then autoconnect doesn't do anything.
  Serial.print("Attempting MQTT connection...");
  if (client.connect(host, mqtt_user, mqtt_pass)) {
    Serial.println("connected");
    client.subscribe("sensor/garage/#");
  } else {
    Serial.print("failed, rc=");
    Serial.print(client.state());
    Serial.println(" try again in 5 seconds");
    // Wait 5 seconds before retrying
    delay(5000);
  }
}

Here is my config.yaml excerpt for the garage door relay:

cover: 
# this makes the garage door card appear in HA 
  - platform: mqtt
    name: "single"
    state_topic: "sensor/garage/state1"
    command_topic: "sensor/garage/action1"
    qos: 1
    payload_open: "OPEN"
    payload_close: "OPEN"
    payload_stop: "OPEN"
    state_open: "open"
    state_closed: "closed"
    optimistic: false
    retain: false
  - platform: mqtt  
  ##if you only have one door you can delete this second entry
    name: "double"
    state_topic: "sensor/garage/state1"
    command_topic: "sensor/garage/action1"
    payload_open: "ON"
    payload_close: "ON"
    payload_stop: "ON"
    state_open: "ON"
    state_closed: "OFF"
    optimistic: false
    retain: false

Can anyone help me determine why the mqtt topic isn’t publishing or why the wemos isn’t sending the signal to pin for relay?

Thank you

Honestly, at this point, I think the issue is with the wemos code and applying… i can see the service being called from within HA. It may be my lack of understanding of how everything works, but, it appears as though the topic is getting sent through the service/cover_open process… but nothing happens. I’m beyond baffled at this point. I have made sure that all of my installed libraries in the arduino ide are up to date… flabbergasted…not sure why this isn’t working. I’m almost at 20 hours tinkering/troubleshooting

Sorry you’re struggling with this.
I hate to do this to you but I think you’d be better off using Tastmota on the D1mini instead of my sketch. When I did this project (sept '17) I didn’t know about tasmota and I don’t think it was as well developed as it is today. It is a great way to control these wifi boards (like the D1mini) without any need to code anything in the arduino IDE.
I’ve done many videos about how I flash tasmota onto any esp8266 based board (like a Sonoff, D1mini, NodeMCU).
This is probably the best explanation of the process I use now: https://youtu.be/KMiP9Ku71To
I did this video about using Tasmota and a sonoff SV for the garage door. It’s a little fast and some things have changed since I did it. https://youtu.be/QMepwpyjMCY
Essentially you set the relay as “relay1” and the reed switch as “switch2”. I think you’ll need to set one pin as “relay2” also, but you won’t connect anything to that. If you don’t have a relay that goes with each switch then you won’t get different topics.
The topic for the relay will be “cmnd/your_sonoff_name/power1” and “stat/your_sonoff_name/power1” And topics for the Reed switch will be “cmnd/your_sonoff_name/power2” and “stat/your_sonoff_name/power2”
You don’t need to change the switchtopic like the video, and you don’t need the automation to turn the relay back off after 1 second. In the tasmota console put “pulsetime 10” and that will reset the relay to off after it’s been on for 1 second.
Hope that helps.

This looks a lot like the project I used from this thread :==> GarHAge - a Home-Automation-friendly ESP8266-based MQTT Garage Door Controller

@dap35 this was Huuuge! I modified the code for my parameters… (ssid, mqtt broker, topic, status, etc) and I’m getting MQTT messages to the D1 mini. I need to look deeper into your code now why I am not getting a relay click. I think I may need to reverse your HIGH/LOW pin settings. I just flipped over here to let you know of my success, but I think I am very close to getting this resolved. Thoughts? I’m basically using DrZzs initial setup with your code. I know you used one NodeMCU for two garages, but i want to save the wires stretching across the ceiling so I’m going to use two individuals and set different topics. Thoughts on what to change for the relay?

// Mapping NodeMCU Ports to Arduino GPIO Pins
// Allows use of NodeMCU Port nomenclature in config.h
#define D0 16      //
#define D1 5       //
#define D2 4       // relay input 
#define D3 0       //
#define D4 2       //
#define D5 14      // reed switch
#define D6 12      //
#define D7 13      //
#define D8 15      //

const char* ssid = "dd-wrt";
const char* password = "******************";

const boolean static_ip = STATIC_IP;
IPAddress ip(IP);
IPAddress gateway(GATEWAY);
IPAddress subnet(SUBNET);

const char* mqtt_broker = "*************";
const char* mqtt_clientId = "Left_Garage";
const char* mqtt_username = "****";
const char* mqtt_password = "*****";

@dap35 hmmm… I set the “const char* door1_statusSwitchLogic = “NO”;” but I’m still not getting any relay pin output… I’ll keep trying

@dap35 I stripped all of the door2 statuses, loops, and functions. Code compiles successfully, flashes good, and connects to MQTT. It publishes topics just fine, but I don’t get any status updates nor relay outputs. I’ve tried moving my relay pin around as well as my Reed switch pin around. Currently I have one end of the relay pin hooked into the 3v3 of the D1 Mini.

Edit: I’ve confirmed my configuration.yaml file topics and states are the same

You’ve got a lot of code that doesn’t have very much commenting. I’m wondering if some of this requires my input and some quotations. I’m trying to cross-check your README file for something I’ve missed.

Here’s the code I’ve compiled:
/*
* GarHAge
* a Home-Automation-friendly ESP8266-based MQTT Garage Door Controller
* Licensed under the MIT License, Copyright © 2017 marthoc
*/

#include <ESP8266WiFi.h>
#include <PubSubClient.h>
#include "config.h"

// Mapping NodeMCU Ports to Arduino GPIO Pins
// Allows use of NodeMCU Port nomenclature in config.h
#define D0 16      //
#define D1 5       //
#define D2 4       // relay input 
#define D3 0       //
#define D4 2       //
#define D5 14      // reed switch
#define D6 12      //
#define D7 13      //
#define D8 15      //

const char* ssid = "dd-wrt";
const char* password = "______";

const boolean static_ip = STATIC_IP;
IPAddress ip(IP);
IPAddress gateway(GATEWAY);
IPAddress subnet(SUBNET);

const char* mqtt_broker = "________ ";
const char* mqtt_clientId = "Left_Garage";
const char* mqtt_username = "_______";
const char* mqtt_password = "________";

const boolean activeHighRelay = ACTIVE_HIGH_RELAY;  // **I've set this to both true and false with no relay output**

const char* door1_alias = "Left_Door";
const char* mqtt_door1_action_topic = "sensor/garage/action1";
const char* mqtt_door1_status_topic = "sensor/garage/state1";
const int door1_openPin = D2;
const int door1_closePin = D2;
const int door1_statusPin = D5;
const char* door1_statusSwitchLogic = "NC";


const int relayActiveTime = 500;
int door1_lastStatusValue = 2;
unsigned long door1_lastSwitchTime = 0;
int debounceTime = 2000;

String availabilityBase = MQTT_CLIENTID;    // **does this require my input? I've entered "Left_garage" to test just in case, no relay output
**   
String availabilitySuffix = "/availability";
String availabilityTopicStr = availabilityBase + availabilitySuffix;
const char* availabilityTopic = availabilityTopicStr.c_str();
const char* birthMessage = "online";
const char* lwtMessage = "offline";

WiFiClient espClient;
PubSubClient client(espClient);

// Wifi setup function

void setup_wifi() {

  delay(10);
  Serial.println();
  Serial.print("Connecting to ");
  Serial.print(ssid);

  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, password);

  if (static_ip) {
WiFi.config(ip, gateway, subnet);
  }

  while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
  }

  Serial.print(" WiFi connected - IP address: ");
  Serial.println(WiFi.localIP());
}

// Callback when MQTT message is received; calls triggerDoorAction(), passing topic and payload as parameters

void callback(char* topic, byte* payload, unsigned int length) {
  Serial.print("Message arrived [");
  Serial.print(topic);
  Serial.print("] ");
  
  for (int i = 0; i < length; i++) {
Serial.print((char)payload[i]);
  }
  
  Serial.println();

  String topicToProcess = topic;
  payload[length] = '\0';
  String payloadToProcess = (char*)payload;
  triggerDoorAction(topicToProcess, payloadToProcess);
}

// Functions that check door status and publish an update when called

void publish_door1_status() {
  if (digitalRead(door1_statusPin) == LOW) {
if (door1_statusSwitchLogic == "NO") {
  Serial.print(door1_alias);
  Serial.print(" closed! Publishing to ");
  Serial.print(mqtt_door1_status_topic);
  Serial.println("...");
  client.publish(mqtt_door1_status_topic, "closed", true);
}
else if (door1_statusSwitchLogic == "NC") {
  Serial.print(door1_alias);
  Serial.print(" open! Publishing to ");
  Serial.print(mqtt_door1_status_topic);
  Serial.println("...");
  client.publish(mqtt_door1_status_topic, "open", true);      
}
else {
  Serial.println("Error! Specify only either NO or NC for DOOR1_STATUS_SWITCH_LOGIC in config.h! Not publishing...");
}
  }
  else {
if (door1_statusSwitchLogic == "NO") {
  Serial.print(door1_alias);
  Serial.print(" open! Publishing to ");
  Serial.print(mqtt_door1_status_topic);
  Serial.println("...");
  client.publish(mqtt_door1_status_topic, "open", true);
}
else if (door1_statusSwitchLogic == "NC") {
  Serial.print(door1_alias);
  Serial.print(" closed! Publishing to ");
  Serial.print(mqtt_door1_status_topic);
  Serial.println("...");
  client.publish(mqtt_door1_status_topic, "closed", true);      
}
else {
  Serial.println("Error! Specify only either NO or NC for DOOR1_STATUS_SWITCH_LOGIC in config.h! Not publishing...");
}
  }
}

// Functions that run in loop() to check each loop if door status (open/closed) has changed and call publish_doorX_status() to publish any change if so

void check_door1_status() {
  int currentStatusValue = digitalRead(door1_statusPin);
  if (currentStatusValue != door1_lastStatusValue) {
unsigned int currentTime = millis();
if (currentTime - door1_lastSwitchTime >= debounceTime) {
  publish_door1_status();
  door1_lastStatusValue = currentStatusValue;
  door1_lastSwitchTime = currentTime;
}
  }
}


// Function that publishes birthMessage

void publish_birth_message() {
  // Publish the birthMessage
  Serial.print("Publishing birth message \"");
  Serial.print(birthMessage);
  Serial.print("\" to ");
  Serial.print(availabilityTopic);
  Serial.println("...");
  client.publish(availabilityTopic, birthMessage, true);
}

// Function that toggles the relevant relay-connected output pin

void toggleRelay(int pin) {
  if (activeHighRelay) {
digitalWrite(pin, HIGH);
delay(relayActiveTime);
digitalWrite(pin, LOW);
  }
  else {
digitalWrite(pin, LOW);
delay(relayActiveTime);
digitalWrite(pin, HIGH);
  }
}

// Function called by callback() when a message is received 
// Passes the message topic as the "requestedDoor" parameter and the message payload as the "requestedAction" parameter

void triggerDoorAction(String requestedDoor, String requestedAction) {
  if (requestedDoor == mqtt_door1_action_topic && requestedAction == "OPEN") {
Serial.print("Triggering ");
Serial.print(door1_alias);
Serial.println(" OPEN relay!");
toggleRelay(door1_openPin);
  }
  else if (requestedDoor == mqtt_door1_action_topic && requestedAction == "CLOSE") {
Serial.print("Triggering ");
Serial.print(door1_alias);
Serial.println(" CLOSE relay!");
toggleRelay(door1_closePin);
  }
  else if (requestedDoor == mqtt_door1_action_topic && requestedAction == "STATE") {
Serial.print("Publishing on-demand status update for ");
Serial.print(door1_alias);
Serial.println("!");
publish_birth_message();
publish_door1_status();
  }
  else { Serial.println("Unrecognized action payload... taking no action!");
  }
}

// Function that runs in loop() to connect/reconnect to the MQTT broker, and publish the current door statuses on connect

void reconnect() {
  // Loop until we're reconnected
  while (!client.connected()) {
Serial.print("Attempting MQTT connection...");
// Attempt to connect
if (client.connect(mqtt_clientId, mqtt_username, mqtt_password, availabilityTopic, 0, true, lwtMessage)) {
  Serial.println("Connected!");

  // Publish the birth message on connect/reconnect
  publish_birth_message();

  // Subscribe to the action topics to listen for action messages
  Serial.print("Subscribing to ");
  Serial.print(mqtt_door1_action_topic);
  Serial.println("...");
  client.subscribe(mqtt_door1_action_topic);
}
  }
}    
void setup() {
  // Setup the output and input pins used in the sketch
  // Set the lastStatusValue variables to the state of the status pins at setup time

  // Setup Door 1 pins
  pinMode(door1_openPin, OUTPUT);
  pinMode(door1_closePin, OUTPUT);
  // Set output pins LOW with an active-high relay
  if (activeHighRelay) {
digitalWrite(door1_openPin, LOW);
digitalWrite(door1_closePin, LOW);
  }
  // Set output pins HIGH with an active-low relay
  else {
digitalWrite(door1_openPin, HIGH);
digitalWrite(door1_closePin, HIGH);
  }
  // Set input pin to use internal pullup resistor
  pinMode(door1_statusPin, INPUT_PULLUP);
  // Update variable with current door state
  door1_lastStatusValue = digitalRead(door1_statusPin);

  // Setup serial output, connect to wifi, connect to MQTT broker, set MQTT message callback
  Serial.begin(115200);

  Serial.println("Starting GarHAge...");

  if (activeHighRelay) {
Serial.println("Relay mode: Active-High");
  }
  else {
Serial.println("Relay mode: Active-Low");
  }

  setup_wifi();
  client.setServer(mqtt_broker, 1883);
  client.setCallback(callback);
}

void loop() {
  // Connect/reconnect to the MQTT broker and listen for messages
  if (!client.connected()) {
reconnect();
  }
  client.loop();
  
  // Check door open/closed status each loop and publish changes
  check_door1_status();
  }

really hoping this helps some

@drzzs thank you for your response, i tune into your live streams. I’m JUST THAT PERSON that doesn’t give up on hardware when I believe it’s a software or PEBKAC error. You got this setup to work once successfully, I should be able to replicate it… I’m not giving up…yet…

@Scott_C For GarHAge you should only modify parameters in config.h, not in the actual GarHAge.ino file. Read the README in the repo, it tells you all you need to know re the relay pin. Start with a fresh copy of the repo and try again only modifying parameters in config.h.

Happy with my opengarage

I looked at open garage and it has some really nice things going for it. The one thing I wanted to avoid was dependance on additional cloud services. Which is why I picked GarHAge.

I did end up adding a completely separate ultrasonic sensor recently to determine if that bay of the garage was occupied. Hindsight is wonderful…

IMG_0047 IMG_0048

You can do without external services. Accessing the local web server of the esp through local LAN.
Once in your homeassistant no cloud needed you access through it

Good to know. I’ve grown my solution over time. I started with GarHAge, then added this WiFi/MQTT car presence sensor for garage door automation which installs in the car. And hopefully wrapped up with the ultrasonic occupancy section above.

@ marthocoo @marthocoo
So I did what you suggested and still no dice.

Here’s what I’m using:
1 Channel Relay Module Interface Board

This is apparently a “low level trigger”?

From the image above, can you tell that my cabling is correct? I’ve tried moving things around in order to get other responses, tried a new D1 mini, tried a new relay, and have checked my arduino settings using the screenshot at this video’s time 8:56

I thought I would rule out the devices by using new chips/relays.
When I open the monitor after programming, it recognizes the MQTT broker, logs in, and can see publishes made to it but I still can get no action for the relay to turn OFF.

This may be a critical part of the troubleshooting, but once the programmer finishes programming, the D1 Mini it seems, immediately turns on the relay. When I unplug that D2, the relay closes and the LED is no longer green on it.

Anyone have any ideas for me?

In config.h are you setting “ACTIVE_HIGH_RELAY” to false? You have an active low relay.

Correct. I think it may be an issue of my loading the program? I’ll copy pasta the code I’m using in config.h as is:`
/*
* GarHAge
* a Home-Automation-friendly ESP8266-based MQTT Garage Door Controller
* Licensed under the MIT License, Copyright © 2017 marthoc
*
* User-configurable Parameters
*/

// Wifi Parameters

#define WIFI_SSID "dd-wrt"
#define WIFI_PASSWORD "########"

// Static IP Parameters

#define STATIC_IP false
#define IP 192,168,1,100
#define GATEWAY 192,168,1,1
#define SUBNET 255,255,255,0

// MQTT Parameters

#define MQTT_BROKER "192.168.1.144"
#define MQTT_CLIENTID "GarHAge"
#define MQTT_USERNAME "gg"
#define MQTT_PASSWORD "gg"

// Relay Parameters

#define ACTIVE_HIGH_RELAY false

// Door 1 Parameters

#define DOOR1_ALIAS "Door 1"
#define MQTT_DOOR1_ACTION_TOPIC "garage/door/1/action"
#define MQTT_DOOR1_STATUS_TOPIC "garage/door/1/status"
#define DOOR1_OPEN_PIN D2
#define DOOR1_CLOSE_PIN D2
#define DOOR1_STATUS_PIN D5
#define DOOR1_STATUS_SWITCH_LOGIC "NO"

// Door 2 Parameters

#define DOOR2_ENABLED false
#define DOOR2_ALIAS "Door 2"
#define MQTT_DOOR2_ACTION_TOPIC "garage/door/2/action"
#define MQTT_DOOR2_STATUS_TOPIC "garage/door/2/status"
#define DOOR2_OPEN_PIN D1
#define DOOR2_CLOSE_PIN D1
#define DOOR2_STATUS_PIN D6
#define DOOR2_STATUS_SWITCH_LOGIC "NO"

`

So I’m not sure. I’ll try true, but I doubt that will work.
my reed sensor also doesn’t seem to work, but 1 thing at a time i suppose…

Okay, so I’ve managed to get both relay responses and publishing to work successfully. I am not at a point of trying to get the relay to toggle. I’m using the MQTT.fx to assist in troubleshooting. I can publish to the chip, (the wemos D1 mini) but I’m not able to get it to actually trigger on the relay. The relay remains quiet.
The code doesn’t seem too daunting, I’m just not sure why an action isn’t sent out to the triggerRelay

any thoughts? Help? anyone out there that understands the language?

/*   
 * GarHAge
 * a Home-Automation-friendly ESP8266-based MQTT Garage Door Controller
 * Licensed under the MIT License, Copyright (c) 2017 marthoc
*/

#include <ESP8266WiFi.h>
#include <PubSubClient.h>
//#include "config.h"


// Mapping NodeMCU Ports to Arduino GPIO Pins
// THIS IS ALL YOU NEED TO CHANGE IN THIS FILE
#define D0 16
#define D1 5
#define D2 15
#define D3 0
#define D4 2
#define D5 14
#define D6 12 
#define D7 13
#define D8 15
#define WIFI_SSID "############"
#define WIFI_PASSWORD "############"
#define MQTT_BROKER "192.168.1.144"
#define MQTT_CLIENTID "GarHage0206"
#define MQTT_USERNAME "gg"
#define MQTT_PASSWORD "gg"
#define ACTIVE_HIGH_RELAY true
#define DOOR1_ALIAS "Door 1"
#define MQTT_DOOR1_ACTION_TOPIC "garage/door/1/action"
#define MQTT_DOOR1_STATUS_TOPIC "garage/door/1/status"
#define DOOR1_OPEN_PIN D2
#define DOOR1_CLOSE_PIN D2
#define DOOR1_STATUS_PIN D8
#define DOOR1_STATUS_SWITCH_LOGIC "NO"

//THAT WAS ALL YOU NEEDED TO CHANGE IN THE FILE



const char* ssid = WIFI_SSID;
const char* password = WIFI_PASSWORD;

//const boolean static_ip = STATIC_IP;
//IPAddress ip(IP);
//IPAddress gateway(GATEWAY);
//IPAddress subnet(SUBNET);

const char* mqtt_broker = MQTT_BROKER;
const char* mqtt_clientId = MQTT_CLIENTID;
const char* mqtt_username = MQTT_USERNAME;
const char* mqtt_password = MQTT_PASSWORD;

const boolean activeHighRelay = ACTIVE_HIGH_RELAY;

const char* door1_alias = DOOR1_ALIAS;
const char* mqtt_door1_action_topic = MQTT_DOOR1_ACTION_TOPIC;
const char* mqtt_door1_status_topic = MQTT_DOOR1_STATUS_TOPIC;
const int door1_openPin = DOOR1_OPEN_PIN;
const int door1_closePin = DOOR1_CLOSE_PIN;
const int door1_statusPin = DOOR1_STATUS_PIN;
const char* door1_statusSwitchLogic = DOOR1_STATUS_SWITCH_LOGIC;

//CHANGING RELAY ACTIVE TIME
const int relayActiveTime = 1000;
int door1_lastStatusValue = 2;
unsigned long door1_lastSwitchTime = 0;
int debounceTime = 2000;

String availabilityBase = MQTT_CLIENTID;
String availabilitySuffix = "/availability";
String availabilityTopicStr = availabilityBase + availabilitySuffix;
const char* availabilityTopic = availabilityTopicStr.c_str();
const char* birthMessage = "online";
const char* lwtMessage = "offline";

WiFiClient espClient;
PubSubClient client(espClient);

// Wifi setup function

void setup_wifi() {

  delay(10);
  Serial.println();
  Serial.print("Connecting to ");
  Serial.print(ssid);

  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, password);

//  if (static_ip) {
//    WiFi.config(ip, gateway, subnet);
//  }

  while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
  }

  Serial.print(" WiFi connected - IP address: ");
  Serial.println(WiFi.localIP());
}

// Callback when MQTT message is received; calls triggerDoorAction(), passing topic and payload as parameters

void callback(char* topic, byte* payload, unsigned int length) {
  Serial.print("Message arrived [");
  Serial.print(topic);
  Serial.print("] ");
  
  for (int i = 0; i < length; i++) {
Serial.print((char)payload[i]);
  }
  
  Serial.println();

  String topicToProcess = topic;
  payload[length] = '\0';
  String payloadToProcess = (char*)payload;
  triggerDoorAction(topicToProcess, payloadToProcess);
}

// Functions that check door status and publish an update when called

void publish_door1_status() {
  if (digitalRead(door1_statusPin) == LOW) {
if (door1_statusSwitchLogic == "NO") {
  Serial.print(door1_alias);
  Serial.print(" closed! Publishing to ");
  Serial.print(mqtt_door1_status_topic);
  Serial.println("...");
  client.publish(mqtt_door1_status_topic, "closed", true);
}
else if (door1_statusSwitchLogic == "NC") {
  Serial.print(door1_alias);
  Serial.print(" open! Publishing to ");
  Serial.print(mqtt_door1_status_topic);
  Serial.println("...");
  client.publish(mqtt_door1_status_topic, "open", true);      
}
else {
  Serial.println("Error! Specify only either NO or NC for DOOR1_STATUS_SWITCH_LOGIC in config.h! Not publishing...");
}
  }
  else {
if (door1_statusSwitchLogic == "NO") {
  Serial.print(door1_alias);
  Serial.print(" open! Publishing to ");
  Serial.print(mqtt_door1_status_topic);
  Serial.println("...");
  client.publish(mqtt_door1_status_topic, "open", true);
}
else if (door1_statusSwitchLogic == "NC") {
  Serial.print(door1_alias);
  Serial.print(" closed! Publishing to ");
  Serial.print(mqtt_door1_status_topic);
  Serial.println("...");
  client.publish(mqtt_door1_status_topic, "closed", true);      
}
else {
  Serial.println("Error! Specify only either NO or NC for DOOR1_STATUS_SWITCH_LOGIC in config.h! Not publishing...");
}
  }
}





// Functions that run in loop() to check each loop if door status (open/closed) has changed and call publish_doorX_status() to publish any change if so

void check_door1_status() {
  int currentStatusValue = digitalRead(door1_statusPin);
  if (currentStatusValue != door1_lastStatusValue) {
unsigned int currentTime = millis();
if (currentTime - door1_lastSwitchTime >= debounceTime) {
  publish_door1_status();
  door1_lastStatusValue = currentStatusValue;
  door1_lastSwitchTime = currentTime;
}
  }
}





// Function that publishes birthMessage

void publish_birth_message() {
  // Publish the birthMessage
  Serial.print("Publishing birth message \"");
  Serial.print(birthMessage);
  Serial.print("\" to ");
  Serial.print(availabilityTopic);
  Serial.println("...");
  client.publish(availabilityTopic, birthMessage, true);
}

// Function that toggles the relevant relay-connected output pin
//******************I THINK THIS IS WHAT NEEDS TO BE FOCUSE ON******************************************#######################
void toggleRelay(int pin) {
  if (activeHighRelay) {
digitalWrite(pin, HIGH);
delay(relayActiveTime);
digitalWrite(pin, LOW);
  }
  else {
digitalWrite(pin, LOW);
delay(relayActiveTime);
digitalWrite(pin, HIGH);
  }
}

// Function called by callback() when a message is received 
// Passes the message topic as the "requestedDoor" parameter and the message payload as the "requestedAction" parameter
// THIS JUST PRINTS OUT THE ACTION AND MESSAGE RECEIVED VIA SERIAL CONNECTION
// KEEP AN EYE OUT FOR THE TOGGLERELAY ACTION
void triggerDoorAction(String requestedDoor, String requestedAction) {
  if (requestedDoor == mqtt_door1_action_topic && requestedAction == "OPEN") {
Serial.print("Triggering ");
Serial.print(door1_alias);
Serial.println(" OPEN relay!");
toggleRelay(door1_openPin);
  }
  else if (requestedDoor == mqtt_door1_action_topic && requestedAction == "CLOSE") {
Serial.print("Triggering ");
Serial.print(door1_alias);
Serial.println(" CLOSE relay!");
toggleRelay(door1_closePin);
  }
  else if (requestedDoor == mqtt_door1_action_topic && requestedAction == "STATE") {
Serial.print("Publishing on-demand status update for ");
Serial.print(door1_alias);
Serial.println("!");
publish_birth_message();
publish_door1_status();
  }
  else { Serial.println("Unrecognized action payload... taking no action!");

 }
}
//ENDS THE ACTION OF WRITING IN SERIAL WHAT WAS RECEIVED AND WHAT IT WAS TOLD TO DO


// Function that runs in loop() to connect/reconnect to the MQTT broker, and publish the current door statuses on connect

void reconnect() {
  // Loop until we're reconnected
  while (!client.connected()) {
Serial.print("Attempting MQTT connection...");
// Attempt to connect
if (client.connect(mqtt_clientId, mqtt_username, mqtt_password, availabilityTopic, 0, true, lwtMessage)) {
  Serial.println("Connected!");

  // Publish the birth message on connect/reconnect
  publish_birth_message();

  // Subscribe to the action topics to listen for action messages
  Serial.print("Subscribing to ");
  Serial.print(mqtt_door1_action_topic);
  Serial.println("...");
  client.subscribe(mqtt_door1_action_topic);
  

  // Publish the current door status on connect/reconnect to ensure status is synced with whatever happened while disconnected
  publish_door1_status();


} 
else {
  Serial.print("failed, rc=");
  Serial.print(client.state());
  Serial.println(" try again in 5 seconds");
  // Wait 5 seconds before retrying
  delay(5000);
}
  }
}



void setup() {
  // Setup the output and input pins used in the sketch
  // Set the lastStatusValue variables to the state of the status pins at setup time

  // Setup Door 1 pins
  pinMode(door1_openPin, OUTPUT);
  pinMode(door1_closePin, OUTPUT);
  // Set output pins LOW with an active-high relay
  if (activeHighRelay) {
digitalWrite(door1_openPin, LOW);
digitalWrite(door1_closePin, LOW);
  }
  // Set output pins HIGH with an active-low relay
  else {
digitalWrite(door1_openPin, HIGH);
digitalWrite(door1_closePin, HIGH);
  }
  // Set input pin to use internal pullup resistor
  pinMode(door1_statusPin, INPUT_PULLUP);
  // Update variable with current door state
  door1_lastStatusValue = digitalRead(door1_statusPin);

//   Setup Door 2 pins
//  if (door2_enabled) {
//    pinMode(door2_openPin, OUTPUT);
//    pinMode(door2_closePin, OUTPUT);
//    Set output pins LOW with an active-high relay
//    if (activeHighRelay) {
//      digitalWrite(door2_openPin, LOW);
//      digitalWrite(door2_closePin, LOW);
//    }
//    // Set output pins HIGH with an active-low relay
//    else {
//      digitalWrite(door2_openPin, HIGH);
//      digitalWrite(door2_closePin, HIGH);
//    }
//    // Set input pin to use internal pullup resistor
//    pinMode(door2_statusPin, INPUT_PULLUP);
//    // Update variable with current door state
//    door2_lastStatusValue = digitalRead(door2_statusPin);
//  }

  // Setup serial output, connect to wifi, connect to MQTT broker, set MQTT message callback
  Serial.begin(115200);

  Serial.println("Starting GarHAge...");

  if (activeHighRelay) {
Serial.println("Relay mode: Active-High");
  }
  else {
Serial.println("Relay mode: Active-Low");
  }

  setup_wifi();
  client.setServer(mqtt_broker, 1883);
  client.setCallback(callback);
}

void loop() {
  // Connect/reconnect to the MQTT broker and listen for messages
  if (!client.connected()) {
reconnect();
  }
  client.loop();
  
  // Check door open/closed status each loop and publish changes
  check_door1_status();
  
}




//*********************************************************************************************************************
//*********************************************************************************************************************
//*********************************************************************************************************************