Bump pyswitchbee to 1.5.3 (#78583)

* Add switchbee to strict-typing

* strict typing

* Bumped pyswitchbee

* bumped library to 1.5.1

* strict-typed the package

* fixed issue

* addressed epenet comments

* fixed requirements_all

* once more
This commit is contained in:
Jafar Atili 2022-09-28 14:51:52 +03:00 committed by GitHub
parent 5438552d4a
commit 653e0917bb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 76 additions and 29 deletions

View File

@ -241,6 +241,7 @@ homeassistant.components.stream.*
homeassistant.components.sun.* homeassistant.components.sun.*
homeassistant.components.surepetcare.* homeassistant.components.surepetcare.*
homeassistant.components.switch.* homeassistant.components.switch.*
homeassistant.components.switchbee.*
homeassistant.components.switcher_kis.* homeassistant.components.switcher_kis.*
homeassistant.components.synology_dsm.* homeassistant.components.synology_dsm.*
homeassistant.components.systemmonitor.* homeassistant.components.systemmonitor.*

View File

@ -29,7 +29,7 @@ STEP_USER_DATA_SCHEMA = vol.Schema(
) )
async def validate_input(hass: HomeAssistant, data: dict[str, Any]): async def validate_input(hass: HomeAssistant, data: dict[str, Any]) -> str:
"""Validate the user input allows us to connect.""" """Validate the user input allows us to connect."""
websession = async_get_clientsession(hass, verify_ssl=False) websession = async_get_clientsession(hass, verify_ssl=False)
@ -45,6 +45,7 @@ async def validate_input(hass: HomeAssistant, data: dict[str, Any]):
raise CannotConnect from exp raise CannotConnect from exp
assert api.mac is not None
return format_mac(api.mac) return format_mac(api.mac)
@ -53,7 +54,9 @@ class ConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
VERSION = 1 VERSION = 1
async def async_step_user(self, user_input=None) -> FlowResult: async def async_step_user(
self, user_input: dict[str, Any] | None = None
) -> FlowResult:
"""Show the setup form to the user.""" """Show the setup form to the user."""
errors: dict[str, str] = {} errors: dict[str, str] = {}

View File

@ -1,5 +1,8 @@
"""SwitchBee integration Coordinator.""" """SwitchBee integration Coordinator."""
from __future__ import annotations
from collections.abc import Mapping
from datetime import timedelta from datetime import timedelta
import logging import logging
@ -15,7 +18,7 @@ from .const import DOMAIN, SCAN_INTERVAL_SEC
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
class SwitchBeeCoordinator(DataUpdateCoordinator[dict[int, SwitchBeeBaseDevice]]): class SwitchBeeCoordinator(DataUpdateCoordinator[Mapping[int, SwitchBeeBaseDevice]]):
"""Class to manage fetching Freedompro data API.""" """Class to manage fetching Freedompro data API."""
def __init__( def __init__(
@ -26,7 +29,11 @@ class SwitchBeeCoordinator(DataUpdateCoordinator[dict[int, SwitchBeeBaseDevice]]
"""Initialize.""" """Initialize."""
self.api: CentralUnitAPI = swb_api self.api: CentralUnitAPI = swb_api
self._reconnect_counts: int = 0 self._reconnect_counts: int = 0
self.mac_formated: str = format_mac(swb_api.mac)
self.mac_formated: str | None = (
None if self.api.mac is None else format_mac(self.api.mac)
)
super().__init__( super().__init__(
hass, hass,
_LOGGER, _LOGGER,
@ -34,7 +41,7 @@ class SwitchBeeCoordinator(DataUpdateCoordinator[dict[int, SwitchBeeBaseDevice]]
update_interval=timedelta(seconds=SCAN_INTERVAL_SEC), update_interval=timedelta(seconds=SCAN_INTERVAL_SEC),
) )
async def _async_update_data(self) -> dict[int, SwitchBeeBaseDevice]: async def _async_update_data(self) -> Mapping[int, SwitchBeeBaseDevice]:
"""Update data via library.""" """Update data via library."""
if self._reconnect_counts != self.api.reconnect_count: if self._reconnect_counts != self.api.reconnect_count:

View File

@ -1,4 +1,6 @@
"""Support for SwitchBee entity.""" """Support for SwitchBee entity."""
from typing import Generic, TypeVar
from switchbee import SWITCHBEE_BRAND from switchbee import SWITCHBEE_BRAND
from switchbee.device import SwitchBeeBaseDevice from switchbee.device import SwitchBeeBaseDevice
@ -8,15 +10,17 @@ from homeassistant.helpers.update_coordinator import CoordinatorEntity
from .const import DOMAIN from .const import DOMAIN
from .coordinator import SwitchBeeCoordinator from .coordinator import SwitchBeeCoordinator
_DeviceTypeT = TypeVar("_DeviceTypeT", bound=SwitchBeeBaseDevice)
class SwitchBeeEntity(CoordinatorEntity[SwitchBeeCoordinator]):
class SwitchBeeEntity(CoordinatorEntity[SwitchBeeCoordinator], Generic[_DeviceTypeT]):
"""Representation of a Switchbee entity.""" """Representation of a Switchbee entity."""
_attr_has_entity_name = True _attr_has_entity_name = True
def __init__( def __init__(
self, self,
device: SwitchBeeBaseDevice, device: _DeviceTypeT,
coordinator: SwitchBeeCoordinator, coordinator: SwitchBeeCoordinator,
) -> None: ) -> None:
"""Initialize the Switchbee entity.""" """Initialize the Switchbee entity."""
@ -26,12 +30,12 @@ class SwitchBeeEntity(CoordinatorEntity[SwitchBeeCoordinator]):
self._attr_unique_id = f"{coordinator.mac_formated}-{device.id}" self._attr_unique_id = f"{coordinator.mac_formated}-{device.id}"
class SwitchBeeDeviceEntity(SwitchBeeEntity): class SwitchBeeDeviceEntity(SwitchBeeEntity[_DeviceTypeT]):
"""Representation of a Switchbee device entity.""" """Representation of a Switchbee device entity."""
def __init__( def __init__(
self, self,
device: SwitchBeeBaseDevice, device: _DeviceTypeT,
coordinator: SwitchBeeCoordinator, coordinator: SwitchBeeCoordinator,
) -> None: ) -> None:
"""Initialize the Switchbee device.""" """Initialize the Switchbee device."""

View File

@ -3,7 +3,7 @@
"name": "SwitchBee", "name": "SwitchBee",
"config_flow": true, "config_flow": true,
"documentation": "https://www.home-assistant.io/integrations/switchbee", "documentation": "https://www.home-assistant.io/integrations/switchbee",
"requirements": ["pyswitchbee==1.4.8"], "requirements": ["pyswitchbee==1.5.3"],
"codeowners": ["@jafar-atili"], "codeowners": ["@jafar-atili"],
"iot_class": "local_polling" "iot_class": "local_polling"
} }

View File

@ -1,9 +1,18 @@
"""Support for SwitchBee switch.""" """Support for SwitchBee switch."""
from __future__ import annotations
import logging import logging
from typing import Any from typing import Any, TypeVar, Union, cast
from switchbee.api import SwitchBeeDeviceOfflineError, SwitchBeeError from switchbee.api import SwitchBeeDeviceOfflineError, SwitchBeeError
from switchbee.device import ApiStateCommand, DeviceType, SwitchBeeBaseDevice from switchbee.device import (
ApiStateCommand,
SwitchBeeGroupSwitch,
SwitchBeeSwitch,
SwitchBeeTimedSwitch,
SwitchBeeTimerSwitch,
)
from homeassistant.components.switch import SwitchEntity from homeassistant.components.switch import SwitchEntity
from homeassistant.config_entries import ConfigEntry from homeassistant.config_entries import ConfigEntry
@ -17,6 +26,16 @@ from .entity import SwitchBeeDeviceEntity
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
_DeviceTypeT = TypeVar(
"_DeviceTypeT",
bound=Union[
SwitchBeeTimedSwitch,
SwitchBeeGroupSwitch,
SwitchBeeSwitch,
SwitchBeeTimerSwitch,
],
)
async def async_setup_entry( async def async_setup_entry(
hass: HomeAssistant, entry: ConfigEntry, async_add_entities: AddEntitiesCallback hass: HomeAssistant, entry: ConfigEntry, async_add_entities: AddEntitiesCallback
@ -27,22 +46,24 @@ async def async_setup_entry(
async_add_entities( async_add_entities(
SwitchBeeSwitchEntity(device, coordinator) SwitchBeeSwitchEntity(device, coordinator)
for device in coordinator.data.values() for device in coordinator.data.values()
if device.type if isinstance(
in [ device,
DeviceType.TimedPowerSwitch, (
DeviceType.GroupSwitch, SwitchBeeTimedSwitch,
DeviceType.Switch, SwitchBeeGroupSwitch,
DeviceType.TimedSwitch, SwitchBeeSwitch,
] SwitchBeeTimerSwitch,
),
)
) )
class SwitchBeeSwitchEntity(SwitchBeeDeviceEntity, SwitchEntity): class SwitchBeeSwitchEntity(SwitchBeeDeviceEntity[_DeviceTypeT], SwitchEntity):
"""Representation of a Switchbee switch.""" """Representation of a Switchbee switch."""
def __init__( def __init__(
self, self,
device: SwitchBeeBaseDevice, device: _DeviceTypeT,
coordinator: SwitchBeeCoordinator, coordinator: SwitchBeeCoordinator,
) -> None: ) -> None:
"""Initialize the Switchbee switch.""" """Initialize the Switchbee switch."""
@ -64,7 +85,7 @@ class SwitchBeeSwitchEntity(SwitchBeeDeviceEntity, SwitchEntity):
def _update_from_coordinator(self) -> None: def _update_from_coordinator(self) -> None:
"""Update the entity attributes from the coordinator data.""" """Update the entity attributes from the coordinator data."""
async def async_refresh_state(): async def async_refresh_state() -> None:
"""Refresh the device state in the Central Unit. """Refresh the device state in the Central Unit.
This function addresses issue of a device that came online back but still report This function addresses issue of a device that came online back but still report
@ -84,7 +105,10 @@ class SwitchBeeSwitchEntity(SwitchBeeDeviceEntity, SwitchEntity):
except SwitchBeeError: except SwitchBeeError:
return return
if self.coordinator.data[self._device.id].state == -1: coordinator_device = cast(_DeviceTypeT, self.coordinator.data[self._device.id])
if coordinator_device.state == -1:
# This specific call will refresh the state of the device in the CU # This specific call will refresh the state of the device in the CU
self.hass.async_create_task(async_refresh_state()) self.hass.async_create_task(async_refresh_state())
@ -108,9 +132,7 @@ class SwitchBeeSwitchEntity(SwitchBeeDeviceEntity, SwitchEntity):
# timed power switch state is an integer representing the number of minutes left until it goes off # timed power switch state is an integer representing the number of minutes left until it goes off
# regulare switches state is ON/OFF (1/0 respectively) # regulare switches state is ON/OFF (1/0 respectively)
self._attr_is_on = ( self._attr_is_on = coordinator_device.state != ApiStateCommand.OFF
self.coordinator.data[self._device.id].state != ApiStateCommand.OFF
)
async def async_turn_on(self, **kwargs: Any) -> None: async def async_turn_on(self, **kwargs: Any) -> None:
"""Async function to set on to switch.""" """Async function to set on to switch."""
@ -120,7 +142,7 @@ class SwitchBeeSwitchEntity(SwitchBeeDeviceEntity, SwitchEntity):
"""Async function to set off to switch.""" """Async function to set off to switch."""
return await self._async_set_state(ApiStateCommand.OFF) return await self._async_set_state(ApiStateCommand.OFF)
async def _async_set_state(self, state: ApiStateCommand) -> None: async def _async_set_state(self, state: str) -> None:
try: try:
await self.coordinator.api.set_state(self._device.id, state) await self.coordinator.api.set_state(self._device.id, state)
except (SwitchBeeError, SwitchBeeDeviceOfflineError) as exp: except (SwitchBeeError, SwitchBeeDeviceOfflineError) as exp:

View File

@ -2163,6 +2163,16 @@ disallow_untyped_defs = true
warn_return_any = true warn_return_any = true
warn_unreachable = true warn_unreachable = true
[mypy-homeassistant.components.switchbee.*]
check_untyped_defs = true
disallow_incomplete_defs = true
disallow_subclassing_any = true
disallow_untyped_calls = true
disallow_untyped_decorators = true
disallow_untyped_defs = true
warn_return_any = true
warn_unreachable = true
[mypy-homeassistant.components.switcher_kis.*] [mypy-homeassistant.components.switcher_kis.*]
check_untyped_defs = true check_untyped_defs = true
disallow_incomplete_defs = true disallow_incomplete_defs = true

View File

@ -1920,7 +1920,7 @@ pystiebeleltron==0.0.1.dev2
pysuez==0.1.19 pysuez==0.1.19
# homeassistant.components.switchbee # homeassistant.components.switchbee
pyswitchbee==1.4.8 pyswitchbee==1.5.3
# homeassistant.components.syncthru # homeassistant.components.syncthru
pysyncthru==0.7.10 pysyncthru==0.7.10

View File

@ -1349,7 +1349,7 @@ pyspcwebgw==0.4.0
pysqueezebox==0.6.0 pysqueezebox==0.6.0
# homeassistant.components.switchbee # homeassistant.components.switchbee
pyswitchbee==1.4.8 pyswitchbee==1.5.3
# homeassistant.components.syncthru # homeassistant.components.syncthru
pysyncthru==0.7.10 pysyncthru==0.7.10