mirror of
https://github.com/home-assistant/core.git
synced 2025-11-09 19:09:32 +00:00
Rewrite APCUPSD sensors using DataUpdateCoordinator (#88467)
* Add test sensor. * Fix sensor test file name. * Add binary sensor test. * Fix comments and styling. * Remove apcupsd from omissions in coveragerc. * Revert "Remove apcupsd from omissions in coveragerc." This reverts commit 66b05fcb8829619a771a650a3d70174089e15d91. * Implement the data coordinator for apcupsd. * Add tests for sensor updates and throttles. * Reorder the statement for better code clarity. * Update docstring. * Add more tests for checking if the coordinator works ok. * Implement a custom debouncer with 5 second cooldown for the coordinator. * Add more tests for checking if our integration is able to properly mark entity's availability. * Make apcupsd a silver integration. * Try to fix non-deterministic test behaviors * Fix JSON format * Use new `with` format in python 3.10 for better readability * Update tests. * Rebase and simplify code. * Add an ups prefix to the property methods of the coordinator * Replace init_integration with async_init_integration * Lint fixes * Fix imports * Update BinarySensor implementation to add initial update of attributes * Fix test failures due to rebases * Reorder the statements for better code clarity * Fix incorrect references to the ups_name property * Simplify BinarySensor value getter code * No need to update when adding coordinator-controlled sensors
This commit is contained in:
@@ -2,6 +2,7 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import logging
|
||||
from typing import Final
|
||||
|
||||
from homeassistant.components.binary_sensor import (
|
||||
BinarySensorEntity,
|
||||
@@ -10,8 +11,9 @@ from homeassistant.components.binary_sensor import (
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
from homeassistant.helpers.update_coordinator import CoordinatorEntity
|
||||
|
||||
from . import DOMAIN, VALUE_ONLINE, APCUPSdData
|
||||
from . import DOMAIN, APCUPSdCoordinator
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
_DESCRIPTION = BinarySensorEntityDescription(
|
||||
@@ -19,6 +21,8 @@ _DESCRIPTION = BinarySensorEntityDescription(
|
||||
name="UPS Online Status",
|
||||
icon="mdi:heart",
|
||||
)
|
||||
# The bit in STATFLAG that indicates the online status of the APC UPS.
|
||||
_VALUE_ONLINE_MASK: Final = 0b1000
|
||||
|
||||
|
||||
async def async_setup_entry(
|
||||
@@ -27,50 +31,36 @@ async def async_setup_entry(
|
||||
async_add_entities: AddEntitiesCallback,
|
||||
) -> None:
|
||||
"""Set up an APCUPSd Online Status binary sensor."""
|
||||
data_service: APCUPSdData = hass.data[DOMAIN][config_entry.entry_id]
|
||||
coordinator: APCUPSdCoordinator = hass.data[DOMAIN][config_entry.entry_id]
|
||||
|
||||
# Do not create the binary sensor if APCUPSd does not provide STATFLAG field for us
|
||||
# to determine the online status.
|
||||
if data_service.statflag is None:
|
||||
if _DESCRIPTION.key.upper() not in coordinator.data:
|
||||
return
|
||||
|
||||
async_add_entities(
|
||||
[OnlineStatus(data_service, _DESCRIPTION)],
|
||||
update_before_add=True,
|
||||
)
|
||||
async_add_entities([OnlineStatus(coordinator, _DESCRIPTION)])
|
||||
|
||||
|
||||
class OnlineStatus(BinarySensorEntity):
|
||||
class OnlineStatus(CoordinatorEntity[APCUPSdCoordinator], BinarySensorEntity):
|
||||
"""Representation of a UPS online status."""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
data_service: APCUPSdData,
|
||||
coordinator: APCUPSdCoordinator,
|
||||
description: BinarySensorEntityDescription,
|
||||
) -> None:
|
||||
"""Initialize the APCUPSd binary device."""
|
||||
super().__init__(coordinator, context=description.key.upper())
|
||||
|
||||
# Set up unique id and device info if serial number is available.
|
||||
if (serial_no := data_service.serial_no) is not None:
|
||||
if (serial_no := coordinator.ups_serial_no) is not None:
|
||||
self._attr_unique_id = f"{serial_no}_{description.key}"
|
||||
self._attr_device_info = data_service.device_info
|
||||
|
||||
self.entity_description = description
|
||||
self._data_service = data_service
|
||||
self._attr_device_info = coordinator.device_info
|
||||
|
||||
def update(self) -> None:
|
||||
"""Get the status report from APCUPSd and set this entity's state."""
|
||||
try:
|
||||
self._data_service.update()
|
||||
except OSError as ex:
|
||||
if self._attr_available:
|
||||
self._attr_available = False
|
||||
_LOGGER.exception("Got exception while fetching state: %s", ex)
|
||||
return
|
||||
|
||||
self._attr_available = True
|
||||
@property
|
||||
def is_on(self) -> bool | None:
|
||||
"""Returns true if the UPS is online."""
|
||||
# Check if ONLINE bit is set in STATFLAG.
|
||||
key = self.entity_description.key.upper()
|
||||
if key not in self._data_service.status:
|
||||
self._attr_is_on = None
|
||||
return
|
||||
|
||||
self._attr_is_on = int(self._data_service.status[key], 16) & VALUE_ONLINE > 0
|
||||
return int(self.coordinator.data[key], 16) & _VALUE_ONLINE_MASK != 0
|
||||
|
||||
Reference in New Issue
Block a user