Skip to content

Commit

Permalink
implement #6
Browse files Browse the repository at this point in the history
  • Loading branch information
pantherale0 committed Jun 24, 2024
1 parent c6fcfae commit 0f91003
Show file tree
Hide file tree
Showing 9 changed files with 151 additions and 45 deletions.
56 changes: 45 additions & 11 deletions custom_components/fuel_prices/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
CONF_RADIUS,
CONF_TIMEOUT,
CONF_SCAN_INTERVAL,
CONF_NAME
)
from homeassistant.core import (
HomeAssistant,
Expand All @@ -25,7 +26,7 @@
)
from homeassistant.exceptions import HomeAssistantError

from .const import DOMAIN, CONF_AREAS, CONF_SOURCES
from .const import DOMAIN, CONF_AREAS, CONF_SOURCES, CONF_CHEAPEST_SENSORS, CONF_CHEAPEST_SENSORS_COUNT, CONF_CHEAPEST_SENSORS_FUEL_TYPE
from .coordinator import FuelPricesCoordinator

_LOGGER = logging.getLogger(__name__)
Expand All @@ -48,7 +49,8 @@ def _build_configured_areas(hass_areas: dict) -> list[dict]:
async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
"""Create ConfigEntry."""
_LOGGER.debug("Got request to setup entry.")
sources = entry.options.get(CONF_SOURCES, entry.data.get(CONF_SOURCES, None))
sources = entry.options.get(
CONF_SOURCES, entry.data.get(CONF_SOURCES, None))
areas = entry.options.get(CONF_AREAS, entry.data.get(CONF_AREAS, None))
timeout = entry.options.get(CONF_TIMEOUT, entry.data.get(CONF_TIMEOUT, 30))
update_interval = entry.options.get(
Expand All @@ -72,13 +74,6 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
_LOGGER.error(err)
raise CannotConnect from err

async def update_listener(hass: HomeAssistant, entry: ConfigEntry):
"""Update listener."""
await hass.data[DOMAIN][entry.entry_id].api.client_session.close()
await hass.config_entries.async_reload(entry.entry_id)

entry.async_on_unload(entry.add_update_listener(update_listener))

await hass.config_entries.async_forward_entry_setups(entry, PLATFORMS)

async def handle_fuel_lookup(call: ServiceCall) -> ServiceResponse:
Expand All @@ -97,7 +92,8 @@ async def handle_fuel_lookup(call: ServiceCall) -> ServiceResponse:
)
}
except ValueError as err:
raise HomeAssistantError("Country not available for fuel data.") from err
raise HomeAssistantError(
"Country not available for fuel data.") from err

async def handle_fuel_location_lookup(call: ServiceCall) -> ServiceResponse:
"""Handle a fuel location lookup call."""
Expand All @@ -112,7 +108,8 @@ async def handle_fuel_location_lookup(call: ServiceCall) -> ServiceResponse:
(lat, long), radius
)
except ValueError as err:
raise HomeAssistantError("Country not available for fuel data.") from err
raise HomeAssistantError(
"Country not available for fuel data.") from err

return {"items": locations, "sources": entry.data.get("sources", [])}

Expand All @@ -136,6 +133,12 @@ async def handle_force_update(call: ServiceCall):

hass.services.async_register(DOMAIN, "force_update", handle_force_update)

async def update_listener(hass: HomeAssistant, entry: ConfigEntry):
"""Update listener."""
await hass.config_entries.async_reload(entry.entry_id)

entry.async_on_unload(entry.add_update_listener(update_listener))

return True


Expand All @@ -148,6 +151,37 @@ async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:

return unload_ok

# Example migration function


async def async_migrate_entry(hass: HomeAssistant, config_entry: ConfigEntry):
"""Migrate old entry."""
_LOGGER.debug("Migrating configuration from version %s",
config_entry.version)

if config_entry.version > 1:
# This means the user has downgraded from a future version
return False

if config_entry.version == 1:

new_data = {**config_entry.data}
if config_entry.options:
new_data = {**config_entry.options}
for area in new_data[CONF_AREAS]:
_LOGGER.debug("Upgrading area definition for %s", area[CONF_NAME])
area[CONF_CHEAPEST_SENSORS] = False
area[CONF_CHEAPEST_SENSORS_COUNT] = 5
area[CONF_CHEAPEST_SENSORS_FUEL_TYPE] = ""

hass.config_entries.async_update_entry(
config_entry, data=new_data, version=2)

_LOGGER.debug("Migration to configuration version %s successful",
config_entry.version)

return True


class CannotConnect(HomeAssistantError):
"""Error to indicate we cannot connect."""
55 changes: 37 additions & 18 deletions custom_components/fuel_prices/config_flow.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
CONF_SCAN_INTERVAL,
)

from .const import DOMAIN, NAME, CONF_AREAS, CONF_SOURCES, CONF_STATE_VALUE, CONF_CHEAPEST_SENSORS, CONF_CHEAPEST_SENSORS_COUNT
from .const import DOMAIN, NAME, CONF_AREAS, CONF_SOURCES, CONF_STATE_VALUE, CONF_CHEAPEST_SENSORS, CONF_CHEAPEST_SENSORS_COUNT, CONF_CHEAPEST_SENSORS_FUEL_TYPE

_LOGGER = logging.getLogger(__name__)

Expand Down Expand Up @@ -52,15 +52,16 @@
max=10,
step=1
)
)
),
vol.Optional(CONF_CHEAPEST_SENSORS_FUEL_TYPE, default=""): selector.TextSelector(),
}
)


class ConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
"""Handle a config flow."""

VERSION = 1
VERSION = 2
configured_areas: list[dict] = []
configured_sources = []
configuring_area = {}
Expand Down Expand Up @@ -181,6 +182,9 @@ async def async_step_area_create(self, user_input: dict[str, Any] | None = None)
CONF_LATITUDE: user_input[CONF_LATITUDE],
CONF_LONGITUDE: user_input[CONF_LONGITUDE],
CONF_RADIUS: user_input[CONF_RADIUS],
CONF_CHEAPEST_SENSORS: user_input[CONF_CHEAPEST_SENSORS],
CONF_CHEAPEST_SENSORS_COUNT: user_input[CONF_CHEAPEST_SENSORS_COUNT],
CONF_CHEAPEST_SENSORS_FUEL_TYPE: user_input[CONF_CHEAPEST_SENSORS_FUEL_TYPE]
}
)
return await self.async_step_area_menu()
Expand Down Expand Up @@ -227,7 +231,8 @@ async def async_step_area_update(self, user_input: dict[str, Any] | None = None)
CONF_LONGITUDE: user_input[CONF_LONGITUDE],
CONF_RADIUS: user_input[CONF_RADIUS],
CONF_CHEAPEST_SENSORS: user_input[CONF_CHEAPEST_SENSORS],
CONF_CHEAPEST_SENSORS_COUNT: user_input[CONF_CHEAPEST_SENSORS_COUNT]
CONF_CHEAPEST_SENSORS_COUNT: user_input[CONF_CHEAPEST_SENSORS_COUNT],
CONF_CHEAPEST_SENSORS_FUEL_TYPE: user_input[CONF_CHEAPEST_SENSORS_FUEL_TYPE]
}
)
return await self.async_step_area_menu()
Expand Down Expand Up @@ -275,7 +280,11 @@ async def async_step_area_update(self, user_input: dict[str, Any] | None = None)
max=10,
step=1
)
)
),
vol.Optional(
CONF_CHEAPEST_SENSORS_FUEL_TYPE,
default=self.configuring_area[CONF_CHEAPEST_SENSORS_FUEL_TYPE]
): selector.TextSelector()
}
),
errors=errors,
Expand Down Expand Up @@ -368,6 +377,19 @@ def configured_area_names(self) -> list[str]:
items.append(area["name"])
return items

async def _async_create_entry(self) -> config_entries.FlowResult:
"""Create an entry."""
return self.async_create_entry(
title=self.config_entry.title,
data={
CONF_AREAS: self.configured_areas,
CONF_SOURCES: self.configured_sources,
CONF_SCAN_INTERVAL: self.interval,
CONF_TIMEOUT: self.timeout,
CONF_STATE_VALUE: self.state_value
}
)

async def async_step_init(self, _: None = None):
"""User init option flow."""
return await self.async_step_main_menu()
Expand Down Expand Up @@ -462,7 +484,8 @@ async def async_step_area_create(self, user_input: dict[str, Any] | None = None)
CONF_LONGITUDE: user_input[CONF_LONGITUDE],
CONF_RADIUS: user_input[CONF_RADIUS],
CONF_CHEAPEST_SENSORS: user_input[CONF_CHEAPEST_SENSORS],
CONF_CHEAPEST_SENSORS_COUNT: user_input[CONF_CHEAPEST_SENSORS_COUNT]
CONF_CHEAPEST_SENSORS_COUNT: user_input[CONF_CHEAPEST_SENSORS_COUNT],
CONF_CHEAPEST_SENSORS_FUEL_TYPE: user_input[CONF_CHEAPEST_SENSORS_FUEL_TYPE]
}
)
return await self.async_step_area_menu()
Expand Down Expand Up @@ -509,7 +532,8 @@ async def async_step_area_update(self, user_input: dict[str, Any] | None = None)
CONF_LONGITUDE: user_input[CONF_LONGITUDE],
CONF_RADIUS: user_input[CONF_RADIUS],
CONF_CHEAPEST_SENSORS: user_input[CONF_CHEAPEST_SENSORS],
CONF_CHEAPEST_SENSORS_COUNT: user_input[CONF_CHEAPEST_SENSORS_COUNT]
CONF_CHEAPEST_SENSORS_COUNT: user_input[CONF_CHEAPEST_SENSORS_COUNT],
CONF_CHEAPEST_SENSORS_FUEL_TYPE: user_input[CONF_CHEAPEST_SENSORS_FUEL_TYPE]
}
)
return await self.async_step_area_menu()
Expand Down Expand Up @@ -557,7 +581,11 @@ async def async_step_area_update(self, user_input: dict[str, Any] | None = None)
max=10,
step=1
)
)
),
vol.Optional(
CONF_CHEAPEST_SENSORS_FUEL_TYPE,
default=self.configuring_area[CONF_CHEAPEST_SENSORS_FUEL_TYPE]
): selector.TextSelector()
}
),
errors=errors,
Expand Down Expand Up @@ -591,16 +619,7 @@ async def async_step_finished(self, user_input: dict[str, Any] | None = None):
"""Save configuration."""
errors: dict[str, str] = {}
if user_input is not None:
user_input[CONF_SOURCES] = (
self.configured_sources
if len(self.configured_sources) > 0
else list(SOURCE_MAP)
)
user_input[CONF_AREAS] = self.configured_areas
user_input[CONF_SCAN_INTERVAL] = self.interval
user_input[CONF_TIMEOUT] = self.timeout
user_input[CONF_STATE_VALUE] = self.state_value
return self.async_create_entry(title=NAME, data=user_input)
return await self._async_create_entry()
return self.async_show_form(step_id="finished", errors=errors, last_step=True)


Expand Down
1 change: 1 addition & 0 deletions custom_components/fuel_prices/const.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,4 @@

CONF_CHEAPEST_SENSORS = "cheapest_stations"
CONF_CHEAPEST_SENSORS_COUNT = "cheapest_stations_count"
CONF_CHEAPEST_SENSORS_FUEL_TYPE = "cheapest_stations_fuel_type"
2 changes: 1 addition & 1 deletion custom_components/fuel_prices/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
"issue_tracker": "https://github.com/pantherale0/ha-fuelprices/issues",
"requirements": [
"these-united-states==1.1.0.21",
"pyfuelprices==2.3.4"
"pyfuelprices==2.5.1"
],
"ssdp": [],
"version": "0.0.0",
Expand Down
52 changes: 48 additions & 4 deletions custom_components/fuel_prices/sensor.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,15 @@

from collections.abc import Mapping
from typing import Any
from datetime import datetime
from datetime import datetime, timedelta

from homeassistant.components.sensor import SensorEntity
from homeassistant.const import CONF_LATITUDE, CONF_LONGITUDE, CONF_RADIUS, CONF_NAME
from homeassistant.const import CONF_LATITUDE, CONF_LONGITUDE, CONF_RADIUS, CONF_NAME, STATE_UNKNOWN
from homeassistant.config_entries import ConfigEntry
from homeassistant.core import HomeAssistant
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from pyfuelprices.const import PROP_FUEL_LOCATION_SOURCE
from .const import CONF_AREAS, DOMAIN, CONF_STATE_VALUE
from .const import CONF_AREAS, DOMAIN, CONF_STATE_VALUE, CONF_CHEAPEST_SENSORS, CONF_CHEAPEST_SENSORS_COUNT, CONF_CHEAPEST_SENSORS_FUEL_TYPE
from .entity import FuelStationEntity, CheapestFuelEntity
from .coordinator import FuelPricesCoordinator

Expand Down Expand Up @@ -51,7 +51,19 @@ async def async_setup_entry(
)
)
found_entities.append(station["id"])

if area[CONF_CHEAPEST_SENSORS]:
_LOGGER.debug("Registering %s cheapest entities for area %s",
area[CONF_CHEAPEST_SENSORS_COUNT],
area[CONF_NAME])
for x in range(0, int(area[CONF_CHEAPEST_SENSORS_COUNT]), 1):
entities.append(CheapestFuelSensor(
coordinator=cooridinator,
count=x+1,
area=area[CONF_NAME],
fuel=area[CONF_CHEAPEST_SENSORS_FUEL_TYPE],
coords=(area[CONF_LATITUDE], area[CONF_LONGITUDE]),
radius=area[CONF_RADIUS]
))
async_add_entities(entities, True)


Expand Down Expand Up @@ -125,3 +137,35 @@ async def async_update(self) -> None:
fuel_type=self._fuel,
radius=self._radius
)
if len(data) >= (int(self._count)-1):
self._cached_data = data[int(self._count)-1]
return True
self._cached_data = None
self._next_update = datetime.now() + timedelta(days=1)

@property
def native_value(self) -> str | float:
"""Return state of entity."""
if self._cached_data is not None:
return self._cached_data["cost"]
return STATE_UNKNOWN

@property
def name(self) -> str:
"""Name of the entity."""
return f"{self._area} cheapest {self._fuel} {self._count}"

@property
def state_class(self) -> str:
"""Return state type."""
if isinstance(self.native_value, float):
return "total"
return None

@property
def extra_state_attributes(self) -> Mapping[str, Any] | None:
"""Return extra state attributes."""
return {
"area": self._area,
**self._cached_data
}
12 changes: 8 additions & 4 deletions custom_components/fuel_prices/strings.json
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,8 @@
"latitude": "Latitude for the center of the search location",
"longitude": "Longitude for the center of the search location",
"cheapest_stations": "Register entities for top n cheapest fuel stations in this area",
"cheapest_stations_count": "Number of cheapest fuel station entities to create"
"cheapest_stations_count": "Number of cheapest fuel station entities to create",
"cheapest_stations_fuel_type": "The fuel type to use for the cheapest fuel station entites"
}
},
"area_update_select": {
Expand All @@ -53,7 +54,8 @@
"latitude": "Latitude for the center of the search location",
"longitude": "Longitude for the center of the search location",
"cheapest_stations": "Register entities for top n cheapest fuel stations in this area",
"cheapest_stations_count": "Number of cheapest fuel station entities to create"
"cheapest_stations_count": "Number of cheapest fuel station entities to create",
"cheapest_stations_fuel_type": "The fuel type to use for the cheapest fuel station entites"
}
},
"area_delete": {
Expand Down Expand Up @@ -125,7 +127,8 @@
"latitude": "Latitude for the center of the search location",
"longitude": "Longitude for the center of the search location",
"cheapest_stations": "Register entities for top n cheapest fuel stations in this area",
"cheapest_stations_count": "Number of cheapest fuel station entities to create"
"cheapest_stations_count": "Number of cheapest fuel station entities to create",
"cheapest_stations_fuel_type": "The fuel type to use for the cheapest fuel station entites"
}
},
"area_update_select": {
Expand All @@ -143,7 +146,8 @@
"latitude": "Latitude for the center of the search location",
"longitude": "Longitude for the center of the search location",
"cheapest_stations": "Register entities for top n cheapest fuel stations in this area",
"cheapest_stations_count": "Number of cheapest fuel station entities to create"
"cheapest_stations_count": "Number of cheapest fuel station entities to create",
"cheapest_stations_fuel_type": "The fuel type to use for the cheapest fuel station entites"
}
},
"area_delete": {
Expand Down
Loading

0 comments on commit 0f91003

Please sign in to comment.