Skip to content

Commit

Permalink
7.1.0 select individual gas station in config flow
Browse files Browse the repository at this point in the history
  • Loading branch information
myTselection committed Aug 5, 2023
1 parent 26563cf commit 16def17
Show file tree
Hide file tree
Showing 8 changed files with 147 additions and 41 deletions.
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,8 @@ For electricity price expectations [this Entso-E HACS integration](https://githu
- Restart Home Assistant
- Add 'Carbu.com' integration via HA Settings > 'Devices and Services' > 'Integrations'
- Provide country, postal code and select the desired sensors
- If your postal code is not unique, the name of the town can be selected from the dropdown in the next step of the setup config flow. See [carbu.com](https://carbu.com) website for known towns and postal codes. (Only for BE/FR/LU)
- The name of the town can be selected from the dropdown in the next step of the setup config flow. See [carbu.com](https://carbu.com) website for known towns and postal codes. (Only for BE/FR/LU)
- For BE/FR/LU: an extra checkbox can be set to select a specific individual gas station. If set, a station can be selected in a dropdown with known gas stations close to the provided postalcode and town. No sensor for 5km and 10km will be made available, only the price sensor for the individual selected station.
- For Italy & Netherlands, the town will be requested in the second step of the config flow
- A filter on supplier brand name can be set (optional). If the filter match, the fuel station will be considered, else next will be searched. A python regex filter value be set

Expand Down
58 changes: 54 additions & 4 deletions custom_components/carbu_com/config_flow.py
Original file line number Diff line number Diff line change
Expand Up @@ -82,10 +82,13 @@ def create_town_carbu_schema(towns):
vol.Required("town", description="Town")
] = selector({
"select": {
"options": towns,
"options": [item['n'] for item in towns],
"mode": "dropdown"
}
})
data_schema[
vol.Optional("individualstation", default=False, description="Select an individual station")
] = bool
data_schema[
vol.Optional(FuelType.OILSTD.name_lowercase, default=default_oilstd, description="Standard oil sensors")
] = bool
Expand All @@ -98,6 +101,23 @@ def create_town_carbu_schema(towns):

return data_schema


def create_station_carbu_schema(stations):
"""Create a default schema based on if a option or if settings
is already filled out.
"""
data_schema = OrderedDict()
data_schema[
vol.Required("station", description="Fuel station")
] = selector({
"select": {
"options": [f"{item['name']}, {item['address']}" for item in stations],
"mode": "dropdown"
}
})

return data_schema

def create_town_schema():
"""Create a default schema based on if a option or if settings
is already filled out.
Expand All @@ -119,6 +139,7 @@ class ComponentFlowHandler(config_entries.ConfigFlow, domain=DOMAIN):
_init_info = {}
_carbuLocationInfo = {}
_towns = []
_stations = []
_session = None

def __init__(self):
Expand All @@ -138,7 +159,7 @@ async def async_step_user(self, user_input=None): # pylint: disable=dangerous-d
self._towns = []
carbuLocationInfo = await self.hass.async_add_executor_job(lambda: self._session.convertPostalCodeMultiMatch(user_input.get('postalcode'), user_input.get('country')))
for location in carbuLocationInfo:
self._towns.append(location.get('n'))
self._towns.append(location)
_LOGGER.debug(f"carbuLocationInfo: {carbuLocationInfo} towns {self._towns}")
return await self.async_step_town_carbu()
# Other countries: get town
Expand All @@ -152,11 +173,26 @@ async def _show_config_form(self, user_input):
return self.async_show_form(
step_id="user", data_schema=vol.Schema(data_schema), errors=self._errors
)

def find_town_by_name(self, target_name):
for item in self._towns:
if item.get('n') == target_name:
return item
return None # If the name is not found in the list

async def async_step_town_carbu(self, user_input=None): # pylint: disable=dangerous-default-value
"""Handle a flow initialized by the user."""
if user_input is not None:
self._init_info.update(user_input)
# _LOGGER.debug(f"individualstation: {user_input.get('individualstation')}")
if user_input.get('individualstation') == True:
town = self.find_town_by_name(user_input.get('town'))
self._stations = []
carbuStationInfo = await self.hass.async_add_executor_job(lambda: self._session.getFuelPrices(self._init_info.get('postalcode'), self._init_info.get('country'), self._init_info.get('town'), town.get('id'), FuelType.DIESEL, False))
for station in carbuStationInfo:
self._stations.append(station)
_LOGGER.debug(f"stations: {self._stations}")
return await self.async_step_station_carbu()
return self.async_create_entry(title=NAME, data=self._init_info)

return await self._show_town_carbu_config_form(self._towns)
Expand All @@ -165,15 +201,29 @@ async def _show_town_carbu_config_form(self, towns):
"""Show the configuration form to edit location data."""
data_schema = create_town_carbu_schema(towns)
return self.async_show_form(
step_id="town", data_schema=vol.Schema(data_schema), errors=self._errors
step_id="town_carbu", data_schema=vol.Schema(data_schema), errors=self._errors
)

async def async_step_town(self, user_input=None): # pylint: disable=dangerous-default-value
async def async_step_station_carbu(self, user_input=None): # pylint: disable=dangerous-default-value
"""Handle a flow initialized by the user."""
if user_input is not None:
self._init_info.update(user_input)
return self.async_create_entry(title=NAME, data=self._init_info)

return await self._show_station_carbu_config_form(self._stations)

async def _show_station_carbu_config_form(self, stations):
"""Show the configuration form to edit location data."""
data_schema = create_station_carbu_schema(stations)
return self.async_show_form(
step_id="station_carbu", data_schema=vol.Schema(data_schema), errors=self._errors
)

async def async_step_town(self, user_input=None): # pylint: disable=dangerous-default-value
"""Handle a flow initialized by the user."""
if user_input is not None:
self._init_info.update(user_input)
return self.async_create_entry(title=NAME, data=self._init_info)
return await self._show_town_config_form(self._towns)

async def _show_town_config_form(self, towns):
Expand Down
2 changes: 1 addition & 1 deletion custom_components/carbu_com/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,5 @@
"iot_class": "cloud_polling",
"issue_tracker": "https://github.com/myTselection/carbu_com/issues",
"requirements": ["bs4","requests","ratelimit"],
"version": "7.0.3"
"version": "7.1.0"
}
75 changes: 43 additions & 32 deletions custom_components/carbu_com/sensor.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,8 @@ async def dry_setup(hass, config_entry, async_add_devices):
postalcode = config.get("postalcode")
town = config.get("town")
filter = config.get("filter")
individualstation = config.get("individualstation", False)
station = config.get("station","")
super95 = config.get(FuelType.SUPER95.name_lowercase)
super98 = config.get(FuelType.SUPER98.name_lowercase)
diesel = config.get(FuelType.DIESEL.name_lowercase)
Expand All @@ -66,57 +68,62 @@ async def dry_setup(hass, config_entry, async_add_devices):
)
await componentData._forced_update()
assert componentData._price_info is not None


# _LOGGER.debug(f"postalcode {postalcode} station: {station} individualstation {individualstation}")

if super95:
sensorSuper95 = ComponentPriceSensor(componentData, FuelType.SUPER95, postalcode, False, 0)
sensorSuper95 = ComponentPriceSensor(componentData, FuelType.SUPER95, postalcode, False, 0, station)
# await sensorSuper95.async_update()
sensors.append(sensorSuper95)

sensorSuper95Neigh = ComponentPriceNeighborhoodSensor(componentData, FuelType.SUPER95, postalcode, 5)
# await sensorSuper95Neigh.async_update()
sensors.append(sensorSuper95Neigh)

sensorSuper95Neigh = ComponentPriceNeighborhoodSensor(componentData, FuelType.SUPER95, postalcode, 10)
# await sensorSuper95Neigh.async_update()
sensors.append(sensorSuper95Neigh)

if not individualstation:
sensorSuper95Neigh = ComponentPriceNeighborhoodSensor(componentData, FuelType.SUPER95, postalcode, 5)
# await sensorSuper95Neigh.async_update()
sensors.append(sensorSuper95Neigh)

sensorSuper95Neigh = ComponentPriceNeighborhoodSensor(componentData, FuelType.SUPER95, postalcode, 10)
# await sensorSuper95Neigh.async_update()
sensors.append(sensorSuper95Neigh)

if country.lower() in ['be','fr','lu']:
sensorSuper95Prediction = ComponentFuelPredictionSensor(componentData, FuelType.SUPER95_Prediction)
# await sensorSuper95Prediction.async_update()
sensors.append(sensorSuper95Prediction)


if super98:
sensorSuper98 = ComponentPriceSensor(componentData, FuelType.SUPER98, postalcode, False, 0)
sensorSuper98 = ComponentPriceSensor(componentData, FuelType.SUPER98, postalcode, False, 0, station)
# await sensorSuper95.async_update()
sensors.append(sensorSuper98)

sensorSuper98Neigh = ComponentPriceNeighborhoodSensor(componentData, FuelType.SUPER98, postalcode, 5)
# await sensorSuper95Neigh.async_update()
sensors.append(sensorSuper98Neigh)

sensorSuper98Neigh = ComponentPriceNeighborhoodSensor(componentData, FuelType.SUPER98, postalcode, 10)
# await sensorSuper95Neigh.async_update()
sensors.append(sensorSuper98Neigh)
if not individualstation:
sensorSuper98Neigh = ComponentPriceNeighborhoodSensor(componentData, FuelType.SUPER98, postalcode, 5)
# await sensorSuper95Neigh.async_update()
sensors.append(sensorSuper98Neigh)

sensorSuper98Neigh = ComponentPriceNeighborhoodSensor(componentData, FuelType.SUPER98, postalcode, 10)
# await sensorSuper95Neigh.async_update()
sensors.append(sensorSuper98Neigh)

if diesel:
sensorDiesel = ComponentPriceSensor(componentData, FuelType.DIESEL, postalcode, False, 0)
sensorDiesel = ComponentPriceSensor(componentData, FuelType.DIESEL, postalcode, False, 0, station)
# await sensorDiesel.async_update()
sensors.append(sensorDiesel)

sensorDieselNeigh = ComponentPriceNeighborhoodSensor(componentData, FuelType.DIESEL, postalcode, 5)
# await sensorDieselNeigh.async_update()
sensors.append(sensorDieselNeigh)
if not individualstation:
sensorDieselNeigh = ComponentPriceNeighborhoodSensor(componentData, FuelType.DIESEL, postalcode, 5)
# await sensorDieselNeigh.async_update()
sensors.append(sensorDieselNeigh)

sensorDieselNeigh = ComponentPriceNeighborhoodSensor(componentData, FuelType.DIESEL, postalcode, 10)
# await sensorDieselNeigh.async_update()
sensors.append(sensorDieselNeigh)

sensorDieselNeigh = ComponentPriceNeighborhoodSensor(componentData, FuelType.DIESEL, postalcode, 10)
# await sensorDieselNeigh.async_update()
sensors.append(sensorDieselNeigh)

if country.lower() in ['be','fr','lu']:
sensorDieselPrediction = ComponentFuelPredictionSensor(componentData, FuelType.DIESEL_Prediction)
# await sensorDieselPrediction.async_update()
sensors.append(sensorDieselPrediction)

if oilstd and country.lower() in ['be','fr','lu']:
sensorOilstd = ComponentPriceSensor(componentData, FuelType.OILSTD, postalcode, True, quantity)
# await sensorOilstd.async_update()
Expand Down Expand Up @@ -229,8 +236,8 @@ async def get_oil_price_prediction_info(self):
self._price_info[FuelType.OILEXTRA_Prediction] = prediction_info
_LOGGER.debug(f"{NAME} prediction_info oilPrediction {prediction_info}")

async def getStationInfoFromPriceInfo(self, priceinfo, postalcode, fueltype, max_distance, filter):
stationInfo = await self._hass.async_add_executor_job(lambda: self._session.getStationInfoFromPriceInfo(priceinfo, postalcode, fueltype, max_distance, filter))
async def getStationInfoFromPriceInfo(self, priceinfo, postalcode, fueltype, max_distance, filter, individual_station=""):
stationInfo = await self._hass.async_add_executor_job(lambda: self._session.getStationInfoFromPriceInfo(priceinfo, postalcode, fueltype, max_distance, filter, individual_station))
return stationInfo


Expand Down Expand Up @@ -304,12 +311,13 @@ def clear_session(self):


class ComponentPriceSensor(Entity):
def __init__(self, data, fueltype: FuelType, postalcode, isOil, quantity):
def __init__(self, data, fueltype: FuelType, postalcode, isOil, quantity, individual_station = ""):
self._data = data
self._fueltype = fueltype
self._postalcode = postalcode
self._isOil = isOil
self._quantity = quantity
self._individual_station = individual_station

self._last_update = None
self._price = None
Expand All @@ -326,6 +334,7 @@ def __init__(self, data, fueltype: FuelType, postalcode, isOil, quantity):
self._date = None
self._score = None
self._country = data._country
self._id = None

@property
def state(self):
Expand Down Expand Up @@ -353,7 +362,8 @@ async def async_update(self):
self._date = self._priceinfo.get("data")[0].get("available").get("visible")# x.data[0].available.visible
# self._quantity = self._priceinfo.get("data")[0].get("quantity")
else:
stationInfo = await self._data.getStationInfoFromPriceInfo(self._priceinfo, self._postalcode, self._fueltype, 0, self._data._filter)
# _LOGGER.debug(f'indiv. station: {self._individual_station}')
stationInfo = await self._data.getStationInfoFromPriceInfo(self._priceinfo, self._postalcode, self._fueltype, 0, self._data._filter, self._individual_station)
# stationInfo = await self._data._hass.async_add_executor_job(lambda: self._data._session.getStationInfoFromPriceInfo(self._priceinfo, self._postalcode, self._fueltype, 0, self._data._filter))
self._price = stationInfo.get("price")
self._supplier = stationInfo.get("supplier")
Expand Down Expand Up @@ -419,7 +429,8 @@ def extra_state_attributes(self) -> dict:
"quantity": self._quantity,
"score": self._score,
"filter": self._data._filter,
"country": self._country
"country": self._country,
"id": self._id
# "suppliers": self._priceinfo
}

Expand Down
12 changes: 12 additions & 0 deletions custom_components/carbu_com/translations/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,25 @@
}
},
"town": {
"data": {
"town": "Town"
}
},
"town_carbu": {
"data": {
"town": "Town",
"individualstation": "Select an individual gas station",
"oilstd": "Mazout Heating Oil standard (50S)",
"oilextra": "Mazout Heating Oil extra",
"quantity": "Mazout Heating Oil quanitity (liters)"
}
},
"station_carbu": {
"description": "Select an individual gas station",
"data": {
"station": "Fuel station"
}
},
"edit": {
"description": "Setup Carbu.com and Mazout.com sensors.",
"data": {
Expand Down
12 changes: 12 additions & 0 deletions custom_components/carbu_com/translations/fr.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,25 @@
}
},
"town": {
"data": {
"town": "Ville"
}
},
"town_carbu": {
"data": {
"town": "Ville",
"individualstation": "Sélectionnez une station-service individuelle",
"oilstd": "Fioul Standard (50S)",
"oilextra": "Fioul Extra",
"quantity": "Quantité Fioul (liters)"
}
},
"station_carbu": {
"description": "Sélectionnez une station-service individuelle",
"data": {
"station": "Fuel station"
}
},
"edit": {
"description": "Configuration des capteurs Carbu.com et Mazout.com.",
"data": {
Expand Down
12 changes: 12 additions & 0 deletions custom_components/carbu_com/translations/nl.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,25 @@
}
},
"town": {
"data": {
"town": "Stad"
}
},
"town_carbu": {
"data": {
"town": "Stad",
"individualstation": "Selecteer een individueel tankstation",
"oilstd": "Standaard Mazout Verwarmingsolie (50S)",
"oilextra": "Extra Mazout Verwarmingsolie",
"quantity": "Hoeveelheid Mazout Verwarmingsolie (liters)"
}
},
"station_carbu": {
"description": "Selecteer een individueel tankstation",
"data": {
"station": "Tank station"
}
},
"edit": {
"description": "Configureer Carbu.com en Mazout.com sensoren.",
"data": {
Expand Down
Loading

0 comments on commit 16def17

Please sign in to comment.