Turn Your Garage Into an IoT Smart Garage

by Chev in Circuits > Arduino

18 Views, 1 Favorites, 0 Comments

Turn Your Garage Into an IoT Smart Garage

00 web interface.jpg

Hey there, fellow maker! You know that moment halfway into a long drive when your inner panic goblin suddenly sits bolt upright and screams, "DID YOU CLOSE THE GARAGE DOOR? YOU NEED TO TURN AROUND AND GO BACK. RIGHT NOW!" Decisions, decisions! It's a common headache, but don't worry—this beginner friendly project will turn your ordinary garage into a smart one. Using affordable electronics like the ESP8266 microcontroller, you can build a device that lets you check your garage door status, control it remotely, and even get alerts for motion, temperature extremes, or unexpected openings—all from your phone, tablet, or computer-anywhere with internet access.

This project is perfect for Arduino enthusiasts or anyone dipping their toes into IoT (Internet of Things). No advanced soldering skills required—you'll start with a breadboard prototype and move to a simple PCB if you want permanence. Estimated build time: 2-4 hours. Total cost: Around $30-50 (depending on what you already have). What you'll learn: Basic wiring, Arduino programming, Wi-Fi connectivity, and cloud integration with ThingSpeak.

Features:

  1. Receive an alert anytime your garage door opens or closes.
  2. Receive an alert if motion is detected in your garage.
  3. Receive an alert if the temperature in your garage is too high or too low.
  4. Open and close your garage door with your computer, tablet, or smartphone.
  5. Allow other people secure access to open or close your garage door.
  6. Posts a record of the garage humidity, temperature, air pressure, and alerts to the cloud.

Supplies

01 ESP8266.jpg
02 bme-280.jpg
03 Relay 5 volt.jpg
04 Pir HC-SR501.jpg
05 Magnetic Switch.jpg
06 PCB Board b.jpg
07 elegoo kit.jpg
08 Female Headers.jpg
09 Male Female Connector.jpg
10 Electrical Box.jpg
11 22 awg.jpg
12 multimeter.jpg
11 5V Power Adapter.jpg

Gather Your Supplies

If you're new to electronics, start with an Elegoo kit. Amazon is included here because it is so ubiquitous; other suppliers include Digi-Key, Mouser, SparkFun, Adafruit, Jameco, eBay, and AliExpress.

ESP8266: Amazon Link The brain of the project—handles Wi-Fi and processing.

BME280 Sensor: Amazon Link Measures temperature, humidity, and air pressure.

5V Relay: Amazon Link Acts as a switch to open/close the garage door.

PIR Motion Sensor: Amazon Link Detects movement for security alerts.

Magnetic Switch: Amazon Link Senses if the door is open or closed.

PCB Board Kit: Amazon Link For soldering a permanent version of the project.

Elegoo Kit: Amazon Link Includes jumper wires, resistors, and a breadboard.

Female Headers: Amazon Link Attaches the ESP8266 to the PCB Board.

Male Female Connector: Amazon Link Connects the magnetic switch and relay.

Electrical Box: Amazon Link Houses the finished project.

22 AWG Hookup Wire: Amazon Link The highway to heaven.

Multimeter: Amazon Link For shooting troubles.

5V Power Adapter with Micro-USB: Amazon Link Powers the ESP8266. Alternative: Any 5V/2A USB charger for a smartphone or tablet with a micro-usb connector you have lying around.

Understand the Basics (For Beginners)

01 wall console.jpg
02 wall console switches.jpg

Before you build, a quick explainer:

ESP8266:

  1. The ESP8266 is a low-cost Wi-Fi microchip with a built-in microcontroller that is used to create Wi-Fi-connected devices. It is a System-on-Chip (SoC) developed by Espressif Systems, featuring a 32-bit processor, Wi-Fi capabilities, and General-Purpose Input/Output (GPIO) pins for connecting to external sensors and devices. This makes it a popular and affordable platform for Internet of Things (IoT) projects and smart home devices.
  2. Wi-Fi connectivity: It operates on the 2.4 GHz frequency band.
  3. GPIO pins: It has multiple GPIO pins that can be used to interface with a variety of sensors, displays, and other hardware.

Sensors:

  1. A PIR, or Passive Infrared sensor, is a type of motion detector that senses movement by detecting changes in infrared radiation emitted by heat-producing objects like people and animals.
  2. The magnetic switch detects whether the garage door is open or closed.
  3. The BME280 detects the temperature, humidity, and air pressure inside the garage.

Relay:

  1. This project is designed to work with a Genie 3024 or similar garage door opener.
  2. The Genie wall console (see image above) has three switches:

1 turns the opener light on/off

2 locks the opener

3 opens and closes the door.

  1. The project relay is wired in parallel with switch 3.
  2. If you activate the relay with the door closed, the door will open as though you pushed switch 3.
  3. If you activate the relay with the door open, the door will close as though you pushed switch 3.
  4. This project is compatible with any garage door opener that has a standard wall console.
  5. If you want to be sure, take the two wires that go to your wall console and momentarily touch the wires together. If touching them together opens/closes the door, you have a standard wall switch.

Safety First:

  1. This project works with low voltage (5 Volts DC).
  2. Unplug your garage opener powerhead during wiring.
  3. NOTE: If you're unsure about electrical work, consult a pro!

Set Up Email Alerts

07 opened.jpg
08 closed.jpg

Create a GMAIL email account with two-factor authentication.

  1. Set up 2-step Verification - Guidebooks with Google
  2. Make a note of your google email app password;
  3. In the Arduino code INO file, the password is entered in the line: const char* AUTHOR_PASSWORD = "XXXXXXXXXXXXXX"; //<CHANGE>

Create an Outlook email alias.

  1. Add or remove an email alias in Outlook.com - Microsoft Support
  2. In the Arduino code INO file, the recipient email is entered in the line: const char* RECIPIENT_EMAIL = "XXXXXXXXX@outlook.com"; //<CHANGE>

Create and audible email alert

  1. Copy the file ESP_email_alert.mp3 to your phone or tablet's Internal storage> Notifications folder.
  2. On an Android Phone or Tablet install the Microsoft Outlook app.
  3. Go to: Settings > Apps > Outlook > Notifications > Notification Categories > Mail > Sound > select ESP_email_alert
  4. Open Outlook > tap + to add the favorite contact that is used to send alerts (such as xxxxxx@gmail.com)

Set Up ThingSpeak

B.jpg
C.jpg
D.jpg

ThingSpeak is a cloud-based IoT analytics platform that allows users to collect, visualize, and analyze live data streams from devices like sensors. It provides a way to aggregate and act on data from the Internet of Things without needing to build a server or develop web software.

How it works

  1. Collect data: Devices send sensor data, such as temperature or pressure readings, to a ThingSpeak channel.
  2. Create channels: You create a channel to organize your data. Each channel can store up to eight fields of data per update.
  3. Visualize data: ThingSpeak can create instant, real-time visualizations of your live data in the form of charts and other widgets.
  4. Analyze data: You can use MATLAB to analyze the data, perform calculations, and trigger actions based on the results.
  5. Access data: Data can be accessed online via the ThingSpeak website or through APIs, allowing for remote control and processing.

To create a ThingSpeak account, go to the ThingSpeak website, click "Get Started For Free," and follow the prompts to create a MathWorks account by providing your personal information and verifying your email. Once you have a MathWorks account, you can sign in to ThingSpeak, agree to the terms, and then create your first channel to start sending data.

Sign In - ThingSpeak IoT

Create a ThingSpeak Garage channel

  1. Log in
  2. Go to Channels > My Channels, click New Channel
  3. Name the channel Garage
  4. Name the Fields as follows:
  5. Field 1: Humidity
  6. Field 2: Temperature
  7. Field 3: Alert
  8. Field 4: Pressure
  9. Click Sharing and select Share channel view with everyone
  10. Save the channel
  11. Click API Keys to find your unique Channel ID and Write API Key
  12. Write down these two values; you will need them later

Breadboard the Circuit

01 schematic.jpg
02 Breadboard.jpg

Set Up the Breadboard:

  1. Place the ESP8266 in the center of the breadboard with the Vin pin in the third hole back from the top left edge.

Wire the BME280 Sensor to ESP8266:

  1. VCC to 3V3.
  2. GND to GND.
  3. SCL to D1.
  4. SDA to D2.

Wire the PIR Motion Sensor to ESP8266:

  1. VCC to Vin.
  2. OUT to D7.
  3. GND to GND.

Connect the Magnetic Switch:

Test

  1. Magnetic switch COM to D6.
  2. Magnetic switch NC to GND.

Alternative Test

  1. Wire 1 from NC push button switch to D6.
  2. Wire 2 from NC push button switch to GND

Wire the Relay to ESP8266:

  1. S (signal) to D5.
  2. + (plus) to Vin.
  3. - (minus) to GND.

Connect power to ESP8266:

  1. Connect a USB cable from your computer to the female micro-usb connector on the ESP8266.

Program the ESP8266

01 usb verify.jpg
02 usb upload.jpg

Program the ESP8266

  1. Download the Arduino Integrated Development Environment (IDE).
  2. Connect your computer to the ESP8266 with a USB cable.
  3. Download the full code (esp_garagemonitor.ino) below.
  4. Place the .ino file in the folder Documents > Arudino > esp_garagemonitor
  5. Open the Arduino IDE
  6. Note: If it isn't installed, you will need the CP210x Windows Drivers v6.7.6 for the ESP8266 board.
  7. Install the ESP8266 board package (Tools > Board > Boards Manager > Search "ESP8266").
  8. Select NodeMCU 1.0 (ESP-12E Module) board
  9. Select the correct COM port.
  10. Install Libraries:
  11. ESP8266WiFi
  12. WiFiUdp
  13. ESPAsyncTCP
  14. ESPAsyncWebServer
  15. Adafruit_BME280
  16. Adafruit_Sensor
  17. TimeLib
  18. TimeAlarms
  19. ThingSpeak
  20. ESP_Mail_Client
  21. NTPClient
  22. ElegantOTA
  23. From Explorer, navigate to the folder Documents > Arudino > esp_garagemonitor
  24. Load esp_garagemonitor.ino into the IDE
  25. Replace 15 const placeholders commented <CHANGE> with your own values.
  26. Replace the myChannelNumber in the String ts_url variable.
  27. Click the Verify button (the check mark below File in the IDE)
  28. If the code compiles, click the Upload button (the right pointing arrow below Edit in the IDE)

Here's the full code:

/*

esp_garagemonitor.ino

Arduino 2.3.3

Release: 12/03/2025

Uses ESP8266 Board version 3.1.2 - https://github.com/esp8266/Arduino

Uses port 8006 - AsyncWebServer server(8006)

Posts HUMIDITY value to ThingSpeak channel Garage - Field 1
Posts TEMPERATURE value to ThingSpeak channel Garage - Field 2
Posts ALERT value to ThingSpeak channel Garage - Field 3
Posts PRESSURE value to ThingSpeak channel Garage - Field 4

PIR
attach pir sensor 1 (VCC) to pin Vin (5v)
attach pir sensor 2 (OUT) to pin D7/gpio13
attach pir sensor 3 (GND) to Gnd
:
BME280
attach bme280 1 VCC to 3V3
attach bme280 2 GND to Gnd
attach bme280 3 SCL terminal to pin D1/gpio5
attach bme280 4 SDA terminal to pin D2/gpio4
:
MAGNETIC REED SWITCH
attach magnetic reed switch Normally Closed (NC) terminal to Gnd
attach magnetic reed switch Common (COM) terminal to pin D6/gpio12 - statusPin=12
Door CLOSED: when the magnet IS near the switch, COM IS connected to NC/GND; therefore, D6 is LOW (0)
Door OPEN: when the magnet IS NOT near the switch, COM IS NOT connected to NC/GND; therefore, D6 is HIGH (1)
:
RELAY
attach relay S terminal to pin D5/gpio14 - activatePin=14
attach relay + terminal to Vin (5 vdc)
attach relay - terminal to Gnd
attach relay output center terminal to Gnd (side 1 of garage door push button)
attach relay output NO terminal to LED (side 2 of garage door push button)

*/

#include <ESP8266WiFi.h> //ver 1.0.0 - Arduino15\packages\esp8266\hardware\esp8266\3.1.2\libraries\ESP8266WiFi
#include <WiFiUdp.h> //ver 1.0.0 - Arduino15\packages\esp8266\hardware\esp8266\3.1.2\libraries\ESP8266WiFi
#include <ESPAsyncTCP.h> //ver 1.2.0 - by Me-No-Dev
#include <ESPAsyncWebServer.h> //ver 3.3.1 - by lacamera
#include <Adafruit_BME280.h> //ver 2.3.0 - by Adafruit
#include <Adafruit_Sensor.h> //ver 1.1.15 - by Adafruit
#include <TimeLib.h> //ver 1.6.1 - by Michael Margolis; maintainer=Paul Stoffregen
#include <TimeAlarms.h> //ver 1.5.0 - by Michael Margolis
#include <ThingSpeak.h> //ver 2.1.1 - by MathWorks
#include <ESP_Mail_Client.h> //ver 3.4.24 - by Mobizt
#include <NTPClient.h> //ver 3.2.1 - by Fabrice Weinberg
#include <ElegantOTA.h> //ver 3.1.7 - by Ayush Sharma

/*
Open ElegantOTA library folder and then open src folder
Open the ElegantOTA.h file in Notepad and change line 27
#ifndef ELEGANTOTA_USE_ASYNC_WEBSERVER
#define ELEGANTOTA_USE_ASYNC_WEBSERVER 0 (line 27)
#endif
Change the 0 to 1
Save the changes to the ElegantOTA.h file.
*/

// CONSTANTS
const char* ntpServer = "pool.ntp.org"; //NTP server
const char* SMTP_HOST = "smtp.gmail.com"; //for email
const char* SUBJECT = "BIG GARAGE DOOR"; //subject text
const int daylightOffset_sec = 0; //0 = let ESP core apply US DST rules
const int SMTP_PORT = 465; //google port #
const int pirsensor = 13; //for PIR - pin D7/gpio13
const int thingvalue = 50; //thingspeak chart value
const int statusPin = 12; //pin D6/gpio12 for the magnetic reed switch COM terminal
const int activatePin = 14; //pin D5/gpio14 for the relay S terminal (control)
const int period = 500; //millis delay period for relay
const long gmtOffset_sec = -21600; //<CHANGE> CST (UTC-6) time zone
const char* ssid = "XXXXXXXXXX"; //<CHANGE> wifi network name (ssid)
const char* password = "XXXXXXXXXXXX"; //<CHANGE> wifi network password
const char* AUTHOR_EMAIL = "XXXXXXXXXXXXXXXXX@gmail.com"; //<CHANGE> NOTE THIS ACCOUNT HAS TWO FACTOR AUTHENTICATION SET
const char* AUTHOR_PASSWORD = "XXXXXXXXXXXXXXXX"; //<CHANGE> NOTE THIS GOOGLE APP PASSWORD FOR XXXXXX
const char* RECIPIENT_NAME = "XXXXXXXXX"; //<CHANGE> Outlook alias
const char* RECIPIENT_EMAIL = "XXXXXXXXX@outlook.com"; //<CHANGE> Outlook alias
const char* http_username = "ADMIN"; //<CHANGE> web page username authentication
const char* http_password = "ADMIN"; //<CHANGE> web page password authentication
const int lowtemp = 5; //<CHANGE> for temp alerts
const int hightemp = 95; //<CHANGE> for temp alerts
const int temp_correction = 0; //<CHANGE> for temperature correction
const int pressure_correction = 1; //<CHANGE> for pressure correction
const int humidity_correction = 0; //<CHANGE> for humidity correction
const char* myWriteAPIKey = "XXXXXXXXXXXXXXXX"; //<CHANGE> thingspeak garage channel write key
const int myChannelNumber = 1234567; //<CHANGE> thingspeak garage channel id (also change it in String ts_url variable below)

// VARIABLES
String ts_url = "<a href=https://thingspeak.mathworks.com/channels/1234567 target=_blank style=color:blue;font-weight:bold>ThingSpeak</a"; //<CHANGE>
unsigned long ota_progress_millis = 0; //for OTA
String doorstring = ""; //for web page door state
float SEALEVELPRESSURE_HPA = (1013.25); //for bme280
float temperature;
float pressure;
float humidity;
unsigned int tempalertcounter = 1; //number of temperature alerts sent
unsigned int piralertcounter = 1; //number of motion alerts sent
Adafruit_BME280 bme; //I2C
unsigned long time_now = 0; //millis current time for relay
int currentDoorState; //current state of door switch
int lastDoorState; //previous state of door switch
bool webswitchstate = false; //controls motion detection - set to 'true' for enabled - set to 'false' for disabled
String motiondetect = "OFF"; //motion dection web page label
bool pirstate = false; //pirsensor is false/LOW/0
String timestring = ""; //time

WiFiClient client; //thingspeak client
AsyncWebServer server(8006); //create AsyncWebServer object on port 8006
WiFiUDP ntpUDP; //NTPClient setup
NTPClient timeClient(ntpUDP, ntpServer, gmtOffset_sec, 86400); //update every 24 hours (60x60x24)

//begin index_html
const char index_html[] PROGMEM = R"rawliteral(
<!DOCTYPE HTML>
<html> <!-- begin html -->
<head>
<title>Large Door Monitor</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta http-equiv="refresh" content="5"> <!-- refresh web page every 5 seconds -->
<link rel="icon" href="data:,">
<style>
html {font-family: Arial; display: inline-block; text-align: center;}
h2 {font-size: 1.5rem;}
p {font-size: 1.rem;}
body {max-width: 600px; margin:0px auto; padding-bottom: 10px;}
.button
{
background-color: #000;
border: .5px solid crimson;
border-radius: 20px;
color: #fff;
padding: 18px;
box-shadow:
0 0 30px 0 crimson,
0 0 30px 0 crimson,
0 0 10px 0 crimson inset;
}
.button:hover {background-color: #000}
.button:active {
background-color: #00ffff;
box-shadow: 0 5px #666;
transform: translateY(4px);
}
</style>
</head>

<body>
<h2>Large Garage Door Monitor</h2>
<p>&nbsp</p>
<!-- Activate Door Button -->
<button class="button" onmousedown="toggleCheckbox('on'); setTimeout(() => toggleCheckbox('off'), 200);">&nbsp;&nbsp;&nbsp;&nbsp;Activate Door&nbsp;&nbsp;&nbsp;&nbsp;</button>
<p>&nbsp</p>
<!-- Motion Detection Button -->
<button class="button" onmousedown="toggleCheckbox('motion');">Motion Detection</button>
<p>&nbsp</p>
<!-- Reset ESP Button -->
<button class="button" onmousedown="toggleCheckbox('reset');">Reset ESP</button>
<p>&nbsp</p>
<p><span class="labels">Door: </span><span id="door"><mark>%DOOR%</mark></span></p>
<p><span class="labels">Motion Detection: </span><span id="motiondetect">%MOTION%</span></p>
<p><span class="labels">Time: </span><span id="time">%TIME%</span></p>
<p><span class="labels">Temperature: </span><span id="temperature">%TEMPERATURE%</span></p>
<p><span class="labels">Humidity: </span><span id="humidity">%HUMIDITY%</span></p>
<p><span class="labels">Pressure: </span><span id="pressure">%PRESSURE%</span></p>
<p><span class="labels"></span><span id="ts_url">%TS_URL%</span></p>
</body>

<script> <!-- begin script -->
function toggleCheckbox(x)
{
var xhr = new XMLHttpRequest();
xhr.open("GET", "/" + x, true);
xhr.send();
}
</script> <!-- end script -->

</html>)rawliteral";
//end index_html

String processor(const String& var) { //begin string processor
if (var == "DOOR") {
if (digitalRead(statusPin)) doorstring = "OPEN"; //statuspin (D6) is HIGH(1)
else doorstring = "CLOSED"; //statuspin (D6) is LOW(0)
return doorstring;
}
if (var == "TIME") return timestring;
if (var == "TEMPERATURE") return String(temperature);
if (var == "HUMIDITY") return String(humidity);
if (var == "PRESSURE") return String(pressure);
if (var == "MOTION") return motiondetect;
if (var == "TS_URL") return ts_url;
return String();
} //end string processor

void setup() { //begin setup
Serial.begin(115200);
Serial.println(" ");
Serial.println(" ");
Serial.println("Begin Setup");

//magnetic switch
pinMode(statusPin, INPUT_PULLUP); //pin D6/gpio12 for magnetic reed (open/close) switch
currentDoorState = digitalRead(statusPin); // read state of pin D6/gpio12

//relay
pinMode(activatePin, OUTPUT); //pin D5/gpio14 for relay S terminal (control)
digitalWrite(activatePin, LOW); //set pin D5/gpio14 LOW

//bme280
if (!bme.begin(0x76)) {
Serial.println("Could not find BME280 device");
while (1)
;
}

//connect to Wi-Fi network with SSID and password
Serial.print("Connecting to ");
Serial.println(ssid);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
Alarm.delay(500);
Serial.print(".");
}
Serial.println(" ");
Serial.print("WiFi connected: ");
Serial.println(WiFi.localIP());
Serial.println(" ");

//Initialize NTP
timeClient.begin(); //start NTP client
while (!timeClient.update()) { //wait for first NTP sync
Serial.print(F("."));
Alarm.delay(1000);
}
Serial.println(F("NTP is synced"));
setTime(timeClient.getEpochTime()); //Seed TimeLib with correct local epoch

//OTA
ElegantOTA.begin(&server); //start ElegantOTA
ElegantOTA.onStart(onOTAStart);
ElegantOTA.onProgress(onOTAProgress);
ElegantOTA.onEnd(onOTAEnd);

//set thingspeak timer
Alarm.timerRepeat(900, Repeat15Min); //set timer to repeat every 15 minutes (60 x 15 = 900)

ThingSpeak.begin(client); //start thingspeak
pinMode(pirsensor, INPUT); //pin D7/gpio13 set to input
bme280_sensor(); //call bme280 procedure

//GET request for login credentials: http_username & http_password
server.on("/", HTTP_GET, [](AsyncWebServerRequest* request) {
if (!request->authenticate(http_username, http_password)) // to remove auth screen, comment out these two lines
return request->requestAuthentication(); // to remove auth screen, comment out these two lines
request->send_P(200, "text/html", index_html, processor);
Serial.println("login");
}); //end login

//GET request for Activate Door /on
server.on("/on", HTTP_GET, [](AsyncWebServerRequest* request) {
digitalWrite(activatePin, HIGH); //a HIGH on relay S terminal causes the relay coil to activate
Serial.println("Activate Door Button Click");
request->send(200, "text/plain", "ok");
});

//GET request for Activate Door /off
server.on("/off", HTTP_GET, [](AsyncWebServerRequest* request) {
time_now = millis(); //millis timer 500 ms
while (millis() < time_now + period) {
//wait for .5 seconds
}
digitalWrite(activatePin, LOW); //a LOW on relay S terminal causes the relay coil to deactivate
Serial.println("Activate Door Button Release");
request->send(200, "text/plain", "ok");
});

//GET request for Motion Detection /motion
server.on("/motion", HTTP_GET, [](AsyncWebServerRequest* request) {
if (webswitchstate) {
webswitchstate = false;
motiondetect = "OFF";
Serial.println("webswitchstate is FALSE - motiondetect is OFF");
} else {
webswitchstate = true;
motiondetect = "ON";
Serial.println("webswitchstate is TRUE - motiondetect is ON");
}
request->send(200, "text/plain", "ok");
});

//GET request for Reset ESP /reset
server.on("/reset", HTTP_GET, [](AsyncWebServerRequest* request) {
ESP.restart(); //reset switch;
request->send(200, "text/plain", "ok");
});

server.begin(); //start webserver
Serial.println("End Setup");
Serial.println("");
} //end setup

void loop() { //begin loop
TimeDisplay();
Alarm.delay(1000);

//garage door check
lastDoorState = currentDoorState; //save last state
currentDoorState = digitalRead(statusPin); //read new state
if (lastDoorState == LOW && currentDoorState == HIGH) //state change: LOW -> HIGH
{
Serial.println("OPENED @ " + timestring);
sendalert("OPENED @ " + timestring);
} else if (lastDoorState == HIGH && currentDoorState == LOW) //state change: HIGH -> LOW
{
Serial.println("CLOSED @ " + timestring);
sendalert("CLOSED @ " + timestring);
}

pir(); //call pir (motion) function
ElegantOTA.loop(); //OTA
} //end loop

void pir() //called from loop
{ //begin pir
pirstate = digitalRead(pirsensor); //if pirsensor is HIGH, pirstate will be 1/true
Alarm.delay(1000);
if (pirstate && webswitchstate && piralertcounter <= 3) {
Serial.println("Motion detected AND Webswitch is Enabled - Send Alert");
Serial.println("");
ThingSpeak.setField(3, thingvalue); //store 50 in thingspeak
ThingSpeak.writeFields(myChannelNumber, myWriteAPIKey);
sendalert("MOTION DETECTED @ " + timestring); //call sendalert
piralertcounter++;
} else if ((pirstate) && !webswitchstate) Serial.println("Motion detected but Webswitch is Disabled"); //pirsensor is high AND webswitch is Disabled
} //end pir

void sendalert(String body) { //begin sendalert
Serial.println("Begin sendalert");
String a = RECIPIENT_NAME;
String b = RECIPIENT_EMAIL;
SMTPSession smtp; //smtp session object
ESP_Mail_Session session; //declare session config data
session.server.host_name = SMTP_HOST;
session.server.port = SMTP_PORT;
session.login.email = AUTHOR_EMAIL;
session.login.password = AUTHOR_PASSWORD;
SMTP_Message message; //declare the message class
message.sender.email = AUTHOR_EMAIL;
message.subject = SUBJECT;
message.addRecipient(RECIPIENT_NAME, RECIPIENT_EMAIL);
message.text.content = body.c_str(); //body of message is passed by call to sendalert
if (!smtp.connect(&session)) //connect to server with the session config
return;
if (!MailClient.sendMail(&smtp, &message)) //send email to recipents and close the session
Serial.println("Error sending Email, " + smtp.errorReason());
smtp.closeSession();
Serial.println("Email sent to " + a + " - " + b + " @ " + timestring);
Serial.println("End sendalert");
} //end sendalert

void bme280_sensor() //called from setup and thingspeakupload
{ //begin bme280_sensor
temperature = (1.8 * bme.readTemperature() + 32); //convert celcius to fahrenheit
humidity = (bme.readHumidity());
pressure = ((bme.readPressure() / 100.0F) / 33.863886666667); //convert hPa to inHg
humidity = humidity + humidity_correction; //humidity correction value
temperature = temperature - temp_correction; //temperature correction value
pressure = pressure + pressure_correction; //air pressure correction value

if ((temperature < lowtemp || temperature > hightemp) && (tempalertcounter <= 3)) {
sendalert("Temp Alert @ " + timestring + " - " + temperature); //call sendalert
tempalertcounter++;
}

Serial.print("Temperature = ");
Serial.print(temperature);
Serial.println(" *F");
Serial.print("Pressure = ");
Serial.print(pressure);
Serial.println(" inHg");
Serial.print("Humidity = ");
Serial.print(humidity);
Serial.println(" %");
Serial.println("");
} //end bme280_sensor

void thingspeakupload() //called from Repeat15Min()
{ //begin thingspeakupload
bme280_sensor(); //call bme280_sensor()
ThingSpeak.setField(1, String(humidity, DEC)); //upload humidity to thingspeak field 1
ThingSpeak.setField(2, String(temperature, DEC)); //upload temperature to thingspeak field 2
ThingSpeak.setField(4, String(pressure, DEC)); //upload pressure to thingspeak field 4
ThingSpeak.writeFields(myChannelNumber, myWriteAPIKey); //post to ThingSpeak
//Serial.println("exit thingspeakupload");
} //end thingspeakupload

void Repeat15Min() {
thingspeakupload();
}

void onOTAStart() { //OTA
Serial.println("OTA update started!");
}

void onOTAProgress(size_t current, size_t final) { //OTA
if (millis() - ota_progress_millis > 1000) {
ota_progress_millis = millis();
Serial.printf("OTA Progress Current: %u bytes, Final: %u bytes\n", current, final);
}
}

void onOTAEnd(bool success) { //OTA
if (success) {
Serial.println("OTA update finished successfully!");
} else {
Serial.println("There was an error during OTA update!");
}
}

void TimeDisplay() { //begin timedisplay
char buf[30];
sprintf(buf, "%02d:%02d:%02d %s %02d/%02d/%04d",
hourFormat12(), minute(), second(),
isAM() ? "AM" : "PM",
month(), day(), year());
timestring = buf;
Serial.println(timestring);
} //end timedisplay

Test the Circuit and Code

01 sign in.jpg
side by side.jpg

Test Functionality

  1. Arrange two windows side-by-side: Browser on left; Arduino IDE on the right as illustrated above.
  2. Switch the Arduino IDE view to the Serial Monitor (click Tools > Serial Monitor).
  3. Press the RST switch on the ESP8266 and watch the Serial Monitor.
  4. The IP assigned to your ESP8266 will be displayed.
  5. Open your browser to the IP address displayed in the Serial Monitor.
  6. Be sure to follow the IP address with :8006; for example, 192.168.1.240:8006
  7. Sign in with username: admin; password: admin (or whatever you changed them to in the ino file).
  8. Watch the Serial Monitor for feedback as you conduct the tests.

PIR Test

  1. Test the PIR by clicking the Motion Detection button on the web interface.
  2. Motion Detection: ON will display.
  3. Wave your hands in front of the PIR; this will generate an alert.
  4. Click the Motion Detection button again on the web interface.
  5. Motion Detection: OFF will display.
  6. Waving your hands in front of the PIR will not generate an alert.

Relay Test

  1. Test the relay by clicking the Activate Door button on the web interface.
  2. The relay will audibly snap when it activates.
  3. If you wish, you can wire the output terminals to a resistor/led to verify the relay closes.

Door Test 1

  1. Test using a magnetic switch.
  2. Moving the magnet near the switch will close the circuit between D6 and GND.
  3. The door will read CLOSED.
  4. Moving the magnet away from the switch will open the circuit between D6 and GND.
  5. The door will read OPEN.

Door Test 2

  1. Test using a NC push button switch in place of a magnetic switch.
  2. Pressing the push button will open the circuit between D6 and GND.
  3. The door will read OPEN.
  4. Releasing the push button will close the circuit between D6 and GND.
  5. The door will read CLOSED.

Construct a Finished Project

03 pcb board.jpg
02 relay connection.jpg
03 magnetic switch connection.jpg
06 powerhead.jpg

Move from the breadboard prototype to a finished product.

Female Headers:

  1. Cut two female headers to 15 hole length.
  2. Solder the two 15 hole female headers to the outside rows of the PCB.
  3. Solder wires to the eight PCB attachment points (VIN, GND (common), 3V3, D7, D6, D5, D2, D1).
  4. Use a tiny solder bridge on the underside of the PCB to connect the header pin to its corresponding wire.
  5. Use a multimeter to test for continuity and shorts

Male/Female Connector:

  1. Female (inside electrical box)
  2. 1 For Magnetic Switch:
  3. Connect the red wire to pin D6.
  4. Connect the black wire to GND.
  5. 2 For Relay:
  6. Connect the red wire to the relay NO terminal
  7. Connect the black wire to the relay COM terminal.
  8. Male (outside electrical box)
  9. 1 For Magnetic Switch:
  10. Connect the red wire to the wire running to the magnetic switch NC terminal
  11. Connect the black wire to the wire running to the magnetic switch COM terminal.
  12. 2 For Relay:
  13. Connect the red wire to the wire running to the powerhead #4 terminal.
  14. Connect the black wire to the wire running to the powerhead #3 terminal.

BME280:

  1. Connect the BME280 VCC pin to the 3V3 wire.
  2. Connect the BME280 GND pin to the common GND wire.
  3. Connect the BME280 SCL pin to the D1 wire.
  4. Connect the BME280 SDA pin to the D2 wire.

PIR:

  1. Connect the PIR VCC pin to the VIN wire.
  2. Connect the PIR OUT pin to the D7 wire.
  3. Connect the PIR GND pin to the common GND wire.

Relay:

  1. Connect the RELAY S pin to the D5 wire.
  2. Connect the RELAY + pin to the VIN wire.
  3. Connect the RELAY - pin to the common GND wire.
  4. Connect the RELAY NO terminal to the red wire running to the female connector.
  5. Connect the RELAY COM terminal to the black wire running to the female connector.

Electrical Box:

  1. Cut an opening for the ESP8266 female port in one of the round cutouts on the side of the box.
  2. Cut openings for the two female connectors on the opposite side of the box.
  3. Mount the two female connectors.
  4. Mount the PCB board with the ESP8266 attached so that the female micro-usb port is accessible.
  5. Cut an opening for the PIR sensor in the bottom of the electrical box.
  6. Make a BME280 sensor shield out of a bottle cap with holes drilled in it.
  7. Cut an opening for the BME280 sensor shield in the side of the electrical box in one of the cutouts.
  8. Label the female connectors: SWITCH and RELAY.

Magnetic Switch:

  1. You may have to make a mounting plate for the magnet out of aluminum.
  2. Mount the switch magnet to the top of the garage door.
  3. Mount the switch terminals on the door frame near the switch magnet.
  4. Make sure the magnet clears the switch terminal when the garage door opens.
  5. Open the door slowly by hand to test the clearance.
  6. Use a multimeter to test the magnetic switch when the door is open and when it is closed.
  7. Run wires from the switch terminals along the top of the chain rail back to the connector near the opener powerhead.

Powerhead (for Genie 3024 or similar):

  1. Mount the Electrical Box on the Powerhead mount rail.
  2. Plug the male Magnetic Switch connector into the female Magnetic Switch connector.
  3. Plug the male Relay connector into the female Relay connector.
  4. Plug the 5 V Power adapter male micro-usb connector into the ESP8266 female connector.
  5. Plug the 5 V Power adapter into an 110 volt receptacle.

Over the Air Update

01 sketch-export compiled binary.jpg
02 ota update.jpg
03 ota-select file.jpg
04 open-bin file.jpg

Over the Air Update (OTA)

ElegantOTA is an Arduino library designed to facilitate Over-The-Air (OTA) firmware updates for wireless microcontrollers like the ESP8266. It provides a user-friendly, interactive web interface for uploading new firmware or filesystem images to these devices wirelessly, typically via Wi-Fi. See ElegantOTA

Key Features and Functionality:

  1. Simplified OTA Updates: ElegantOTA simplifies the process of performing OTA updates compared to the built-in Arduino OTA functionalities, offering a more intuitive user experience.
  2. Web-Based Interface: It provides a sleek web portal that users can access through a web browser to upload .bin files containing firmware or filesystem images. This interface displays the status and progress of the update.

Update Procedure:

In Arduino IDE, click Sketch > Export Compiled Binary

  1. Open your browser to the IP address 192.168.1.X:8006/update
  2. In the ElegantOTA window, click Select File
  3. Navigate to the folder: Documents > Arduino > esp_garagemonitor > build > esp8266.esp8266.nodemcuv2
  4. Click the file esp_garagemonitor.ino.bin and click Open (to upload it to the ESP8266)
  5. Open your browser to the IP address 192.168.1.X:8006 to view the new code running on the ESP8266

Router Setup for Static IP and Port Forward

wnw.jpg
02 what.jpg

Wireless Network Watcher is a small utility that scans your wireless network and displays a list of devices that are currently connected to your network, including the internal/private/LAN (lan: Local Area Network) IP address of each device; for example, 192.168.1.240 may be assigned to your ESP8266.

What Is My IP Address will tell you your external/public/WAN (wan: Wide Area Network) IPv4 address that your Internet Service Provider (ISP) assigns to your router. This address is what allows your internal network to communicate with the external internet; for example, 103.52.23.70 may be assigned to your router. It is imperative that this IP is static; if it is dynamic and changes, there are ways around this but it gets a tad complicated. You can ask your ISP for a Static IP or use Dynamic DNS (DDNS), or DuckDNS. GROK is you friend if you need to go down this route.

If you simply want to access your Garage Monitor web page from your internal network, you open your browser and type in the internal IP address; for example, 192.168.1.240 and press Enter.

On the other hand, if you want to access your Garage Monitor web page from the external internet (say when you're out and about with your phone) you open your phone's browser and type in the external IP address followed by a colon and 8006; for example, 103.52.23.70:8006 and press Enter. The number 8006 is the port number for the AsyncWebServer that displays your Garage Monitor web page. In order for this to work; however, you must make two changes to your router.

  1. You must make the IP address assigned to your ESP8266 static rather than dynamic (DHCP).
  2. You must forward the port 8006.

If you need help making these changes, start by writing down the make and model of your router. Then go to Grok and type Router Setup for Static IP and Port Forward and press Enter. Grok will help you from there. If you tell Grok your exact router model (or ISP modem model), it can give you the exact clicks. And while you're there, thank Elon.

Dedication

chevy.jpg

For my friend Chevy