{"id":38,"date":"2025-09-17T09:32:11","date_gmt":"2025-09-17T08:32:11","guid":{"rendered":"https:\/\/busman.io\/?p=38"},"modified":"2025-09-17T09:33:14","modified_gmt":"2025-09-17T08:33:14","slug":"garage-door-opener-with-esp32","status":"publish","type":"post","link":"https:\/\/busman.io\/?p=38","title":{"rendered":"Garage door opener with ESP32"},"content":{"rendered":"\n<p class=\"wp-block-paragraph\">This code is used by the ESP 32 to function as a garage door opener<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>#include &lt;WiFi.h>\n#include &lt;PubSubClient.h>\n\nconst char* ssid = \"WiFi\";\nconst char* password = \"&lt;password here>\";\nconst char* mqtt_server = \"192.168.200.132\";      \/\/ Your MQTT broker IP\nconst char* mqtt_user = \"mqtt_user\";            \/\/ MQTT username\nconst char* mqtt_pass = \"mqtt001\";            \/\/ MQTT password\n\n#define RELAY_PIN 16\n#define DEVICE_ID \"garage-opener\"\n\nWiFiClient espClient;\nPubSubClient client(espClient);\n\nconst char* commandTopic = \"home\/esp32\/garage\/trigger\";\nconst char* availabilityTopic = \"home\/esp32\/garage\/availability\";\nconst char* discoveryTopic = \"homeassistant\/button\/esp32garage1\/config\";\n\nvoid setup_wifi() {\n  Serial.begin(115200);  \/\/ \ud83d\udd27 Set baudrate for serial debug\n  delay(10);\n  Serial.println(\"\\n&#91;INFO] Connecting to WiFi...\");\n  WiFi.begin(ssid, password);\n\n  while (WiFi.status() != WL_CONNECTED) {\n    delay(500);\n    Serial.print(\".\");\n  }\n  Serial.println(\"\\n&#91;INFO] WiFi connected. IP address: \");\n  Serial.println(WiFi.localIP());\n}\n\nvoid publishDiscovery() {\n  Serial.println(\"&#91;INFO] Publishing MQTT discovery payload...\");\n\n  String payload = R\"rawliteral({\n    \"name\": \"Opener\",\n    \"command_topic\": \"home\/esp32\/garage\/trigger\",\n    \"availability_topic\": \"home\/esp32\/garage\/availability\",\n    \"payload_press\": \"PRESS\",\n    \"unique_id\": \"garage-opener\",\n    \"device\": {\n      \"identifiers\": &#91;\"esp32garage1\"],\n      \"name\": \"Garage\"\n    }\n  })rawliteral\";\n\n  bool success = client.publish(\"homeassistant\/button\/esp32garage1\/config\", payload.c_str(), true);\n  Serial.println(success ? \"&#91;OK] MQTT discovery published.\" : \"&#91;ERROR] Failed to publish discovery payload.\");\n}\n\nunsigned long firstPressTime = 0;\nconst unsigned long doublePressInterval = 1000;  \/\/ max time between presses (ms)\nbool waitingForSecondPress = false;\n\nvoid handleButtonPress() {\n  unsigned long now = millis();\n\n  if (!waitingForSecondPress) {\n    \/\/ First press detected, start timer\n    waitingForSecondPress = true;\n    firstPressTime = now;\n    Serial.println(\"&#91;INFO] First press detected, waiting for second...\");\n  } else {\n    \/\/ Second press detected: check if within interval\n    if (now - firstPressTime &lt;= doublePressInterval) {\n      Serial.println(\"&#91;INFO] Double press confirmed! Triggering relay...\");\n      triggerRelay();\n    } else {\n      Serial.println(\"&#91;INFO] Second press too late, resetting...\");\n    }\n    \/\/ Reset for next detection\n    waitingForSecondPress = false;\n  }\n}\n\nvoid triggerRelay() {\n  digitalWrite(RELAY_PIN, HIGH);\n  delay(500);\n  digitalWrite(RELAY_PIN, LOW);\n  Serial.println(\"&#91;OK] Relay triggered for 500ms\");\n}\n\nvoid callback(char* topic, byte* payload, unsigned int length) {\n  Serial.print(\"&#91;INFO] MQTT message received on topic: \");\n  Serial.println(topic);\n\n  String msg;\n  for (unsigned int i = 0; i &lt; length; i++) {\n    msg += (char)payload&#91;i];\n  }\n  msg.trim();\n\n  Serial.print(\"&#91;INFO] Payload: \");\n  Serial.println(msg);\n\n  if (String(topic) == commandTopic &amp;&amp; msg == \"PRESS\") {\n    handleButtonPress();  \/\/ Enforces double press logic\n  }\n}\n\nvoid reconnect() {\n  while (!client.connected()) {\n    Serial.print(\"&#91;INFO] Connecting to MQTT...\");\n    if (client.connect(\"ESP32GarageClient\", mqtt_user, mqtt_pass)) {\n      Serial.println(\"&#91;OK] Connected to MQTT broker\");\n      client.subscribe(commandTopic);\n      client.publish(availabilityTopic, \"online\", true);\n      publishDiscovery();\n    } else {\n      Serial.print(\"&#91;ERROR] MQTT connect failed, rc=\");\n      Serial.println(client.state());\n      delay(5000);\n    }\n  }\n}\n\nvoid setup() {\n  pinMode(RELAY_PIN, OUTPUT);\n  digitalWrite(RELAY_PIN, LOW);\n  setup_wifi();\n  client.setServer(mqtt_server, 1883);\n  client.setCallback(callback);\n}\n\nvoid loop() {\n  if (!client.connected()) {\n    reconnect();\n  }\n  client.loop();\n}\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\"><\/p>\n","protected":false},"excerpt":{"rendered":"<p>This code is used by the ESP 32 to function as a garage door opener<\/p>\n","protected":false},"author":1,"featured_media":40,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"site-sidebar-layout":"default","site-content-layout":"","ast-site-content-layout":"default","site-content-style":"default","site-sidebar-style":"default","ast-global-header-display":"","ast-banner-title-visibility":"","ast-main-header-display":"","ast-hfb-above-header-display":"","ast-hfb-below-header-display":"","ast-hfb-mobile-header-display":"","site-post-title":"","ast-breadcrumbs-content":"","ast-featured-img":"","footer-sml-layout":"","theme-transparent-header-meta":"","adv-header-id-meta":"","stick-header-meta":"","header-above-stick-meta":"","header-main-stick-meta":"","header-below-stick-meta":"","astra-migrate-meta-layouts":"default","ast-page-background-enabled":"default","ast-page-background-meta":{"desktop":{"background-color":"var(--ast-global-color-5)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"tablet":{"background-color":"","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"mobile":{"background-color":"","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""}},"ast-content-background-meta":{"desktop":{"background-color":"var(--ast-global-color-4)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"tablet":{"background-color":"var(--ast-global-color-4)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"mobile":{"background-color":"var(--ast-global-color-4)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""}},"_jetpack_memberships_contains_paid_content":false,"footnotes":""},"categories":[1],"tags":[],"class_list":["post-38","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-uncategorized"],"jetpack_featured_media_url":"https:\/\/busman.io\/wp-content\/uploads\/2025\/09\/65365e83-8c09-4cdb-82e8-94be51e5240b.webp","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/busman.io\/index.php?rest_route=\/wp\/v2\/posts\/38","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/busman.io\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/busman.io\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/busman.io\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/busman.io\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=38"}],"version-history":[{"count":1,"href":"https:\/\/busman.io\/index.php?rest_route=\/wp\/v2\/posts\/38\/revisions"}],"predecessor-version":[{"id":39,"href":"https:\/\/busman.io\/index.php?rest_route=\/wp\/v2\/posts\/38\/revisions\/39"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/busman.io\/index.php?rest_route=\/wp\/v2\/media\/40"}],"wp:attachment":[{"href":"https:\/\/busman.io\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=38"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/busman.io\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=38"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/busman.io\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=38"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}