Add reconnect logic and proper reporting to MotionMount integration (#125670)
* Add reconnect logic and proper reporting * Use snake_case * Log on warning, not on info * Reduce line length * Refactor non-raising code out of try blocks * Remove `_ensure_connected()` from action functions
This commit is contained in:
parent
18e2c2f6dd
commit
e6b86b662a
3 changed files with 59 additions and 9 deletions
|
@ -1,5 +1,7 @@
|
|||
"""Support for MotionMount sensors."""
|
||||
|
||||
import logging
|
||||
import socket
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
import motionmount
|
||||
|
@ -12,6 +14,8 @@ from homeassistant.helpers.entity import Entity
|
|||
|
||||
from .const import DOMAIN, EMPTY_MAC
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class MotionMountEntity(Entity):
|
||||
"""Representation of a MotionMount entity."""
|
||||
|
@ -70,3 +74,23 @@ class MotionMountEntity(Entity):
|
|||
self.mm.remove_listener(self.async_write_ha_state)
|
||||
self.mm.remove_listener(self.update_name)
|
||||
await super().async_will_remove_from_hass()
|
||||
|
||||
async def _ensure_connected(self) -> bool:
|
||||
"""Make sure there is a connection with the MotionMount.
|
||||
|
||||
Returns false if the connection failed to be ensured.
|
||||
"""
|
||||
|
||||
if self.mm.is_connected:
|
||||
return True
|
||||
try:
|
||||
await self.mm.connect()
|
||||
except (ConnectionError, TimeoutError, socket.gaierror):
|
||||
# We're not interested in exceptions here. In case of a failed connection
|
||||
# the try/except from the caller will report it.
|
||||
# The purpose of `_ensure_connected()` is only to make sure we try to
|
||||
# reconnect, where failures should not be logged each time
|
||||
return False
|
||||
else:
|
||||
_LOGGER.warning("Successfully reconnected to MotionMount")
|
||||
return True
|
||||
|
|
|
@ -1,11 +1,14 @@
|
|||
"""Support for MotionMount numeric control."""
|
||||
|
||||
import socket
|
||||
|
||||
import motionmount
|
||||
|
||||
from homeassistant.components.number import NumberEntity
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.const import PERCENTAGE
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.exceptions import HomeAssistantError
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
|
||||
from .const import DOMAIN
|
||||
|
@ -46,7 +49,10 @@ class MotionMountExtension(MotionMountEntity, NumberEntity):
|
|||
|
||||
async def async_set_native_value(self, value: float) -> None:
|
||||
"""Set the new value for extension."""
|
||||
try:
|
||||
await self.mm.set_extension(int(value))
|
||||
except (TimeoutError, socket.gaierror) as ex:
|
||||
raise HomeAssistantError("Failed to communicate with MotionMount") from ex
|
||||
|
||||
|
||||
class MotionMountTurn(MotionMountEntity, NumberEntity):
|
||||
|
@ -69,4 +75,7 @@ class MotionMountTurn(MotionMountEntity, NumberEntity):
|
|||
|
||||
async def async_set_native_value(self, value: float) -> None:
|
||||
"""Set the new value for turn."""
|
||||
try:
|
||||
await self.mm.set_turn(int(value * -1))
|
||||
except (TimeoutError, socket.gaierror) as ex:
|
||||
raise HomeAssistantError("Failed to communicate with MotionMount") from ex
|
||||
|
|
|
@ -1,15 +1,23 @@
|
|||
"""Support for MotionMount numeric control."""
|
||||
|
||||
from datetime import timedelta
|
||||
import logging
|
||||
import socket
|
||||
|
||||
import motionmount
|
||||
|
||||
from homeassistant.components.select import SelectEntity
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.exceptions import HomeAssistantError
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
|
||||
from .const import DOMAIN, WALL_PRESET_NAME
|
||||
from .entity import MotionMountEntity
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
SCAN_INTERVAL = timedelta(seconds=60)
|
||||
|
||||
|
||||
async def async_setup_entry(
|
||||
hass: HomeAssistant, entry: ConfigEntry, async_add_entities: AddEntitiesCallback
|
||||
|
@ -23,6 +31,7 @@ async def async_setup_entry(
|
|||
class MotionMountPresets(MotionMountEntity, SelectEntity):
|
||||
"""The presets of a MotionMount."""
|
||||
|
||||
_attr_should_poll = True
|
||||
_attr_translation_key = "motionmount_preset"
|
||||
|
||||
def __init__(
|
||||
|
@ -44,7 +53,14 @@ class MotionMountPresets(MotionMountEntity, SelectEntity):
|
|||
|
||||
async def async_update(self) -> None:
|
||||
"""Get latest state from MotionMount."""
|
||||
if not await self._ensure_connected():
|
||||
return
|
||||
|
||||
try:
|
||||
self._presets = await self.mm.get_presets()
|
||||
except (TimeoutError, socket.gaierror) as ex:
|
||||
_LOGGER.warning("Failed to communicate with MotionMount: %s", ex)
|
||||
else:
|
||||
self._update_options(self._presets)
|
||||
|
||||
@property
|
||||
|
@ -72,8 +88,9 @@ class MotionMountPresets(MotionMountEntity, SelectEntity):
|
|||
async def async_select_option(self, option: str) -> None:
|
||||
"""Set the new option."""
|
||||
index = int(option[:1])
|
||||
try:
|
||||
await self.mm.go_to_preset(index)
|
||||
except (TimeoutError, socket.gaierror) as ex:
|
||||
raise HomeAssistantError("Failed to communicate with MotionMount") from ex
|
||||
else:
|
||||
self._attr_current_option = option
|
||||
|
||||
# Perform an update so we detect changes to the presets (changes are not pushed)
|
||||
self.async_schedule_update_ha_state(True)
|
||||
|
|
Loading…
Add table
Reference in a new issue