Automatic Garage door opener through GPS-phone and IP

Show or discuss your existing Home automation project here, so a detailed explanation!.....
Post Reply
insaneLX
Starting Member
Starting Member
Posts: 4
Joined: Sat Oct 17, 2009 11:34 pm
Location: Austria
Contact:

Automatic Garage door opener through GPS-phone and IP

Post by insaneLX »

Hi Everybody,

I thought I'd post some information about a quite geeky project I've almost completed this weekend.

First, I bought a house.
Then I needed a door to my parking area. There were no doors available, which could close an opening of 4.2 meter width while parking in 2.3 meters width - so I built a door and equiped it with an electric opener (modified Einhelll BGT 63)
No that's not exactly home automation. Automatic doors are not worth mentioning anymore. However...

I became quite annoyed with having to wait 17 seconds in fornt of the door before could drive into my house so I decided to automated not just the opening of the door, but also the pressing of the "open" button.

The concept:
I have a smartphone with built-in GPS (Nokia E71). Using GPS, the phone knows when I'm approaching my home by car and opens the door 300 meters before I'm at home. The door is open when I reach my house and I don't need to wait on the side of the road anymore.
Furthermore I can check whether the door is open and open/close it from wherever I am.

How did I do it?

The Nokia phone is programmed using pyhton. The python program talks via an internet connection (any data connection GPRS, EDGE, UMTS, WLAN whatever is selected as access point) to the DSL router in my house which forwards the connection to a neat, simple and cheap (27) Ethernet to Input/Output card (Avr NetIO from Pollin Electronics).
Two of the digital inputs of the board are "sniffing" the voltage open/close contacts of the door, two analog inputs measure the voltage on the two pins of the door motor and one digital output is connected to a transistor which acts as external IO siwtch.

-----

The software development environment:

The phone (Nokia E71) runs Symbian 3rd Edition FP2 as operating system and has GPS installed.
The door opener is programmed in Python. I chose Python over C++ or Java for ease of development. It's really the fastest way to get things done on a Symbian Mobile Phone. (generate a file "import audio; audio.say("Hello World") " start it - and you've got synthetic voice output - nice, isn't it? ). If you google for Pyhton S60 you'll find plenty of links to get you started.

---

The statemachine

The statemachine is work in progress. At the moment GPS is always on and the behaviour of the software is simple: It continously measures the distance from my house. If I get nearer the 300 meters and If I'm faster than 30km/h it assumes opens the door.

In future I want to extend the statemachine in order to save battery on my smartphone. GPS consumes a lot of battery, but you can easily find the approximate location by simply asking for the current GSM/UMTS cell identification code.
So what is plan to do: GPS is generelly not active. The software finds out that I left home when I'm not in one of the GMS cells which are close to home. Once I've left home it waits until I reach one of the "home cells" again. If that's the case GPS is activated so the phone can exactly find out where I am and when it should open the door. As soon as it has opened the door, it will switch off GPS and wait until I leave the "home cell" again.

The software runs in Background - so you don't notice it normally.

-- The infrastructure --

This is the easy part:

Nokia E71 => The Ether => DSL Router => Cable => AVR NetIO => Door opener Electronics

For the Phone application I preselect my acess point so I don't get annoying popups when the app needs to connect to my door.
The DSL router does port forwarding to the IP Address of the AVR Net IO board. Luckily (not only by chance), I've got a fixed IP Address from my provider for my router.
The AVR Net IO uses a fixed IP Address.

-- The Hardware --

When building the door I bought a cheapo door opener, because I thought the cheapter, the easier to modify.
The Einhell BGT 63 is an extremly simple design. The motor runs of 24V, switched by relais. The open/close end contacts are simply contacts to GND, pulled to internal 5V with a 1k Resistor.
The external open/close switch is also referenced to GND.

This design makes interfacing with the AVR netio really simple.
7 Resistors, one Transistor and 4 capacitors is all you need.
I used a resisitive divider with a smoothing capacitor (82k/10k / 1uF) to feed the voltage from the motor pins to the analog inputs of the board. The transistor is directly connected (Digital Output - Resistor - Transistor) to the switch.
I added a first order Low pass (R-C Filter 100k 1u) to the digital inputs just to be safe.




The AVR Netio board is supplied with an old mobile phone charger (nokia) The Einhell and AVR NetIO GNDs are connected, so I don't worry about galvanic isolation.

Open Points:

I still need to get an IR "curtain" to stop the door movement if something is close to it. At the moment this automatism is a real safety threat to children (although the door stops when 150 Netowns more than usual are required to move the door). The door is prepared for that already - so it's just a matter of selecting the right parts and installing them.


So that's it.

I took me about 4 days to design the door, 3 days to build it.
About 3 nights to get the grips on pyhton on the mobile phone (first time python programmer)
About 3 nights to get the phone running
About 1 day to install the AVR netIO board.

Total cost:
door: 550 Euro (the door itself, the metal, the wood, the concrete, the bearings, the cables)

door automation: 35 Euros. (27 Euro AVR Netion, Rest: cables and small bits and pieces)

Yeah - geeky - isn't it.

[img]uploaded/insaneLX/2009101821238_AVRNetio.jpg[/img]
This is the AVR NetIO

A video of the door opening:
Edwin2008
Advanced Member
Advanced Member
Posts: 721
Joined: Fri Nov 28, 2008 4:14 pm
Location: Netherlands

Automatic Garage door opener through GPS-phone and IP

Post by Edwin2008 »

pictures? sounds nice.
drmacchi
Advanced Member
Advanced Member
Posts: 827
Joined: Wed Aug 08, 2007 5:48 pm
Location: Italy

Automatic Garage door opener through GPS-phone and IP

Post by drmacchi »

To see the movie, you must be registered. could you publish over Youtube or similar please?
insaneLX
Starting Member
Starting Member
Posts: 4
Joined: Sat Oct 17, 2009 11:34 pm
Location: Austria
Contact:

Automatic Garage door opener through GPS-phone and IP

Post by insaneLX »

Ah sorry - I'll change the link.
insaneLX
Starting Member
Starting Member
Posts: 4
Joined: Sat Oct 17, 2009 11:34 pm
Location: Austria
Contact:

Automatic Garage door opener through GPS-phone and IP

Post by insaneLX »

And this is the source code of my Python applet - this is more a mockup than real source-code. Dirty, buggy, no exception handling - a python mock-up so to say.

<font color="brown">

import btsocket as socket
import sys
import appuifw
import e32, positioning, graphics, location, math
import time
import audio

#First this fills the gps_data with 0.0 so that there is something before the first gps update
gps_data = {
'satellites': {'horizontal_dop': 0.0, 'used_satellites': 0, 'vertical_dop': 0.0, 'time': 0.0,'satellites': 0, 'time_dop':0.0},
'position': {'latitude': 0.0, 'altitude': 0.0, 'vertical_accuracy': 0.0, 'longitude': 0.0, 'horizontal_accuracy': 0.0},
'course': {'speed': 0.0, 'heading': 0.0, 'heading_accuracy': 0.0, 'speed_accuracy': 0.0}
}

current_door_state = "uninitialized"

def gps_init():
#This function will start the updating of global variable (dictionary) 'gps_data' every 0.2 sec.
#0.2 sec comes form 'interval = 200000' set according to your needs
#This function uses callback funtion gps
global gps_data
try:
positioning.select_module(positioning.default_module())
positioning.set_requestors([{"type":"service","format":"application","data":"gps_app"}])
positioning.position(course=1,satellites=1,callback=gps, interval=200000,partial=0)
except:
appuifw.note(u'Problem with GPS init','error')

def gps(event):
global gps_data
gps_data = event

def gps_stop():
#This function stops GPS
try:
positioning.stop_position()
except:
appuifw.note(u'Problem with GPS stop','error')

aps = ""

def sel_access_point():
""" Select the default access point.
Return True if the selection was done or False if not
"""
aps = socket.access_points()
if not aps:
note(u"No access points available","error")
return False

ap_labels = map(lambda x: x['name'], aps)
item = appuifw.popup_menu(ap_labels,u"Access points:")
if item is None:
return False
apo = socket.access_point(aps[item]['iapid'])
socket.set_default_access_point(apo)

return True

def connect():
global sock
sock=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
sock.connect(("and here is my ip", --the port--))
print "Connection OK."

def scomm(command):
global recData
global sock
global status_message

try
sock.send(command + "\r")
recData = sock.recv(1024).strip()
except
if ("NAK" in recData):
raise "NAK from AVR netio (answererd %s to %s)" % (recData, command)
draw_state()
return recData


def draw_state():
canvas.clear()
canvas.text((0,12),u'Counting %8d Status: %s' % (count, status_message))
canvas.text((0,24),u'State: ' + current_state.__name__)
canvas.text((0,36),u'GPS lock: %s , %+10.5f %+10.5f' % ('gps_lock', gps_data['position']['latitude'], gps_data['position']['longitude']))
canvas.text((0,48),u'%f km from home.' % (calcDistance (home_base['position']['latitude'],home_base['position']['longitude'],
gps_data['position']['latitude'],gps_data['position']['longitude'])))
canvas.text((0,60),u'Home Base , %+10.5f %+10.5f' % (home_base['position']['latitude'],home_base['position']['longitude']))
canvas.text((0,72),u'GSM Cell:', 0x008000)
canvas.text((0,84),u' %i is faked? %s' % (get_cellId(), gsmFake ))
canvas.text((0,100),u'last keycode ' + str(last_keycode))
canvas.text((0,112),u'%f last Distance' % (last_distance))
canvas.text((0,124),u'AVR netio answer: %s ' % repr(recData))
canvas.text((0,136),u'Door is: %s ' % current_door_state)
canvas.text((0,148),u'7: close app')
canvas.text((0,160),u'8: push door button')


def keyCallback(event):
global last_keycode
if event['type'] == appuifw.EEventKeyDown:
keyboard_state[event['scancode']]=1
elif event['type'] == appuifw.EEventKeyUp:
keyboard_state[event['scancode']]=0
elif event['type'] == appuifw.EEventKey:
last_keycode=event['keycode']
draw_state()



# States and transitions
# at_home_no_gps
# at_home_with_gps
# far_away
# close_to_home_starting_gps
# close_to_home_with_gps
# unknown
# unknown_starting_gps


home_base = {'position': {'latitude': 123456789, 'longitude': +123456789}, 'gsm_cellid': 123456789}

close_to_home_cellIds = (123456789, 12345678)
threshold_distance = 0.005

kmPerLat = 60.00721 / 1.852
kmPerLongitude = 60.10793 / 1.852
rad = math.pi / 180.0

def calcDistance(lat1, lon1, lat2, lon2):
"""
Caclulate distance between two lat lons in NM
"""
yDistance = (lat2 - lat1) * kmPerLat
xDistance = (math.cos(lat1 * rad) + math.cos(lat2 * rad)) * (lon2 - lon1) * (kmPerLongitude / 2)

distance = math.sqrt( yDistance**2 + xDistance**2 )

return distance

gsmFake = 'no'
gsmFakeCells = {'home_cell': 2083142,
'close_to_home': 2083143,
'far_away': 100,
'none': 0 }

recData = ""

def get_cellId():
global gsmFake
global last_keycode

if last_keycode == 49:
gsmFake = 'home_cell'
elif str(last_keycode) == '50':
gsmFake = 'close_to_home'
elif str(last_keycode) == '51':
gsmFake = 'far_away'
elif str(last_keycode) == '52':
gsmFake = 'none'
elif str(last_keycode) == '53':
gsmFake = 'no'

if gsmFake == 'no':
gsmloc = location.gsm_location()
else:
gsmloc = [0,1,2,gsmFakeCells[gsmFake]]

if gsmloc is None:
return 0
else:
return gsmloc[3]




def distance_from_home():
return (calcDistance (home_base['position']['latitude'],home_base['position']['longitude'],gps_data['position']['latitude'],gps_data['position']['longitude']))


def get_door_state():
runThreshold = 200
global current_door_state
closed_switch = scomm('getport 3')
e32.ao_sleep(0.1)
opened_switch = scomm('getport 4')
e32.ao_sleep(0.1)
# motor voltage is > 200 counts when clsoing

motor_voltage = int(scomm('getadc 1'))
e32.ao_sleep(0.1)
motor_voltage = motor_voltage - int(scomm('getadc 2'))
e32.ao_sleep(0.1)

if (closed_switch == "0"):
current_door_state = "closed"
return current_door_state

if (opened_switch == "0"):
current_door_state = "open"
return current_door_state

if (motor_voltage > +runThreshold):
current_door_state = "closing"
return current_door_state

if (motor_voltage < -runThreshold):
current_door_state = "opening"
return current_door_state

current_door_state = "half_open"
return current_door_state

def press_button():
scomm("setport 1.1")
e32.ao_sleep(1)
scomm("setport 1.0")
e32.ao_sleep(1)


def opening_door():
global current_state
global status_message

if (get_door_state() == "open"):
status_message = "do not need to open door"
return 1

if (get_door_state() == "closed"):
status_message = "opening door"
press_button()

if (get_door_state() == "opening"):
status_message = "door is already opening"
return 1

if (get_door_state() == "closing"):
status_message = "door is closing: stopping"
press_button()
e32.ao_sleep(3)
opening_door() # recursively calling open door.
# This is OK, because now it should be "half_open" an the recursion will stop
return 1

if (get_door_state() == "half_open"):
status_message = "door is half_open: trying to close"
press_button()
e32.ao_sleep(3)
return 1

current_state = simple_one


def closing_door():
global current_state
current_state = simple_one


def simple_one_waiting():
global last_distance
global current_state

if (gps_data['position']['latitude'] != 0):
last_distance = distance_from_home()
current_state = simple_one
e32.ao_sleep(1)

def simple_one():
global last_distance
global current_state
global status_message
global gps_data


distance = distance_from_home()
if (distance < threshold_distance) and (last_distance >= threshold_distance) and (gps_data['course']['speed'] > 0):
status_message = 'Coming home'
current_state = opening_door
if (distance > threshold_distance) and (last_distance <= threshold_distance):
status_message = 'Leaving home'
current_state = closing_door

last_distance = distance
e32.ao_sleep(1)

status_message = 'Application started'
current_state = simple_one_waiting

gps_init()
keyboard_state={}
last_keycode = 0
count = 0
last_distance = -1

canvas=appuifw.Canvas(event_callback=keyCallback,
redraw_callback=lambda rect:draw_state())

appuifw.app.body=canvas

if not aps:
sel_access_point()
connect()

while last_keycode != 55:
count = count + 1
current_state()

if (last_keycode == 56):
press_button()
status_message = 'Fake Buttonpress'
last_keycode = 0
get_door_state()
draw_state()

gps_stop()
sock.close()
</font id="brown">
User avatar
Snelvuur
Forum Moderator
Forum Moderator
Posts: 3156
Joined: Fri Apr 06, 2007 11:01 pm
Location: Netherlands
Contact:

Automatic Garage door opener through GPS-phone and IP

Post by Snelvuur »

another fine example of doing it yourself, cost less then the real deal. (more fun too)

// Erik (binkey.nl)
User avatar
Noel
Senior Member
Senior Member
Posts: 1887
Joined: Tue Feb 12, 2008 12:13 am
Location: Netherlands
Contact:

Automatic Garage door opener through GPS-phone and IP

Post by Noel »

looks like you will be a dady soon!

--
Jeffrey
Member
Member
Posts: 136
Joined: Tue Jun 09, 2009 3:34 pm
Location: Netherlands

Automatic Garage door opener through GPS-phone and IP

Post by Jeffrey »

What a cool project! Really nice...now I only need a carport [:p]
coco
Starting Member
Starting Member
Posts: 2
Joined: Mon Oct 19, 2009 8:09 pm
Location: Romania
Contact:

Automatic Garage door opener through GPS-phone and IP

Post by coco »

very nice project!
insaneLX
Starting Member
Starting Member
Posts: 4
Joined: Sat Oct 17, 2009 11:34 pm
Location: Austria
Contact:

Automatic Garage door opener through GPS-phone and IP

Post by insaneLX »

<blockquote id="quote"><font size="1" face="Verdana, Arial, Helvetica" id="quote">quote:<hr height="1" noshade id="quote"><i>Originally posted by wifi</i>
<br />looks like you will be a dady soon!

--

<hr height="1" noshade id="quote"></font id="quote"></blockquote id="quote">

Well actually the video is more than a month old (first trial of the door mechanics). My boy is 5 weeks already :-)
User avatar
Noel
Senior Member
Senior Member
Posts: 1887
Joined: Tue Feb 12, 2008 12:13 am
Location: Netherlands
Contact:

Automatic Garage door opener through GPS-phone and IP

Post by Noel »

Nice one.. I still remeber my boy beeing 5 weeks old (he is now 17 months).. Good luck, and sleep well :-)

--
Post Reply

Return to “Home Automation Projects”