-
Notifications
You must be signed in to change notification settings - Fork 20
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
changes to support guest accounts #42
base: master
Are you sure you want to change the base?
Changes from all commits
6072eec
91ab20c
c39b5d0
5204a86
ea5b05d
f6cbd82
40c618b
2d4b6cc
4e1a239
10a8642
ed484dc
a3b705a
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||||||
---|---|---|---|---|---|---|---|---|---|---|
|
@@ -15,21 +15,22 @@ class HiveApi: | |||||||||
def __init__(self, hiveSession=None, websession=None, token=None): | ||||||||||
"""Hive API initialisation.""" | ||||||||||
self.cameraBaseUrl = "prod.hcam.bgchtest.info" | ||||||||||
self.baseUrl = "https://beekeeper.hivehome.com/1.0" | ||||||||||
|
||||||||||
self.urls = { | ||||||||||
"properties": "https://sso.hivehome.com/", | ||||||||||
"login": "https://beekeeper.hivehome.com/1.0/cognito/login", | ||||||||||
"refresh": "https://beekeeper.hivehome.com/1.0/cognito/refresh-token", | ||||||||||
"long_lived": "https://api.prod.bgchprod.info/omnia/accessTokens", | ||||||||||
"base": "https://beekeeper-uk.hivehome.com/1.0", | ||||||||||
"weather": "https://weather.prod.bgchprod.info/weather", | ||||||||||
"holiday_mode": "/holiday-mode", | ||||||||||
"all": "/nodes/all?products=true&devices=true&actions=true", | ||||||||||
"alarm": "/security-lite?homeId=", | ||||||||||
"all": f"{self.baseUrl}/nodes/all", | ||||||||||
"alarm": f"{self.baseUrl}/security-lite", | ||||||||||
"cameraImages": f"https://event-history-service.{self.cameraBaseUrl}/v1/events/cameras?latest=true&cameraId={{0}}", | ||||||||||
"cameraRecordings": f"https://event-history-service.{self.cameraBaseUrl}/v1/playlist/cameras/{{0}}/events/{{1}}.m3u8", | ||||||||||
"devices": "/devices", | ||||||||||
"products": "/products", | ||||||||||
"actions": "/actions", | ||||||||||
"devices": f"{self.baseUrl}/devices", | ||||||||||
"products": f"{self.baseUrl}/products", | ||||||||||
"actions": f"{self.baseUrl}/actions", | ||||||||||
"nodes": "/nodes/{0}/{1}", | ||||||||||
} | ||||||||||
self.timeout = 10 | ||||||||||
|
@@ -40,7 +41,28 @@ def __init__(self, hiveSession=None, websession=None, token=None): | |||||||||
self.session = hiveSession | ||||||||||
self.token = token | ||||||||||
|
||||||||||
def request(self, type, url, jsc=None, camera=False): | ||||||||||
self.homeID = None | ||||||||||
if self.session is not None: | ||||||||||
self.homeID = self.session.config.homeID | ||||||||||
|
||||||||||
def getParams(self, products=False, devices=False, actions=False): | ||||||||||
"""Get parameters.""" | ||||||||||
params = { | ||||||||||
"products": products, | ||||||||||
"devices": devices, | ||||||||||
"actions": actions, | ||||||||||
} | ||||||||||
if self.homeID is not None: | ||||||||||
params.update({"homeId": self.homeID}) | ||||||||||
return params | ||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You need and else if here if someone requests to the send the homeId but its actually set to None. to do this you will also need to create a new exception in the Hive exceptions file and import it into this module
Suggested change
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This would change the behaviour of the sync api to require a homeId in the case of one home in hive. I've tried to make sure my change only effects cases where a homeID is actually set. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thinking about it, there's nowhere we don't want to send homeID if it isn't set; except There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What about if your the account owner with a single home and you don’t need to send a homeID. is your thinking to send one anyway? |
||||||||||
|
||||||||||
def getHomeIdParam(self): | ||||||||||
"""Get homeId parameter if set.""" | ||||||||||
if self.homeID is not None: | ||||||||||
return {"homeId": self.homeID} | ||||||||||
return {} | ||||||||||
|
||||||||||
def request(self, type, url, jsc=None, camera=False, params={}): | ||||||||||
"""Make API request.""" | ||||||||||
if self.session is not None: | ||||||||||
if camera: | ||||||||||
|
@@ -73,11 +95,19 @@ def request(self, type, url, jsc=None, camera=False): | |||||||||
|
||||||||||
if type == "GET": | ||||||||||
return requests.get( | ||||||||||
url=url, headers=self.headers, data=jsc, timeout=self.timeout | ||||||||||
url=url, | ||||||||||
headers=self.headers, | ||||||||||
data=jsc, | ||||||||||
timeout=self.timeout, | ||||||||||
params=params, | ||||||||||
) | ||||||||||
if type == "POST": | ||||||||||
return requests.post( | ||||||||||
url=url, headers=self.headers, data=jsc, timeout=self.timeout | ||||||||||
url=url, | ||||||||||
headers=self.headers, | ||||||||||
data=jsc, | ||||||||||
timeout=self.timeout, | ||||||||||
params=params, | ||||||||||
) | ||||||||||
|
||||||||||
def refreshTokens(self, tokens={}): | ||||||||||
|
@@ -97,8 +127,8 @@ def refreshTokens(self, tokens={}): | |||||||||
data = json.loads(info.text) | ||||||||||
if "token" in data and self.session: | ||||||||||
self.session.updateTokens(data) | ||||||||||
self.urls.update({"base": data["platform"]["endpoint"]}) | ||||||||||
self.urls.update({"camera": data["platform"]["cameraPlatform"]}) | ||||||||||
self.baseUrl = info["platform"]["endpoint"] | ||||||||||
self.cameraBaseUrl = info["platform"]["cameraPlatform"] | ||||||||||
self.json_return.update({"original": info.status_code}) | ||||||||||
self.json_return.update({"parsed": info.json()}) | ||||||||||
except (OSError, RuntimeError, ZeroDivisionError): | ||||||||||
|
@@ -132,23 +162,47 @@ def getLoginInfo(self): | |||||||||
def getAll(self): | ||||||||||
"""Build and query all endpoint.""" | ||||||||||
json_return = {} | ||||||||||
url = self.urls["base"] + self.urls["all"] | ||||||||||
url = self.urls["all"] | ||||||||||
params = self.getParams( | ||||||||||
products=True, devices=True, actions=True | ||||||||||
) | ||||||||||
try: | ||||||||||
info = self.request("GET", url) | ||||||||||
info = self.request("GET", url, params=params) | ||||||||||
json_return.update({"original": info.status_code}) | ||||||||||
json_return.update({"parsed": info.json()}) | ||||||||||
except (OSError, RuntimeError, ZeroDivisionError): | ||||||||||
self.error() | ||||||||||
|
||||||||||
return json_return | ||||||||||
|
||||||||||
def getHomes(self): | ||||||||||
"""Build and query all endpoint.""" | ||||||||||
json_return = {} | ||||||||||
url = self.urls["all"] | ||||||||||
params = self.getParams() | ||||||||||
try: | ||||||||||
info = self.request("GET", url, params=params) | ||||||||||
all = info.json() | ||||||||||
json_return.update({"original": info.status_code}) | ||||||||||
json_return.update({"parsed": all["homes"]}) | ||||||||||
except (OSError, RuntimeError, ZeroDivisionError): | ||||||||||
self.error() | ||||||||||
|
||||||||||
return json_return | ||||||||||
|
||||||||||
def getAlarm(self, homeID=None): | ||||||||||
"""Build and query alarm endpoint.""" | ||||||||||
if self.session is not None: | ||||||||||
homeID = self.session.config.homeID | ||||||||||
url = self.urls["base"] + self.urls["alarm"] + homeID | ||||||||||
url = self.urls["alarm"] | ||||||||||
params = {} | ||||||||||
if homeID: | ||||||||||
params = {"homeID": homeID} | ||||||||||
if self.homeID: | ||||||||||
# ignore homeID if set in session | ||||||||||
params = self.getHomeIdParam() | ||||||||||
try: | ||||||||||
info = self.request("GET", url) | ||||||||||
info = self.request("GET", url, params=params) | ||||||||||
self.json_return.update({"original": info.status_code}) | ||||||||||
self.json_return.update({"parsed": info.json()}) | ||||||||||
except (OSError, RuntimeError, ZeroDivisionError): | ||||||||||
|
@@ -186,9 +240,10 @@ def getCameraRecording(self, device=None, eventId=None): | |||||||||
|
||||||||||
def getDevices(self): | ||||||||||
"""Call the get devices endpoint.""" | ||||||||||
url = self.urls["base"] + self.urls["devices"] | ||||||||||
url = self.urls["devices"] | ||||||||||
params = self.getParams(devices=True) | ||||||||||
try: | ||||||||||
response = self.request("GET", url) | ||||||||||
response = self.request("GET", url, params=params) | ||||||||||
self.json_return.update({"original": response.status_code}) | ||||||||||
self.json_return.update({"parsed": response.json()}) | ||||||||||
except (OSError, RuntimeError, ZeroDivisionError): | ||||||||||
|
@@ -198,9 +253,10 @@ def getDevices(self): | |||||||||
|
||||||||||
def getProducts(self): | ||||||||||
"""Call the get products endpoint.""" | ||||||||||
url = self.urls["base"] + self.urls["products"] | ||||||||||
url = self.urls["products"] | ||||||||||
params = self.getParams(products=True) | ||||||||||
try: | ||||||||||
response = self.request("GET", url) | ||||||||||
response = self.request("GET", url, params=params) | ||||||||||
self.json_return.update({"original": response.status_code}) | ||||||||||
self.json_return.update({"parsed": response.json()}) | ||||||||||
except (OSError, RuntimeError, ZeroDivisionError): | ||||||||||
|
@@ -210,11 +266,13 @@ def getProducts(self): | |||||||||
|
||||||||||
def getActions(self): | ||||||||||
"""Call the get actions endpoint.""" | ||||||||||
url = self.urls["base"] + self.urls["actions"] | ||||||||||
url = self.urls["all"] | ||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. How come this has been updated to point to all? getDevices & getProducts still points to the individual endpoints. if we can get all data from the all endpoint maybe we should remove the individual endpoints. What do you think? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I have no idea, I did this in July. Sorry. |
||||||||||
params = self.getHomeIdParam() | ||||||||||
try: | ||||||||||
response = self.request("GET", url) | ||||||||||
response = self.request("GET", url, params=params) | ||||||||||
all = response.json() | ||||||||||
self.json_return.update({"original": response.status_code}) | ||||||||||
self.json_return.update({"parsed": response.json()}) | ||||||||||
self.json_return.update({"parsed": all["actions"]}) | ||||||||||
except (OSError, RuntimeError, ZeroDivisionError): | ||||||||||
self.error() | ||||||||||
|
||||||||||
|
@@ -256,6 +314,10 @@ def getWeather(self, weather_url): | |||||||||
|
||||||||||
return self.json_return | ||||||||||
|
||||||||||
def setHome(self, homeID): | ||||||||||
"""Set the homeID.""" | ||||||||||
self.homeID = homeID | ||||||||||
|
||||||||||
def setState(self, n_type, n_id, **kwargs): | ||||||||||
"""Set the state of a Device.""" | ||||||||||
jsc = ( | ||||||||||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -27,8 +27,9 @@ def __init__(self, hiveSession=None, websession: Optional[ClientSession] = None) | |
"login": f"{self.baseUrl}/cognito/login", | ||
"refresh": f"{self.baseUrl}/cognito/refresh-token", | ||
"holiday_mode": f"{self.baseUrl}/holiday-mode", | ||
"all": f"{self.baseUrl}/nodes/all?products=true&devices=true&actions=true", | ||
"alarm": f"{self.baseUrl}/security-lite?homeId=", | ||
"all": f"{self.baseUrl}/nodes/all", | ||
"homes": f"{self.baseUrl}/nodes/all", | ||
"alarm": f"{self.baseUrl}/security-lite", | ||
"cameraImages": f"https://event-history-service.{self.cameraBaseUrl}/v1/events/cameras?latest=true&cameraId={{0}}", | ||
"cameraRecordings": f"https://event-history-service.{self.cameraBaseUrl}/v1/playlist/cameras/{{0}}/events/{{1}}.m3u8", | ||
"devices": f"{self.baseUrl}/devices", | ||
|
@@ -44,10 +45,30 @@ def __init__(self, hiveSession=None, websession: Optional[ClientSession] = None) | |
"parsed": "No response to Hive API request", | ||
} | ||
self.session = hiveSession | ||
self.homeID = None | ||
if self.session is not None: | ||
self.homeID = self.session.config.homeID | ||
self.websession = ClientSession() if websession is None else websession | ||
|
||
def getParams(self, products=False, devices=False, actions=False): | ||
"""Get parameters.""" | ||
params = { | ||
"products": 'true' if products else 'false', | ||
"devices": 'true' if devices else 'false', | ||
"actions": 'true' if actions else 'false', | ||
} | ||
if self.homeID: | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You seemed to have catered for it here but not in the sync api |
||
params.update({"homeId": self.homeID}) | ||
return params | ||
|
||
def getHomeIdParam(self): | ||
"""Get homeId parameter if set.""" | ||
if self.homeID is not None: | ||
return {"homeId": self.homeID} | ||
return {} | ||
|
||
async def request( | ||
self, method: str, url: str, camera: bool = False, **kwargs | ||
self, method: str, url: str, camera: bool = False, params={}, **kwargs | ||
) -> ClientResponse: | ||
"""Make a request.""" | ||
data = kwargs.get("data", None) | ||
|
@@ -73,7 +94,7 @@ async def request( | |
raise NoApiToken | ||
|
||
async with self.websession.request( | ||
method, url, headers=headers, data=data | ||
method, url, headers=headers, data=data, params=params | ||
) as resp: | ||
await resp.text() | ||
if operator.contains(str(resp.status), "20"): | ||
|
@@ -142,21 +163,40 @@ async def getAll(self): | |
"""Build and query all endpoint.""" | ||
json_return = {} | ||
url = self.urls["all"] | ||
params = self.getParams( | ||
products=True, devices=True, actions=True | ||
) | ||
try: | ||
resp = await self.request("get", url) | ||
resp = await self.request("get", url, params=params) | ||
json_return.update({"original": resp.status}) | ||
json_return.update({"parsed": await resp.json(content_type=None)}) | ||
except (OSError, RuntimeError, ZeroDivisionError): | ||
await self.error() | ||
|
||
return json_return | ||
|
||
async def getHomes(self): | ||
"""Build and query all endpoint for homes.""" | ||
json_return = {} | ||
url = self.urls["all"] | ||
params = self.getParams() | ||
try: | ||
resp = await self.request("get", url, params=params) | ||
all = await resp.json(content_type=None) | ||
json_return.update({"original": resp.status}) | ||
json_return.update({"parsed": all["homes"]}) | ||
except (OSError, RuntimeError, ZeroDivisionError): | ||
await self.error() | ||
|
||
return json_return | ||
|
||
async def getAlarm(self): | ||
"""Build and query alarm endpoint.""" | ||
json_return = {} | ||
url = self.urls["alarm"] + self.session.config.homeID | ||
url = self.urls["alarm"] | ||
params = self.getHomeIdParam() | ||
try: | ||
resp = await self.request("get", url) | ||
resp = await self.request("get", url, params=params) | ||
json_return.update({"original": resp.status}) | ||
json_return.update({"parsed": await resp.json(content_type=None)}) | ||
except (OSError, RuntimeError, ZeroDivisionError): | ||
|
@@ -197,8 +237,9 @@ async def getDevices(self): | |
"""Call the get devices endpoint.""" | ||
json_return = {} | ||
url = self.urls["devices"] | ||
params = self.getParams(devices=True) | ||
try: | ||
resp = await self.request("get", url) | ||
resp = await self.request("get", url, params=params) | ||
json_return.update({"original": resp.status}) | ||
json_return.update({"parsed": await resp.json(content_type=None)}) | ||
except (OSError, RuntimeError, ZeroDivisionError): | ||
|
@@ -210,8 +251,9 @@ async def getProducts(self): | |
"""Call the get products endpoint.""" | ||
json_return = {} | ||
url = self.urls["products"] | ||
params = self.getParams(products=True) | ||
try: | ||
resp = await self.request("get", url) | ||
resp = await self.request("get", url, params=params) | ||
json_return.update({"original": resp.status}) | ||
json_return.update({"parsed": await resp.json(content_type=None)}) | ||
except (OSError, RuntimeError, ZeroDivisionError): | ||
|
@@ -222,11 +264,13 @@ async def getProducts(self): | |
async def getActions(self): | ||
"""Call the get actions endpoint.""" | ||
json_return = {} | ||
url = self.urls["actions"] | ||
url = self.urls["all"] | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same comment here as the sync one |
||
params = self.getParams(actions=True) | ||
try: | ||
resp = await self.request("get", url) | ||
resp = await self.request("get", url, params=params) | ||
all = await resp.json(content_type=None) | ||
json_return.update({"original": resp.status}) | ||
json_return.update({"parsed": await resp.json(content_type=None)}) | ||
json_return.update({"parsed": all["actions"]}) | ||
except (OSError, RuntimeError, ZeroDivisionError): | ||
await self.error() | ||
|
||
|
@@ -270,6 +314,10 @@ async def getWeather(self, weather_url): | |
|
||
return json_return | ||
|
||
def setHome(self, homeID): | ||
"""Set the home ID.""" | ||
self.homeID = homeID | ||
|
||
async def setState(self, n_type, n_id, **kwargs): | ||
"""Set the state of a Device.""" | ||
json_return = {} | ||
|
@@ -306,10 +354,12 @@ async def setAlarm(self, **kwargs): | |
+ "}" | ||
) | ||
|
||
url = f"{self.urls['alarm']}{self.session.config.homeID}" | ||
url = self.urls["alarm"] | ||
params = self.getHomeIdParam() | ||
|
||
try: | ||
await self.isFileBeingUsed() | ||
resp = await self.request("post", url, data=jsc) | ||
resp = await self.request("post", url, data=jsc, params=params) | ||
json_return["original"] = resp.status | ||
json_return["parsed"] = await resp.json(content_type=None) | ||
except (FileInUse, OSError, RuntimeError, ConnectionError) as e: | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I did some testing of the the sync code and the api didn't seem to work with the params when they where booleans. When I changed them to be lower case f and in quotes the api then worked as expected.
The other option would be to the leave the params as booleans and update the dictionary to be as per below converting them to string and lowercasing them.