Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

2025.2.0 #34

Draft
wants to merge 5 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 30 additions & 0 deletions .github/workflows/documentation.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
name: documentation
on:
push:
branches:
- main
permissions:
contents: write
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Configure Git Credentials
run: |
git config user.name github-actions[bot]
git config user.email 41898282+github-actions[bot]@users.noreply.github.com
- uses: actions/setup-python@v5
with:
python-version: 3.x
- run: echo "cache_id=$(date --utc '+%V')" >> $GITHUB_ENV
- uses: actions/cache@v4
with:
key: mkdocs-material-${{ env.cache_id }}
path: .cache
restore-keys: |
mkdocs-material-
- name: "Install requirements"
run: python3 -m pip install -r "${{ github.workspace }}/docs/requirements.txt"
- run: cd "${{ github.workspace }}/docs"
- run: mkdocs gh-deploy --force
10 changes: 7 additions & 3 deletions custom_components/fuel_prices/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ class FuelPricesConfig:

coordinator: FuelPricesCoordinator
areas: list[dict]
config: ConfigEntry


type FuelPricesConfigEntry = ConfigEntry[FuelPricesConfig]
Expand Down Expand Up @@ -92,10 +93,11 @@ async def handle_fuel_lookup(call: ServiceCall) -> ServiceResponse:
lat = call.data.get("location", {}).get("latitude", default_lat)
long = call.data.get("location", {}).get("longitude", default_long)
fuel_type = call.data.get("type")
source = call.data.get("source", "")
try:
return {
"fuels": await fuel_prices.find_fuel_from_point(
(lat, long), radius, fuel_type
(lat, long), radius, fuel_type, source
)
}
except ValueError as err:
Expand All @@ -110,9 +112,10 @@ async def handle_fuel_location_lookup(call: ServiceCall) -> ServiceResponse:
radius = radius / 1609
lat = call.data.get("location", {}).get("latitude", default_lat)
long = call.data.get("location", {}).get("longitude", default_long)
source = call.data.get("source", "")
try:
locations = await fuel_prices.find_fuel_locations_from_point(
(lat, long), radius
(lat, long), radius, source
)
except ValueError as err:
raise HomeAssistantError(
Expand Down Expand Up @@ -140,7 +143,8 @@ async def handle_force_update(call: ServiceCall):

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

entry.runtime_data = FuelPricesConfig(coordinator=coordinator, areas=areas)
entry.runtime_data = FuelPricesConfig(
coordinator=coordinator, areas=areas, config=entry)

await hass.config_entries.async_forward_entry_setups(entry, PLATFORMS)

Expand Down
9 changes: 6 additions & 3 deletions custom_components/fuel_prices/config_flow.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,8 @@
): selector.SelectSelector(
selector.SelectSelectorConfig(
mode=selector.SelectSelectorMode.DROPDOWN,
options=list(SOURCE_MAP),
options=[k for k, v in SOURCE_MAP.items() if v[1] ==
1 and v[2] == 1],
multiple=True,
)
),
Expand Down Expand Up @@ -288,7 +289,8 @@ async def async_step_finished(self, user_input: dict[str, Any] | None = None):
user_input[CONF_SOURCES] = COUNTRY_MAP.get(
self.hass.config.country)
else:
user_input[CONF_SOURCES] = list(SOURCE_MAP)
user_input[CONF_SOURCES] = [
k for k, v in SOURCE_MAP.items() if v[1] == 1 and v[2] == 1]
user_input[CONF_AREAS] = self.configured_areas
user_input[CONF_SCAN_INTERVAL] = self.interval
user_input[CONF_TIMEOUT] = self.timeout
Expand Down Expand Up @@ -502,7 +504,8 @@ async def async_step_finished(self, user_input: dict[str, Any] | None = None):
user_input[CONF_SOURCES] = COUNTRY_MAP.get(
self.hass.config.country)
else:
user_input[CONF_SOURCES] = list(SOURCE_MAP)
user_input[CONF_SOURCES] = [
k for k, v in SOURCE_MAP.items() if v[1] == 1 and v[2] == 1]
user_input[CONF_AREAS] = self.configured_areas
user_input[CONF_SCAN_INTERVAL] = self.interval
user_input[CONF_TIMEOUT] = self.timeout
Expand Down
17 changes: 13 additions & 4 deletions custom_components/fuel_prices/entity.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,25 @@

from homeassistant.helpers.entity import Entity
from homeassistant.helpers.update_coordinator import CoordinatorEntity
from homeassistant.config_entries import ConfigEntry

from .coordinator import FuelPricesCoordinator


class FuelStationEntity(CoordinatorEntity):
class FuelPriceEntity:
"""Top level entity type."""

config: ConfigEntry


class FuelStationEntity(FuelPriceEntity, CoordinatorEntity):
"""Represents a fuel station."""

def __init__(
self, coordinator: FuelPricesCoordinator, fuel_station_id, entity_id, source, area, state_value
self, coordinator: FuelPricesCoordinator, fuel_station_id, entity_id, source, area, state_value, config: ConfigEntry
) -> None:
"""Initialize."""
self.config = config
super().__init__(coordinator)
self.coordinator: FuelPricesCoordinator = coordinator
self._fuel_station_id = fuel_station_id
Expand All @@ -36,13 +44,14 @@ def unique_id(self) -> str | None:
return f"fuelprices_{self._fuel_station_id}_{self._entity_id}"


class CheapestFuelEntity(Entity):
class CheapestFuelEntity(FuelPriceEntity, Entity):
"""Represents a fuel."""

def __init__(
self, coordinator: FuelPricesCoordinator, count: str, area: str, fuel: str, coords: tuple, radius: float):
self, coordinator: FuelPricesCoordinator, count: str, area: str, fuel: str, coords: tuple, radius: float, config: ConfigEntry):
"""Initialize."""
self.coordinator: FuelPricesCoordinator = coordinator
self.config = config
self._count = count
self._area = area
self._coords = coords
Expand Down
2 changes: 1 addition & 1 deletion custom_components/fuel_prices/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
"xmltodict",
"brotli",
"these-united-states==1.1.0.21",
"pyfuelprices==2025.1.2"
"pyfuelprices==2025.2.2"
],
"ssdp": [],
"version": "0.0.0",
Expand Down
13 changes: 9 additions & 4 deletions custom_components/fuel_prices/sensor.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@

from homeassistant.components.sensor import SensorEntity
from homeassistant.components.sensor.const import SensorDeviceClass
from homeassistant.const import CONF_LATITUDE, CONF_LONGITUDE, CONF_RADIUS, CONF_NAME, STATE_UNKNOWN
from homeassistant.const import CONF_LATITUDE, CONF_LONGITUDE, CONF_RADIUS, CONF_NAME, STATE_UNKNOWN, CONF_SCAN_INTERVAL
from homeassistant.core import HomeAssistant
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from pyfuelprices.const import PROP_FUEL_LOCATION_SOURCE
Expand Down Expand Up @@ -47,7 +47,8 @@ async def async_setup_entry(
entity_id="devicetracker",
source=station["props"][PROP_FUEL_LOCATION_SOURCE],
area=area[CONF_NAME],
state_value=state_value
state_value=state_value,
config=entry
)
)
found_entities.append(station["id"])
Expand All @@ -62,7 +63,8 @@ async def async_setup_entry(
area=area[CONF_NAME],
fuel=area[CONF_CHEAPEST_SENSORS_FUEL_TYPE],
coords=(area[CONF_LATITUDE], area[CONF_LONGITUDE]),
radius=area[CONF_RADIUS]
radius=area[CONF_RADIUS],
config=entry
))
async_add_entities(entities, True)

Expand Down Expand Up @@ -148,7 +150,10 @@ async def async_update(self) -> None:
)
if len(data) >= (int(self._count)-1):
self._last_update = datetime.now()
self._next_update = datetime.now() + timedelta(minutes=5)
self._next_update = datetime.now() + timedelta(minutes=self.config.options.get(
CONF_SCAN_INTERVAL, self.config.data.get(
CONF_SCAN_INTERVAL, 1440)
))
if len(data) >= self._count:
self._cached_data = data[int(self._count)-1]
else:
Expand Down
10 changes: 10 additions & 0 deletions custom_components/fuel_prices/services.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,11 @@ find_fuel_station:
selector:
location:
radius: true
source:
required: false
selector:
text:
multiline: false
find_fuels:
fields:
location:
Expand All @@ -18,3 +23,8 @@ find_fuels:
selector:
text:
multiline: false
source:
required: false
selector:
text:
multiline: false
8 changes: 8 additions & 0 deletions custom_components/fuel_prices/strings.json
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,10 @@
"type": {
"name": "Fuel Type",
"description": "The fuel type to search for (such as E5, E10, B7, SDV)"
},
"source": {
"name": "Data Source to search",
"description": "The data source ID to search, defaults to 'any' for all data sources."
}
}
},
Expand All @@ -91,6 +95,10 @@
"location": {
"name": "Location",
"description": "The location of the area to search"
},
"source": {
"name": "Data Source to search",
"description": "The data source ID to search, defaults to 'any' for all data sources."
}
}
}
Expand Down
8 changes: 8 additions & 0 deletions custom_components/fuel_prices/translations/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,10 @@
"type": {
"name": "Fuel Type",
"description": "The fuel type to search for (such as E5, E10, B7, SDV)"
},
"source": {
"name": "Data Source to search",
"description": "The data source ID to search, defaults to 'any' for all data sources."
}
}
},
Expand All @@ -91,6 +95,10 @@
"location": {
"name": "Location",
"description": "The location of the area to search"
},
"source": {
"name": "Data Source to search",
"description": "The data source ID to search, defaults to 'any' for all data sources."
}
}
}
Expand Down
1 change: 1 addition & 0 deletions docs/docs/.pages
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
title: Fuel Prices
15 changes: 15 additions & 0 deletions docs/docs/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# Getting Started

This is a data finder integration to retrieve local (or remote) fuel price data for Home Assistant using the `pyfuelprices` library. This library aims to provide the most extensive set of data sources for fuel prices in the world.

You can use this service to:

- Track fuel prices in your local area
- Query for fuel prices in an automation
- Calculate how much it will cost to fill your tank of fuel
- Find the cheapest station near a entity providing latitude and longitude (script required)

## Warnings

- Commercial usage of this integration and its Python library is strictly prohibited.
- You may fork and modify as you require or contribute to the project freely.
30 changes: 30 additions & 0 deletions docs/docs/installation.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# Installation

1. Add the repository to HACS
1. Install integration
1. Follow prompts to configure integration

## Configuration Parameters

The main configuration entry point is provided via a configuration flow. Using a `configuration.yaml` file to configure is not supported and will not be added in the future following Home Assistant's own design principles

### Area Configuration Options

| Option | Description | Type | Default |
|-----------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|------------------------------------|---------|
| `name` | (Required) The name of the area. | Text | None |
| `radius` | (Required) The radius of the area in miles. | Number (miles) | 5.0 |
| `latitude` | (Required, with `longitude`) The latitude of the center of the area. Must be used with `longitude`. | Latitude | None |
| `longitude` | (Required, with `latitude`) The longitude of the center of the area. Must be used with `latitude`. | Longitude | None |
| `cheapest_sensors` | (Optional) A boolean value to determine whether cheapest sensors should be created for this area. | Flag | False |
| `cheapest_sensors_count` | (Required, with `cheapest_sensors`) The number of cheapest sensors to create. Only used if `cheapest_sensors` is true. | Number (Min: 1, Max: 10, Step: 1) | 5 |
| `cheapest_sensors_fuel_type` | (Required, with `cheapest_sensors`) The fuel type for which the cheapest sensors should be created. Only used if `cheapest_sensors` is true. | Text | "" |

### System Configuration Options

| Option | Description | Type | Default |
|---------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-------------------------------------------|---------|
| `sources` | (Required) A list of data sources (fuel price providers) to use. If not provided, the integration will attempt to determine the data source based on your Home Assistant configuration's country setting. | Dropdown, Multiple | None |
| `timeout` | (Optional) The timeout in seconds for requests to the data sources. | Number (Box, Unit: s, Min: 5, Max: 60) | 30 |
| `scan_interval` | (Optional) The interval in minutes between updates of the fuel prices. | Number (Box, Unit: m, Min: 360, Max: 1440) | 1440 |
| `state_value` | (Optional) The attribute to use for the state of the fuel price sensors. Used to select which piece of information from the source data is shown as the sensor's value (e.g., name, B7, E5, address). | Text | name |
24 changes: 24 additions & 0 deletions docs/docs/services/find_fuel_station.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# Find fuel stations from locations `find_fuel_station`

**Name:** Find fuel stations from location

**Description:** Find all of the available fuel stations, alongside available fuels and cost for a given location. The results are *not* sorted.

**Fields:**

| Field | Description | Required | Selector Type |
|------------|---------------------------------|----------|---------------|
| `location` | The location of the area to search. | Yes | Location (with radius) |

**Example:**

```yaml
service: fuel_prices.find_fuel_station
data:
location:
latitude: 52.520008
longitude: 13.404954
radius: 5
```

This example would find fuel stations within a 5 mile radius of the provided coordinates.
26 changes: 26 additions & 0 deletions docs/docs/services/find_fuels.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# Find fuels from location `find_fuels`

**Name:** Find fuel prices from location

**Description:** This service retrieves all fuel prices for a given location, sorted by the cheapest first.

**Fields:**

| Field | Description | Required | Selector Type |
|------------|-------------------------------------------------|----------|---------------|
| `location` | The location of the area to search. | Yes | Location (with radius) |
| `type` | The fuel type to search for (such as E5, E10, B7, SDV). | Yes | Text (single line) |

**Example:**

```yaml
service: fuel_prices.find_fuels
data:
location:
latitude: 52.520008
longitude: 13.404954
radius: 10
type: E10
```

This example would find prices for E10 fuel within a 10-mile radius of the given latitude and longitude.
10 changes: 10 additions & 0 deletions docs/mkdocs.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
site_name: Home Assistant Fuel Prices
theme:
name: material
features:
- navigation.instant
- navigation.instant.progress
site_url: https://fuelprices.system32.uk
plugins:
- search
- awesome-pages
2 changes: 2 additions & 0 deletions docs/requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
mkdocs-material
mkdocs-awesome-pages-plugin
2 changes: 1 addition & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,4 @@ colorlog==6.7.0
homeassistant==2024.11.0
pip>=21.0,<23.2
ruff==0.0.292
pyfuelprices==2025.1.2
pyfuelprices==2025.2.2