diff --git a/homeassistant/components/opentherm_gw/__init__.py b/homeassistant/components/opentherm_gw/__init__.py index 643f80ae8f9..3a1255e3697 100644 --- a/homeassistant/components/opentherm_gw/__init__.py +++ b/homeassistant/components/opentherm_gw/__init__.py @@ -1,4 +1,5 @@ """Support for OpenTherm Gateway devices.""" +import asyncio import logging from datetime import datetime, date @@ -344,6 +345,18 @@ def register_services(hass): ) +async def async_unload_entry(hass, entry): + """Cleanup and disconnect from gateway.""" + await asyncio.gather( + hass.config_entries.async_forward_entry_unload(entry, COMP_BINARY_SENSOR), + hass.config_entries.async_forward_entry_unload(entry, COMP_CLIMATE), + hass.config_entries.async_forward_entry_unload(entry, COMP_SENSOR), + ) + gateway = hass.data[DATA_OPENTHERM_GW][DATA_GATEWAYS][entry.data[CONF_ID]] + await gateway.cleanup() + return True + + class OpenThermGatewayDevice: """OpenTherm Gateway device class.""" @@ -358,18 +371,21 @@ class OpenThermGatewayDevice: self.update_signal = f"{DATA_OPENTHERM_GW}_{self.gw_id}_update" self.options_update_signal = f"{DATA_OPENTHERM_GW}_{self.gw_id}_options_update" self.gateway = pyotgw.pyotgw() + self.gw_version = None + + async def cleanup(self, event=None): + """Reset overrides on the gateway.""" + await self.gateway.set_control_setpoint(0) + await self.gateway.set_max_relative_mod("-") + await self.gateway.disconnect() async def connect_and_subscribe(self): """Connect to serial device and subscribe report handler.""" - await self.gateway.connect(self.hass.loop, self.device_path) + self.status = await self.gateway.connect(self.hass.loop, self.device_path) _LOGGER.debug("Connected to OpenTherm Gateway at %s", self.device_path) + self.gw_version = self.status.get(gw_vars.OTGW_BUILD) - async def cleanup(event): - """Reset overrides on the gateway.""" - await self.gateway.set_control_setpoint(0) - await self.gateway.set_max_relative_mod("-") - - self.hass.bus.async_listen(EVENT_HOMEASSISTANT_STOP, cleanup) + self.hass.bus.async_listen(EVENT_HOMEASSISTANT_STOP, self.cleanup) async def handle_report(status): """Handle reports from the OpenTherm Gateway.""" diff --git a/homeassistant/components/opentherm_gw/binary_sensor.py b/homeassistant/components/opentherm_gw/binary_sensor.py index 36867feda61..39fd78f5fe8 100644 --- a/homeassistant/components/opentherm_gw/binary_sensor.py +++ b/homeassistant/components/opentherm_gw/binary_sensor.py @@ -7,6 +7,7 @@ from homeassistant.core import callback from homeassistant.helpers.dispatcher import async_dispatcher_connect from homeassistant.helpers.entity import async_generate_entity_id +from . import DOMAIN from .const import BINARY_SENSOR_INFO, DATA_GATEWAYS, DATA_OPENTHERM_GW @@ -44,14 +45,27 @@ class OpenThermBinarySensor(BinarySensorDevice): self._state = None self._device_class = device_class self._friendly_name = friendly_name_format.format(gw_dev.name) + self._unsub_updates = None async def async_added_to_hass(self): """Subscribe to updates from the component.""" _LOGGER.debug("Added OpenTherm Gateway binary sensor %s", self._friendly_name) - async_dispatcher_connect( + self._unsub_updates = async_dispatcher_connect( self.hass, self._gateway.update_signal, self.receive_report ) + async def async_will_remove_from_hass(self): + """Unsubscribe from updates from the component.""" + _LOGGER.debug( + "Removing OpenTherm Gateway binary sensor %s", self._friendly_name + ) + self._unsub_updates() + + @property + def entity_registry_enabled_default(self): + """Disable binary_sensors by default.""" + return False + @callback def receive_report(self, status): """Handle status updates from the component.""" @@ -63,6 +77,22 @@ class OpenThermBinarySensor(BinarySensorDevice): """Return the friendly name.""" return self._friendly_name + @property + def device_info(self): + """Return device info.""" + return { + "identifiers": {(DOMAIN, self._gateway.gw_id)}, + "name": self._gateway.name, + "manufacturer": "Schelte Bron", + "model": "OpenTherm Gateway", + "sw_version": self._gateway.gw_version, + } + + @property + def unique_id(self): + """Return a unique ID.""" + return f"{self._gateway.gw_id}-{self._var}" + @property def is_on(self): """Return true if the binary sensor is on.""" diff --git a/homeassistant/components/opentherm_gw/climate.py b/homeassistant/components/opentherm_gw/climate.py index 28a0ae98270..8c21c6560c1 100644 --- a/homeassistant/components/opentherm_gw/climate.py +++ b/homeassistant/components/opentherm_gw/climate.py @@ -3,7 +3,7 @@ import logging from pyotgw import vars as gw_vars -from homeassistant.components.climate import ClimateDevice +from homeassistant.components.climate import ClimateDevice, ENTITY_ID_FORMAT from homeassistant.components.climate.const import ( CURRENT_HVAC_COOL, CURRENT_HVAC_HEAT, @@ -25,7 +25,9 @@ from homeassistant.const import ( ) from homeassistant.core import callback from homeassistant.helpers.dispatcher import async_dispatcher_connect +from homeassistant.helpers.entity import async_generate_entity_id +from . import DOMAIN from .const import CONF_FLOOR_TEMP, CONF_PRECISION, DATA_GATEWAYS, DATA_OPENTHERM_GW @@ -56,6 +58,9 @@ class OpenThermClimate(ClimateDevice): def __init__(self, gw_dev, options): """Initialize the device.""" self._gateway = gw_dev + self.entity_id = async_generate_entity_id( + ENTITY_ID_FORMAT, gw_dev.gw_id, hass=gw_dev.hass + ) self.friendly_name = gw_dev.name self.floor_temp = options.get(CONF_FLOOR_TEMP, DEFAULT_FLOOR_TEMP) self.temp_precision = options.get(CONF_PRECISION, DEFAULT_PRECISION) @@ -68,6 +73,8 @@ class OpenThermClimate(ClimateDevice): self._away_mode_b = None self._away_state_a = False self._away_state_b = False + self._unsub_options = None + self._unsub_updates = None @callback def update_options(self, entry): @@ -79,13 +86,19 @@ class OpenThermClimate(ClimateDevice): async def async_added_to_hass(self): """Connect to the OpenTherm Gateway device.""" _LOGGER.debug("Added OpenTherm Gateway climate device %s", self.friendly_name) - async_dispatcher_connect( + self._unsub_updates = async_dispatcher_connect( self.hass, self._gateway.update_signal, self.receive_report ) - async_dispatcher_connect( + self._unsub_options = async_dispatcher_connect( self.hass, self._gateway.options_update_signal, self.update_options ) + async def async_will_remove_from_hass(self): + """Unsubscribe from updates from the component.""" + _LOGGER.debug("Removing OpenTherm Gateway climate %s", self.friendly_name) + self._unsub_options() + self._unsub_updates() + @callback def receive_report(self, status): """Receive and handle a new report from the Gateway.""" @@ -139,6 +152,17 @@ class OpenThermClimate(ClimateDevice): """Return the friendly name.""" return self.friendly_name + @property + def device_info(self): + """Return device info.""" + return { + "identifiers": {(DOMAIN, self._gateway.gw_id)}, + "name": self._gateway.name, + "manufacturer": "Schelte Bron", + "model": "OpenTherm Gateway", + "sw_version": self._gateway.gw_version, + } + @property def unique_id(self): """Return a unique ID.""" diff --git a/homeassistant/components/opentherm_gw/sensor.py b/homeassistant/components/opentherm_gw/sensor.py index c77a73cd180..cd9ce9fb095 100644 --- a/homeassistant/components/opentherm_gw/sensor.py +++ b/homeassistant/components/opentherm_gw/sensor.py @@ -7,6 +7,7 @@ from homeassistant.core import callback from homeassistant.helpers.dispatcher import async_dispatcher_connect from homeassistant.helpers.entity import Entity, async_generate_entity_id +from . import DOMAIN from .const import DATA_GATEWAYS, DATA_OPENTHERM_GW, SENSOR_INFO @@ -47,14 +48,25 @@ class OpenThermSensor(Entity): self._device_class = device_class self._unit = unit self._friendly_name = friendly_name_format.format(gw_dev.name) + self._unsub_updates = None async def async_added_to_hass(self): """Subscribe to updates from the component.""" _LOGGER.debug("Added OpenTherm Gateway sensor %s", self._friendly_name) - async_dispatcher_connect( + self._unsub_updates = async_dispatcher_connect( self.hass, self._gateway.update_signal, self.receive_report ) + async def async_will_remove_from_hass(self): + """Unsubscribe from updates from the component.""" + _LOGGER.debug("Removing OpenTherm Gateway sensor %s", self._friendly_name) + self._unsub_updates() + + @property + def entity_registry_enabled_default(self): + """Disable sensors by default.""" + return False + @callback def receive_report(self, status): """Handle status updates from the component.""" @@ -69,6 +81,22 @@ class OpenThermSensor(Entity): """Return the friendly name of the sensor.""" return self._friendly_name + @property + def device_info(self): + """Return device info.""" + return { + "identifiers": {(DOMAIN, self._gateway.gw_id)}, + "name": self._gateway.name, + "manufacturer": "Schelte Bron", + "model": "OpenTherm Gateway", + "sw_version": self._gateway.gw_version, + } + + @property + def unique_id(self): + """Return a unique ID.""" + return f"{self._gateway.gw_id}-{self._var}" + @property def device_class(self): """Return the device class."""