Update pypoint to use async http requests (#41546)
* Remove domain after entities * Add support for async http-requests * Fix, handle network issues (update _is_available status) * Fix missing await for alarm_arm * Fix alarm status * Update tests to async * Bump pypoint version * Fix doc string * Apply suggestions from code review, remove pylint disable * Fix black
This commit is contained in:
parent
32204821c1
commit
8bdc824b6c
8 changed files with 49 additions and 46 deletions
|
@ -75,22 +75,22 @@ async def async_setup(hass, config):
|
|||
async def async_setup_entry(hass: HomeAssistantType, entry: ConfigEntry):
|
||||
"""Set up Point from a config entry."""
|
||||
|
||||
def token_saver(token):
|
||||
_LOGGER.debug("Saving updated token")
|
||||
async def token_saver(token, **kwargs):
|
||||
_LOGGER.debug("Saving updated token %s", token)
|
||||
hass.config_entries.async_update_entry(
|
||||
entry, data={**entry.data, CONF_TOKEN: token}
|
||||
)
|
||||
|
||||
# Force token update.
|
||||
entry.data[CONF_TOKEN]["expires_in"] = -1
|
||||
session = PointSession(
|
||||
hass.helpers.aiohttp_client.async_get_clientsession(),
|
||||
entry.data["refresh_args"][CONF_CLIENT_ID],
|
||||
entry.data["refresh_args"][CONF_CLIENT_SECRET],
|
||||
token=entry.data[CONF_TOKEN],
|
||||
auto_refresh_kwargs=entry.data["refresh_args"],
|
||||
token_saver=token_saver,
|
||||
)
|
||||
|
||||
if not session.is_authorized:
|
||||
try:
|
||||
await session.ensure_active_token()
|
||||
except Exception: # pylint: disable=broad-except
|
||||
_LOGGER.error("Authentication Error")
|
||||
return False
|
||||
|
||||
|
@ -120,8 +120,7 @@ async def async_setup_webhook(hass: HomeAssistantType, entry: ConfigEntry, sessi
|
|||
CONF_WEBHOOK_URL: webhook_url,
|
||||
},
|
||||
)
|
||||
await hass.async_add_executor_job(
|
||||
session.update_webhook,
|
||||
await session.update_webhook(
|
||||
entry.data[CONF_WEBHOOK_URL],
|
||||
entry.data[CONF_WEBHOOK_ID],
|
||||
["*"],
|
||||
|
@ -136,14 +135,14 @@ async def async_unload_entry(hass: HomeAssistantType, entry: ConfigEntry):
|
|||
"""Unload a config entry."""
|
||||
hass.components.webhook.async_unregister(entry.data[CONF_WEBHOOK_ID])
|
||||
session = hass.data[DOMAIN].pop(entry.entry_id)
|
||||
await hass.async_add_executor_job(session.remove_webhook)
|
||||
|
||||
if not hass.data[DOMAIN]:
|
||||
hass.data.pop(DOMAIN)
|
||||
await session.remove_webhook()
|
||||
|
||||
for component in ("binary_sensor", "sensor"):
|
||||
await hass.config_entries.async_forward_entry_unload(entry, component)
|
||||
|
||||
if not hass.data[DOMAIN]:
|
||||
hass.data.pop(DOMAIN)
|
||||
|
||||
return True
|
||||
|
||||
|
||||
|
@ -181,12 +180,10 @@ class MinutPointClient:
|
|||
|
||||
async def _sync(self):
|
||||
"""Update local list of devices."""
|
||||
if (
|
||||
not await self._hass.async_add_executor_job(self._client.update)
|
||||
and self._is_available
|
||||
):
|
||||
if not await self._client.update() and self._is_available:
|
||||
self._is_available = False
|
||||
_LOGGER.warning("Device is unavailable")
|
||||
async_dispatcher_send(self._hass, SIGNAL_UPDATE_ENTITY)
|
||||
return
|
||||
|
||||
async def new_device(device_id, component):
|
||||
|
@ -221,24 +218,26 @@ class MinutPointClient:
|
|||
|
||||
def is_available(self, device_id):
|
||||
"""Return device availability."""
|
||||
if not self._is_available:
|
||||
return False
|
||||
return device_id in self._client.device_ids
|
||||
|
||||
def remove_webhook(self):
|
||||
async def remove_webhook(self):
|
||||
"""Remove the session webhook."""
|
||||
return self._client.remove_webhook()
|
||||
return await self._client.remove_webhook()
|
||||
|
||||
@property
|
||||
def homes(self):
|
||||
"""Return known homes."""
|
||||
return self._client.homes
|
||||
|
||||
def alarm_disarm(self, home_id):
|
||||
async def async_alarm_disarm(self, home_id):
|
||||
"""Send alarm disarm command."""
|
||||
return self._client.alarm_disarm(home_id)
|
||||
return await self._client.alarm_disarm(home_id)
|
||||
|
||||
def alarm_arm(self, home_id):
|
||||
async def async_alarm_arm(self, home_id):
|
||||
"""Send alarm arm command."""
|
||||
return self._client.alarm_arm(home_id)
|
||||
return await self._client.alarm_arm(home_id)
|
||||
|
||||
|
||||
class MinutPointEntity(Entity):
|
||||
|
|
|
@ -99,15 +99,15 @@ class MinutPointAlarmControl(AlarmControlPanelEntity):
|
|||
"""Return the user the last change was triggered by."""
|
||||
return self._changed_by
|
||||
|
||||
def alarm_disarm(self, code=None):
|
||||
async def async_alarm_disarm(self, code=None):
|
||||
"""Send disarm command."""
|
||||
status = self._client.alarm_disarm(self._home_id)
|
||||
status = await self._client.async_alarm_disarm(self._home_id)
|
||||
if status:
|
||||
self._home["alarm_status"] = "off"
|
||||
|
||||
def alarm_arm_away(self, code=None):
|
||||
async def async_alarm_arm_away(self, code=None):
|
||||
"""Send arm away command."""
|
||||
status = self._client.alarm_arm(self._home_id)
|
||||
status = await self._client.async_alarm_arm(self._home_id)
|
||||
if status:
|
||||
self._home["alarm_status"] = "on"
|
||||
|
||||
|
|
|
@ -102,7 +102,6 @@ class PointFlowHandler(config_entries.ConfigFlow):
|
|||
except Exception: # pylint: disable=broad-except
|
||||
_LOGGER.exception("Unexpected error generating auth url")
|
||||
return self.async_abort(reason="authorize_url_fail")
|
||||
|
||||
return self.async_show_form(
|
||||
step_id="auth",
|
||||
description_placeholders={"authorization_url": url},
|
||||
|
@ -111,11 +110,14 @@ class PointFlowHandler(config_entries.ConfigFlow):
|
|||
|
||||
async def _get_authorization_url(self):
|
||||
"""Create Minut Point session and get authorization url."""
|
||||
|
||||
flow = self.hass.data[DATA_FLOW_IMPL][self.flow_impl]
|
||||
client_id = flow[CONF_CLIENT_ID]
|
||||
client_secret = flow[CONF_CLIENT_SECRET]
|
||||
point_session = PointSession(client_id, client_secret=client_secret)
|
||||
point_session = PointSession(
|
||||
self.hass.helpers.aiohttp_client.async_get_clientsession(),
|
||||
client_id,
|
||||
client_secret,
|
||||
)
|
||||
|
||||
self.hass.http.register_view(MinutAuthCallbackView())
|
||||
|
||||
|
@ -143,17 +145,19 @@ class PointFlowHandler(config_entries.ConfigFlow):
|
|||
flow = self.hass.data[DATA_FLOW_IMPL][DOMAIN]
|
||||
client_id = flow[CONF_CLIENT_ID]
|
||||
client_secret = flow[CONF_CLIENT_SECRET]
|
||||
point_session = PointSession(client_id, client_secret=client_secret)
|
||||
token = await self.hass.async_add_executor_job(
|
||||
point_session.get_access_token, code
|
||||
point_session = PointSession(
|
||||
self.hass.helpers.aiohttp_client.async_get_clientsession(),
|
||||
client_id,
|
||||
client_secret,
|
||||
)
|
||||
token = await point_session.get_access_token(code)
|
||||
_LOGGER.debug("Got new token")
|
||||
if not point_session.is_authorized:
|
||||
_LOGGER.error("Authentication Error")
|
||||
return self.async_abort(reason="auth_error")
|
||||
|
||||
_LOGGER.info("Successfully authenticated Point")
|
||||
user_email = point_session.user().get("email") or ""
|
||||
user_email = (await point_session.user()).get("email") or ""
|
||||
|
||||
return self.async_create_entry(
|
||||
title=user_email,
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
"name": "Minut Point",
|
||||
"config_flow": true,
|
||||
"documentation": "https://www.home-assistant.io/integrations/point",
|
||||
"requirements": ["pypoint==1.1.2"],
|
||||
"requirements": ["pypoint==2.0.0"],
|
||||
"dependencies": ["webhook", "http"],
|
||||
"codeowners": ["@fredrike"],
|
||||
"quality_scale": "gold"
|
||||
|
|
|
@ -57,13 +57,11 @@ class MinutPointSensor(MinutPointEntity):
|
|||
|
||||
async def _update_callback(self):
|
||||
"""Update the value of the sensor."""
|
||||
_LOGGER.debug("Update sensor value for %s", self)
|
||||
if self.is_updated:
|
||||
_LOGGER.debug("Update sensor value for %s", self)
|
||||
self._value = await self.hass.async_add_executor_job(
|
||||
self.device.sensor, self.device_class
|
||||
)
|
||||
self._value = await self.device.sensor(self.device_class)
|
||||
self._updated = parse_datetime(self.device.last_update)
|
||||
self.async_write_ha_state()
|
||||
self.async_write_ha_state()
|
||||
|
||||
@property
|
||||
def icon(self):
|
||||
|
|
|
@ -1600,7 +1600,7 @@ pypck==0.7.2
|
|||
pypjlink2==1.2.1
|
||||
|
||||
# homeassistant.components.point
|
||||
pypoint==1.1.2
|
||||
pypoint==2.0.0
|
||||
|
||||
# homeassistant.components.profiler
|
||||
pyprof2calltree==1.4.5
|
||||
|
|
|
@ -783,7 +783,7 @@ pyowm==2.10.0
|
|||
pyownet==0.10.0.post1
|
||||
|
||||
# homeassistant.components.point
|
||||
pypoint==1.1.2
|
||||
pypoint==2.0.0
|
||||
|
||||
# homeassistant.components.profiler
|
||||
pyprof2calltree==1.4.5
|
||||
|
|
|
@ -33,11 +33,13 @@ def mock_pypoint(is_authorized): # pylint: disable=redefined-outer-name
|
|||
with patch(
|
||||
"homeassistant.components.point.config_flow.PointSession"
|
||||
) as PointSession:
|
||||
PointSession.return_value.get_access_token.return_value = {
|
||||
"access_token": "boo"
|
||||
}
|
||||
PointSession.return_value.get_access_token = AsyncMock(
|
||||
return_value={"access_token": "boo"}
|
||||
)
|
||||
PointSession.return_value.is_authorized = is_authorized
|
||||
PointSession.return_value.user.return_value = {"email": "john.doe@example.com"}
|
||||
PointSession.return_value.user = AsyncMock(
|
||||
return_value={"email": "john.doe@example.com"}
|
||||
)
|
||||
yield PointSession
|
||||
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue