diff --git a/.coveragerc b/.coveragerc index c0425c1bb81..ab1e7642836 100644 --- a/.coveragerc +++ b/.coveragerc @@ -759,6 +759,8 @@ omit = homeassistant/components/openexchangerates/sensor.py homeassistant/components/opengarage/__init__.py homeassistant/components/opengarage/cover.py + homeassistant/components/opengarage/entity.py + homeassistant/components/opengarage/sensor.py homeassistant/components/openhome/__init__.py homeassistant/components/openhome/media_player.py homeassistant/components/openhome/const.py diff --git a/homeassistant/components/opengarage/__init__.py b/homeassistant/components/opengarage/__init__.py index d64a608a3ef..4f890d07f9a 100644 --- a/homeassistant/components/opengarage/__init__.py +++ b/homeassistant/components/opengarage/__init__.py @@ -16,7 +16,7 @@ from .const import CONF_DEVICE_KEY, DOMAIN _LOGGER = logging.getLogger(__name__) -PLATFORMS = ["cover"] +PLATFORMS = ["cover", "sensor"] async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: diff --git a/homeassistant/components/opengarage/const.py b/homeassistant/components/opengarage/const.py index 7cf9287e182..93f3179b1a9 100644 --- a/homeassistant/components/opengarage/const.py +++ b/homeassistant/components/opengarage/const.py @@ -1,9 +1,5 @@ """Constants for the OpenGarage integration.""" -ATTR_DISTANCE_SENSOR = "distance_sensor" -ATTR_DOOR_STATE = "door_state" -ATTR_SIGNAL_STRENGTH = "wifi_signal" - CONF_DEVICE_KEY = "device_key" DEFAULT_NAME = "OpenGarage" diff --git a/homeassistant/components/opengarage/cover.py b/homeassistant/components/opengarage/cover.py index 6952e4bff24..8737a0499fb 100644 --- a/homeassistant/components/opengarage/cover.py +++ b/homeassistant/components/opengarage/cover.py @@ -25,17 +25,9 @@ from homeassistant.const import ( ) from homeassistant.core import callback import homeassistant.helpers.config_validation as cv -from homeassistant.helpers.entity import DeviceInfo -from homeassistant.helpers.update_coordinator import CoordinatorEntity -from .const import ( - ATTR_DISTANCE_SENSOR, - ATTR_DOOR_STATE, - ATTR_SIGNAL_STRENGTH, - CONF_DEVICE_KEY, - DEFAULT_PORT, - DOMAIN, -) +from .const import CONF_DEVICE_KEY, DEFAULT_PORT, DOMAIN +from .entity import OpenGarageEntity _LOGGER = logging.getLogger(__name__) @@ -81,7 +73,7 @@ async def async_setup_entry(hass, entry, async_add_entities): ) -class OpenGarageCover(CoordinatorEntity, CoverEntity): +class OpenGarageCover(OpenGarageEntity, CoverEntity): """Representation of a OpenGarage cover.""" _attr_device_class = DEVICE_CLASS_GARAGE @@ -89,14 +81,10 @@ class OpenGarageCover(CoordinatorEntity, CoverEntity): def __init__(self, open_garage_data_coordinator, device_id): """Initialize the cover.""" - super().__init__(open_garage_data_coordinator) - self._state = None self._state_before_move = None - self._attr_extra_state_attributes = {} - self._attr_unique_id = self._device_id = device_id - self._device_name = None - self._update_attr() + + super().__init__(open_garage_data_coordinator, device_id) @property def is_closed(self): @@ -138,12 +126,9 @@ class OpenGarageCover(CoordinatorEntity, CoverEntity): @callback def _update_attr(self) -> None: """Update the state and attributes.""" - if (status := self.coordinator.data) is None: - _LOGGER.error("Unable to connect to OpenGarage device") - self._attr_available = False - return + status = self.coordinator.data - self._device_name = self._attr_name = status["name"] + self._attr_name = status["name"] state = STATES_MAP.get(status.get("door")) if self._state_before_move is not None: if self._state_before_move != state: @@ -152,20 +137,6 @@ class OpenGarageCover(CoordinatorEntity, CoverEntity): else: self._state = state - _LOGGER.debug("%s status: %s", self.name, self._state) - if status.get("rssi") is not None: - self._attr_extra_state_attributes[ATTR_SIGNAL_STRENGTH] = status.get("rssi") - if status.get("dist") is not None: - self._attr_extra_state_attributes[ATTR_DISTANCE_SENSOR] = status.get("dist") - if self._state is not None: - self._attr_extra_state_attributes[ATTR_DOOR_STATE] = self._state - - @callback - def _handle_coordinator_update(self) -> None: - """Handle updated data from the coordinator.""" - self._update_attr() - self.async_write_ha_state() - async def _push_button(self): """Send commands to API.""" result = await self.coordinator.open_garage_connection.push_button() @@ -181,13 +152,3 @@ class OpenGarageCover(CoordinatorEntity, CoverEntity): self._state = self._state_before_move self._state_before_move = None - - @property - def device_info(self): - """Return the device_info of the device.""" - device_info = DeviceInfo( - identifiers={(DOMAIN, self._device_id)}, - name=self._device_name, - manufacturer="Open Garage", - ) - return device_info diff --git a/homeassistant/components/opengarage/entity.py b/homeassistant/components/opengarage/entity.py new file mode 100644 index 00000000000..7c6d169935a --- /dev/null +++ b/homeassistant/components/opengarage/entity.py @@ -0,0 +1,43 @@ +"""Entity for the opengarage.io component.""" + +from homeassistant.components.opengarage import DOMAIN +from homeassistant.core import callback +from homeassistant.helpers.entity import DeviceInfo +from homeassistant.helpers.update_coordinator import CoordinatorEntity + + +class OpenGarageEntity(CoordinatorEntity): + """Representation of a OpenGarage entity.""" + + def __init__(self, open_garage_data_coordinator, device_id, description=None): + """Initialize the entity.""" + super().__init__(open_garage_data_coordinator) + + if description is not None: + self.entity_description = description + self._attr_unique_id = f"{device_id}_{description.key}" + else: + self._attr_unique_id = device_id + + self._device_id = device_id + self._update_attr() + + @callback + def _update_attr(self) -> None: + """Update the state and attributes.""" + + @callback + def _handle_coordinator_update(self) -> None: + """Handle updated data from the coordinator.""" + self._update_attr() + self.async_write_ha_state() + + @property + def device_info(self): + """Return the device_info of the device.""" + device_info = DeviceInfo( + identifiers={(DOMAIN, self._device_id)}, + name=self.coordinator.data["name"], + manufacturer="Open Garage", + ) + return device_info diff --git a/homeassistant/components/opengarage/sensor.py b/homeassistant/components/opengarage/sensor.py new file mode 100644 index 00000000000..e6b6a73c0c6 --- /dev/null +++ b/homeassistant/components/opengarage/sensor.py @@ -0,0 +1,65 @@ +"""Platform for the opengarage.io sensor component.""" +from __future__ import annotations + +import logging + +from homeassistant.components.sensor import ( + STATE_CLASS_MEASUREMENT, + SensorEntity, + SensorEntityDescription, +) +from homeassistant.const import ( + DEVICE_CLASS_SIGNAL_STRENGTH, + ENTITY_CATEGORY_DIAGNOSTIC, + LENGTH_CENTIMETERS, + SIGNAL_STRENGTH_DECIBELS, +) +from homeassistant.core import callback + +from .const import DOMAIN +from .entity import OpenGarageEntity + +_LOGGER = logging.getLogger(__name__) + +SENSOR_TYPES: tuple[SensorEntityDescription, ...] = ( + SensorEntityDescription( + key="dist", + native_unit_of_measurement=LENGTH_CENTIMETERS, + state_class=STATE_CLASS_MEASUREMENT, + ), + SensorEntityDescription( + key="rssi", + device_class=DEVICE_CLASS_SIGNAL_STRENGTH, + entity_category=ENTITY_CATEGORY_DIAGNOSTIC, + entity_registry_enabled_default=False, + native_unit_of_measurement=SIGNAL_STRENGTH_DECIBELS, + state_class=STATE_CLASS_MEASUREMENT, + ), +) + + +async def async_setup_entry(hass, entry, async_add_entities): + """Set up the OpenGarage sensors.""" + open_garage_data_coordinator = hass.data[DOMAIN][entry.entry_id] + async_add_entities( + [ + OpenGarageSensor( + open_garage_data_coordinator, + entry.unique_id, + description, + ) + for description in SENSOR_TYPES + ], + ) + + +class OpenGarageSensor(OpenGarageEntity, SensorEntity): + """Representation of a OpenGarage sensor.""" + + @callback + def _update_attr(self) -> None: + """Handle updated data from the coordinator.""" + self._attr_name = ( + f'{self.coordinator.data["name"]} {self.entity_description.key}' + ) + self._attr_native_value = self.coordinator.data.get(self.entity_description.key)