Skip to content

Instantly share code, notes, and snippets.

@fuzzylogiq
Created June 3, 2016 13:24
Show Gist options
  • Select an option

  • Save fuzzylogiq/585f58684bfde6aa31a0761eac85d880 to your computer and use it in GitHub Desktop.

Select an option

Save fuzzylogiq/585f58684bfde6aa31a0761eac85d880 to your computer and use it in GitHub Desktop.
#!/usr/bin/python
# encoding: utf-8
"""
lightify.py
!!description goes here!!
Copyright (c) Ben Goodstein 2016
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but without any warranty; without even the implied warranty of
merchantability or fitness for a particular purpose. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
"""
import requests
from requests.auth import AuthBase
from requests.exceptions import ConnectionError
import logging
__all__ = ['LightifyAuth', 'Lightify']
logger = logging.getLogger(__name__)
logging.basicConfig(level=logging.DEBUG)
logging.getLogger("requests").setLevel(logging.WARNING)
logging.getLogger("urllib3").setLevel(logging.WARNING)
class LightifyAuth(AuthBase):
def __init__(self, token):
self.__token = token
def __call__(self, request):
request.headers['authorization'] = self.__token
return request
class Lightify(object):
def __init__(self, api, username, password, sn):
'''Initialises Lightify object with defaults and refreshes data'''
self.devices = []
self.groups = []
self.scenes = {}
self.gateway = ""
self.version = ""
self.__api = api
self.__username = username
self.__password = password
self.__sn = sn
self.__token = ""
self._session = requests.session()
# Add header that all reqs will need
self._session.headers.update({'Content-Type': 'application/json'})
# Add auth_hook before each request
self._session.hooks = dict(response=self._auth_hook)
self._bad_creds = False
logger.info('Refreshing all data...')
self.refresh_all()
def _auth_hook(self, response, *args, **kwargs):
'''Hook for each response to check status code and ensure we are
authenticated'''
# Avoid loop if credentials are incorrect
if not self._bad_creds:
logger.info('Made request to %s', response.url)
# Authenticate if securityToken invalid
if (response.status_code == 400 and
response.json()['errorCode'] == 5003):
logger.warn(response.json()['errorMessage'])
self._authenticate()
# Retrieve original request
request = response.request
# Add securityToken to headers
request.headers.update({'authorization': self.__token})
logger.info('Successfully authenticated.')
# Resend request
return self._session.send(request)
elif response.status_code == 200:
logger.info('Success!')
else:
if response.json():
logger.warn("error %i: %s",
response.json()['errorCode'],
response.json()['errorMessage'])
else:
logger.warn('Failed to authenticate with supplied credentials.')
def _authenticate(self):
'''Sends credentials to receive securityToken'''
logger.info('Authenticating at %s/session', self.__api)
resp = requests.post('%s/session' % self.__api,
headers={'Content-Type': 'application/json'},
json={'username': self.__username,
'password': self.__password,
'serialNumber': self.__sn})
if resp.status_code == 200:
self.__token = resp.json()['securityToken']
self._session.auth = LightifyAuth(self.__token)
else:
# We have a problem with credentials, no point trying further
self._bad_creds = True
def _api_call(self, url, params=None):
'''Calls the API with the specified URL and parameters'''
try:
response = self._session.get('%s%s' % (self.__api, url),
params=params,
timeout=10)
if response.status_code == 200:
return response
else:
return None
except ConnectionError:
logger.warn('Cannot connect to API. Are you connected to the'
'internet?')
def refresh_devices(self):
'''Updates all device data'''
response = self._api_call('/devices')
if response:
self.devices = response.json()
def refresh_groups(self):
'''Updates all group data'''
response = self._api_call('/groups')
if response:
self.groups = response.json()
for group in self.groups:
self.scenes.update(group['scenes'])
def refresh_version(self):
'''Updates version of API'''
response = self._api_call('/version')
if response:
self.version = response.json()['apiversion']
def refresh_gateway_version(self):
'''Updates version of gateway'''
response = self._api_call('/gateway')
if response:
self.gateway = response.json()['version']
def refresh_all(self):
'''Updates all data'''
self.refresh_devices()
self.refresh_groups()
self.refresh_gateway_version()
self.refresh_version()
def set_device(self, params):
'''Sets a device's state with a dictionary of parameters'''
if self._api_call('/device/set', params=params):
self.refresh_devices()
def set_all_devices(self, params):
'''Sets all devices' state with a dictionary of parameters'''
if self._api_call('/device/all/set', params=params):
self.refresh_devices()
def set_group(self, params):
'''Sets a group's state with a dictionary of parameters'''
if self._api_call('/group/set', params=params):
self.refresh_devices()
def set_scene(self, params):
'''Recalls scene with a dictionary of parameters'''
if self._api_call('/scene/recall', params=params):
self.refresh_devices()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment