Need help with MQTT + In built security system (Reed Sensors) Set up

Hello HA Community,

For past couple of weeks I have been trying to get in built home security system configured in HA setup. (Inspired By @CCOSTAN - http://www.vmwareinfo.com/2017/06/building-my-home-alarm-system-hardware.html) I have been successfully configure HA, ESP8266 and MQTT to get it working in my test environment (using jumper cables directly rather than actual reed sensors) but when I plug it in with actual reed sensors I don’t get any for of updates. I have checked reed sensors in with multimeter and they all are working properly. Below I’m including all my code. Please let me know if you see something that I am doing wrong or incorrectly. Any feedback / comment / pointers are highly appreciated.

ESP8266 Code

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

#define wifi_ssid "wifi_ssid"
#define wifi_password "wifi_password"

#define mqtt_server "mqtt_server"
#define mqtt_user "mqtt_user"
#define mqtt_password "mqtt_pwd"

class ReedSensor {
  public:
    int pin;
    int last_status;
    unsigned long last_switch_time;
    String mqtt_topic;
};

ReedSensor *front;
ReedSensor *back;
ReedSensor *deck;

#define FRONT_DOOR_STATUS_TOPIC "NodeMCU_Door/GPIO14/Status"
#define FRONT_DOOR_STATUS_PIN 14           //Black Wire
unsigned long FRONT_DOOR_LAST_SWITCH_TIME = 0;
int FRONT_DOOR_LAST_STATUS_VALUE = 2;


#define BACK_DOOR_STATUS_TOPIC "NodeMCU_Door/GPIO12/Status"
#define BACK_DOOR_STATUS_PIN 12             //White Wire
unsigned long BACK_DOOR_LAST_SWITCH_TIME = 0;
int BACK_DOOR_LAST_STATUS_VALUE = 2;

#define DECK_DOOR_STATUS_TOPIC "NodeMCU_Door/GPIO13/Status"
#define DECK_DOOR_STATUS_PIN 13             // Gray Wire
unsigned long DECK_DOOR_LAST_SWITCH_TIME = 0;
int DECK_DOOR_LAST_STATUS_VALUE = 2;


void init_reed_sensor(ReedSensor *senor, int pin, String mqtt_topic) {
senor->pin = pin;
senor->last_status = 2;
senor->last_switch_time = 0;
senor->mqtt_topic = mqtt_topic;
}

void setup_reed_switches() {
front = new ReedSensor();
init_reed_sensor(front, FRONT_DOOR_STATUS_PIN, FRONT_DOOR_STATUS_TOPIC);
back = new ReedSensor();
init_reed_sensor(back, BACK_DOOR_STATUS_PIN, BACK_DOOR_STATUS_TOPIC);
deck = new ReedSensor();
init_reed_sensor(deck, DECK_DOOR_STATUS_PIN, DECK_DOOR_STATUS_TOPIC);

//Doors
pinMode(FRONT_DOOR_STATUS_PIN, INPUT_PULLUP);
pinMode(BACK_DOOR_STATUS_PIN, INPUT_PULLUP);
pinMode(DECK_DOOR_STATUS_PIN, INPUT_PULLUP);
}

WiFiClient espClient;
PubSubClient client(espClient);

int debounceTime = 100;

void setup_wifi(){
  delay(10);
  Serial.println();
  Serial.print("Connecting to ");
  Serial.println(wifi_ssid);

  WiFi.mode(WIFI_STA);
  WiFi.begin(wifi_ssid, wifi_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 reconnect() {
  // Loop until we're reconnected
  while (!client.connected()) {
    Serial.print("Attempting MQTT connection...");
    // Attempt to connect
    if (client.connect("NodeMCU_Door", mqtt_user, mqtt_password)) {
      Serial.println("connected");
      client.subscribe("NodeMCU_Door/#");
    } 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() {
  Serial.begin(115200);
  Serial.println("Booting Security System NodeMCU Door");  
  
  //Setup WiFi
  setup_wifi();

  client.setServer(mqtt_server, 1883);
  client.setCallback(callback);

  //Setup Reed Switches
  setup_reed_switches();
}

// the loop function runs over and over again forever
void loop() {
  if (!client.connected()) {
    reconnect();
  }
  client.loop();
  checkStatusForReedSensors();
}

void checkStatusForReedSensors() {
    checkStatusFrontDoor();
    checkStatusBackDoor();
    checkStatusDeckDoor();
  }

//Front Door
void checkStatusFrontDoor() {
  int currentStatusValue = digitalRead(FRONT_DOOR_STATUS_PIN);
  int lastStatusValue = lastStatusValueForSensor(FRONT_DOOR_STATUS_PIN);
  unsigned long lastSwitchTime = lastSwitchTimeForSensor(FRONT_DOOR_STATUS_PIN);
  if (currentStatusValue != lastStatusValue) {
    unsigned int currentTime = millis();
    if (currentTime - lastSwitchTime >= debounceTime) {
      publishStatus(FRONT_DOOR_STATUS_PIN);
      setLastStatusValueForSensor(FRONT_DOOR_STATUS_PIN, currentStatusValue);
      setLastSwitchTimeForSensor(FRONT_DOOR_STATUS_PIN, currentTime);
    }
  }
}

// Back Door
void checkStatusBackDoor() {
  int currentStatusValue = digitalRead(BACK_DOOR_STATUS_PIN);
  int lastStatusValue = lastStatusValueForSensor(BACK_DOOR_STATUS_PIN);
  unsigned long lastSwitchTime = lastSwitchTimeForSensor(BACK_DOOR_STATUS_PIN);
  if (currentStatusValue != lastStatusValue) {
    unsigned int currentTime = millis();
    if (currentTime - lastSwitchTime >= debounceTime) {
      publishStatus(BACK_DOOR_STATUS_PIN);
      setLastStatusValueForSensor(BACK_DOOR_STATUS_PIN, currentStatusValue);
      setLastSwitchTimeForSensor(BACK_DOOR_STATUS_PIN, currentTime);
    }
  }
}

// Deck Door
void checkStatusDeckDoor() {
  int currentStatusValue = digitalRead(DECK_DOOR_STATUS_PIN);
  int lastStatusValue = lastStatusValueForSensor(DECK_DOOR_STATUS_PIN);
  unsigned long lastSwitchTime = lastSwitchTimeForSensor(DECK_DOOR_STATUS_PIN);
  if (currentStatusValue != lastStatusValue) {
    unsigned int currentTime = millis();
    if (currentTime - lastSwitchTime >= debounceTime) {
      publishStatus(DECK_DOOR_STATUS_PIN);
      setLastStatusValueForSensor(DECK_DOOR_STATUS_PIN, currentStatusValue);
      setLastSwitchTimeForSensor(DECK_DOOR_STATUS_PIN, currentTime);
    }
  }
}

void publishStatus(int SENSOR_PIN) {
    String topic = statusTopicForSensor(SENSOR_PIN);
    const char *stateTopic = topic.c_str();
    if(digitalRead(SENSOR_PIN) == LOW) {
      client.publish(stateTopic, "closed", true);
    } else {
      client.publish(stateTopic, "open", true);
    }
}

int lastStatusValueForSensor(int SENSOR_PIN) {
    switch(SENSOR_PIN){
      case FRONT_DOOR_STATUS_PIN: return FRONT_DOOR_LAST_STATUS_VALUE;
      case BACK_DOOR_STATUS_PIN: return BACK_DOOR_LAST_STATUS_VALUE;
      case DECK_DOOR_STATUS_PIN: return DECK_DOOR_LAST_STATUS_VALUE;
      default : return 2;
    }
    return 2;
  }

unsigned long lastSwitchTimeForSensor(int SENSOR_PIN) {
    switch(SENSOR_PIN){
      case FRONT_DOOR_STATUS_PIN: return FRONT_DOOR_LAST_SWITCH_TIME;
      case BACK_DOOR_STATUS_PIN: return BACK_DOOR_LAST_SWITCH_TIME;
      case DECK_DOOR_STATUS_PIN: return DECK_DOOR_LAST_SWITCH_TIME;
      default : return 0;
    }
    return 0;
  }

void setLastStatusValueForSensor(int SENSOR_PIN, int statusValue) {
    switch(SENSOR_PIN){
      case FRONT_DOOR_STATUS_PIN: FRONT_DOOR_LAST_STATUS_VALUE = statusValue;
      case BACK_DOOR_STATUS_PIN: BACK_DOOR_LAST_STATUS_VALUE = statusValue;
      case DECK_DOOR_STATUS_PIN: DECK_DOOR_LAST_STATUS_VALUE = statusValue;
      default : return;
    }
    return;
  }

void setLastSwitchTimeForSensor(int SENSOR_PIN, unsigned long switchTime) {
    switch(SENSOR_PIN){
      case FRONT_DOOR_STATUS_PIN: FRONT_DOOR_LAST_SWITCH_TIME = switchTime;
      case BACK_DOOR_STATUS_PIN: BACK_DOOR_LAST_SWITCH_TIME = switchTime;
      case DECK_DOOR_STATUS_PIN: DECK_DOOR_LAST_SWITCH_TIME = switchTime;
      default : return;
    }
    return;
  }

String statusTopicForSensor(int SENSOR_PIN) {
  switch(SENSOR_PIN){
    case FRONT_DOOR_STATUS_PIN: return FRONT_DOOR_STATUS_TOPIC;
    case BACK_DOOR_STATUS_PIN: return BACK_DOOR_STATUS_TOPIC;
    case DECK_DOOR_STATUS_PIN: return DECK_DOOR_STATUS_TOPIC;
    default : return "ERROR";
    }
    return "ERROR";
  }

void callback(char* topic, byte* payload, unsigned int length) {
  payload[length] = '\0';
  String strTopic = String((char*)topic);
  String payloadValue = String((char*)payload);

  Serial.print("Topic - ");
  Serial.println(strTopic);

  Serial.print("Payload - ");
  Serial.println(payloadValue);
}

HA Config File

....
binary_sensor:
  - platform: mqtt
    state_topic: "NodeMCU_Door/GPIO14/Status"
    name: "NodeMCU_Door_GPIO14"
    payload_on: "open"
    payload_off: "closed"
    device_class: opening

  - platform: mqtt
    state_topic: "NodeMCU_Door/GPIO12/Status"
    name: "NodeMCU_Door_GPIO12"
    payload_on: "open"
    payload_off: "closed"
    device_class: opening

  - platform: mqtt
    state_topic: "NodeMCU_Door/GPIO13/Status"
    name: "NodeMCU_Door_GPIO13"
    payload_on: "open"
    payload_off: "closed"
    device_class: opening
....

MQTT Broker Options

{
  "plain": true,
  "ssl": false,
  "anonymous": false,
  "logins": [
    {
      "username": "mqtt_username",
      "password": "mqtt_password"
    }
  ],
  "customize": {
    "active": false,
    "folder": "mosquitto"
  },
  "certfile": "fullchain.pem",
  "keyfile": "privkey.pem"
}

I’m afraid this has the hallmarks of a hardware problem rather than software. Can you disconnect or short out the reed switch to see if you get a signal?

How exactly did you check the operation of the reed switch?

It looks to me that there is something with the code. There is a pinMode to pull up the pin and prevent the pin floating. But I can’t see any definition for the initial state of the pin. And you are not publishing the topics with retain, when you start the sensor you’ll get status unknown for the sensor until you open and close the door…

Try changing the line

if(digitalRead(SENSOR_PIN) == LOW) {

to

if(digitalRead(SENSOR_PIN) == HIGH) {

If you want to try a different sketch, check

It is made for just one sensor but is ok for you to test. If you want i can make it multisensor, just send me a message.
The sketch has web interface, telnet, MQTT, serial interface, debug, etc.

By putting multimeter in continuity mode and testing if circuits break on opening/closing appropriate door and window.

I do send retain true in publish message. Setting initial state made it work. I think I will still have to improve my code to consider all cases. Thank you for helping me out.