Garage door opener with ESP32

This code is used by the ESP 32 to function as a garage door opener

#include <WiFi.h>
#include <PubSubClient.h>

const char* ssid = "WiFi";
const char* password = "<password here>";
const char* mqtt_server = "192.168.200.132";      // Your MQTT broker IP
const char* mqtt_user = "mqtt_user";            // MQTT username
const char* mqtt_pass = "mqtt001";            // MQTT password

#define RELAY_PIN 16
#define DEVICE_ID "garage-opener"

WiFiClient espClient;
PubSubClient client(espClient);

const char* commandTopic = "home/esp32/garage/trigger";
const char* availabilityTopic = "home/esp32/garage/availability";
const char* discoveryTopic = "homeassistant/button/esp32garage1/config";

void setup_wifi() {
  Serial.begin(115200);  // 🔧 Set baudrate for serial debug
  delay(10);
  Serial.println("\n[INFO] Connecting to WiFi...");
  WiFi.begin(ssid, password);

  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("\n[INFO] WiFi connected. IP address: ");
  Serial.println(WiFi.localIP());
}

void publishDiscovery() {
  Serial.println("[INFO] Publishing MQTT discovery payload...");

  String payload = R"rawliteral({
    "name": "Opener",
    "command_topic": "home/esp32/garage/trigger",
    "availability_topic": "home/esp32/garage/availability",
    "payload_press": "PRESS",
    "unique_id": "garage-opener",
    "device": {
      "identifiers": ["esp32garage1"],
      "name": "Garage"
    }
  })rawliteral";

  bool success = client.publish("homeassistant/button/esp32garage1/config", payload.c_str(), true);
  Serial.println(success ? "[OK] MQTT discovery published." : "[ERROR] Failed to publish discovery payload.");
}

unsigned long firstPressTime = 0;
const unsigned long doublePressInterval = 1000;  // max time between presses (ms)
bool waitingForSecondPress = false;

void handleButtonPress() {
  unsigned long now = millis();

  if (!waitingForSecondPress) {
    // First press detected, start timer
    waitingForSecondPress = true;
    firstPressTime = now;
    Serial.println("[INFO] First press detected, waiting for second...");
  } else {
    // Second press detected: check if within interval
    if (now - firstPressTime <= doublePressInterval) {
      Serial.println("[INFO] Double press confirmed! Triggering relay...");
      triggerRelay();
    } else {
      Serial.println("[INFO] Second press too late, resetting...");
    }
    // Reset for next detection
    waitingForSecondPress = false;
  }
}

void triggerRelay() {
  digitalWrite(RELAY_PIN, HIGH);
  delay(500);
  digitalWrite(RELAY_PIN, LOW);
  Serial.println("[OK] Relay triggered for 500ms");
}

void callback(char* topic, byte* payload, unsigned int length) {
  Serial.print("[INFO] MQTT message received on topic: ");
  Serial.println(topic);

  String msg;
  for (unsigned int i = 0; i < length; i++) {
    msg += (char)payload[i];
  }
  msg.trim();

  Serial.print("[INFO] Payload: ");
  Serial.println(msg);

  if (String(topic) == commandTopic && msg == "PRESS") {
    handleButtonPress();  // Enforces double press logic
  }
}

void reconnect() {
  while (!client.connected()) {
    Serial.print("[INFO] Connecting to MQTT...");
    if (client.connect("ESP32GarageClient", mqtt_user, mqtt_pass)) {
      Serial.println("[OK] Connected to MQTT broker");
      client.subscribe(commandTopic);
      client.publish(availabilityTopic, "online", true);
      publishDiscovery();
    } else {
      Serial.print("[ERROR] MQTT connect failed, rc=");
      Serial.println(client.state());
      delay(5000);
    }
  }
}

void setup() {
  pinMode(RELAY_PIN, OUTPUT);
  digitalWrite(RELAY_PIN, LOW);
  setup_wifi();
  client.setServer(mqtt_server, 1883);
  client.setCallback(callback);
}

void loop() {
  if (!client.connected()) {
    reconnect();
  }
  client.loop();
}

Scroll to Top