Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Smartthings #29

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 17 additions & 1 deletion alarmserver-example.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ logfile=
## seconds with the web ui's. To disable all these set this to False
logurlrequests=True


## The server runs with SSL. You need a certificate and key
## server.crt and server.key are included but you should
## generate your own.
Expand All @@ -34,10 +33,12 @@ httpsport=8111
eventtimeago=True

## Name of your parition(s)
## Note: For callbackURL setup only defined zones and paritions are sent callback data
partition1=Home

## Zone names. Delete the zones you're not using to have them hidden.
## Add more zoneXX if you need more zones
## Note: For callbackURL setup only defined zones and paritions are sent callback data
zone1=A
zone2=B
zone3=C
Expand All @@ -60,6 +61,21 @@ user1=MyUser1
user2=MyUser2
user3=MyUser3

## Experimental CallbackURL functionality - Mainly for Smartthings right now
## The resulting path for callbackurls looks like this
## This likely needs to be fixed to allow more flexibility for any service?
## Suggestions welcome
## ${callbackurl_base}/${callbackurl_app_id}/panel/${code}/${zoneorpartitionnumber}?access_token=${callbackurl_access_token}

## Smartthings or generic callback URL setup
callbackurl_base=https://graph.api.smartthings.com/api/smartapps/installations
callbackurl_app_id=your_app_id_from_smartthings_or_other_oAuth_setup
callbackurl_access_token=your_resulting_acces_token_after_auth_setup
## Define the event codes you want callbacks for, the codes below
## cover zone open/close, partition ready, not ready, armed, exit delay, entry delay and in alarm status
## these should cover most use cases
callbackurl_event_codes=601,602,609,610,650,651,652,654,656,657

[pushover]
enable=False
usertoken=tokengoeshere
Expand Down
48 changes: 45 additions & 3 deletions alarmserver.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
import hashlib
import time
import getopt
import requests

from envisalinkdefs import evl_ResponseTypes
from envisalinkdefs import evl_Defaults
Expand Down Expand Up @@ -92,6 +93,10 @@ def __init__(self, configfile):
self.ALARMCODE = self.read_config_var('envisalink', 'alarmcode', 1111, 'int')
self.EVENTTIMEAGO = self.read_config_var('alarmserver', 'eventtimeago', True, 'bool')
self.LOGFILE = self.read_config_var('alarmserver', 'logfile', '', 'str')
self.CALLBACKURL_BASE = self.read_config_var('alarmserver', 'callbackurl_base', '', 'str')
self.CALLBACKURL_APP_ID = self.read_config_var('alarmserver', 'callbackurl_app_id', '', 'str')
self.CALLBACKURL_ACCESS_TOKEN = self.read_config_var('alarmserver', 'callbackurl_access_token', '', 'str')
self.CALLBACKURL_EVENT_CODES = self.read_config_var('alarmserver', 'callbackurl_event_codes', '', 'str')
global LOGTOFILE
if self.LOGFILE == '':
LOGTOFILE = False
Expand Down Expand Up @@ -337,7 +342,8 @@ def handle_event(self, code, parameters, event, message):
if event['type'] in ('partition', 'zone'):
if event['type'] == 'zone':
if int(parameters) in self._config.ZONENAMES:
if not int(parameters) in ALARMSTATE[event['type']]: ALARMSTATE[event['type']][int(parameters)] = {'name' : self._config.ZONENAMES[int(parameters)]}
if not int(parameters) in ALARMSTATE[event['type']]:
ALARMSTATE[event['type']][int(parameters)] = {'name' : self._config.ZONENAMES[int(parameters)]}
else:
if not int(parameters) in ALARMSTATE[event['type']]: ALARMSTATE[event['type']][int(parameters)] = {}
elif event['type'] == 'partition':
Expand Down Expand Up @@ -365,13 +371,49 @@ def handle_event(self, code, parameters, event, message):
if len(ALARMSTATE[event['type']]['lastevents']) > self._config.MAXALLEVENTS:
ALARMSTATE[event['type']]['lastevents'].pop(0)
ALARMSTATE[event['type']]['lastevents'].append({'datetime' : str(datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")), 'message' : message})
self.callbackurl_event(code, parameters, event, message)

def handle_zone(self, code, parameters, event, message):
self.handle_event(code, parameters[1:], event, message)

def handle_partition(self, code, parameters, event, message):
self.handle_event(code, parameters[0], event, message)

def callbackurl_event(self, code, parameters, event, message):
myEvents = self._config.CALLBACKURL_EVENT_CODES.split(',')
# Determin what events we are sending to smartthings then send if we match
if str(code) in myEvents:
# Now check if Zone has a custom name, if it does then send notice to Smartthings
# Check for event type
if event['type'] == 'partition':
# Is our partition setup with a custom name?
if int(parameters[0]) in self._config.PARTITIONNAMES:
myURL = self._config.CALLBACKURL_BASE + "/" + self._config.CALLBACKURL_APP_ID + "/panel/" + str(code) + "/" + str(int(parameters[0])) + "?access_token=" + self._config.CALLBACKURL_ACCESS_TOKEN
else:
# We don't care about this partition
return
elif event['type'] == 'zone':
# Is our zone setup with a custom name, if so we care about it
if self._config.ZONENAMES[int(parameters)]:
myURL = self._config.CALLBACKURL_BASE + "/" + self._config.CALLBACKURL_APP_ID + "/panel/" + str(code) + "/" + str(int(parameters)) + "?access_token=" + self._config.CALLBACKURL_ACCESS_TOKEN
else:
# We don't care about this zone
return
else:
# Unhandled event type..
return

# If we made it here we should send to Smartthings
try:
# Note: I don't currently care about the return value, fire and forget right now
requests.get(myURL)
#print "myURL: ", myURL
#print "Exit code: ", r.status_code
#print "Response data: ", r.text
time.sleep(0.5)
except:
print sys.exc_info()[0]

class push_FileProducer:
# a producer which reads data from a file object

Expand Down Expand Up @@ -410,9 +452,9 @@ def handle_accept(self):
alarmserver_logger('Incoming web connection from %s' % repr(addr))

try:
# HTTPChannel(self, conn, addr)
HTTPChannel(self, ssl.wrap_socket(conn, server_side=True, certfile=config.CERTFILE, keyfile=config.KEYFILE, ssl_version=ssl.PROTOCOL_TLSv1), addr)
except ssl.SSLError:
alarmserver_logger('Failed https connection, attempted with http')
return

def handle_request(self, channel, method, request, header):
Expand Down Expand Up @@ -607,4 +649,4 @@ def main(argv):

server.shutdown(socket.SHUT_RDWR)
server.close()
sys.exit()
sys.exit()