MQTT Cover

I’m afraid you’ll have to explain that again. I don’t understand the problem.

Ok maybe I didn’t explain it correctly but now what happens is if I only use home assistant to open/close the door it is fine and won’t misfire because of the flag. The problem I am having is that if I open it with home assistant but then close it with a garage door opener then the NodeMCU will fire once because the state is no longer the same and the flag gets reset when the Reed switch state changes. I don’t know why the message is still being fired even after the state of the reed switch is changed. I think it has to do with the retain flag because my program reconnects to mqtt broker all the time but not sure how to fix that

To clear out any topics that have been set with the retain flag, you need to send a null payload with the retain flag sent e.g.

$ mosquitto_pub -t "topic" -r -n

Even so, sorting out the re connections does seem like the next step. Can you tell from the serial output if the network is disconnecting, or just the MQTT connection?

I believe it is just the MQTT connection. There have been a few times the network has gone out but it reconnects and does not seem to be the issue here.

How often you see the status messages on your broker? Maybe you are flooding the mqtt broker with this unnecessary updates.

home/garage/door3 0
home/garage/status 0
home/garage/status 0
home/garage/status 0
home/garage/status 0
home/garage/status 0

etc…

How often you see the status messages on your broker? Maybe you are flooding the mqtt broker with this unnecessary updates.

home/garage/door3 0
home/garage/status 0
home/garage/status 0
home/garage/status 0
home/garage/status 0
home/garage/status 0

etc…

The only time home/garage/status is posted to the broker now is after a state change in the relay. This is also the time when the flag is set to zero. I commented out all the unnecessary stuff that was posting to the serial port and it seems to be running better however I still have the issue of if i were to open or close with a manual remote that does not post to mqtt like a car remote then it will try to open/shut the garage door one more time.

Ok so I think I figured it out although it is not perfect and not exactly how I want it but I think I will be ok with this. Thanks everyone for all the help I really appreciate it. So how I have it set up is that every time the open or close button is pushed in MQTT a hold flag is triggered and to reset this flag the stop button has to be pushed first then the open/close button can be pushed. The stop button also updates the state of the reed switch. Also I added some code so if the open/close button is pushed but the stop button was not pushed then after the counter reaches 500 it will update the status of the reed switch. So below is my code:

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

// Use these lines to setup MQTT Server and WiFi
#define MQTT_SERVER "XXXXXXXXXXXX"
const char* ssid = "XXXXXX";
const char* password = "XXXXXX";

// Define GPIO on NodeMCU
const int doorPin = 13;
const int relayPin = 14;

char* DOOR_CLOSED = "0";
char* DOOR_OPEN = "1";
char* DOOR_WAIT = "5";
char* DOOR_CLEAR = "8";

// Define Variables
//int garageRelay = 0;
bool isOpen = false;
int hold = 1;
int counter = 0;

// Topics to Publish to
char* relayTopic = "home/garage/door";

// Topics to Subscribe to
char* doorTopic = "home/garage/status";

WiFiClient wifiClient;
PubSubClient client(MQTT_SERVER, 1883, callback, wifiClient);


void setup() {
  pinMode(doorPin, INPUT);
  pinMode(relayPin, OUTPUT);
  digitalWrite(relayPin, HIGH);

  // Start the serial line for debugging
  Serial.begin(115200);   // com to computer

  delay(100);

  // Start wifi subsystem
  WiFi.begin(ssid, password);

  // Attempt to connect to the WIFI network and then connect to the MQTT server
  reconnect();

  // Get Initial Door State
  bool doorState = digitalRead(doorPin);
  if (doorState == 0) { //If Door is Closed
    // Publish Door Closed to doorTopic
    client.publish(doorTopic, DOOR_CLOSED);  //send close
  }
  else if (doorState == 1) { //If Door is Open
    // Publish Door Open to doorTopic
    client.publish(doorTopic, DOOR_OPEN);  //send close
  }

  // Wait for a bit before starting main loop
  delay(2000);
}

void loop() {
  // Reconnect if connection is lost
  if (!client.connected() && WiFi.status() == 3) {
    reconnect();
  }

  // Maintain MQTT connection
  client.loop();

  if(counter == 500){
    bool doorState = digitalRead(doorPin);
      if (doorState == LOW) { //if door is open and the state closed, publish
        client.publish(doorTopic, DOOR_CLOSED); //send closed
        client.publish(relayTopic, "3");
        Serial.println("Low");
      }
      else if (doorState == HIGH) { //if door is closed and the state is open, publish
        client.publish(doorTopic, DOOR_OPEN); //send open
        client.publish(relayTopic, "3");
        Serial.println("High");
      }
      counter=0;
  }

  //grab the current garage door state
  bool doorState = digitalRead(doorPin);
  if (!doorState && !isOpen) { //if door is open and the state closed, publish
    client.publish(doorTopic, DOOR_CLOSED); //send closed
    isOpen = true;
//    hold = 0; // Set hold to 0 to allow MQTT
//    Serial.println("Hold = 0");
  }
  else if (doorState && isOpen) { //if door is closed and the state is open, publish
    client.publish(doorTopic, DOOR_OPEN); //send open
    isOpen = false;
    //    hold=0; // Set hold to 0 to allow MQTT
    //    Serial.println("Hold = 0");
  }

  // Delay to allow ESP8266 WIFI functions to run
  delay(50);
  counter = counter + 1;
  Serial.println(counter);
}

// MQTT callback function -(Use only if topics are being subscribed to)
void callback(char* topic, byte* payload, unsigned int length) {

  // Convert topic to string to make it easier to work with
  String topicStr = topic;
  char byteToSend = 0;


  // Handle relayTopic
  if (topicStr.equals(relayTopic)) {
    // Grab the current garage door state
    bool doorState = digitalRead(doorPin);
    if (hold == 0) {
      if (payload[0] == '1') {
        if (doorState == 0) { //If Door is Closed
          // Open Door
          digitalWrite(relayPin, LOW);
          delay(1000);
          digitalWrite(relayPin, HIGH);
          hold = 1;
          // End Open Door
          Serial.println("");
          Serial.println("Open Called");
          Serial.println("Hold = 1");
        }
      }

      else if (payload[0] == '0') {
        if (doorState == 1) { //If Door is Open
          // Close Door
          digitalWrite(relayPin, LOW);
          delay(1000);
          digitalWrite(relayPin, HIGH);
          hold = 1;
          // End Close Door
          Serial.println("");
          Serial.println("Close Called");
          Serial.println("Hold = 1");
        }
      }
    }

    if (payload[0] == '5') {
      digitalWrite(relayPin, HIGH);
      hold = 0; // Set hold to 0 to allow MQTT
//      Serial.println("Hold = 0");
      //grab the current garage door state
      bool doorState = digitalRead(doorPin);
      if (doorState == LOW) { //if door is open and the state closed, publish
        client.publish(doorTopic, DOOR_CLOSED); //send closed
//        isOpen = true;
//        hold = 0; // Set hold to 0 to allow MQTT
//        Serial.println("Hold = 0");
      }
      else if (doorState == HIGH) { //if door is closed and the state is open, publish
        client.publish(doorTopic, DOOR_OPEN); //send open
//        isOpen = false;
//        hold=0; // Set hold to 0 to allow MQTT
//        Serial.println("Hold = 0");
      }
      
    }
  }
}


void reconnect() {
  //attempt to connect to the wifi if connection is lost
  if (WiFi.status() != WL_CONNECTED) {
    //debug printing
    Serial.print("Connecting to ");
    Serial.println(ssid);

    //loop while we wait for connection
    while (WiFi.status() != WL_CONNECTED) {
      delay(500);
      Serial.print(".");
    }

    //print out some more debug once connected
    Serial.println("");
    Serial.println("WiFi connected");
    Serial.println("IP address: ");
    Serial.println(WiFi.localIP());
  }

  //make sure we are connected to WIFI before attemping to reconnect to MQTT
  if (WiFi.status() == WL_CONNECTED) {
    // Loop until we're reconnected to the MQTT server
    while (!client.connected()) {
      //Serial.println("");
      //Serial.print("Attempting MQTT connection...");

      // Generate client name based on MAC address and last 8 bits of microsecond counter
      String clientName;
      clientName += "esp8266-";
      uint8_t mac[6];
      WiFi.macAddress(mac);
      clientName += macToStr(mac);

      //if connected, subscribe to the topic(s) we want to be notified about
      if (client.connect("(char*) clientName.c_str()", "XXXXXX", "XXXXXX")) {
        //Serial.println("");
        //Serial.print("\tMTQQ Connected");
        //        client.subscribe(doorTopic);
        client.subscribe(relayTopic);
      }


      //otherwise print failed for debugging
      else {
        Serial.println("\tFailed.");
        abort();
      }
    }
  }
}

// Generate unique name from MAC addr
String macToStr(const uint8_t* mac) {

  String result;

  for (int i = 0; i < 6; ++i) {
    result += String(mac[i], 16);

    if (i < 5) {
      result += ':';
    }
  }

  return result;
}