diff --git a/.coveragerc b/.coveragerc index d020a59c712..73814938619 100644 --- a/.coveragerc +++ b/.coveragerc @@ -1197,6 +1197,7 @@ omit = homeassistant/components/tado/water_heater.py homeassistant/components/tank_utility/sensor.py homeassistant/components/tankerkoenig/__init__.py + homeassistant/components/tankerkoenig/binary_sensor.py homeassistant/components/tankerkoenig/const.py homeassistant/components/tankerkoenig/sensor.py homeassistant/components/tapsaff/binary_sensor.py diff --git a/homeassistant/components/tankerkoenig/__init__.py b/homeassistant/components/tankerkoenig/__init__.py index 3051d70b06d..08520c8f5cc 100644 --- a/homeassistant/components/tankerkoenig/__init__.py +++ b/homeassistant/components/tankerkoenig/__init__.py @@ -75,7 +75,7 @@ CONFIG_SCHEMA = vol.Schema( extra=vol.ALLOW_EXTRA, ) -PLATFORMS = [Platform.SENSOR] +PLATFORMS = [Platform.BINARY_SENSOR, Platform.SENSOR] async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool: @@ -170,14 +170,14 @@ class TankerkoenigDataUpdateCoordinator(DataUpdateCoordinator): update_interval=timedelta(minutes=update_interval), ) - self._api_key = entry.data[CONF_API_KEY] - self._selected_stations = entry.data[CONF_STATIONS] + self._api_key: str = entry.data[CONF_API_KEY] + self._selected_stations: list[str] = entry.data[CONF_STATIONS] self._hass = hass self.stations: dict[str, dict] = {} - self.fuel_types = entry.data[CONF_FUEL_TYPES] - self.show_on_map = entry.options[CONF_SHOW_ON_MAP] + self.fuel_types: list[str] = entry.data[CONF_FUEL_TYPES] + self.show_on_map: bool = entry.options[CONF_SHOW_ON_MAP] - def setup(self): + def setup(self) -> bool: """Set up the tankerkoenig API.""" for station_id in self._selected_stations: try: @@ -205,7 +205,7 @@ class TankerkoenigDataUpdateCoordinator(DataUpdateCoordinator): ) return True - async def _async_update_data(self): + async def _async_update_data(self) -> dict: """Get the latest data from tankerkoenig.de.""" _LOGGER.debug("Fetching new data from tankerkoenig.de") station_ids = list(self.stations) diff --git a/homeassistant/components/tankerkoenig/binary_sensor.py b/homeassistant/components/tankerkoenig/binary_sensor.py new file mode 100644 index 00000000000..4b58ea26703 --- /dev/null +++ b/homeassistant/components/tankerkoenig/binary_sensor.py @@ -0,0 +1,78 @@ +"""Tankerkoenig binary sensor integration.""" +from __future__ import annotations + +import logging + +from homeassistant.components.binary_sensor import ( + BinarySensorDeviceClass, + BinarySensorEntity, +) +from homeassistant.config_entries import ConfigEntry +from homeassistant.const import ATTR_ID, ATTR_LATITUDE, ATTR_LONGITUDE +from homeassistant.core import HomeAssistant +from homeassistant.helpers.entity import DeviceInfo +from homeassistant.helpers.entity_platform import AddEntitiesCallback +from homeassistant.helpers.update_coordinator import CoordinatorEntity + +from . import TankerkoenigDataUpdateCoordinator +from .const import DOMAIN + +_LOGGER = logging.getLogger(__name__) + + +async def async_setup_entry( + hass: HomeAssistant, entry: ConfigEntry, async_add_entities: AddEntitiesCallback +) -> None: + """Set up the tankerkoenig binary sensors.""" + + coordinator: TankerkoenigDataUpdateCoordinator = hass.data[DOMAIN][entry.unique_id] + + stations = coordinator.stations.values() + entities = [] + for station in stations: + sensor = StationOpenBinarySensorEntity( + station, + coordinator, + coordinator.show_on_map, + ) + entities.append(sensor) + _LOGGER.debug("Added sensors %s", entities) + + async_add_entities(entities) + + +class StationOpenBinarySensorEntity(CoordinatorEntity, BinarySensorEntity): + """Shows if a station is open or closed.""" + + _attr_device_class = BinarySensorDeviceClass.DOOR + + def __init__( + self, + station: dict, + coordinator: TankerkoenigDataUpdateCoordinator, + show_on_map: bool, + ) -> None: + """Initialize the sensor.""" + super().__init__(coordinator) + self._station_id = station["id"] + self._attr_name = ( + f"{station['brand']} {station['street']} {station['houseNumber']} status" + ) + self._attr_unique_id = f"{station['id']}_status" + self._attr_device_info = DeviceInfo( + identifiers={(ATTR_ID, station["id"])}, + name=f"{station['brand']} {station['street']} {station['houseNumber']}", + model=station["brand"], + configuration_url="https://www.tankerkoenig.de", + ) + if show_on_map: + self._attr_extra_state_attributes = { + ATTR_LATITUDE: station["lat"], + ATTR_LONGITUDE: station["lng"], + } + + @property + def is_on(self) -> bool | None: + """Return true if the station is open.""" + data = self.coordinator.data[self._station_id] + return data is not None and "status" in data diff --git a/homeassistant/components/tankerkoenig/const.py b/homeassistant/components/tankerkoenig/const.py index 5c4746bd3a1..c2a1dba9b6a 100644 --- a/homeassistant/components/tankerkoenig/const.py +++ b/homeassistant/components/tankerkoenig/const.py @@ -10,3 +10,12 @@ DEFAULT_RADIUS = 2 DEFAULT_SCAN_INTERVAL = 30 FUEL_TYPES = {"e5": "Super", "e10": "Super E10", "diesel": "Diesel"} + +ATTR_BRAND = "brand" +ATTR_CITY = "city" +ATTR_FUEL_TYPE = "fuel_type" +ATTR_HOUSE_NUMBER = "house_number" +ATTR_POSTCODE = "postcode" +ATTR_STATION_NAME = "station_name" +ATTR_STREET = "street" +ATTRIBUTION = "Data provided by https://www.tankerkoenig.de" diff --git a/homeassistant/components/tankerkoenig/sensor.py b/homeassistant/components/tankerkoenig/sensor.py index e22a7c1c82e..bbaeda44fd7 100644 --- a/homeassistant/components/tankerkoenig/sensor.py +++ b/homeassistant/components/tankerkoenig/sensor.py @@ -18,22 +18,21 @@ from homeassistant.helpers.entity_platform import AddEntitiesCallback from homeassistant.helpers.update_coordinator import CoordinatorEntity from . import TankerkoenigDataUpdateCoordinator -from .const import DOMAIN, FUEL_TYPES +from .const import ( + ATTR_BRAND, + ATTR_CITY, + ATTR_FUEL_TYPE, + ATTR_HOUSE_NUMBER, + ATTR_POSTCODE, + ATTR_STATION_NAME, + ATTR_STREET, + ATTRIBUTION, + DOMAIN, + FUEL_TYPES, +) _LOGGER = logging.getLogger(__name__) -ATTR_BRAND = "brand" -ATTR_CITY = "city" -ATTR_FUEL_TYPE = "fuel_type" -ATTR_HOUSE_NUMBER = "house_number" -ATTR_IS_OPEN = "is_open" -ATTR_POSTCODE = "postcode" -ATTR_STATION_NAME = "station_name" -ATTR_STREET = "street" -ATTRIBUTION = "Data provided by https://creativecommons.tankerkoenig.de" - -ICON = "mdi:gas-station" - async def async_setup_entry( hass: HomeAssistant, entry: ConfigEntry, async_add_entities: AddEntitiesCallback @@ -67,79 +66,41 @@ class FuelPriceSensor(CoordinatorEntity, SensorEntity): """Contains prices for fuel in a given station.""" _attr_state_class = STATE_CLASS_MEASUREMENT + _attr_icon = "mdi:gas-station" def __init__(self, fuel_type, station, coordinator, show_on_map): """Initialize the sensor.""" super().__init__(coordinator) - self._station = station self._station_id = station["id"] self._fuel_type = fuel_type - self._latitude = station["lat"] - self._longitude = station["lng"] - self._city = station["place"] - self._house_number = station["houseNumber"] - self._postcode = station["postCode"] - self._street = station["street"] - self._brand = self._station["brand"] - self._price = station[fuel_type] - self._show_on_map = show_on_map + self._attr_name = f"{station['brand']} {station['street']} {station['houseNumber']} {FUEL_TYPES[fuel_type]}" + self._attr_native_unit_of_measurement = CURRENCY_EURO + self._attr_unique_id = f"{station['id']}_{fuel_type}" + self._attr_device_info = DeviceInfo( + identifiers={(ATTR_ID, station["id"])}, + name=f"{station['brand']} {station['street']} {station['houseNumber']}", + model=station["brand"], + configuration_url="https://www.tankerkoenig.de", + ) - @property - def name(self): - """Return the name of the sensor.""" - return f"{self._brand} {self._street} {self._house_number} {FUEL_TYPES[self._fuel_type]}" + attrs = { + ATTR_ATTRIBUTION: ATTRIBUTION, + ATTR_BRAND: station["brand"], + ATTR_FUEL_TYPE: fuel_type, + ATTR_STATION_NAME: station["name"], + ATTR_STREET: station["street"], + ATTR_HOUSE_NUMBER: station["houseNumber"], + ATTR_POSTCODE: station["postCode"], + ATTR_CITY: station["place"], + } - @property - def icon(self): - """Icon to use in the frontend.""" - return ICON - - @property - def native_unit_of_measurement(self): - """Return unit of measurement.""" - return CURRENCY_EURO + if show_on_map: + attrs[ATTR_LATITUDE] = station["lat"] + attrs[ATTR_LONGITUDE] = station["lng"] + self._attr_extra_state_attributes = attrs @property def native_value(self): """Return the state of the device.""" # key Fuel_type is not available when the fuel station is closed, use "get" instead of "[]" to avoid exceptions return self.coordinator.data[self._station_id].get(self._fuel_type) - - @property - def unique_id(self) -> str: - """Return a unique identifier for this entity.""" - return f"{self._station_id}_{self._fuel_type}" - - @property - def device_info(self) -> DeviceInfo | None: - """Return device info.""" - return DeviceInfo( - identifiers={(ATTR_ID, self._station_id)}, - name=f"{self._brand} {self._street} {self._house_number}", - model=self._brand, - configuration_url="https://www.tankerkoenig.de", - ) - - @property - def extra_state_attributes(self): - """Return the attributes of the device.""" - data = self.coordinator.data[self._station_id] - - attrs = { - ATTR_ATTRIBUTION: ATTRIBUTION, - ATTR_BRAND: self._station["brand"], - ATTR_FUEL_TYPE: self._fuel_type, - ATTR_STATION_NAME: self._station["name"], - ATTR_STREET: self._street, - ATTR_HOUSE_NUMBER: self._house_number, - ATTR_POSTCODE: self._postcode, - ATTR_CITY: self._city, - } - - if self._show_on_map: - attrs[ATTR_LATITUDE] = self._latitude - attrs[ATTR_LONGITUDE] = self._longitude - - if data is not None and "status" in data: - attrs[ATTR_IS_OPEN] = data["status"] == "open" - return attrs