Skip to content

Commit

Permalink
chore: use coordinator as the name for *Coordinator. (#163)
Browse files Browse the repository at this point in the history
Also removes the redundant self._device member because
super().__init__()
already set self.coordinator.

The name is consistent with the naming convention from the ha developer
docs:

https://developers.home-assistant.io/docs/integration_fetching_data/#coordinated-single-api-poll-for-data-for-all-entities

(also the Entity class examples appear to still use the confusing
'device' as the name of the updater; seems like coordinators were
introduced after that document was written).

For the next step, I am debating whether to expose the blueair_api.*Device as
coordinator.device, since adding the type annotation propagation is a
lot of work with no obvious gain in neither layer cleanness or
functionatliy.

But this change is large enough that I would like to file it first.
  • Loading branch information
rainwoodman authored Dec 14, 2024
1 parent 0481414 commit 33562aa
Show file tree
Hide file tree
Showing 8 changed files with 176 additions and 176 deletions.
16 changes: 8 additions & 8 deletions custom_components/ha_blueair/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -81,27 +81,27 @@ async def async_setup_entry(hass: HomeAssistant, config_entry: ConfigEntry):
region=region,
)

def create_updaters(device):
def create_coordinators(device):
return BlueairDataUpdateCoordinator(
hass=hass,
blueair_api_device=device,
)

data[DATA_DEVICES] = list(map(create_updaters, devices))
data[DATA_DEVICES] = list(map(create_coordinators, devices))

for updater in data[DATA_DEVICES]:
await updater.async_config_entry_first_refresh()
for coordinator in data[DATA_DEVICES]:
await coordinator.async_config_entry_first_refresh()

def create_aws_updaters(device):
def create_aws_coordinators(device):
return BlueairAwsDataUpdateCoordinator(
hass=hass,
blueair_api_device=device,
)

data[DATA_AWS_DEVICES] = list(map(create_aws_updaters, aws_devices))
data[DATA_AWS_DEVICES] = list(map(create_aws_coordinators, aws_devices))

for updater in data[DATA_AWS_DEVICES]:
await updater.async_config_entry_first_refresh()
for coordinator in data[DATA_AWS_DEVICES]:
await coordinator.async_config_entry_first_refresh()

hass.data[DOMAIN] = data

Expand Down
50 changes: 25 additions & 25 deletions custom_components/ha_blueair/binary_sensor.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,74 +20,74 @@ async def async_setup_entry(hass, config_entry, async_add_entities):
[FeatureEnum.CHILD_LOCK, BlueairChildLockSensor],
[FeatureEnum.WATER_SHORTAGE, BlueairWaterShortageSensor],
]
devices: list[BlueairDataUpdateCoordinator] = hass.data[DOMAIN][DATA_DEVICES]
coordinators: list[BlueairDataUpdateCoordinator] = hass.data[DOMAIN][DATA_DEVICES]
entities = []
for device in devices:
for coordinator in coordinators:
entities.extend(
[
BlueairChildLockSensor(device),
BlueairFilterExpiredSensor(device),
BlueairOnlineSensor(device),
BlueairChildLockSensor(coordinator),
BlueairFilterExpiredSensor(coordinator),
BlueairOnlineSensor(coordinator),
]
)
async_add_entities(entities)

aws_devices: list[BlueairAwsDataUpdateCoordinator] = hass.data[DOMAIN][
aws_coordinators: list[BlueairAwsDataUpdateCoordinator] = hass.data[DOMAIN][
DATA_AWS_DEVICES
]
entities = []
for device in aws_devices:
entities.append(BlueairOnlineSensor(device))
for coordinator in aws_coordinators:
entities.append(BlueairOnlineSensor(coordinator))
for feature_class in feature_class_mapping:
if device.blueair_api_device.model.supports_feature(feature_class[0]):
entities.append(feature_class[1](device))
if coordinator.blueair_api_device.model.supports_feature(feature_class[0]):
entities.append(feature_class[1](coordinator))
async_add_entities(entities)


class BlueairChildLockSensor(BlueairEntity, BinarySensorEntity):
_attr_icon = "mdi:account-child-outline"

def __init__(self, device):
super().__init__("Child Lock", device)
def __init__(self, coordinator):
super().__init__("Child Lock", coordinator)

@property
def is_on(self) -> bool | None:
"""Return true if the binary sensor is on."""
return self._device.child_lock
return self.coordinator.child_lock


class BlueairFilterExpiredSensor(BlueairEntity, BinarySensorEntity):
_attr_icon = "mdi:air-filter"

def __init__(self, device):
def __init__(self, coordinator):
"""Initialize the temperature sensor."""
self.entity_description = EntityDescription(
key=f"#{device.blueair_api_device.uuid}-filter-expired",
key=f"#{coordinator.blueair_api_device.uuid}-filter-expired",
device_class=BinarySensorDeviceClass.PROBLEM,
)
super().__init__("Filter Expiration", device)
super().__init__("Filter Expiration", coordinator)

@property
def is_on(self) -> bool | None:
"""Return true if the binary sensor is on."""
return self._device.filter_expired
return self.coordinator.filter_expired


class BlueairOnlineSensor(BlueairEntity, BinarySensorEntity):
_attr_icon = "mdi:wifi-check"

def __init__(self, device):
def __init__(self, coordinator):
"""Initialize the temperature sensor."""
self.entity_description = EntityDescription(
key=f"#{device.blueair_api_device.uuid}-online",
key=f"#{coordinator.blueair_api_device.uuid}-online",
device_class=BinarySensorDeviceClass.CONNECTIVITY,
)
super().__init__("Online", device)
super().__init__("Online", coordinator)

@property
def is_on(self) -> bool | None:
"""Return true if the binary sensor is on."""
return self._device.online
return self.coordinator.online

@property
def icon(self) -> str | None:
Expand All @@ -100,14 +100,14 @@ def icon(self) -> str | None:
class BlueairWaterShortageSensor(BlueairEntity, BinarySensorEntity):
_attr_icon = "mdi:water-alert-outline"

def __init__(self, device):
def __init__(self, coordinator):
self.entity_description = EntityDescription(
key=f"#{device.blueair_api_device.uuid}-water-shortage",
key=f"#{coordinator.blueair_api_device.uuid}-water-shortage",
device_class=BinarySensorDeviceClass.PROBLEM,
)
super().__init__("Water Shortage", device)
super().__init__("Water Shortage", coordinator)

@property
def is_on(self) -> bool | None:
"""Return true if the binary sensor is on."""
return self._device.water_shortage
return self.coordinator.water_shortage
16 changes: 8 additions & 8 deletions custom_components/ha_blueair/diagnostics.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,22 +26,22 @@ async def async_get_config_entry_diagnostics(
hass: HomeAssistant, config_entry: ConfigEntry
) -> dict[str, dict[str, Any]]:
"""Return diagnostics for a config entry."""
device_updaters: list[BlueairDataUpdateCoordinator] = hass.data[DOMAIN][DATA_DEVICES]
device_aws_updaters: list[BlueairAwsDataUpdateCoordinator] = hass.data[DOMAIN][DATA_AWS_DEVICES]
updaters = device_updaters + device_aws_updaters
device_coordinators: list[BlueairDataUpdateCoordinator] = hass.data[DOMAIN][DATA_DEVICES]
device_aws_coordinators: list[BlueairAwsDataUpdateCoordinator] = hass.data[DOMAIN][DATA_AWS_DEVICES]
coordinators = device_coordinators + device_aws_coordinators
data = {
"entry": async_redact_data(config_entry.as_dict(), TO_REDACT),
}
for updater in updaters:
data[updater.blueair_api_device.mac] = updater.blueair_api_device.__repr__()
for coordinator in coordinators:
data[coordinator.blueair_api_device.mac] = coordinator.blueair_api_device.__repr__()

device_registry = dr.async_get(hass)
entity_registry = er.async_get(hass)
hass_device = device_registry.async_get_device(
identifiers={(DOMAIN, updater.id)}
identifiers={(DOMAIN, coordinator.id)}
)
if hass_device is not None:
data[updater.blueair_api_device.mac]["device"] = {
data[coordinator.blueair_api_device.mac]["device"] = {
**async_redact_data(attr.asdict(hass_device), TO_REDACT_DEVICE),
"entities": {},
}
Expand All @@ -62,7 +62,7 @@ async def async_get_config_entry_diagnostics(
# The context doesn't provide useful information in this case.
state_dict.pop("context", None)

data[updater.blueair_api_device.mac]["device"]["entities"][entity_entry.entity_id] = {
data[coordinator.blueair_api_device.mac]["device"]["entities"][entity_entry.entity_id] = {
**async_redact_data(
attr.asdict(
entity_entry,
Expand Down
26 changes: 13 additions & 13 deletions custom_components/ha_blueair/entity.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,34 +19,34 @@ class BlueairEntity(CoordinatorEntity):
def __init__(
self,
entity_type: str,
device: BlueairAwsDataUpdateCoordinator | BlueairDataUpdateCoordinator,
coordinator: BlueairAwsDataUpdateCoordinator | BlueairDataUpdateCoordinator,
**kwargs,
) -> None:
super().__init__(device)
self._attr_name = f"{device.blueair_api_device.name} {entity_type}"
self._attr_unique_id = f"{device.blueair_api_device.uuid}_{entity_type}"
super().__init__(coordinator)
self._attr_name = f"{coordinator.blueair_api_device.name} {entity_type}"
self._attr_unique_id = f"{coordinator.blueair_api_device.uuid}_{entity_type}"

self._device: BlueairAwsDataUpdateCoordinator = device
self.coordinator: BlueairAwsDataUpdateCoordinator = coordinator

@property
def device_info(self) -> DeviceInfo:
connections = {(dr.CONNECTION_NETWORK_MAC, self._device.blueair_api_device.mac)}
connections = {(dr.CONNECTION_NETWORK_MAC, self.coordinator.blueair_api_device.mac)}
return DeviceInfo(
connections=connections,
identifiers={(DOMAIN, self._device.id)},
manufacturer=self._device.manufacturer,
model=self._device.model,
name=self._device.blueair_api_device.name,
identifiers={(DOMAIN, self.coordinator.id)},
manufacturer=self.coordinator.manufacturer,
model=self.coordinator.model,
name=self.coordinator.blueair_api_device.name,
)

async def async_update(self):
"""Update Blueair entity."""
if not self.enabled:
return

await self._device.async_request_refresh()
self._attr_available = self._device.blueair_api_device.wifi_working
await self.coordinator.async_request_refresh()
self._attr_available = self.coordinator.blueair_api_device.wifi_working

async def async_added_to_hass(self):
"""When entity is added to hass."""
self.async_on_remove(self._device.async_add_listener(self.async_write_ha_state))
self.async_on_remove(self.coordinator.async_add_listener(self.async_write_ha_state))
42 changes: 21 additions & 21 deletions custom_components/ha_blueair/fan.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,22 +14,22 @@

async def async_setup_entry(hass, config_entry, async_add_entities):
"""Set up the Blueair fans from config entry."""
devices: list[BlueairDataUpdateCoordinator] = hass.data[DOMAIN][DATA_DEVICES]
coordinators: list[BlueairDataUpdateCoordinator] = hass.data[DOMAIN][DATA_DEVICES]
entities = []
for device in devices:
for coordinator in coordinators:
entities.extend(
[
BlueairFan(device),
BlueairFan(coordinator),
]
)
async_add_entities(entities)

devices: list[BlueairAwsDataUpdateCoordinator] = hass.data[DOMAIN][DATA_AWS_DEVICES]
coordinators: list[BlueairAwsDataUpdateCoordinator] = hass.data[DOMAIN][DATA_AWS_DEVICES]
entities = []
for device in devices:
for coordinator in coordinators:
entities.extend(
[
BlueairAwsFan(device),
BlueairAwsFan(coordinator),
]
)
async_add_entities(entities)
Expand All @@ -38,22 +38,22 @@ async def async_setup_entry(hass, config_entry, async_add_entities):
class BlueairFan(BlueairEntity, FanEntity):
"""Controls Fan."""

def __init__(self, device: BlueairDataUpdateCoordinator):
def __init__(self, coordinator: BlueairDataUpdateCoordinator):
"""Initialize the temperature sensor."""
super().__init__("Fan", device)
super().__init__("Fan", coordinator)

@property
def supported_features(self) -> int:
return FanEntityFeature.SET_SPEED | FanEntityFeature.TURN_ON | FanEntityFeature.TURN_OFF

@property
def is_on(self) -> int:
return self._device.is_on
return self.coordinator.is_on

@property
def percentage(self) -> int:
"""Return the current speed percentage."""
return int(round(self._device.fan_speed * 33.33, 0))
return int(round(self.coordinator.fan_speed * 33.33, 0))

async def async_set_percentage(self, percentage: int) -> None:
"""Sets fan speed percentage."""
Expand All @@ -66,19 +66,19 @@ async def async_set_percentage(self, percentage: int) -> None:
else:
new_speed = "0"

await self._device.set_fan_speed(new_speed)
await self.coordinator.set_fan_speed(new_speed)
self.async_write_ha_state()

async def async_turn_off(self, **kwargs: any) -> None:
await self._device.set_fan_speed("0")
await self.coordinator.set_fan_speed("0")

async def async_turn_on(
self,
percentage: int | None = None,
preset_mode: str | None = None,
**kwargs: any,
) -> None:
await self._device.set_fan_speed("1")
await self.coordinator.set_fan_speed("1")
self.async_write_ha_state()
if percentage is not None:
await self.async_set_percentage(percentage=percentage)
Expand All @@ -92,29 +92,29 @@ def speed_count(self) -> int:
class BlueairAwsFan(BlueairEntity, FanEntity):
"""Controls Fan."""

def __init__(self, device: BlueairAwsDataUpdateCoordinator):
def __init__(self, coordinator: BlueairAwsDataUpdateCoordinator):
"""Initialize the temperature sensor."""
super().__init__("Fan", device)
super().__init__("Fan", coordinator)

@property
def supported_features(self) -> int:
return FanEntityFeature.SET_SPEED | FanEntityFeature.TURN_ON | FanEntityFeature.TURN_OFF

@property
def is_on(self) -> int:
return self._device.is_on
return self.coordinator.is_on

@property
def percentage(self) -> int:
"""Return the current speed percentage."""
return int((self._device.fan_speed * 100) // self._device.speed_count)
return int((self.coordinator.fan_speed * 100) // self.coordinator.speed_count)

async def async_set_percentage(self, percentage: int) -> None:
await self._device.set_fan_speed(int(round(percentage / 100 * self._device.speed_count)))
await self.coordinator.set_fan_speed(int(round(percentage / 100 * self.coordinator.speed_count)))
self.async_write_ha_state()

async def async_turn_off(self, **kwargs: any) -> None:
await self._device.set_running(False)
await self.coordinator.set_running(False)
self.async_write_ha_state()

async def async_turn_on(
Expand All @@ -123,7 +123,7 @@ async def async_turn_on(
preset_mode: str | None = None,
**kwargs: any,
) -> None:
await self._device.set_running(True)
await self.coordinator.set_running(True)
self.async_write_ha_state()
if percentage is None:
# FIXME: i35 (and probably others) do not remember the
Expand All @@ -138,4 +138,4 @@ async def async_turn_on(
@property
def speed_count(self) -> int:
"""Return the number of speeds the fan supports."""
return self._device.speed_count
return self.coordinator.speed_count
Loading

0 comments on commit 33562aa

Please sign in to comment.