Skip to content

Commit

Permalink
extra exception handling + support LPG official for BE/FR/LU/NL
Browse files Browse the repository at this point in the history
  • Loading branch information
myTselection committed Aug 31, 2024
1 parent d123703 commit 7b1391a
Show file tree
Hide file tree
Showing 3 changed files with 88 additions and 67 deletions.
7 changes: 4 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,11 +46,11 @@ For cheapest Belgian gas and electricity contracts, prices and promotions, pleas
- 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 (for which a price is available) close to the provided postalcode and town. No sensor for 5km and 10km will be created, only the price sensor for the individual selected station. The name of the sensor will contain the name of the supplier.
- For Italy, Netherlands, Spain and US the town will be requested in the second step of the config flow
- Get an API key at [Geoapify.com](https://myprojects.geoapify.com/register), which has a free tier for 3K geocoding requests per day. If the API key is not set, countries IT, NL, ES and US will not function and services to find fuel price on route or at coordinate will not function. The API key can also be set/updated on existing sensors using the 'Configure' entity option.
- 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
- 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 can be set
- An option is avaible to show a logo (entity picture) with price or the original logo provided by the source. This is mainly visible when mapping the sensor on a map.
- After setting up the integration, the configuration can be updated using the 'Configure' button of the integration. The usage of a station filter can be enabled and set, the usage of a template to set the 'friendly name' of each sensor type can be enabled and set and the usage of icons with price indication can be enabled or disabled.
- The checkboxes are required since else clearing the text of the configuration was not recorded (HA bug?) and filter or templates could no longer be removed once set.
- When setting a sensor 'friendly name' template, any sensor attribute can be used as a placeholder which will be replaced with the actual value. Eg: `Price {fueltype} {fuelname} {supplier}` could be used as a template for te Price sensor. All available attributes can be fetched using the 'Developer Tools' > 'States' > 'Attributes' view in HA or using the tables listed below.
- When setting a sensor 'friendly name' template, any sensor attribute can be used as a placeholder which will be replaced with the actual value. Eg: `Price {fueltype} {fuelname} {supplier}` could be used as a template for the Price sensor. All available attributes can be fetched using the 'Developer Tools' > 'States' > 'Attributes' view in HA or using the tables listed below.

## Integration
### Sensors
Expand Down Expand Up @@ -108,7 +108,7 @@ For cheapest Belgian gas and electricity contracts, prices and promotions, pleas
| `id` | Unique id of the supplier |
</details>

- <details><summary>Sensor with official diesel and super price <code>sensor.carbu_com_[fueltype]_officia_[fueltypecode]</code>, only supported for BE/FR/LU</summary>
- <details><summary>Sensor with official diesel and super price <code>sensor.carbu_com_[fueltype]_officia_[fueltypecode]</code>, only supported for BE/FR/LU/NL</summary>

| Attribute | Description |
| --------- | ----------- |
Expand All @@ -117,6 +117,7 @@ For cheapest Belgian gas and electricity contracts, prices and promotions, pleas
| `fueltype` | Fuel type |
| `price` | Price |
| `date` | Date for the validity of the price |
| `country` | Country |
| `price next` | Next official price |
| `date next` | Date as of when the next price will be applicable |
</details>
Expand Down
144 changes: 81 additions & 63 deletions custom_components/carbu_com/sensor.py
Original file line number Diff line number Diff line change
Expand Up @@ -317,22 +317,31 @@ async def get_oil_price_info(self, fuel_type: FuelType):

async def get_fuel_price_prediction_info(self, fuel_type: FuelType):
_LOGGER.debug(f"{NAME} getting prediction price_info {fuel_type.name_lowercase}")
prediction_info = await self._hass.async_add_executor_job(lambda: self._session.getFuelPrediction(fuel_type.code))
self._price_info[fuel_type] = prediction_info
_LOGGER.debug(f"{NAME} prediction_info {fuel_type.name_lowercase} Prediction {prediction_info}")
try:
prediction_info = await self._hass.async_add_executor_job(lambda: self._session.getFuelPrediction(fuel_type.code))
self._price_info[fuel_type] = prediction_info
_LOGGER.debug(f"{NAME} prediction_info {fuel_type.name_lowercase} Prediction {prediction_info}")
except Exception as e:
_LOGGER.error(f"ERROR: prediction failed for {fuel_type.name_lowercase} : {e}")

async def get_fuel_price_official_info(self, fuel_type: FuelType):
_LOGGER.debug(f"{NAME} getting official price_info {fuel_type.name_lowercase}")
official_info = await self._hass.async_add_executor_job(lambda: self._session.getFuelOfficial(fuel_type, self._country))
self._price_info[fuel_type] = official_info
_LOGGER.debug(f"{NAME} official_info {fuel_type.name_lowercase} Official {official_info}")
try:
official_info = await self._hass.async_add_executor_job(lambda: self._session.getFuelOfficial(fuel_type, self._country))
self._price_info[fuel_type] = official_info
_LOGGER.debug(f"{NAME} official_info {fuel_type.name_lowercase} Official {official_info}")
except Exception as e:
_LOGGER.error(f"ERROR: prediction failed for {fuel_type.name_lowercase} : {e}")

async def get_oil_price_prediction_info(self):
_LOGGER.debug(f"{NAME} getting price_info oil prediction")
prediction_info = await self._hass.async_add_executor_job(lambda: self._session.getOilPrediction())
self._price_info[FuelType.OILSTD_PREDICTION] = prediction_info
self._price_info[FuelType.OILEXTRA_PREDICTION] = prediction_info
_LOGGER.debug(f"{NAME} prediction_info oilPrediction {prediction_info}")
try:
prediction_info = await self._hass.async_add_executor_job(lambda: self._session.getOilPrediction())
self._price_info[FuelType.OILSTD_PREDICTION] = prediction_info
self._price_info[FuelType.OILEXTRA_PREDICTION] = prediction_info
_LOGGER.debug(f"{NAME} prediction_info oilPrediction {prediction_info}")
except Exception as e:
_LOGGER.error(f"ERROR: prediction failed for oil : {e}")

async def getStationInfoFromPriceInfo(self, priceinfo, postalcode, fueltype, max_distance, individual_station=""):
if self._filter_choice:
Expand Down Expand Up @@ -790,12 +799,15 @@ async def async_update(self):
await self._data.update()
self._last_update = self._data._lastupdate

priceinfo = self._data._price_info.get(self._fueltype)
try:
priceinfo = self._data._price_info.get(self._fueltype)


self._trend = round( priceinfo[0],3)

self._date = priceinfo[1]

self._trend = round( priceinfo[0],3)

self._date = priceinfo[1]
except Exception as e:
_LOGGER.error(f"ERROR: prediction failed for {self._fueltype.name_lowercase} : {e}")



Expand Down Expand Up @@ -895,41 +907,44 @@ async def async_update(self):
await self._data.update()
self._last_update = self._data._lastupdate

priceinfo = self._data._price_info.get(self._fueltype)

code = self._fueltype.code

if int(self._quantity) < 2000:
code += "Inf2000"
else:
code += "Sup2000"

table = priceinfo.get("data").get("table")
# _LOGGER.debug(f"{NAME} code {code} table: {table}")

todayPrice = 0
tomorrowPrice = 0

for element in table:
if element.get("code").lower() == code.lower():
self._fuelname = element.get("name")
if element.get("data")[1]:
todayPrice = element.get("data")[1].get("price")
if element.get("data")[2]:
tomorrowPrice = element.get("data")[2].get("price")
elif element.get("data")[1]:
tomorrowPrice = element.get("data")[1].get("price")
break

self._price = tomorrowPrice

if todayPrice != 0:
self._trend = round(100 * ((tomorrowPrice - todayPrice) / todayPrice),3)
self._officialPriceToday = todayPrice
try:
priceinfo = self._data._price_info.get(self._fueltype)

if len(priceinfo.get("data").get("heads")) > 1:
self._date = priceinfo.get("data").get("heads")[2].get("name")
self._officialPriceTodayDate = priceinfo.get("data").get("heads")[1].get("name")
code = self._fueltype.code

if int(self._quantity) < 2000:
code += "Inf2000"
else:
code += "Sup2000"

table = priceinfo.get("data").get("table")
# _LOGGER.debug(f"{NAME} code {code} table: {table}")

todayPrice = 0
tomorrowPrice = 0

for element in table:
if element.get("code").lower() == code.lower():
self._fuelname = element.get("name")
if element.get("data")[1]:
todayPrice = element.get("data")[1].get("price")
if element.get("data")[2]:
tomorrowPrice = element.get("data")[2].get("price")
elif element.get("data")[1]:
tomorrowPrice = element.get("data")[1].get("price")
break

self._price = tomorrowPrice

if todayPrice != 0:
self._trend = round(100 * ((tomorrowPrice - todayPrice) / todayPrice),3)
self._officialPriceToday = todayPrice

if len(priceinfo.get("data").get("heads")) > 1:
self._date = priceinfo.get("data").get("heads")[2].get("name")
self._officialPriceTodayDate = priceinfo.get("data").get("heads")[1].get("name")
except Exception as e:
_LOGGER.error(f"ERROR: prediction failed for {self._fueltype.name_lowercase} : {e}")



Expand Down Expand Up @@ -1036,21 +1051,24 @@ async def async_update(self):
await self._data.update()
self._last_update = self._data._lastupdate

priceinfo = self._data._price_info.get(self._fueltype)
# _LOGGER.debug(f"official priceinfo: {priceinfo}")

if self._country.lower() in ['be','fr','lu']:
self._price= priceinfo.get(self._fueltype.sp_code)
self._date = priceinfo.get('Brandstof')
try:
priceinfo = self._data._price_info.get(self._fueltype)
# _LOGGER.debug(f"official priceinfo: {priceinfo}")

self._priceNext= priceinfo.get(self._fueltype.sp_code+"Next")
self._dateNext = priceinfo.get('BrandstofNext')
elif self._country.lower() == 'nl':
self._price= priceinfo.get(self._fueltype.nl_name).get("GLA")
self._date = priceinfo.get(self._fueltype.nl_name).get("date")

self._priceNext= None
self._dateNext = None
if self._country.lower() in ['be','fr','lu']:
self._price= priceinfo.get(self._fueltype.sp_code)
self._date = priceinfo.get('Brandstof')

self._priceNext= priceinfo.get(self._fueltype.sp_code+"Next")
self._dateNext = priceinfo.get('BrandstofNext')
elif self._country.lower() == 'nl':
self._price= priceinfo.get(self._fueltype.nl_name).get("GLA")
self._date = priceinfo.get(self._fueltype.nl_name).get("date")

self._priceNext= None
self._dateNext = None
except Exception as e:
_LOGGER.error(f"ERROR: official failed for {self._fueltype.name_lowercase} : {e}")



Expand Down
4 changes: 3 additions & 1 deletion custom_components/carbu_com/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ class FuelType(Enum):
OILEXTRA = "2",0
OILEXTRA_PREDICTION = "extra",0
LPG = "GPL", 1, "gpl","lpg","17"
LPG_OFFICIAL = "GPL", 1, "gpl","LPG","LPG"
LPG_OFFICIAL = "lpg", 1, "gpl","LPG","LPG"


@property
Expand Down Expand Up @@ -839,6 +839,7 @@ def getFuelOfficial(self, fueltype: FuelType, country):

# Super 95: https://carbu.com/belgie/super95
# Diesel: https://carbu.com/belgie/diesel
# Diesel: https://carbu.com/belgie/lpg
_LOGGER.debug(f"https://carbu.com/belgie/{fueltype_prediction_code}")

response = self.s.get(f"https://carbu.com/belgie/{fueltype_prediction_code}",headers=header,timeout=30)
Expand Down Expand Up @@ -1664,6 +1665,7 @@ def get_nested_element(self, json_obj, key_string):

# test nl official
# session.getFuelOfficial(FuelType.DIESEL_OFFICIAL_B7, "NL")
# session.getFuelOfficial(FuelType.LPG_OFFICIAL, "BE")

#test US
# ZIP Code 10001 - New York, New York
Expand Down

0 comments on commit 7b1391a

Please sign in to comment.