Welcome to Hackster!
Hackster is a community dedicated to learning hardware, from beginner to pro. Join us, it's free!
Miles Barbick
Published

Simple Garage Door Notification System

A smart alert system that notifies you when your garage door stays open too long, using real-time email notifications.

BeginnerFull instructions provided156
Simple Garage Door Notification System

Things used in this project

Hardware components

Photon 2
Particle Photon 2
×1
Ultrasonic Sensor - HC-SR04 (Generic)
Ultrasonic Sensor - HC-SR04 (Generic)
×1
Jumper wires (generic)
Jumper wires (generic)
×1

Software apps and online services

Particle Build Web IDE
Particle Build Web IDE
Google Sheets
Google Sheets
Google Apps Script

Story

Read more

Schematics

Wiring

Connect the VCC pin of the sensor to the USB pin on the Photon. Attach the GND pin of the sensor to the GND pin on the Photon. Connect the Trig pin of the sensor to any digital pin on the Photon, I used D6. This will be used to send out ultrasonic pulses. Finally, connect the Echo pin of the sensor to another digital pin on the Photon, I used D2.

Code

Particle Photon Code

C/C++
This code runs on the Photon microcontroller to monitor the garage door's state using an HC-SR04 ultrasonic sensor. It measures the distance to determine if the garage door is open or closed, then publishes the status as a JSON object to Particle Cloud.
#include "Particle.h"
#include "HC_SR04.h"

SYSTEM_THREAD(ENABLED);

SerialLogHandler logHandler;

// How often to publish a value
const std::chrono::milliseconds publishPeriod = 5s;

// The event name to publish with
const char *eventName = "homeAutomation";

unsigned long lastPublish;
int counter = 0;

void publishTest(const char* doorStatus, int inches);

double cm = 0.0;
double inches = 0.0;

int trigPin = D6;  // Trig on D6
int echoPin = D2;  // Echo on D2

HC_SR04 rangefinder = HC_SR04(trigPin, echoPin, 1.0, 250.0);

// Threshold for the door being open (greater than 10 cm means door is open)
const double doorOpenThreshold = 10.0;

void setup()
{
    Spark.variable("cm", &cm, DOUBLE);
    Spark.variable("inches", &inches, DOUBLE);
    Serial.begin(9600);
}

void loop()
{
    cm = rangefinder.getDistanceCM();
    inches = rangefinder.getDistanceInch();
    Serial.println(inches);
    delay(100);

    if (Particle.connected()) {
        if (millis() - lastPublish >= publishPeriod.count()) {
            lastPublish = millis();

            // Check if the distance is greater than the threshold (door open condition)
            if (inches > doorOpenThreshold) {
                Serial.println("Garage door is open!");
                publishTest("open", int(inches));
            } else {
                Serial.println("Garage door is closed.");
                publishTest("closed", int(inches));
            }
        }
    }
}

void publishTest(const char* doorStatus, int inches) {
    char buf[128];
    
    // Publish a valid JSON object
    snprintf(buf, sizeof(buf), "{\"counter\":%d,\"inches\":%d,\"doorStatus\":\"%s\"}", ++counter, inches, doorStatus);

    Particle.publish(eventName, buf, PRIVATE);
    Log.info("published: %s", buf);
}

Google Apps Script Code

JavaScript
Follow the setup guide to integrate Particle with Google Sheets: https://docs.particle.io/integrations/community-integrations/publish-to-google-sheets/

Replace your.email@example.com with your actual email address.
function doPost(e) {
  Logger.log("Received data: " + JSON.stringify(e));  // Log the entire event object

  var publishedAt = new Date(e.parameter.published_at);
  var data = {};

  try {
    data = JSON.parse(e.parameter.data);  // Parse the JSON string from Particle
  } catch (error) {
    Logger.log("Error parsing data: " + error);
    return ContentService.createTextOutput(JSON.stringify({ok: false, error: "Invalid data format"}))
        .setMimeType(ContentService.MimeType.JSON);
  }

  var sheet = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
  var scriptProperties = PropertiesService.getScriptProperties(); // State tracking

  // Retrieve the last known state and timestamp from script properties
  var lastStatus = scriptProperties.getProperty("lastDoorStatus") || "closed";
  var lastOpenTimestamp = scriptProperties.getProperty("lastOpenTimestamp");
  var now = new Date().getTime();

  if (data.counter && data.inches && data.doorStatus) {
    var row = [e.parameter.coreid, publishedAt, data.counter, data.inches, data.doorStatus];
    sheet.appendRow(row);
    Logger.log("Row appended: " + JSON.stringify(row));

    if (data.doorStatus === "open") {
      if (lastStatus === "closed") {
        // Door just opened, record the current time
        scriptProperties.setProperty("lastOpenTimestamp", now.toString());
      } else if (lastStatus === "open" && lastOpenTimestamp) {
        // Check if the door has been open for more than 1 minute
        if (now - parseInt(lastOpenTimestamp) >= 60000) { // 1 minute in milliseconds
          var emailAddress = 'your.email@example.com'; // Replace with your actual email
          var subject = 'Garage Door Open Alert!';
          var message = 'The garage door has been open for over 1 minute as of ' + publishedAt + '.';
          MailApp.sendEmail(emailAddress, subject, message);
          Logger.log("Email sent to " + emailAddress);

          // Reset the open timestamp to prevent duplicate notifications
          scriptProperties.setProperty("lastOpenTimestamp", "");
        }
      }
    } else if (data.doorStatus === "closed") {
      // Reset state when the door closes
      scriptProperties.setProperty("lastOpenTimestamp", "");
    }

    // Update the last known state
    scriptProperties.setProperty("lastDoorStatus", data.doorStatus);
  } else {
    Logger.log("Unexpected data format: " + e.parameter.data);
  }

  var result = { ok: true };
  return ContentService.createTextOutput(JSON.stringify(result))
      .setMimeType(ContentService.MimeType.JSON);
}

Credits

Miles Barbick
1 project • 0 followers
Contact

Comments

Please log in or sign up to comment.