1- """Module for handling Cozify Cloud API operations
2-
3- Attributes:
4- cloudBase(str): API endpoint including version
5-
1+ """Module for handling Cozify Cloud highlevel operations.
62"""
73
8- import json , requests , logging , datetime
4+ import logging , datetime
95
106from . import config as c
117from . import hub
8+ from . import hub_api
9+ from . import cloud_api
1210
1311from .Error import APIError , AuthenticationError
1412
15- cloudBase = 'https://cloud2.cozify.fi/ui/0.2/'
16-
1713def authenticate (trustCloud = True , trustHub = True , remote = False , autoremote = True ):
1814 """Authenticate with the Cozify Cloud and Hub.
1915
@@ -44,7 +40,7 @@ def authenticate(trustCloud=True, trustHub=True, remote=False, autoremote=True):
4440
4541 if _need_cloud_token (trustCloud ):
4642 try :
47- _requestlogin (email )
43+ cloud_api . requestlogin (email )
4844 except APIError :
4945 resetState () # a bogus email will shaft all future attempts, better to reset
5046 raise
@@ -57,7 +53,7 @@ def authenticate(trustCloud=True, trustHub=True, remote=False, autoremote=True):
5753 raise AuthenticationError (message )
5854
5955 try :
60- cloud_token = _emaillogin (email , otp )
56+ cloud_token = cloud_api . emaillogin (email , otp )
6157 except APIError :
6258 logging .error ('OTP authentication has failed.' )
6359 resetState ()
@@ -71,9 +67,9 @@ def authenticate(trustCloud=True, trustHub=True, remote=False, autoremote=True):
7167 cloud_token = _getAttr ('remoteToken' )
7268
7369 if _need_hub_token (trustHub ):
74- localHubs = _lan_ip () # will only work if we're local to the Hub, otherwise None
70+ localHubs = cloud_api . lan_ip () # will only work if we're local to the Hub, otherwise None
7571 # TODO(artanicus): unknown what will happen if there is a local hub but another one remote. Needs testing by someone with multiple hubs. Issue #7
76- hubkeys = _hubkeys (cloud_token ) # get all registered hubs and their keys from the cloud.
72+ hubkeys = cloud_api . hubkeys (cloud_token ) # get all registered hubs and their keys from the cloud.
7773 if not hubkeys :
7874 logging .critical ('You have not registered any hubs to the Cozify Cloud, hence a hub cannot be used yet.' )
7975
@@ -87,18 +83,18 @@ def authenticate(trustCloud=True, trustHub=True, remote=False, autoremote=True):
8783 # if we're remote, we didn't get a valid ip
8884 if not localHubs :
8985 logging .info ('No local Hubs detected, attempting authentication via Cozify Cloud.' )
90- hub_info = hub . _hub ( cloud_token = cloud_token , hub_token = hub_token )
86+ hub_info = hub_api . hub ( remote = True , cloud_token = cloud_token , hub_token = hub_token )
9187 # if the hub wants autoremote we flip the state
9288 if hub .autoremote and not hub .remote :
9389 logging .info ('[autoremote] Flipping hub remote status from local to remote.' )
9490 hub .remote = True
9591 else :
9692 # localHubs is valid so a hub is in the lan. A mixed environment cannot yet be detected.
97- # _lan_ip cannot provide a map as to which ip is which hub. Thus we actually need to determine the right one.
93+ # cloud_api.lan_ip cannot provide a map as to which ip is which hub. Thus we actually need to determine the right one.
9894 # TODO(artanicus): Need to truly test how multihub works before implementing ip to hub resolution. See issue #7
9995 logging .debug ('data structure: {0}' .format (localHubs ))
10096 hub_ip = localHubs [0 ]
101- hub_info = hub . _hub (host = hub_ip )
97+ hub_info = hub_api . hub (host = hub_ip , remote = False )
10298 # if the hub wants autoremote we flip the state
10399 if hub .autoremote and hub .remote :
104100 logging .info ('[autoremote] Flipping hub remote status from remote to local.' )
@@ -149,7 +145,7 @@ def ping(autorefresh=True, expiry=None):
149145 """
150146
151147 try :
152- _hubkeys (token ()) # TODO(artanicus): see if there's a cheaper API call
148+ cloud_api . hubkeys (token ()) # TODO(artanicus): see if there's a cheaper API call
153149 except APIError as e :
154150 if e .status_code == 401 :
155151 return False
@@ -177,7 +173,7 @@ def refresh(force=False, expiry=datetime.timedelta(days=1)):
177173 """
178174 if _need_refresh (force , expiry ):
179175 try :
180- cloud_token = _refreshsession (token ())
176+ cloud_token = cloud_api . refreshsession (token ())
181177 except APIError as e :
182178 if e .status_code == 401 :
183179 # too late, our token is already dead
@@ -333,111 +329,3 @@ def email(new_email=None):
333329 if new_email :
334330 _setAttr ('email' , new_email )
335331 return _getAttr ('email' )
336-
337- def _requestlogin (email ):
338- """Raw Cloud API call, request OTP to be sent to account email address.
339-
340- Args:
341- email(str): Email address connected to Cozify account.
342- """
343-
344- payload = { 'email' : email }
345- response = requests .post (cloudBase + 'user/requestlogin' , params = payload )
346- if response .status_code is not 200 :
347- raise APIError (response .status_code , response .text )
348-
349- def _emaillogin (email , otp ):
350- """Raw Cloud API call, request cloud token with email address & OTP.
351-
352- Args:
353- email(str): Email address connected to Cozify account.
354- otp(int): One time passcode.
355-
356- Returns:
357- str: cloud token
358- """
359-
360- payload = {
361- 'email' : email ,
362- 'password' : otp
363- }
364-
365- response = requests .post (cloudBase + 'user/emaillogin' , params = payload )
366- if response .status_code == 200 :
367- return response .text
368- else :
369- raise APIError (response .status_code , response .text )
370-
371- def _lan_ip ():
372- """1:1 implementation of hub/lan_ip
373-
374- This call will fail with an APIError if the requesting source address is not the same as that of the hub, i.e. if they're not in the same NAT network.
375- The above is based on observation and may only be partially true.
376-
377- Returns:
378- list: List of Hub ip addresses.
379- """
380- response = requests .get (cloudBase + 'hub/lan_ip' )
381- if response .status_code == 200 :
382- return json .loads (response .text )
383- else :
384- raise APIError (response .status_code , response .text )
385-
386- def _hubkeys (cloud_token ):
387- """1:1 implementation of user/hubkeys
388-
389- Args:
390- cloud_token(str) Cloud remote authentication token.
391-
392- Returns:
393- dict: Map of hub_id: hub_token pairs.
394- """
395- headers = {
396- 'Authorization' : cloud_token
397- }
398- response = requests .get (cloudBase + 'user/hubkeys' , headers = headers )
399- if response .status_code == 200 :
400- return json .loads (response .text )
401- else :
402- raise APIError (response .status_code , response .text )
403-
404- def _refreshsession (cloud_token ):
405- """1:1 implementation of user/refreshsession
406-
407- Args:
408- cloud_token(str) Cloud remote authentication token.
409-
410- Returns:
411- str: New cloud remote authentication token. Not automatically stored into state.
412- """
413- headers = {
414- 'Authorization' : cloud_token
415- }
416- response = requests .get (cloudBase + 'user/refreshsession' , headers = headers )
417- if response .status_code == 200 :
418- return response .text
419- else :
420- raise APIError (response .status_code , response .text )
421-
422- def _remote (cloud_token , hub_token , apicall , put = False ):
423- """1:1 implementation of 'hub/remote'
424-
425- Args:
426- cloud_token(str): Cloud remote authentication token.
427- hub_token(str): Hub authentication token.
428- apicall(str): Full API call that would normally go directly to hub, e.g. '/cc/1.6/hub/colors'
429-
430- Returns:
431- requests.response: Requests response object.
432- """
433-
434- headers = {
435- 'Authorization' : cloud_token ,
436- 'X-Hub-Key' : hub_token
437- }
438- if put :
439- response = requests .put (cloudBase + 'hub/remote' + apicall , headers = headers )
440- else :
441- response = requests .get (cloudBase + 'hub/remote' + apicall , headers = headers )
442-
443- return response
0 commit comments