164 lines
5.0 KiB
Python
164 lines
5.0 KiB
Python
"""Tankerkoenig sensor integration."""
|
|
|
|
import logging
|
|
|
|
from homeassistant.const import ATTR_ATTRIBUTION, ATTR_LATITUDE, ATTR_LONGITUDE
|
|
from homeassistant.helpers.entity import Entity
|
|
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed
|
|
|
|
from .const import DOMAIN, NAME
|
|
|
|
_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_platform(hass, config, async_add_entities, discovery_info=None):
|
|
"""Set up the tankerkoenig sensors."""
|
|
|
|
if discovery_info is None:
|
|
return
|
|
|
|
tankerkoenig = hass.data[DOMAIN]
|
|
|
|
async def async_update_data():
|
|
"""Fetch data from API endpoint."""
|
|
try:
|
|
return await tankerkoenig.fetch_data()
|
|
except LookupError:
|
|
raise UpdateFailed("Failed to fetch data")
|
|
|
|
coordinator = DataUpdateCoordinator(
|
|
hass,
|
|
_LOGGER,
|
|
name=NAME,
|
|
update_method=async_update_data,
|
|
update_interval=tankerkoenig.update_interval,
|
|
)
|
|
|
|
# Fetch initial data so we have data when entities subscribe
|
|
await coordinator.async_refresh()
|
|
|
|
stations = discovery_info.values()
|
|
entities = []
|
|
for station in stations:
|
|
for fuel in tankerkoenig.fuel_types:
|
|
if fuel not in station:
|
|
_LOGGER.warning(
|
|
"Station %s does not offer %s fuel", station["id"], fuel
|
|
)
|
|
continue
|
|
sensor = FuelPriceSensor(
|
|
fuel,
|
|
station,
|
|
coordinator,
|
|
f"{NAME}_{station['name']}_{fuel}",
|
|
tankerkoenig.show_on_map,
|
|
)
|
|
entities.append(sensor)
|
|
_LOGGER.debug("Added sensors %s", entities)
|
|
|
|
async_add_entities(entities)
|
|
|
|
|
|
class FuelPriceSensor(Entity):
|
|
"""Contains prices for fuel in a given station."""
|
|
|
|
def __init__(self, fuel_type, station, coordinator, name, show_on_map):
|
|
"""Initialize the sensor."""
|
|
self._station = station
|
|
self._station_id = station["id"]
|
|
self._fuel_type = fuel_type
|
|
self._coordinator = coordinator
|
|
self._name = name
|
|
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._price = station[fuel_type]
|
|
self._show_on_map = show_on_map
|
|
|
|
@property
|
|
def name(self):
|
|
"""Return the name of the sensor."""
|
|
return self._name
|
|
|
|
@property
|
|
def icon(self):
|
|
"""Icon to use in the frontend."""
|
|
return ICON
|
|
|
|
@property
|
|
def unit_of_measurement(self):
|
|
"""Return unit of measurement."""
|
|
return "€"
|
|
|
|
@property
|
|
def should_poll(self):
|
|
"""No need to poll. Coordinator notifies of updates."""
|
|
return False
|
|
|
|
@property
|
|
def state(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_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
|
|
|
|
@property
|
|
def available(self):
|
|
"""Return if entity is available."""
|
|
return self._coordinator.last_update_success
|
|
|
|
async def async_added_to_hass(self):
|
|
"""When entity is added to hass."""
|
|
self._coordinator.async_add_listener(self.async_write_ha_state)
|
|
|
|
async def async_will_remove_from_hass(self):
|
|
"""When entity will be removed from hass."""
|
|
self._coordinator.async_remove_listener(self.async_write_ha_state)
|
|
|
|
async def async_update(self):
|
|
"""Update the entity."""
|
|
await self._coordinator.async_request_refresh()
|