diff --git a/homeassistant/components/hunterdouglas_powerview/cover.py b/homeassistant/components/hunterdouglas_powerview/cover.py index 78a62e5bb88..453d5c4e920 100644 --- a/homeassistant/components/hunterdouglas_powerview/cover.py +++ b/homeassistant/components/hunterdouglas_powerview/cover.py @@ -71,7 +71,6 @@ async def async_setup_entry( entities: list[ShadeEntity] = [] for shade in pv_entry.shade_data.values(): - coordinator.data.update_shade_position(shade.id, shade.current_position) room_name = getattr(pv_entry.room_data.get(shade.room_id), ATTR_NAME, "") entities.extend( create_powerview_shade_entity( diff --git a/homeassistant/components/hunterdouglas_powerview/number.py b/homeassistant/components/hunterdouglas_powerview/number.py index b37331c08df..8551a11337e 100644 --- a/homeassistant/components/hunterdouglas_powerview/number.py +++ b/homeassistant/components/hunterdouglas_powerview/number.py @@ -41,7 +41,7 @@ def store_velocity( value: float | None, ) -> None: """Store the desired shade velocity in the coordinator.""" - coordinator.data.update_shade_velocity(shade_id, ShadePosition(velocity=value)) + coordinator.data.update_shade_position(shade_id, ShadePosition(velocity=value)) NUMBERS: Final = ( diff --git a/homeassistant/components/hunterdouglas_powerview/shade_data.py b/homeassistant/components/hunterdouglas_powerview/shade_data.py index 4d780b83ecb..e6b20312f27 100644 --- a/homeassistant/components/hunterdouglas_powerview/shade_data.py +++ b/homeassistant/components/hunterdouglas_powerview/shade_data.py @@ -2,6 +2,7 @@ from __future__ import annotations +from dataclasses import fields import logging from typing import Any @@ -12,74 +13,66 @@ from .util import async_map_data_by_id _LOGGER = logging.getLogger(__name__) +POSITION_FIELDS = fields(ShadePosition) + + +def copy_position_data(source: ShadePosition, target: ShadePosition) -> ShadePosition: + """Copy position data from source to target for None values only.""" + # the hub will always return a velocity of 0 on initial connect, + # separate definition to store consistent value in HA + # this value is purely driven from HA + for field in POSITION_FIELDS: + if (value := getattr(source, field.name)) is not None: + setattr(target, field.name, value) + class PowerviewShadeData: """Coordinate shade data between multiple api calls.""" def __init__(self) -> None: """Init the shade data.""" - self._group_data_by_id: dict[int, dict[str | int, Any]] = {} - self._shade_data_by_id: dict[int, BaseShade] = {} + self._raw_data_by_id: dict[int, dict[str | int, Any]] = {} + self._shade_group_data_by_id: dict[int, BaseShade] = {} self.positions: dict[int, ShadePosition] = {} def get_raw_data(self, shade_id: int) -> dict[str | int, Any]: """Get data for the shade.""" - return self._group_data_by_id[shade_id] + return self._raw_data_by_id[shade_id] def get_all_raw_data(self) -> dict[int, dict[str | int, Any]]: """Get data for all shades.""" - return self._group_data_by_id + return self._raw_data_by_id def get_shade(self, shade_id: int) -> BaseShade: """Get specific shade from the coordinator.""" - return self._shade_data_by_id[shade_id] + return self._shade_group_data_by_id[shade_id] def get_shade_position(self, shade_id: int) -> ShadePosition: """Get positions for a shade.""" if shade_id not in self.positions: - self.positions[shade_id] = ShadePosition() + shade_position = ShadePosition() + # If we have the group data, use it to populate the initial position + if shade := self._shade_group_data_by_id.get(shade_id): + copy_position_data(shade.current_position, shade_position) + self.positions[shade_id] = shade_position return self.positions[shade_id] def update_from_group_data(self, shade_id: int) -> None: """Process an update from the group data.""" - self.update_shade_positions(self._shade_data_by_id[shade_id]) + data = self._shade_group_data_by_id[shade_id] + copy_position_data(data.current_position, self.get_shade_position(data.id)) def store_group_data(self, shade_data: PowerviewData) -> None: """Store data from the all shades endpoint. - This does not update the shades or positions + This does not update the shades or positions (self.positions) as the data may be stale. update_from_group_data with a shade_id will update a specific shade from the group data. """ - self._shade_data_by_id = shade_data.processed - self._group_data_by_id = async_map_data_by_id(shade_data.raw) + self._shade_group_data_by_id = shade_data.processed + self._raw_data_by_id = async_map_data_by_id(shade_data.raw) - def update_shade_position(self, shade_id: int, shade_data: ShadePosition) -> None: + def update_shade_position(self, shade_id: int, new_position: ShadePosition) -> None: """Update a single shades position.""" - if shade_id not in self.positions: - self.positions[shade_id] = ShadePosition() - - # ShadePosition will return None if the value is not set - if shade_data.primary is not None: - self.positions[shade_id].primary = shade_data.primary - if shade_data.secondary is not None: - self.positions[shade_id].secondary = shade_data.secondary - if shade_data.tilt is not None: - self.positions[shade_id].tilt = shade_data.tilt - - def update_shade_velocity(self, shade_id: int, shade_data: ShadePosition) -> None: - """Update a single shades velocity.""" - if shade_id not in self.positions: - self.positions[shade_id] = ShadePosition() - - # the hub will always return a velocity of 0 on initial connect, - # separate definition to store consistent value in HA - # this value is purely driven from HA - if shade_data.velocity is not None: - self.positions[shade_id].velocity = shade_data.velocity - - def update_shade_positions(self, data: BaseShade) -> None: - """Update a shades from data dict.""" - _LOGGER.debug("Raw data update: %s", data.raw_data) - self.update_shade_position(data.id, data.current_position) + copy_position_data(new_position, self.get_shade_position(shade_id))