Created
June 3, 2016 13:24
-
-
Save fuzzylogiq/585f58684bfde6aa31a0761eac85d880 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/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