Use a single source of data for switchbot (#84215)

pull/84254/head
J. Nick Koston 2022-12-19 07:47:42 -10:00 committed by GitHub
parent 6e612a45ff
commit 7c13e7cdfd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 39 additions and 55 deletions

View File

@ -54,7 +54,7 @@ async def async_setup_entry(
coordinator: SwitchbotDataUpdateCoordinator = hass.data[DOMAIN][entry.entry_id]
async_add_entities(
SwitchBotBinarySensor(coordinator, binary_sensor)
for binary_sensor in coordinator.data["data"]
for binary_sensor in coordinator.device.parsed_data
if binary_sensor in BINARY_SENSOR_TYPES
)
@ -77,4 +77,4 @@ class SwitchBotBinarySensor(SwitchbotEntity, BinarySensorEntity):
@property
def is_on(self) -> bool:
"""Return the state of the sensor."""
return self.data["data"][self._sensor]
return self.parsed_data[self._sensor]

View File

@ -4,7 +4,7 @@ from __future__ import annotations
import asyncio
import contextlib
import logging
from typing import TYPE_CHECKING, Any
from typing import TYPE_CHECKING
import async_timeout
import switchbot
@ -25,14 +25,6 @@ _LOGGER = logging.getLogger(__name__)
DEVICE_STARTUP_TIMEOUT = 30
def flatten_sensors_data(sensor):
"""Deconstruct SwitchBot library temp object C/Fº readings from dictionary."""
if "temp" in sensor["data"]:
sensor["data"]["temperature"] = sensor["data"]["temp"]["c"]
return sensor
class SwitchbotDataUpdateCoordinator(PassiveBluetoothDataUpdateCoordinator):
"""Class to manage fetching switchbot data."""
@ -57,7 +49,6 @@ class SwitchbotDataUpdateCoordinator(PassiveBluetoothDataUpdateCoordinator):
)
self.ble_device = ble_device
self.device = device
self.data: dict[str, Any] = {}
self.device_name = device_name
self.base_unique_id = base_unique_id
self.model = model
@ -88,11 +79,12 @@ class SwitchbotDataUpdateCoordinator(PassiveBluetoothDataUpdateCoordinator):
return
if "modelName" in adv.data:
self._ready_event.set()
_LOGGER.debug("%s: Switchbot data: %s", self.ble_device.address, self.data)
_LOGGER.debug(
"%s: Switchbot data: %s", self.ble_device.address, self.device.data
)
if not self.device.advertisement_changed(adv) and not self._was_unavailable:
return
self._was_unavailable = False
self.data = flatten_sensors_data(adv.data)
self.device.update_from_advertisement(adv)
super()._async_handle_bluetooth_event(service_info, change)

View File

@ -98,7 +98,7 @@ class SwitchBotCurtainEntity(SwitchbotEntity, CoverEntity, RestoreEntity):
@callback
def _handle_coordinator_update(self) -> None:
"""Handle updated data from the coordinator."""
self._attr_current_cover_position = self.data["data"]["position"]
self._attr_is_closed = self.data["data"]["position"] <= 20
self._attr_is_opening = self.data["data"]["inMotion"]
self._attr_current_cover_position = self.parsed_data["position"]
self._attr_is_closed = self.parsed_data["position"] <= 20
self._attr_is_opening = self.parsed_data["inMotion"]
self.async_write_ha_state()

View File

@ -1,7 +1,6 @@
"""An abstract class common to all Switchbot entities."""
from __future__ import annotations
from abc import abstractmethod
from collections.abc import Mapping
import logging
from typing import Any
@ -54,15 +53,37 @@ class SwitchbotEntity(PassiveBluetoothCoordinatorEntity):
)
@property
def data(self) -> dict[str, Any]:
"""Return coordinator data for this entity."""
return self.coordinator.data
def parsed_data(self) -> dict[str, Any]:
"""Return parsed device data for this entity."""
return self.coordinator.device.parsed_data
@property
def extra_state_attributes(self) -> Mapping[Any, Any]:
"""Return the state attributes."""
return {"last_run_success": self._last_run_success}
@callback
def _async_update_attrs(self) -> None:
"""Update the entity attributes."""
@callback
def _handle_coordinator_update(self) -> None:
"""Handle data update."""
self._async_update_attrs()
self.async_write_ha_state()
async def async_added_to_hass(self) -> None:
"""Register callbacks."""
self.async_on_remove(self._device.subscribe(self._handle_coordinator_update))
return await super().async_added_to_hass()
async def async_update(self) -> None:
"""Update the entity.
Only used by the generic entity update service.
"""
await self._device.update()
class SwitchbotSwitchedEntity(SwitchbotEntity, ToggleEntity):
"""Base class for Switchbot entities that can be turned on and off."""
@ -86,29 +107,3 @@ class SwitchbotSwitchedEntity(SwitchbotEntity, ToggleEntity):
if self._last_run_success:
self._attr_is_on = False
self.async_write_ha_state()
class SwitchbotSubscribeEntity(SwitchbotEntity):
"""Base class for Switchbot entities that use subscribe."""
@abstractmethod
def _async_update_attrs(self) -> None:
"""Update the entity attributes."""
@callback
def _handle_coordinator_update(self) -> None:
"""Handle data update."""
self._async_update_attrs()
self.async_write_ha_state()
async def async_added_to_hass(self) -> None:
"""Register callbacks."""
self.async_on_remove(self._device.subscribe(self._handle_coordinator_update))
return await super().async_added_to_hass()
async def async_update(self) -> None:
"""Update the entity.
Only used by the generic entity update service.
"""
await self._device.update()

View File

@ -22,7 +22,7 @@ from homeassistant.util.color import (
from .const import DOMAIN
from .coordinator import SwitchbotDataUpdateCoordinator
from .entity import SwitchbotSubscribeEntity
from .entity import SwitchbotEntity
SWITCHBOT_COLOR_MODE_TO_HASS = {
SwitchBotColorMode.RGB: ColorMode.RGB,
@ -42,7 +42,7 @@ async def async_setup_entry(
async_add_entities([SwitchbotLightEntity(coordinator)])
class SwitchbotLightEntity(SwitchbotSubscribeEntity, LightEntity):
class SwitchbotLightEntity(SwitchbotEntity, LightEntity):
"""Representation of switchbot light bulb."""
_device: SwitchbotBaseLight

View File

@ -89,11 +89,8 @@ async def async_setup_entry(
"""Set up Switchbot sensor based on a config entry."""
coordinator: SwitchbotDataUpdateCoordinator = hass.data[DOMAIN][entry.entry_id]
entities = [
SwitchBotSensor(
coordinator,
sensor,
)
for sensor in coordinator.data["data"]
SwitchBotSensor(coordinator, sensor)
for sensor in coordinator.device.parsed_data
if sensor in SENSOR_TYPES
]
entities.append(SwitchbotRSSISensor(coordinator, "rssi"))
@ -117,7 +114,7 @@ class SwitchBotSensor(SwitchbotEntity, SensorEntity):
@property
def native_value(self) -> str | int | None:
"""Return the state of the sensor."""
return self.data["data"][self._sensor]
return self.parsed_data[self._sensor]
class SwitchbotRSSISensor(SwitchBotSensor):