Clean up mobile app (#48607)

Co-authored-by: Martin Hjelmare <marhje52@gmail.com>
This commit is contained in:
Paulus Schoutsen 2021-04-01 16:22:08 -07:00 committed by GitHub
parent 34ddea536e
commit 051531d9c1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 51 additions and 27 deletions

View File

@ -1,6 +1,4 @@
"""Binary sensor platform for mobile_app.""" """Binary sensor platform for mobile_app."""
from functools import partial
from homeassistant.components.binary_sensor import BinarySensorEntity from homeassistant.components.binary_sensor import BinarySensorEntity
from homeassistant.const import CONF_NAME, CONF_UNIQUE_ID, CONF_WEBHOOK_ID, STATE_ON from homeassistant.const import CONF_NAME, CONF_UNIQUE_ID, CONF_WEBHOOK_ID, STATE_ON
from homeassistant.core import callback from homeassistant.core import callback
@ -48,7 +46,7 @@ async def async_setup_entry(hass, config_entry, async_add_entities):
async_add_entities(entities) async_add_entities(entities)
@callback @callback
def handle_sensor_registration(webhook_id, data): def handle_sensor_registration(data):
if data[CONF_WEBHOOK_ID] != webhook_id: if data[CONF_WEBHOOK_ID] != webhook_id:
return return
@ -66,7 +64,7 @@ async def async_setup_entry(hass, config_entry, async_add_entities):
async_dispatcher_connect( async_dispatcher_connect(
hass, hass,
f"{DOMAIN}_{ENTITY_TYPE}_register", f"{DOMAIN}_{ENTITY_TYPE}_register",
partial(handle_sensor_registration, webhook_id), handle_sensor_registration,
) )

View File

@ -34,13 +34,14 @@ class MobileAppEntity(RestoreEntity):
self._registration = entry.data self._registration = entry.data
self._unique_id = config[CONF_UNIQUE_ID] self._unique_id = config[CONF_UNIQUE_ID]
self._entity_type = config[ATTR_SENSOR_TYPE] self._entity_type = config[ATTR_SENSOR_TYPE]
self.unsub_dispatcher = None
self._name = config[CONF_NAME] self._name = config[CONF_NAME]
async def async_added_to_hass(self): async def async_added_to_hass(self):
"""Register callbacks.""" """Register callbacks."""
self.unsub_dispatcher = async_dispatcher_connect( self.async_on_remove(
self.hass, SIGNAL_SENSOR_UPDATE, self._handle_update async_dispatcher_connect(
self.hass, SIGNAL_SENSOR_UPDATE, self._handle_update
)
) )
state = await self.async_get_last_state() state = await self.async_get_last_state()
@ -49,11 +50,6 @@ class MobileAppEntity(RestoreEntity):
self.async_restore_last_state(state) self.async_restore_last_state(state)
async def async_will_remove_from_hass(self):
"""Disconnect dispatcher listener when removed."""
if self.unsub_dispatcher is not None:
self.unsub_dispatcher()
@callback @callback
def async_restore_last_state(self, last_state): def async_restore_last_state(self, last_state):
"""Restore previous state.""" """Restore previous state."""

View File

@ -84,17 +84,16 @@ def log_rate_limits(hass, device_name, resp, level=logging.INFO):
async def async_get_service(hass, config, discovery_info=None): async def async_get_service(hass, config, discovery_info=None):
"""Get the mobile_app notification service.""" """Get the mobile_app notification service."""
session = async_get_clientsession(hass) service = hass.data[DOMAIN][DATA_NOTIFY] = MobileAppNotificationService(hass)
service = hass.data[DOMAIN][DATA_NOTIFY] = MobileAppNotificationService(session)
return service return service
class MobileAppNotificationService(BaseNotificationService): class MobileAppNotificationService(BaseNotificationService):
"""Implement the notification service for mobile_app.""" """Implement the notification service for mobile_app."""
def __init__(self, session): def __init__(self, hass):
"""Initialize the service.""" """Initialize the service."""
self._session = session self._hass = hass
@property @property
def targets(self): def targets(self):
@ -141,7 +140,9 @@ class MobileAppNotificationService(BaseNotificationService):
try: try:
with async_timeout.timeout(10): with async_timeout.timeout(10):
response = await self._session.post(push_url, json=data) response = await async_get_clientsession(self._hass).post(
push_url, json=data
)
result = await response.json() result = await response.json()
if response.status in [HTTP_OK, HTTP_CREATED, HTTP_ACCEPTED]: if response.status in [HTTP_OK, HTTP_CREATED, HTTP_ACCEPTED]:

View File

@ -1,6 +1,4 @@
"""Sensor platform for mobile_app.""" """Sensor platform for mobile_app."""
from functools import partial
from homeassistant.components.sensor import SensorEntity from homeassistant.components.sensor import SensorEntity
from homeassistant.const import CONF_NAME, CONF_UNIQUE_ID, CONF_WEBHOOK_ID from homeassistant.const import CONF_NAME, CONF_UNIQUE_ID, CONF_WEBHOOK_ID
from homeassistant.core import callback from homeassistant.core import callback
@ -50,7 +48,7 @@ async def async_setup_entry(hass, config_entry, async_add_entities):
async_add_entities(entities) async_add_entities(entities)
@callback @callback
def handle_sensor_registration(webhook_id, data): def handle_sensor_registration(data):
if data[CONF_WEBHOOK_ID] != webhook_id: if data[CONF_WEBHOOK_ID] != webhook_id:
return return
@ -68,7 +66,7 @@ async def async_setup_entry(hass, config_entry, async_add_entities):
async_dispatcher_connect( async_dispatcher_connect(
hass, hass,
f"{DOMAIN}_{ENTITY_TYPE}_register", f"{DOMAIN}_{ENTITY_TYPE}_register",
partial(handle_sensor_registration, webhook_id), handle_sensor_registration,
) )

View File

@ -472,6 +472,7 @@ async def webhook_update_sensor_states(hass, config_entry, data):
device_name = config_entry.data[ATTR_DEVICE_NAME] device_name = config_entry.data[ATTR_DEVICE_NAME]
resp = {} resp = {}
for sensor in data: for sensor in data:
entity_type = sensor[ATTR_SENSOR_TYPE] entity_type = sensor[ATTR_SENSOR_TYPE]
@ -495,8 +496,6 @@ async def webhook_update_sensor_states(hass, config_entry, data):
} }
continue continue
entry = {CONF_WEBHOOK_ID: config_entry.data[CONF_WEBHOOK_ID]}
try: try:
sensor = sensor_schema_full(sensor) sensor = sensor_schema_full(sensor)
except vol.Invalid as err: except vol.Invalid as err:
@ -513,9 +512,8 @@ async def webhook_update_sensor_states(hass, config_entry, data):
} }
continue continue
new_state = {**entry, **sensor} sensor[CONF_WEBHOOK_ID] = config_entry.data[CONF_WEBHOOK_ID]
async_dispatcher_send(hass, SIGNAL_SENSOR_UPDATE, sensor)
async_dispatcher_send(hass, SIGNAL_SENSOR_UPDATE, new_state)
resp[unique_id] = {"success": True} resp[unique_id] = {"success": True}

View File

@ -11,7 +11,7 @@ import traceback
from typing import Any, Awaitable, Callable, Coroutine, cast, overload from typing import Any, Awaitable, Callable, Coroutine, cast, overload
from homeassistant.const import EVENT_HOMEASSISTANT_CLOSE from homeassistant.const import EVENT_HOMEASSISTANT_CLOSE
from homeassistant.core import HomeAssistant, callback from homeassistant.core import HomeAssistant, callback, is_callback
class HideSensitiveDataFilter(logging.Filter): class HideSensitiveDataFilter(logging.Filter):
@ -138,6 +138,7 @@ def catch_log_exception(
log_exception(format_err, *args) log_exception(format_err, *args)
wrapper_func = async_wrapper wrapper_func = async_wrapper
else: else:
@wraps(func) @wraps(func)
@ -148,6 +149,9 @@ def catch_log_exception(
except Exception: # pylint: disable=broad-except except Exception: # pylint: disable=broad-except
log_exception(format_err, *args) log_exception(format_err, *args)
if is_callback(check_func):
wrapper = callback(wrapper)
wrapper_func = wrapper wrapper_func = wrapper
return wrapper_func return wrapper_func

View File

@ -1,11 +1,13 @@
"""Test Home Assistant logging util methods.""" """Test Home Assistant logging util methods."""
import asyncio import asyncio
from functools import partial
import logging import logging
import queue import queue
from unittest.mock import patch from unittest.mock import patch
import pytest import pytest
from homeassistant.core import callback, is_callback
import homeassistant.util.logging as logging_util import homeassistant.util.logging as logging_util
@ -80,3 +82,30 @@ async def test_async_create_catching_coro(hass, caplog):
await hass.async_block_till_done() await hass.async_block_till_done()
assert "This is a bad coroutine" in caplog.text assert "This is a bad coroutine" in caplog.text
assert "in test_async_create_catching_coro" in caplog.text assert "in test_async_create_catching_coro" in caplog.text
def test_catch_log_exception():
"""Test it is still a callback after wrapping including partial."""
async def async_meth():
pass
assert asyncio.iscoroutinefunction(
logging_util.catch_log_exception(partial(async_meth), lambda: None)
)
@callback
def callback_meth():
pass
assert is_callback(
logging_util.catch_log_exception(partial(callback_meth), lambda: None)
)
def sync_meth():
pass
wrapped = logging_util.catch_log_exception(partial(sync_meth), lambda: None)
assert not is_callback(wrapped)
assert not asyncio.iscoroutinefunction(wrapped)