Catch Shelly set state exceptions when device is inaccessible (#50064)

This commit is contained in:
Shay Levy 2021-05-04 19:10:28 +03:00 committed by GitHub
parent 786c5db5be
commit c21add195a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 57 additions and 12 deletions

View File

@ -83,24 +83,24 @@ class ShellyCover(ShellyBlockEntity, CoverEntity):
async def async_close_cover(self, **kwargs): async def async_close_cover(self, **kwargs):
"""Close cover.""" """Close cover."""
self.control_result = await self.block.set_state(go="close") self.control_result = await self.set_state(go="close")
self.async_write_ha_state() self.async_write_ha_state()
async def async_open_cover(self, **kwargs): async def async_open_cover(self, **kwargs):
"""Open cover.""" """Open cover."""
self.control_result = await self.block.set_state(go="open") self.control_result = await self.set_state(go="open")
self.async_write_ha_state() self.async_write_ha_state()
async def async_set_cover_position(self, **kwargs): async def async_set_cover_position(self, **kwargs):
"""Move the cover to a specific position.""" """Move the cover to a specific position."""
self.control_result = await self.block.set_state( self.control_result = await self.set_state(
go="to_pos", roller_pos=kwargs[ATTR_POSITION] go="to_pos", roller_pos=kwargs[ATTR_POSITION]
) )
self.async_write_ha_state() self.async_write_ha_state()
async def async_stop_cover(self, **_kwargs): async def async_stop_cover(self, **_kwargs):
"""Stop the cover.""" """Stop the cover."""
self.control_result = await self.block.set_state(go="stop") self.control_result = await self.set_state(go="stop")
self.async_write_ha_state() self.async_write_ha_state()
@callback @callback

View File

@ -1,11 +1,13 @@
"""Shelly entity helper.""" """Shelly entity helper."""
from __future__ import annotations from __future__ import annotations
import asyncio
from dataclasses import dataclass from dataclasses import dataclass
import logging import logging
from typing import Any, Callable from typing import Any, Callable
import aioshelly import aioshelly
import async_timeout
from homeassistant.core import callback from homeassistant.core import callback
from homeassistant.helpers import ( from homeassistant.helpers import (
@ -17,7 +19,7 @@ from homeassistant.helpers import (
from homeassistant.helpers.restore_state import RestoreEntity from homeassistant.helpers.restore_state import RestoreEntity
from . import ShellyDeviceRestWrapper, ShellyDeviceWrapper from . import ShellyDeviceRestWrapper, ShellyDeviceWrapper
from .const import COAP, DATA_CONFIG_ENTRY, DOMAIN, REST from .const import AIOSHELLY_DEVICE_TIMEOUT_SEC, COAP, DATA_CONFIG_ENTRY, DOMAIN, REST
from .utils import async_remove_shelly_entity, get_entity_name from .utils import async_remove_shelly_entity, get_entity_name
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
@ -218,6 +220,22 @@ class ShellyBlockEntity(entity.Entity):
"""Handle device update.""" """Handle device update."""
self.async_write_ha_state() self.async_write_ha_state()
async def set_state(self, **kwargs):
"""Set block state (HTTP request)."""
_LOGGER.debug("Setting state for entity %s, state: %s", self.name, kwargs)
try:
async with async_timeout.timeout(AIOSHELLY_DEVICE_TIMEOUT_SEC):
return await self.block.set_state(**kwargs)
except (asyncio.TimeoutError, OSError) as err:
_LOGGER.error(
"Setting state for entity %s failed, state: %s, error: %s",
self.name,
kwargs,
repr(err),
)
self.wrapper.last_update_success = False
return None
class ShellyBlockAttributeEntity(ShellyBlockEntity, entity.Entity): class ShellyBlockAttributeEntity(ShellyBlockEntity, entity.Entity):
"""Helper class to represent a block attribute.""" """Helper class to represent a block attribute."""

View File

@ -1,7 +1,11 @@
"""Light for Shelly.""" """Light for Shelly."""
from __future__ import annotations from __future__ import annotations
import asyncio
import logging
from aioshelly import Block from aioshelly import Block
import async_timeout
from homeassistant.components.light import ( from homeassistant.components.light import (
ATTR_BRIGHTNESS, ATTR_BRIGHTNESS,
@ -24,6 +28,7 @@ from homeassistant.util.color import (
from . import ShellyDeviceWrapper from . import ShellyDeviceWrapper
from .const import ( from .const import (
AIOSHELLY_DEVICE_TIMEOUT_SEC,
COAP, COAP,
DATA_CONFIG_ENTRY, DATA_CONFIG_ENTRY,
DOMAIN, DOMAIN,
@ -34,6 +39,8 @@ from .const import (
from .entity import ShellyBlockEntity from .entity import ShellyBlockEntity
from .utils import async_remove_shelly_entity from .utils import async_remove_shelly_entity
_LOGGER = logging.getLogger(__name__)
async def async_setup_entry(hass, config_entry, async_add_entities): async def async_setup_entry(hass, config_entry, async_add_entities):
"""Set up lights for device.""" """Set up lights for device."""
@ -199,7 +206,7 @@ class ShellyLight(ShellyBlockEntity, LightEntity):
async def async_turn_on(self, **kwargs) -> None: async def async_turn_on(self, **kwargs) -> None:
"""Turn on light.""" """Turn on light."""
if self.block.type == "relay": if self.block.type == "relay":
self.control_result = await self.block.set_state(turn="on") self.control_result = await self.set_state(turn="on")
self.async_write_ha_state() self.async_write_ha_state()
return return
@ -233,17 +240,37 @@ class ShellyLight(ShellyBlockEntity, LightEntity):
ATTR_RGBW_COLOR ATTR_RGBW_COLOR
] ]
if set_mode and self.mode != set_mode: if await self.set_light_mode(set_mode):
self.mode_result = await self.wrapper.device.switch_light_mode(set_mode) self.control_result = await self.set_state(**params)
self.control_result = await self.block.set_state(**params)
self.async_write_ha_state() self.async_write_ha_state()
async def async_turn_off(self, **kwargs) -> None: async def async_turn_off(self, **kwargs) -> None:
"""Turn off light.""" """Turn off light."""
self.control_result = await self.block.set_state(turn="off") self.control_result = await self.set_state(turn="off")
self.async_write_ha_state() self.async_write_ha_state()
async def set_light_mode(self, set_mode):
"""Change device mode color/white if mode has changed."""
if set_mode is None or self.mode == set_mode:
return True
_LOGGER.debug("Setting light mode for entity %s, mode: %s", self.name, set_mode)
try:
async with async_timeout.timeout(AIOSHELLY_DEVICE_TIMEOUT_SEC):
self.mode_result = await self.wrapper.device.switch_light_mode(set_mode)
except (asyncio.TimeoutError, OSError) as err:
_LOGGER.error(
"Setting light mode for entity %s failed, state: %s, error: %s",
self.name,
set_mode,
repr(err),
)
self.wrapper.last_update_success = False
return False
return True
@callback @callback
def _update_callback(self): def _update_callback(self):
"""When device updates, clear control & mode result that overrides state.""" """When device updates, clear control & mode result that overrides state."""

View File

@ -62,12 +62,12 @@ class RelaySwitch(ShellyBlockEntity, SwitchEntity):
async def async_turn_on(self, **kwargs): async def async_turn_on(self, **kwargs):
"""Turn on relay.""" """Turn on relay."""
self.control_result = await self.block.set_state(turn="on") self.control_result = await self.set_state(turn="on")
self.async_write_ha_state() self.async_write_ha_state()
async def async_turn_off(self, **kwargs): async def async_turn_off(self, **kwargs):
"""Turn off relay.""" """Turn off relay."""
self.control_result = await self.block.set_state(turn="off") self.control_result = await self.set_state(turn="off")
self.async_write_ha_state() self.async_write_ha_state()
@callback @callback