↑ Return to Projects

Open Sesame garage door

After building my Photon powered garage door interface it was obvious it needed to do more….

The first thought was “Can I get the garage door to automatically close after I pull my car out?” followed quickly by “Can I get the garage door to automatically open when I come home?”

So to start “close the garage door automatically after I pull out the car”…

The obvious question is what constitutes “after I pull out the car”.  Because the description is stated as “After” something implies this really needs a state machine to properly execute, ie close the door when the car transitions from being “in the garage” to being “outside the garage”.

Detecting the car in the garage was already part of the Photon garage door via an IR sensor I had placed on the garage floor.  Detecting the car outside of the garage was a bit more problematic.

In the end, I opted for a 3 state transition:

Car present => Car absent but door blocked => Car absent and door not blocked => only then, close the door

One problem with the above transition plan.  If the car was gone, the door was open and some PERSON walked out the door, it would look like the car leaving and would close the door.  We couldn’t have that, so the first state became “If I was in the car and the car was present“.  Which in the end technically became, “if my phone was connected to the car Bluetooth and the car was present

Now, the “Car Present” sensor already existed in the Photon garage door interface, the needed to add a “Door Blocked” sensor.  I initially thought about tying into the door block sensor already on the garage door opening, but that had three problems.  First, it’s not a direct digital interface (some analog thing with power included on two wires).  Second, it’s at ground level and needs to be to keep someone from getting trapped under a closing door and third, that ground level position meant it was a car wheel sensor, not a car body sensor.

Eventually I simply took the same type sensor I was using for “Car Present” and mounted it about knee high across the garage door opening.   This way it really is a car body sensor with one Off/On/Off transition when the car existed.  Much simpler.

While modifying the Photon code to support the “Door Blocked” sensor, I also added another two more cloud callable functions called “Door Close” and “Door Open”.  These differed from the initial “push button” function in that “Door Close” tested to make sure the door was in an open state before ‘pressing’ the garage door opener button and of course “Door Open” first tested to make sure the door was in a closed state.  simple 🙂

This left two big functionality gaps.  I needed a state engine and I needed to interface the phone into the system so the state of the phone’s Bluetooth connection could become part of the equation.

But before I tell you that story, I have to tell you this story….

Initially I wanted to record temperatures and states from the Photon into a SQL database.  Initially I wrote a script in PHP that periodically polled the cloud for published variables and logged them into a SQL database. That worked OK, but the periodic nature meant it didn’t really get the transition time of state changes.  So I enhanced the PHP to also accept incoming WebHooks from the cloud.

The problem with going out to the Particle cloud for all this was it wasn’t 100% reliable and it meant going all the way out to the cloud and back.  Lots of round trip traffic.

So I expanded the PHP functionality again to accept incoming JSON requests to log data and events.  I also modified the Photon code to include a simple HTTP client.   Now the Photon could periodically post JSON requests with data to log as well as post JSON requests indicating state changes such as Door Opened, Door Closed or Car Left all without going out onto the Internet.  This pretty much eliminated the cloud except for the function calls used to press the garage door opener button.

A side benefit of this PHP/JSON functionality was the ability now to accept requests coming from IFTTT.  PHP/JSON seemed a natural fit.

Now back to the main story…

With a PHP back-end in place accepting state data from the Photon, it was as simple matter to code up the necessary state machine in PHP.   That part was easy.

Interfacing with the phone was a problem until I realized that Android Tasker also had a HTTP client.  Again, easy to post a JSON request from the phone using Tasker when the phone connected  to the car’s Bluetooth interface.

Easy-peazy, now when I get in the car and pull out of the garage, the garage door automatically closes.

Here’s some specifics:

This is the Tasker Task that gets triggered when my phone connects to the car Bluetooth:

Say In Car (7)
A1: Say [ Text:You’re in the car Engine:Voice:default:default Stream:3 Pitch:5 Speed:5 Respect Audio Focus:On Network:Off Continue Task Immediately:Off ]
A2: Variable Set [ Name:%iii To:0 Recurse Variables:Off Do Maths:Off Append:Off ]
<InCar>
A3: HTTP Post [ Server:Port:https://zzzzzzzzzzz.noip.me:99999 Path:JSONPost.php Data / File:{“Function”:”StateChange “,”User”:”SomeStringHere”,”VarName” :”TomInTomCar”,”State”:”1″} Cookies: User Agent: Timeout:60 Content Type:application/json Output File: Trust Any Certificate:On Continue Task After Error:On ]
A4: Goto [ Type:Action Label Number:1 Label:Bottom ] If [ %HTTPR neq -1 ]
A5: Variable Add [ Name:%iii Value:1 Wrap Around:0 ]
A6: Goto [ Type:Action Label Number:1 Label:Bottom ] If [ %iii > 20 ]
A7: Wait [ MS:0 Seconds:1 Minutes:0 Hours:0 Days:0 ]
A8: Goto [ Type:Action Label Number:1 Label:InCar ]
<Bottom>

Couple of notes on this.  Had some problems with the post failing now and then so the test for HTTPR neq -1 allows the post to be retried if it fails.  but like 6 limits the number of retries to 20.  Note the Trust Any Certificate flag because I’m using a local self-signed cert.  And note the https and alternative port are both used for a bit of enhanced security as well as forcing a username in the JSON string.  Without a valid username, the php code simply does nothing.

The PHP code on the receiving end is pretty straight forward.  Simply needs to parse the posted JSON string like this:

$json = file_get_contents(‘php://input’);
$obj = json_decode($json);
$PostFunc = trim($obj->{‘Function’});
$PostUser = trim($obj->{‘User’});
$PostVarName = trim($obj->{‘VarName’});
$PostState = trim($obj->{‘State’});
$MailSubj = trim($obj->{‘MailSubj’});
$MailBody = trim($obj->{‘MailBody’});

 

The other PHP trick (and the one that took the longest to figure out) was that initially the post would actually take some time simply due to performance on the back-end.  Likely this was what was causing some of the posts from the phone to fail.  it wasn’t failing, it was hitting the time limit on the Tasker post command.

The solution was to code the PHP script to ‘release’ the HTTP connection as soon as the incoming JSON string was parsed. Some diligent Googling and trial and error ended up with this PHP code to tell the PHP script to release the HTTP channel.

set_time_limit(0);
ob_end_clean();
ignore_user_abort(true);
header(“Connection: close\r\n”);
header(“Content-Encoding: none\r\n”);
ob_start();
echo date(‘Y-m-d H:i:s’).PHP_EOL;
$size = ob_get_length();
header(“Content-Length: $size”,TRUE);
ob_end_flush();
ob_flush();
flush();

Now of course that I had the garage door automatically closing, the next step was figuring out how to get it to automatically OPEN when I came back home. That ended up being a more difficult trick than simply closing the door on exit.

How to open the garage door?

On the surface, a much easier task.  No state machine, just a simple: “When my phone is in the car and the phone comes ‘home’, open the garage door”.

Having used Tasker already to detect Phone “In the car” via a Tasker profile, I thought using the Tasker Location in combination with the “In the Car” profile would be quick and easy with an entry task that sent a JSON message to open the garage door.  Coded that right up and tried it and… the door didn’t open….

The logic and code was right, the problem was the Tasker location updates too slowly.   You can update the Tasker location polling interval somewhat, but to get close to fast enough you have to also reduce the timeouts on GPS read.  Ultimately got it close, but still sometimes had to pause 2-3 seconds outside the garage before Tasker would trigger the ‘home’ profile.  Not working 🙁

I tried using the detection of my home WiFi network, that wasn’t fast enough either.

After much trial and error I ended up with a looping Tasker task that stays active while in the car.  The task periodically looks at the %LOC variable and calculates the distance to home.  The task repeats at two different intervals, slowly if the distance is large, and quickly if the distance is small.  Here’s the looping Tasker task (below), it uses a JavaScriptlet to calculate the distance in meters from the current location to ‘home’.  It calculates that and sets it as a global Tasker variable.  When the distance is less than 400 meters is re-calculates the distance every 5 seconds, otherwise it recalculates every 30 seconds (5+25).  Finally the looping dies when the “In the Car” profile is no longer active.

Log GPS (27)
<Top>
A1: Variable Split [ Name:%LOC Splitter:, Delete Base:Off ]
A2: JavaScriptlet [ Code:var R = 6371; // earth radius in KM
var lat1 =  nn.nnnn; // home location
var lon1 = nn.nnnn;

var lat2 = parseFloat(global(‘LOC1’));
var lon2 = parseFloat(global(‘LOC2’));
var acc = parseFloat(global(‘LOCACC’)) *1.2;

var latDistance = (lat2 – lat1)*Math.PI / 180.0;
var lonDistance = (lon2 – lon1)*Math.PI/180.0;
var a = Math.sin(latDistance / 2) * Math.sin(latDistance / 2)
+ Math.cos(lat1*Math.PI/180.0) * Math.cos(lat2*Math.PI/180.0)
* Math.sin(lonDistance / 2) * Math.sin(lonDistance / 2);
var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 – a));
var distance = R * c * 1000; // convert to meters

if(distance > acc) { // only change if delta is larger than accuracy of measure
setGlobal(‘Hdist’,distance);
} Libraries:Math Auto Exit:On Timeout (Seconds):45 ]
<InsideHood>
A3: Wait [ MS:0 Seconds:5 Minutes:0 Hours:0 Days:0 ]
<OutsideHood>
A4: Wait [ MS:0 Seconds:25 Minutes:0 Hours:0 Days:0 ] If [ %Hdist > 400.0 ]
A5: Goto [ Type:Action Label Number:1 Label:Top ] If [ %PACTIVE ~ *,In The Car,* ]

 

Once a relatively responsive way to determine when I was ‘in the car’ and ‘home’ is was easy to create another Tasker profile representing that condition, which has an entry task that does the necessary JSON post to open the garage door.

So now, once I start pulling into the driveway, the garage door magically opens.  Open Sesame!!!