-
-
Notifications
You must be signed in to change notification settings - Fork 34.1k
Add sensor.nsw_fuel_station component #14757
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
Add sensor.nsw_fuel_station component #14757
Conversation
@property | ||
def name(self) -> str: | ||
"""Return the name of the sensor.""" | ||
return 'NSW Fuel Station {} {}'.format(self._station_data.station_name, self._fuel_type) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
line too long (96 > 79 characters)
station_data = StationPriceData(client, station_id, station_name) | ||
station_data.update() | ||
|
||
add_devices([StationPriceSensor(station_data, fuel_type) for fuel_type in fuel_types]) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
line too long (90 > 79 characters)
PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ | ||
vol.Required(CONF_STATION_ID): cv.positive_int, | ||
vol.Required(CONF_STATION_NAME): cv.string, | ||
vol.Required(CONF_FUEL_TYPES, default=[]): vol.All(cv.ensure_list, [cv.string]), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
line too long (84 > 79 characters)
b8761a3
to
93d08e5
Compare
PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ | ||
vol.Required(CONF_STATION_ID): cv.positive_int, | ||
vol.Required(CONF_STATION_NAME): cv.string, | ||
vol.Required(CONF_FUEL_TYPES, default=[]): vol.All( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if it is required there is no point in having a default, maybe make it option and have the default a non empty list ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great suggestion - I have changed the default to now be the full set of available fuel types and have updated the platform setup to only create sensors where there is an available fuel type to match in the station data (some stations don't supply every type of fuel)
"""Return the price of the given fuel type.""" | ||
if self._data is None: | ||
return None | ||
return next((x for x in self._data if x.fuel_type == fuel_type), None) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
maybe renaming x to price ?
Can you work the test to use This would enable for the removal of the dependency from requirements_test_all.txt |
I think it is good to go! Just remove your dependency from |
Looks like the tests are failing due to the missing dependency, since Is there a proper way for me to patch the module so that the tests will still run even if the package isn't installed.? |
That's where MockDependency I mentioned you some comments above comes in. Just look into other tests that already use MockDependency |
|
||
from homeassistant.components import sensor | ||
from homeassistant.setup import setup_component | ||
from tests.common import get_test_home_assistant, assert_setup_component, MockDependency |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
line too long (88 > 79 characters)
Ah perfect, I must have overlooked that. Thanks for the review 👍 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
Component to display the current fuel prices at a NSW fuel station. | ||
|
||
For more details about this component, please refer to the documentation at | ||
https://home-assistant.io/components/nsw_fuel_station/ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
URL is wrong. Should be https://home-assistant.io/components/sensor.nsw_fuel_station/
.
""" | ||
Component to display the current fuel prices at a NSW fuel station. | ||
|
||
For more details about this component, please refer to the documentation at |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's a platform and not a component. nsw_fuel_station
is a sensor platform.
""" | ||
import datetime | ||
from typing import Optional | ||
import voluptuous as vol |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please keep the import ordered -> https://developers.home-assistant.io/docs/en/development_guidelines.html
|
||
|
||
def setup_platform(hass, config, add_devices, discovery_info=None): | ||
"""Set up the NSW Fuel Station component.""" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Use sensor
instead of component
please.
|
||
PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ | ||
vol.Required(CONF_STATION_ID): cv.positive_int, | ||
vol.Required(CONF_STATION_NAME): cv.string, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Must this really be required
. station_id
is used to retrieve the data incl. the station name. Best would be to let the users set their own name (CONF_NAME
) and fall-back to the name which the request returns.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unfortunately the response from the API does not return the fuel station name:
https://api.onegov.nsw.gov.au/FuelCheckApp/v1/fuel/prices/station/2119
An alternative to this could be to just use the station id as the component name? What do you think is a better user experience?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm, I just checked one station from https://www.fuelcheck.nsw.gov.au and the name seems to be there.
[{
"ServiceStationID":1706,
"Name":"BP Edgecliff",
"Lat":-33.876974,
"Long":151.231099,
[...]
Let the users have the option to name a sensor according their needs in the configuration will avoid that they have to use customize:
. I personally prefer if the default name let me identify the sensor quickly, thus I would just use Fuel Price
+ fuel type. Station Id is not that useful, IMHO.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Gotcha, I thought you were implying I obtained the station name by using the same request/endpoint. I will update the setup_platform
to make an addition request during setup to find the name of the station using another endpoint. Definitely makes sense to make this easier to configure
Let the users have the option to name a sensor according their needs in the configuration will avoid that they have to use customize:
I'll remove the need for a name in the config entirely
thus I would just use Fuel Price + fuel type. Station Id is not that useful, IMHO.
Just double checking, I think you mean Name
+ fuel type?
for fuel_type in fuel_types | ||
if fuel_type in available_fuel_types | ||
]) | ||
return True |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not needed.
def __init__(self, client, station_id: int, station_name: str) -> None: | ||
"""Initialize the sensor.""" | ||
self.station_id = station_id | ||
self.station_name = station_name |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not needed. Thus no need to pass it.
@property | ||
def name(self) -> str: | ||
"""Return the name of the sensor.""" | ||
return 'NSW Fuel Station {} {}'.format( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Remove NSW Fuel Station
because this will create very long identifier and makes it not very handy to use in templates. Limit it to station name and fuel type. With CONF_NAME
can the still add NSW Fuel Station
if needed.
Entity ID: sensor.nsw_fuel_station_caltex_woolworths_peak
Friendly name: NSW Fuel Station Caltex Woolworths Peakhurst P95
"""Return the state attributes of the device.""" | ||
attr = {} | ||
attr['Station ID'] = self._station_data.station_id | ||
attr['Station Name'] = self._station_data.station_name |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please add an attribution for the source of the data.
fuel_types = config[CONF_FUEL_TYPES] | ||
|
||
client = FuelCheckClient() | ||
station_data = StationPriceData(client, station_id, station_name) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The setup of the platform should fail if the station ID is wrong/not available and an error logged (log file and/or persistent notification). Otherwise will be users end up with a non-functional platform.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"""Return the state of the sensor.""" | ||
price_info = self._station_data.for_fuel_type(self._fuel_type) | ||
if price_info: | ||
return price_info.price |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please return None
explicitly if no price is found.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed!
Also, nickw444/nsw-fuel-api-client#1 should be addressed and the requirements updated. |
message, | ||
title=NOTIFICATION_TITLE, | ||
notification_id=NOTIFICATION_ID) | ||
return False |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just return
.
self.station_id) | ||
except FuelCheckError as exc: | ||
self.error = str(exc) | ||
_LOGGER.exception( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Use error level.
except FuelCheckError as exc: | ||
self.error = str(exc) | ||
_LOGGER.error( | ||
'Failed to fetch NSW Fuel station reference data', exc_info=exc) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
line too long (84 > 79 characters)
self.error = str(exc) | ||
_LOGGER.error( | ||
'Failed to fetch NSW Fuel station reference data', | ||
exc_info=exc) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just pass the exception as a string formatting parameter to the logging string message. Don't use exc_info
kwarg.
_LOGGER.error("bla bla %s", exc)
except FuelCheckError as exc: | ||
self.error = str(exc) | ||
_LOGGER.error( | ||
'Failed to fetch NSW Fuel station price data', exc_info=exc) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
See above.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good!
@fabaff should approve. But looks mergeable when build passes. |
* Add sensor.nsw_fuel_station component * bump dependency * PR Changes * flake8 * Use MockPrice * Fix requirements * Fix tests * line length * wip * Handle errors and show persistent notification * update tests * Address @MartinHjelmare's comments * Fetch station name from API * Update tests * Update requirements * Address comments
Description:
Adds a new component,
sensor.nsw_fuel_station
to show fuel prices from fuel stations in NSW, Australia.Pull request in home-assistant.github.io with documentation (if applicable): home-assistant/home-assistant.io#5477
Example entry for
configuration.yaml
(if applicable):Checklist:
tox
. Your PR cannot be merged unless tests passIf user exposed functionality or configuration variables are added/changed:
If the code communicates with devices, web services, or third-party tools:
REQUIREMENTS
variable (example).requirements_all.txt
by runningscript/gen_requirements_all.py
..coveragerc
.If the code does not interact with devices: