Project tutorial
IoT Garage Door Monitor/Opener with Finger Print Scanner

IoT Garage Door Monitor/Opener with Finger Print Scanner

Monitor and control your garage door from the web.

  • 18,178 views
  • 9 comments
  • 44 respects

Components and supplies

Adafruit CC3000 WiFi Module w/UFL antenna
×1
TTL Level Shifter
×1
Fingerprint Scanner
×1
Ard nano
Arduino Nano R3
×1
DC jack and DC plug
×1
Relay (generic)
×1
5V 1A Power Supply
×1
Buttons
×2

Apps and online services

Blynk

About this project

I’ve got a lot of stuff in my garage, and having 3 kids (one of them being me!) with forgetful minds, the garage door is sometimes left open over night.  I don’t really like that sinking feeling after waking up the next day to find the door was left open.  Between loosing valuables and critters that make a mess of garbage, I finally decided it’s time to take a stance!  I have an IP Cam mounted inside the garage and, for the past few years, have used it as a means to monitor valuables.  I wanted to take it to the next step by getting notifications of door status both inside my house (blinking LED in the hallway I could check before bed time) and on my various smart devices (iOs/Android).  I also wanted to be able to remotely open/close the doors as well as do away with the keycode entry system I have, and instead use a fingerprint scanner to open/close the doors.  (I’m good at scope creep).  During my daytime job I spend much of my time managing it, and, in my hobbies, loosing control of it! It’s my style, what can I say.


A full write-up with quality pics and details can be found here.

What it Does: 

  • Monitors both garage doors identifies status via:
  • LED that blinks inside the house (to alert us before we go to bed)
  • iOS / Android Blynk App for notifications and remote control of doors.
  • Allow open / closing of either garage door by:
  • Simple buttons on the controller itself inside the garage (Allows the garage to be closed from inside without needing to enter a code).
  • Fingerprint sensor mounted on the outside of the garage.
  • Remotely using the Blynk app on Android or iOS devices.
  • Includes Patented MeagerSecure password encryption. 😉
  • Uses Arduino and IOT connected components to web-enable the hardware.

How it works:

The project takes a number of features of the garage openers that are already in place.   I pulled additional lines from each opener that are uses for the manual opener buttons already located in the garage.   These are connected to 2 relays in the controller and triggered by Blynk or the fingerprint scanner.  I also added to limit switches to each door.  The circuit is closed when a door is fully open and open when the door closes.  These are used to feed status to the Open? LED’s in Blynk.  Wires for the open/close, limit switches and remote LED monitors all run into the enclosure.

Key Components:

  • Adafruit CC3000 WiFi Module w/UFL antenna
  • Sparkfun Fingerprint Scanner – TTL (GT-511C3) – Datasheet
  • Arduino Nano (with Optiboot bootloader)
  • TTL Level Shifter (for the FPS)
  • 2 Relays (1 per door).  Here or go with SSR’s here .
  • 2.x mm DC jack and DC plug.
  • Various switches / resistors / LEDs / connectors / wire
  • Blynk Connected App.
  • Custom milled  CNC enclosure with acrylic cover.
  • 3D printed enclosure for the fingerprint scanner module and remote LED monitor.
  • 5V 1A power supply

Fingerprint Scanner:

The fingerprint scanner is going to be mounted outside in the elements.  Many hours were spent on Tinkercad designing an enclosure that would shelter the unit from the elements while still providing ease of access.  I also decided to take a gamble and try waterproofing the fingerprint scanner board.  After doing some research I came across NeverWet.  Although Rustoleum does not recommend it be used on electronics, it seems many people have tried with success, so I decided to roll the dice.  I decided to first try it on a spare Nano I had laying around.  After it was complete, I did the water dunk test and it worked fine.   It leaves a milky residue layer over everything.  I did some testing to see if the layer provided any conductivity which would be bad news – but did not detect any.   Afterwards, I took a chance on the Fingerprint Scanner, which also worked.   I’m still toying around with designs on the enclosure. Primarily to come up with something that provides better shelter from the elements.   As for functionality, the FPS allows for enrolment of up to 200 finger scans, so I can do the whole family.Latest Design:  Allows for a cover to protect the unit and will open/close on its own:

Remote Control via iOS / Android:

I am using Blynk to remotely monitor and control the garage doors.  The picture over there>> is the iOS version.  It’s a pretty slick app and approach.   You can create buttons, sliders, graphs, LEDs and tag them to Analog, Digital or Virtual Pins on your Arduino.  They can  be on the sending or receiving end of state changes.  The Analog and Digital pins match those pins on your Duino directly.  The real benefit is in the Virtual pins.  Blynk needs a method to assign actions to react, and uses Virtual Pins for this.  The idea is you assign a Blynk button to a virtual pin, then use a subroutine within your sketch to intercept the state change (i.e from 0 to 1) and then write whatever code you want to react.  In my case, when one of the door buttons are pressed, the function catches that, and triggers a door to open.    I added a password-like feature by using 4 sliders.  The concept is that you use each slider to identify a digit of a 4-digit password, then the app unlocks the buttons to open / close the doors for a period of time.  The Arduino sketch actually takes care of this.  The sliders will reset to 0 after a period of time.  Additionally, a LED illuminates when the correct password was entered.  Although it’s obvious that this whole approach is limited in security, it adds an additional level of obfuscation that does the trick for what I am trying to achieve here.  As they say, it keeps the honest people honest.Blynk is relatively new and  the developers are adding new functionality all the time.  I have high hopes for the upcoming LCD widget.  As my sketch has quickly approached the 32K limit, I will be looking to the LCD widget to offload some code responsibility to allow me to use the Blynk app to enrol new fingerprints to the scanner (amongst other things).  I’ll be using the LCD widget to relay next step text while enrolling.

Prototyping phase:

Showing components hooked up via breadboard and the Blynk app customized with a few buttons and status LEDs.  If you are looking for an easy way to get our device into the IOT world, you have to check out Blynk.  It’s easy to setup and use.  Took me less than 5 minutes to get it integrated into this project!  The great thing about the app is that you simply download it, generate an Authorize token, open a sample Blynk app, add in the auth token and fire up the connection. Done.  The sample apps provide enough examples to get you started with building your project.

Final Control Board & Custom Enclosure with FPS ready for install:

This was one of my bigger projects as it contained many components and spanned both local control and the Internet via smartphone.  The enclosure was custom milled out of a single cutting board.  One of the biggest challenges I had was issues with the Nano / CC3000 freezing and locking up.  This not good as it required a physical power cycle.  This thing sat mostly complete on my desk for 2 weeks while I tried to figure out how to solve the issue.  I also used this as debugging time to see how long it would remain running.  Now that I have fixed the crashing issue, it has been running non-stope for days now.  More on that below.

Items of Interest:

Final Mounting:

Challenges:

The Nano/CC3000 crashed about once per day. The controller would lock up and could not be recovered without physically powering cycling the controller.   To deal with the issue I tried a few different methods:

  • CC3000 Catch:Catch the CC3000 by checking it’s connection state and re-initiating it.  This did not work as the crash was at the Nano level (I used a blinking LED for a heartbeat – which always stopped.
  • Software Reset:Added a software reset routing based on a timer (about every 5 minutes) and a digital pin wired to RESET.  This did work to reset the Duino, but it did not catch the issue when the controller crashed. The loop simply stopped running.
  • Watchdog Timer:I then stumbled across the built-in Watchdog timer (AVR WDT)   I landed on this simple method (other options here).  However, using a Nano clone, I ran into some snags.   Turns out that these clones use some base bootloader that has certain default features. Namely, when the Watchdog catches a fault and triggers the Nano to restart, it goes into an endless bootloop (see tips below how to fix this).  The fix.  I stumbled across Optiboot  and followed the steps to install it.  However, I ran across another issue – the boards did not show up in Arduino IDE 1.6.4, so I opened 1.0.5, followed the steps to add the Optiboot there.  Then, selected the Nano / Due…  328p Optiboot in the Boards menu.   re-complied the code with the WDT settings added, downloaded and voila! It works.  I left the controller on overnight and it’s still ticking along.  I presume it has done at least 1 restart since.    The code is as simple as:
  • #include – add this to the include section.
  • wdt_enable(WDTO_8S);   – I used the 8 second option, but there are many choices.  You will want to make sure that the WDT is only enabled after any start-up routines are done. Mine weas placed at the end of Setup().  For example, I am using the Adafruit CC3000 which needs to establish a connection to WiFi in the Setup routine.  I added this after that call completes.
  • wdt_reset(); –  Then, all you have to do is put the reset call in your main loop.  A good idea is to put it at the beginning.  If you have sub-routines that may take more than 8 seconds to complete their task, you will also want to add this call within them.  The idea here is that these are normal operations for your code, and all you are doing is telling the Watchdog Timer to NOT restart the Arduino by resetting the timer back to 0 seconds.    If your Duino should crash, the Watchdog Timer is running as a separate process and continues running.  It will no longer see the reset call and trigger the Duino to restart.  Also it is important to note that this does not trigger the reset of peripherals connected to your Duino.  If you need that, you may want to use a digital pin that goes HIGH to trigger some sort of relay or transistor to turn on the peripherals.  That way, when the Nano resets, you can bring that pin LOW, then HIGH when the code restarts.

Reality vs Prototyping:

It never fails…  Try as best as possible to re-create a similar environment to what it would be like in the garage, I ran into a few issues.

  • WiFi Signal:  I suspected this would be an issue and it was.  The controller is mounted at the front of the garage interior.  It has to go through a fair bit of concrete to reach my router in the basement.  I had started with a stubby antenna and, although it connected, it seems the signal was too weak. Luckily I had a longer antenna and swapped them out.  I still have some concerns as the connection is more flaky as  my kids get on their iPads and eat up some of the bandwidth.
  • Door Limits:  This one completely caught me off guard.  It was one of the simpler components of the system.  Each door has a limit switch attached to it.  If a door is open, the switch is closed and thus I can do a simple continuity check on the pins for each door.  In code,  I had a simple check for 4 states.  When one door is open, I check as follows ( if ((d1LimVal >= 1000) && (d2LimVal == 0))).   What I found was that although the open door (> 1000) evaluate to be true, the open door did not.  During testing, with the limit NOT tripped, the value was 0.  However, when wires were all connected, I the 2nd value was seeing numbers between 2-6.   A simple adjustment to the sketched fixed it, but I was not expecting this.
  • Something else to keep in mind.  No matter how well you plan, you are likely to screw up pin or variable assignments.  What I am getting at here is I have 2 doors.  They both need to be monitored, they both need to have a physical switch, and also be connected to relays.  That’s 6 places to screw up.  The great advantage of the config this can be easily remedied during installation by swapping variables or pin assignments after everything is hooked up.  The only (minor) glitch I ran into is the 2 physical door opener switches had no software component and I wired them up wrong to the 2 relays.  A simple swap of the pins in the connector did the trick.

Other Thoughts:

  • Could use an ESP8266 or similar WiFi-enabled device.  I have an Adafruit Huzzah that I wanted to try, but it came too late in the project phase.  Given the CC3000 is a bit flaky, I may switch out to the Huzzah at some point in the future.  Unless of course there’s code out there to detect and reset the CC3000 when it freezes.
  • Pebble Time integration – Now that I have my Pebble Time,  I’d like to see the Blynk app send notificaitons to it, and be able to trigger responses (i.e. Open / Close a door).  If I get more free time, I might venture to develop an app for this myself.

Tips:

  • Watchdog Bootloop:  If you were toying around with the AVR Watchdog and discovered (as I did) that you have a Duino who’s bootloader does not play well with the Watchdog, you will want to follow the steps I noted above to install the Optiboot bootloader.  Here’s a tip to get your Duino working again. Remove all power from the Nano / project.  Plug the USB into your PC, comment out the offending watchdog lines of code (namely the wdt_enable(xxxxxx) statement), re-download the sketch.  Note, in some Nano’s, you have to click the reset button the moment the IDE starts uploading.
  • I also have an IP Cam in the garage.  I’m hopeful the Blynk folks will consider adding a viewer widget to allow me to plop timed stills of my IPCam in the app.  The concept here is the status LED’s would tell me if doors are opened and when they are closing, but it is always nice to see that I’m not going to close the door on a car that is half parked in the garage. Worst case situation, I can open my IP Cam app separately and look at the IP view before triggering a door to close.

Code

Untitled filePlain text
    // Garage 2x Door Monitor and Fingerprint Opener
// Dave Astolfo www.plastibots.com
// Uses Blynk to process and display info over net from IOS/Android
// Uses Adafruit CC3000 breakout board for WiFi comms
// Uses Optiboot Nano bootloader (use Arduino v1.0.5 me)
// Uses watchdog timer due to issue with either Nano or CC3000 crashing - forces restart

// ********  Must select board:  [Optiboot] Arduino Duemilaove or Nano w/Atmega328 **********

#include <avr/wdt.h>         // required for watchdog timer
#include <SoftwareSerial.h>
#include "FPS_GT511C3.h" //the fps (fingerprint scanner) library
//#define BLYNK_PRINT Serial    // Comment this out to disable prints and save space

// These are the interrupt and control pins for 3000
#define ADAFRUIT_CC3000_IRQ   3
#define ADAFRUIT_CC3000_VBAT  5
#define ADAFRUIT_CC3000_CS    10

#include <SPI.h>
#include <Adafruit_CC3000.h>
#include <BlynkSimpleCC3000.h>


FPS_GT511C3 fps(2, 4); //RX, TX

const int door1ClosePin = 6;
const int door2ClosePin = 7;
const int door1LimitPin = A0;
const int door2LimitPin = A1;
const int OKLedPin = A5;
const int NotOKLedPin = A4;
const int doorStatLEDPin = 8; 
const int delayVal = 100; //in milliseconds
int i = 0;
int doorState = 0;  //value
int d1S, d2S, d1LimVal, d2LimVal;
boolean door_p1, door_p2, door_p3, door_p4;  //bits for door 1 pwd
unsigned long pwdEntryStartTime = 0;
long interval = 30000;  //30 second grace period to retain password to allow opening of doors.

// You should get Auth Token in the Blynk App. Go to the Project Settings (nut icon).
char auth[] = "authcodehere";


void setup()
{

  //Serial.begin(9600);  //for debugging - disable once live.
  
  
  pinMode(OKLedPin, OUTPUT);
  pinMode(NotOKLedPin, OUTPUT);  
  pinMode(doorStatLEDPin, OUTPUT);    
  pinMode(door1ClosePin, OUTPUT);        
  pinMode(door2ClosePin, OUTPUT);        
  pinMode(door1LimitPin, INPUT);    
  pinMode(door2LimitPin, INPUT);      

  
  fps.Open();
  fps.SetLED(true); //the fps LED
  fps.UseSerialDebug = false; //set to true for fps debugging through serial
  blink(OKLedPin, 1000, 1);
  Blynk.begin(auth, "SSID", "PASSCODE", WLAN_SEC_WPA2);
  blink(OKLedPin, 500, 3);
  wdt_enable(WDTO_8S);   //turns on watchdog timer with 8 second countdoor.  Sketch requires wtd_reset() to reset this, else a reboot is forced
}

void loop()
{

  wdt_reset();  //reset as it goes through each loop - necessary to ensure the watchdog timer does not reset the Duino when it's working fine.
  
  if (!cc3000.checkConnected())
  {
    wdt_reset(); //reset the watchdog timer in any normal op that may take time.
    Blynk.begin(auth, "SSID", "PASSCODE", WLAN_SEC_WPA2);
    blink(OKLedPin, 500, 3);
  }

  Blynk.run();                //start polling the system and reporting to the Blynk app.
  Blynk.virtualWrite(4, 1);   //sends a heartbeat to the Blynk app.
  
  // Only want to send / check door state values every 0.5s (500ms) seconds.  Based on the delay value set in the main loop
  // this takes care of it without using a timer - this also does not slow down the main loop
  i++;
  if (i == (1000 / delayVal) - 1)
  {
   Blynk.virtualWrite(4, 0); 
   checkDoorState();
   i = 0;
   blink(OKLedPin, 100, 1);  
  }
  //end timing a door state check
  
  
  //scan and identify the finger when one is put on it
  chkForFingerPrint();

  delay(delayVal);  
  
}



//************************************************************************************************************************************************
//future enhancement - allow for enrolling new fingerprints
void Enroll()
{
}


//************************************************************************************************************************************************
void chkForFingerPrint()
{
	if (fps.IsPressFinger())
	{
                wdt_reset();	//reset the watchdog timer for any normal op that may take time.	
                fps.CaptureFinger(false);
		int id = fps.Identify1_N();
		if (id < 200)
		{
			//Serial.print("Verified ID:");
			//Serial.println(id);
                        blink(OKLedPin, 100, 2);
                        Action(1);   //Open the Garage door
		}
		else
		{
			//Serial.println("Finger not found");
                        blink(NotOKLedPin, 100, 3);
		}
	}  
}

//************************************************************************************************************************************************
void blink(int whichLED, int dly, int numTimes)
{
  for (int i = 1; i<=numTimes; i++){  
    digitalWrite(whichLED, HIGH);
    delay(dly);
    digitalWrite(whichLED, LOW);
    delay(100);    
  }
}

//************************************************************************************************************************************************
void checkDoorState()
{
  //the master controller will send values to this analog pin when the doors are open. When closed, the value will be 0
  //will need to have 4 door state values.
  // door 1 = open, door 1 & 2 open, door 2 open.  all doors closed
  d1LimVal = analogRead(door1LimitPin);
  d2LimVal = analogRead(door2LimitPin);
  
  //Serial.print("Limit1Val:  ");
  //Serial.print(d1LimVal);
  //Serial.print("   Limit2Val:  ");  
  //Serial.println(d2LimVal);
    
    
  if ((d1LimVal >= 1000) && (d2LimVal >= 1000))  //both door limit switches are closed. 1023
  {
    d1S = 1;
    d2S = 1;
    blink(NotOKLedPin, 100, 1);
    msgOut(doorStatLEDPin, 1);
  }
  else if ((d1LimVal >= 1000) && (d2LimVal < 50))
  {
    d1S = 1;
    d2S = 0;
    blink(NotOKLedPin, 100, 1);
    msgOut(doorStatLEDPin, 1);   
  }
  else if ((d1LimVal < 50) && (d2LimVal >= 1000))
  {
    d1S = 0;
    d2S = 1;
    blink(NotOKLedPin, 100, 1);
    msgOut(doorStatLEDPin, 1);    
  }
  else
  {
    d1S = 0;
    d2S = 0;    
    msgOut(doorStatLEDPin, 0);
  }

  Blynk.virtualWrite(1, d1S);  //sends the state of Garage door 1 - if 1, then open
  Blynk.virtualWrite(3, d2S);  // sends the state of Garage door 2 - if 1, then open  
  
 
  //reset the timer values used for pwd entry
  if (millis() - pwdEntryStartTime > interval)
  {
    door_p1 = false, door_p2 = false, door_p3 = false, door_p4 = false;
    //reset the sliders in the Blynk app - do this after the interval time has elapsed.
	Blynk.virtualWrite(9, 0);  //pwd is no longer valid - update LED to OFF state
    Blynk.virtualWrite(5, 0);  //reset the pwd sliders to 0
    Blynk.virtualWrite(6, 0);  //reset the pwd sliders to 0  
    Blynk.virtualWrite(7, 0);  //reset the pwd sliders to 0
    Blynk.virtualWrite(8, 0);  //reset the pwd sliders to 0      
    pwdEntryStartTime = 0;
  }
  
  if (door_p1 && door_p2 && door_p3 && door_p4)
  {
    Blynk.virtualWrite(9, 1);  //pwd is correct - illuminate LED
  }
  else
  {
    Blynk.virtualWrite(9, 0);  //pwd is no longer correct - illuminate LED    
  }
  
    
}

//************************************************************************************************************************************************
// a state of 0 means one or more doors open. Else, 1 means all good
// Uses AnalogRead on slave ATTiny85 to determine which state was sent and blink either a red or green LED.
void msgOut(int statLED, int state)
{
 if (state == 1)
 {
   //red LED - one or more doors are open
   //analogWrite(statLED, 255);
   digitalWrite(statLED, HIGH);
 }
 else
 {
   //green LED - everything good
   //analogWrite(statLED, 0);
   digitalWrite(statLED, LOW);
 } 
}
//************************************************************************************************************************************************
// DOOR 1
// This function will be called every time when the Blynk App writes value to Virtual Pin 0  - This will be when Door 1 is clicked to init closing the door
//Note - when App Virtual Button is set as Push - it will send 2 commands, first HIGH, then LOW one right afer each other. 
BLYNK_WRITE(0)
{
  //BLYNK_LOG("Got a value: %s", param.asStr());
  // You can also use: asInt() and asDouble()
  //digitalWrite(OKLedPin, param.asInt());
  //label = 1;  //tell it to act on door 2
  //Serial.print("Param:  ");
  //Serial.println(param.asInt());

  
  if (param.asInt() == 1 && (door_p1 && door_p2 && door_p3 && door_p4))  //passcode must be true.  if so and clicks button open door.
  {  
    if (millis() - pwdEntryStartTime < interval)
    {
      Action(1);   //send command to master to open/close door.
    }  
    //door_p1 = false, door_p2 = false, door_p3 = false, door_p4 = false;
  }  
}
//************************************************************************************************************************************************
// DOOR 2
// This function will be called every time when the Blynk App writes value to Virtual Pin 2  - This will be when Door 2 is clicked to init closing the door
BLYNK_WRITE(2)
{
  //BLYNK_LOG("Got a value: %s", param.asStr());
  // You can also use: asInt() and asDouble()
  //digitalWrite(OKLedPin, param.asInt());
  if (param.asInt() == 1 && (door_p1 && door_p2 && door_p3 && door_p4))  //passcode must be true.  if so and clicks button open door.
  {  
   if (millis() - pwdEntryStartTime < interval)
   {
     Action(2);   //send command to master to open/close door.
   }
    //door_p1 = false, door_p2 = false, door_p3 = false, door_p4 = false;
  }
}
//************************************************************************************************************************************************


// Door 1 passcode values - uses sliders in Blynk
BLYNK_WRITE(5)
{
  pwdEntryStartTime = millis();  //start the timer 
  //Blynk.virtualWrite(9, 1);  //illuminate the led to indicate pwd entry is valid.
  if (param.asInt() == 1) {  door_p1 = true; } else  { door_p1 = false; }  
}
BLYNK_WRITE(6)
{
  if (param.asInt() == 1) {  door_p2 = true; } else  {    door_p2 = false; }  
}
BLYNK_WRITE(7)
{
  if (param.asInt() == 1) {  door_p3 = true; } else  {    door_p3 = false; }  
}
BLYNK_WRITE(8)
{
  if (param.asInt() == 1) {  door_p4 = true; } else  {    door_p4 = false; }  
}

//************************************************************************************************************************************************

void Action(int label)
{
  //digitalWrite(OKLedPin, HIGH);
  if(label == 1)
  {
    digitalWrite(door1ClosePin, HIGH);delay(200);digitalWrite(door1ClosePin,LOW);   
  }
  if(label == 2)
  {
    digitalWrite(door2ClosePin, HIGH); delay(200); digitalWrite(door2ClosePin, LOW);
  }
  delay(500);
  //digitalWrite(OKLedPin, LOW);
}
//************************************************************************************************************************************************
Github
https://github.com/Optiboot/optiboot

Schematics

garageMonDescriptions.jpg
Garagemondescriptions

Comments

Similar projects you might like

IoT arduino ESP Garage Door opener (UD)

Project in progress by David Smerkous

  • 10,865 views
  • 6 comments
  • 16 respects

$20 Zigbee Door Chime

Project tutorial by BuddyC

  • 25,151 views
  • 10 comments
  • 51 respects

Android App-Based Home Automation System Using IOT

Project tutorial by Team Autoshack

  • 24,825 views
  • 17 comments
  • 75 respects

Automatic Sliding Door for the Garage

Project tutorial by DVDMDN

  • 15,907 views
  • 37 comments
  • 68 respects

OH HAI! on Windows 10 IoT Core

Project in progress by BuddyC

  • 12,538 views
  • 3 comments
  • 48 respects
Add projectSign up / Login