Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update opentherm_gw.binary_sensor to use entity_description #121969

Merged
merged 5 commits into from
Aug 20, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
350 changes: 291 additions & 59 deletions homeassistant/components/opentherm_gw/binary_sensor.py
Original file line number Diff line number Diff line change
@@ -1,25 +1,287 @@
"""Support for OpenTherm Gateway binary sensors."""

import logging
from dataclasses import dataclass

from homeassistant.components.binary_sensor import ENTITY_ID_FORMAT, BinarySensorEntity
from pyotgw import vars as gw_vars

from homeassistant.components.binary_sensor import (
ENTITY_ID_FORMAT,
BinarySensorDeviceClass,
BinarySensorEntity,
BinarySensorEntityDescription,
)
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import CONF_ID
from homeassistant.core import HomeAssistant, callback
from homeassistant.helpers.device_registry import DeviceInfo
from homeassistant.helpers.dispatcher import async_dispatcher_connect
from homeassistant.helpers.entity import async_generate_entity_id
from homeassistant.helpers.entity_platform import AddEntitiesCallback

from . import DOMAIN
from .const import (
BINARY_SENSOR_INFO,
DATA_GATEWAYS,
DATA_OPENTHERM_GW,
TRANSLATE_SOURCE,
)
from . import OpenThermGatewayDevice
from .const import DATA_GATEWAYS, DATA_OPENTHERM_GW
from .entity import OpenThermEntity, OpenThermEntityDescription


@dataclass(frozen=True, kw_only=True)
class OpenThermBinarySensorEntityDescription(
BinarySensorEntityDescription, OpenThermEntityDescription
):
"""Describes opentherm_gw binary sensor entity."""


_LOGGER = logging.getLogger(__name__)
BINARY_SENSOR_INFO: tuple[
tuple[list[str], OpenThermBinarySensorEntityDescription], ...
] = (
(
[gw_vars.BOILER, gw_vars.THERMOSTAT],
OpenThermBinarySensorEntityDescription(
key=gw_vars.DATA_MASTER_CH_ENABLED,
friendly_name_format="Thermostat Central Heating {}",
),
),
(
[gw_vars.BOILER, gw_vars.THERMOSTAT],
OpenThermBinarySensorEntityDescription(
key=gw_vars.DATA_MASTER_DHW_ENABLED,
friendly_name_format="Thermostat Hot Water {}",
),
),
(
[gw_vars.BOILER, gw_vars.THERMOSTAT],
OpenThermBinarySensorEntityDescription(
key=gw_vars.DATA_MASTER_COOLING_ENABLED,
friendly_name_format="Thermostat Cooling {}",
),
),
(
[gw_vars.BOILER, gw_vars.THERMOSTAT],
OpenThermBinarySensorEntityDescription(
key=gw_vars.DATA_MASTER_OTC_ENABLED,
friendly_name_format="Thermostat Outside Temperature Correction {}",
),
),
(
[gw_vars.BOILER, gw_vars.THERMOSTAT],
OpenThermBinarySensorEntityDescription(
key=gw_vars.DATA_MASTER_CH2_ENABLED,
friendly_name_format="Thermostat Central Heating 2 {}",
),
),
(
[gw_vars.BOILER, gw_vars.THERMOSTAT],
OpenThermBinarySensorEntityDescription(
key=gw_vars.DATA_SLAVE_FAULT_IND,
friendly_name_format="Boiler Fault {}",
device_class=BinarySensorDeviceClass.PROBLEM,
),
),
(
[gw_vars.BOILER, gw_vars.THERMOSTAT],
OpenThermBinarySensorEntityDescription(
key=gw_vars.DATA_SLAVE_CH_ACTIVE,
friendly_name_format="Boiler Central Heating {}",
device_class=BinarySensorDeviceClass.HEAT,
),
),
(
[gw_vars.BOILER, gw_vars.THERMOSTAT],
OpenThermBinarySensorEntityDescription(
key=gw_vars.DATA_SLAVE_DHW_ACTIVE,
friendly_name_format="Boiler Hot Water {}",
device_class=BinarySensorDeviceClass.HEAT,
),
),
(
[gw_vars.BOILER, gw_vars.THERMOSTAT],
OpenThermBinarySensorEntityDescription(
key=gw_vars.DATA_SLAVE_FLAME_ON,
friendly_name_format="Boiler Flame {}",
device_class=BinarySensorDeviceClass.HEAT,
),
),
(
[gw_vars.BOILER, gw_vars.THERMOSTAT],
OpenThermBinarySensorEntityDescription(
key=gw_vars.DATA_SLAVE_COOLING_ACTIVE,
friendly_name_format="Boiler Cooling {}",
device_class=BinarySensorDeviceClass.COLD,
),
),
(
[gw_vars.BOILER, gw_vars.THERMOSTAT],
OpenThermBinarySensorEntityDescription(
key=gw_vars.DATA_SLAVE_CH2_ACTIVE,
friendly_name_format="Boiler Central Heating 2 {}",
device_class=BinarySensorDeviceClass.HEAT,
),
),
(
[gw_vars.BOILER, gw_vars.THERMOSTAT],
OpenThermBinarySensorEntityDescription(
key=gw_vars.DATA_SLAVE_DIAG_IND,
friendly_name_format="Boiler Diagnostics {}",
device_class=BinarySensorDeviceClass.PROBLEM,
),
),
(
[gw_vars.BOILER, gw_vars.THERMOSTAT],
OpenThermBinarySensorEntityDescription(
key=gw_vars.DATA_SLAVE_DHW_PRESENT,
friendly_name_format="Boiler Hot Water Present {}",
),
),
(
[gw_vars.BOILER, gw_vars.THERMOSTAT],
OpenThermBinarySensorEntityDescription(
key=gw_vars.DATA_SLAVE_CONTROL_TYPE,
friendly_name_format="Boiler Control Type {}",
),
),
(
[gw_vars.BOILER, gw_vars.THERMOSTAT],
OpenThermBinarySensorEntityDescription(
key=gw_vars.DATA_SLAVE_COOLING_SUPPORTED,
friendly_name_format="Boiler Cooling Support {}",
),
),
(
[gw_vars.BOILER, gw_vars.THERMOSTAT],
OpenThermBinarySensorEntityDescription(
key=gw_vars.DATA_SLAVE_DHW_CONFIG,
friendly_name_format="Boiler Hot Water Configuration {}",
),
),
(
[gw_vars.BOILER, gw_vars.THERMOSTAT],
OpenThermBinarySensorEntityDescription(
key=gw_vars.DATA_SLAVE_MASTER_LOW_OFF_PUMP,
friendly_name_format="Boiler Pump Commands Support {}",
),
),
(
[gw_vars.BOILER, gw_vars.THERMOSTAT],
OpenThermBinarySensorEntityDescription(
key=gw_vars.DATA_SLAVE_CH2_PRESENT,
friendly_name_format="Boiler Central Heating 2 Present {}",
),
),
(
[gw_vars.BOILER, gw_vars.THERMOSTAT],
OpenThermBinarySensorEntityDescription(
key=gw_vars.DATA_SLAVE_SERVICE_REQ,
friendly_name_format="Boiler Service Required {}",
device_class=BinarySensorDeviceClass.PROBLEM,
),
),
(
[gw_vars.BOILER, gw_vars.THERMOSTAT],
OpenThermBinarySensorEntityDescription(
key=gw_vars.DATA_SLAVE_REMOTE_RESET,
friendly_name_format="Boiler Remote Reset Support {}",
),
),
(
[gw_vars.BOILER, gw_vars.THERMOSTAT],
OpenThermBinarySensorEntityDescription(
key=gw_vars.DATA_SLAVE_LOW_WATER_PRESS,
friendly_name_format="Boiler Low Water Pressure {}",
device_class=BinarySensorDeviceClass.PROBLEM,
),
),
(
[gw_vars.BOILER, gw_vars.THERMOSTAT],
OpenThermBinarySensorEntityDescription(
key=gw_vars.DATA_SLAVE_GAS_FAULT,
friendly_name_format="Boiler Gas Fault {}",
device_class=BinarySensorDeviceClass.PROBLEM,
),
),
(
[gw_vars.BOILER, gw_vars.THERMOSTAT],
OpenThermBinarySensorEntityDescription(
key=gw_vars.DATA_SLAVE_AIR_PRESS_FAULT,
friendly_name_format="Boiler Air Pressure Fault {}",
device_class=BinarySensorDeviceClass.PROBLEM,
),
),
(
[gw_vars.BOILER, gw_vars.THERMOSTAT],
OpenThermBinarySensorEntityDescription(
key=gw_vars.DATA_SLAVE_WATER_OVERTEMP,
friendly_name_format="Boiler Water Overtemperature {}",
device_class=BinarySensorDeviceClass.PROBLEM,
),
),
(
[gw_vars.BOILER, gw_vars.THERMOSTAT],
OpenThermBinarySensorEntityDescription(
key=gw_vars.DATA_REMOTE_TRANSFER_DHW,
friendly_name_format="Remote Hot Water Setpoint Transfer Support {}",
),
),
(
[gw_vars.BOILER, gw_vars.THERMOSTAT],
OpenThermBinarySensorEntityDescription(
key=gw_vars.DATA_REMOTE_TRANSFER_MAX_CH,
friendly_name_format="Remote Maximum Central Heating Setpoint Write Support {}",
),
),
(
[gw_vars.BOILER, gw_vars.THERMOSTAT],
OpenThermBinarySensorEntityDescription(
key=gw_vars.DATA_REMOTE_RW_DHW,
friendly_name_format="Remote Hot Water Setpoint Write Support {}",
),
),
(
[gw_vars.BOILER, gw_vars.THERMOSTAT],
OpenThermBinarySensorEntityDescription(
key=gw_vars.DATA_REMOTE_RW_MAX_CH,
friendly_name_format="Remote Central Heating Setpoint Write Support {}",
),
),
(
[gw_vars.BOILER, gw_vars.THERMOSTAT],
OpenThermBinarySensorEntityDescription(
key=gw_vars.DATA_ROVRD_MAN_PRIO,
friendly_name_format="Remote Override Manual Change Priority {}",
),
),
(
[gw_vars.BOILER, gw_vars.THERMOSTAT],
OpenThermBinarySensorEntityDescription(
key=gw_vars.DATA_ROVRD_AUTO_PRIO,
friendly_name_format="Remote Override Program Change Priority {}",
),
),
(
[gw_vars.OTGW],
OpenThermBinarySensorEntityDescription(
key=gw_vars.OTGW_GPIO_A_STATE,
friendly_name_format="Gateway GPIO A {}",
),
),
(
[gw_vars.OTGW],
OpenThermBinarySensorEntityDescription(
key=gw_vars.OTGW_GPIO_B_STATE,
friendly_name_format="Gateway GPIO B {}",
),
),
(
[gw_vars.OTGW],
OpenThermBinarySensorEntityDescription(
key=gw_vars.OTGW_IGNORE_TRANSITIONS,
friendly_name_format="Gateway Ignore Transitions {}",
),
),
(
[gw_vars.OTGW],
OpenThermBinarySensorEntityDescription(
key=gw_vars.OTGW_OVRD_HB,
friendly_name_format="Gateway Override High Byte {}",
),
),
)


async def async_setup_entry(
Expand All @@ -31,65 +293,35 @@
gw_dev = hass.data[DATA_OPENTHERM_GW][DATA_GATEWAYS][config_entry.data[CONF_ID]]

async_add_entities(
OpenThermBinarySensor(
gw_dev,
var,
source,
info[0],
info[1],
)
for var, info in BINARY_SENSOR_INFO.items()
for source in info[2]
OpenThermBinarySensor(gw_dev, source, description)
for sources, description in BINARY_SENSOR_INFO
for source in sources
)


class OpenThermBinarySensor(BinarySensorEntity):
class OpenThermBinarySensor(OpenThermEntity, BinarySensorEntity):
"""Represent an OpenTherm Gateway binary sensor."""

_attr_should_poll = False
_attr_entity_registry_enabled_default = False
_attr_available = False
entity_description: OpenThermBinarySensorEntityDescription

def __init__(self, gw_dev, var, source, device_class, friendly_name_format):
def __init__(
self,
gw_dev: OpenThermGatewayDevice,
source: str,
description: OpenThermBinarySensorEntityDescription,
) -> None:
"""Initialize the binary sensor."""
self.entity_id = async_generate_entity_id(
ENTITY_ID_FORMAT, f"{var}_{source}_{gw_dev.gw_id}", hass=gw_dev.hass
)
self._gateway = gw_dev
self._var = var
self._source = source
self._attr_device_class = device_class
if TRANSLATE_SOURCE[source] is not None:
friendly_name_format = (
f"{friendly_name_format} ({TRANSLATE_SOURCE[source]})"
)
self._attr_name = friendly_name_format.format(gw_dev.name)
self._unsub_updates = None
self._attr_unique_id = f"{gw_dev.gw_id}-{source}-{var}"
self._attr_device_info = DeviceInfo(
identifiers={(DOMAIN, gw_dev.gw_id)},
manufacturer="Schelte Bron",
model="OpenTherm Gateway",
name=gw_dev.name,
sw_version=gw_dev.gw_version,
ENTITY_ID_FORMAT,
f"{description.key}_{source}_{gw_dev.gw_id}",
hass=gw_dev.hass,
)

async def async_added_to_hass(self) -> None:
"""Subscribe to updates from the component."""
_LOGGER.debug("Added OpenTherm Gateway binary sensor %s", self._attr_name)
self._unsub_updates = async_dispatcher_connect(
self.hass, self._gateway.update_signal, self.receive_report
)

async def async_will_remove_from_hass(self) -> None:
"""Unsubscribe from updates from the component."""
_LOGGER.debug("Removing OpenTherm Gateway binary sensor %s", self._attr_name)
self._unsub_updates()
super().__init__(gw_dev, source, description)

@callback
def receive_report(self, status):
def receive_report(self, status: dict[str, dict]) -> None:
"""Handle status updates from the component."""
self._attr_available = self._gateway.connected
state = status[self._source].get(self._var)
state = status[self._source].get(self.entity_description.key)

Check warning on line 325 in homeassistant/components/opentherm_gw/binary_sensor.py

View check run for this annotation

Codecov / codecov/patch

homeassistant/components/opentherm_gw/binary_sensor.py#L325

Added line #L325 was not covered by tests
self._attr_is_on = None if state is None else bool(state)
self.async_write_ha_state()
Loading