I decided I wanted to be able to control my garage door using my phone. After some research, I decided to use an ESP8266 based Wemos D1 Mini and Home Assistant.

Here are the parts that will be needed:

Software Requirements:

Home Assistant configured with an MQTT broker such as Mosquitto

Arduino IDE

I’m going to assume that Home Assistant, MQTT, and Arduino IDE are all setup. There are plenty of guides out there on how to set those up. If anyone reading this does need help with any of that, feel free to post a comment.

The first thing we will need to do is wire up the Wemos. The schematic below shows how I wired mine. If for any reason, you don’t use the same pins as I did on the Wemos, keep in mind that the chip will send some pins to high on startup. That would trigger the relay, and unexpectedly open your garage door. Be mindful of which pin you use.

Next, we need to upload the code below to the Wemos. You will need to edit the custom parameters section as needed. The first time you upload the firmware, you will need to do it via serial using a USB cable. After the firmware is on there, you can do the updates Over-The-Air (OTA). The code below uses WifiManager, which starts the Wemos as an AP if it can’t connect to a Wifi network. You can then connect to the AP to setup Wifi on the Wemos. The settings will be saved across reboots. For OTA, in Arduino IDE, click Tools -> Flash Size -> 4M (1M SPIFFS). If you don’t do this, the firmware will not work on the Wemos. Next, compile it in Arduino IDE using CTRL+ALT+S. That will compile a *.bin file in the same directory as your *.ino. You can use your web browser to go to http://<Wemos IP>/WebFirmwareUpgrade and upload the *.bin file. It will then reboot in about 30 seconds with the new code.

#include <ESP8266WiFi.h> //ESP8266 Core WiFi Library (you most likely already have this in your sketch) #include <DNSServer.h> //Local DNS Server used for redirecting all requests to the configuration portal #include <ESP8266WebServer.h> //Local WebServer used to serve the configuration portal #include <WiFiManager.h> //https://github.com/tzapu/WiFiManager WiFi Configuration Magic #include <PubSubClient.h> //MQTT #include <ESP8266mDNS.h> #include <ESP8266HTTPUpdateServer.h> ////**********START CUSTOM PARAMS******************// //Define parameters for the http firmware update const char* host = "GarageESP"; const char* update_path = "/WebFirmwareUpgrade"; const char* update_username = "admin"; const char* update_password = "YourPassWordHere"; //Define the pins #define RELAY_PIN 5 #define DOOR_PIN 4 //Define MQTT Params. If you don't need to #define mqtt_server "MQTT Broker IP Address" #define door_topic "garage/door" #define button_topic "garage/button" const char* mqtt_user = "mqtt_user"; const char* mqtt_pass = "mqtt_pass"; //************END CUSTOM PARAMS********************// //This can be used to output the date the code was compiled const char compile_date[] = __DATE__ " " __TIME__; //Setup the web server for http OTA updates. ESP8266WebServer httpServer(80); ESP8266HTTPUpdateServer httpUpdater; WiFiClient espClient; //Initialize MQTT PubSubClient client(espClient); //Setup Variables String switch1; String strTopic; String strPayload; char* door_state = "UNDEFINED"; char* last_state = ""; //Wifi Manager will try to connect to the saved AP. If that fails, it will start up as an AP //which you can connect to and setup the wifi WiFiManager wifiManager; long lastMsg = 0; void setup() { //Set Relay(output) and Door(input) pins pinMode(RELAY_PIN, OUTPUT); pinMode(RELAY_PIN, LOW); pinMode(DOOR_PIN, INPUT); Serial.begin(115200); //Set the wifi config portal to only show for 3 minutes, then continue. wifiManager.setConfigPortalTimeout(180); wifiManager.autoConnect(host); //sets up the mqtt server, and sets callback() as the function that gets called //when a subscribed topic has data client.setServer(mqtt_server, 1883); client.setCallback(callback); //callback is the function that gets called for a topic sub //setup http firmware update page. MDNS.begin(host); httpUpdater.setup(&httpServer, update_path, update_username, update_password); httpServer.begin(); MDNS.addService("http", "tcp", 80); Serial.printf("HTTPUpdateServer ready! Open http://%s.local%s in your browser and login with username '%s' and your password

", host, update_path, update_username); } 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 httpServer.handleClient(); //handles requests for the firmware update page } void callback(char* topic, byte* payload, unsigned int length) { //if the 'garage/button' topic has a payload "OPEN", then 'click' the relay payload[length] = '\0'; strTopic = String((char*)topic); if (strTopic == button_topic) { switch1 = String((char*)payload); if (switch1 == "OPEN") { //'click' the relay Serial.println("ON"); pinMode(RELAY_PIN, HIGH); delay(600); pinMode(RELAY_PIN, LOW); } } } 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 = "OPENED"; else if (digitalRead(DOOR_PIN) == 1) door_state = "CLOSED"; if (last_state != door_state) { // if the state has changed then publish the change client.publish(door_topic, door_state); Serial.println(door_state); } //pub every minute, regardless of a change. long now = millis(); if (now - lastMsg > 60000) { lastMsg = now; client.publish(door_topic, door_state); } } void reconnect() { //Reconnect to Wifi and to MQTT. If Wifi is already connected, then autoconnect doesn't do anything. wifiManager.autoConnect(host); Serial.print("Attempting MQTT connection..."); if (client.connect(host, mqtt_user, mqtt_pass)) { Serial.println("connected"); client.subscribe("garage/#"); } else { Serial.print("failed, rc="); Serial.print(client.state()); Serial.println(" try again in 5 seconds"); // Wait 5 seconds before retrying delay(5000); } }