-
-
Notifications
You must be signed in to change notification settings - Fork 31.3k
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
GeoJSON platform #16610
GeoJSON platform #16610
Conversation
@MartinHjelmare: Here comes the first platform for the new geo location component. I decided to go with GeoJSON feeds first before looking at GeoRSS again, because GeoJSON is a bit simpler and does not depend on the |
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.
I didn't look at the tests.
Please rename device to entity consistently cause that's what is referred to here.
from homeassistant.components.sensor.rest import RestData | ||
from homeassistant.const import CONF_RADIUS, CONF_URL, CONF_SCAN_INTERVAL, \ | ||
EVENT_HOMEASSISTANT_START, ATTR_ID, LENGTH_KILOMETERS, LENGTH_METERS | ||
from homeassistant.helpers.config_validation import PLATFORM_SCHEMA |
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.
Import this from the geo_location 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.
OK
vol.Required(CONF_URL): cv.string, | ||
vol.Optional(CONF_RADIUS, default=DEFAULT_RADIUS_IN_KM): | ||
vol.Coerce(float), | ||
vol.Optional(CONF_SCAN_INTERVAL, default=DEFAULT_SCAN_INTERVAL): |
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.
This is already present in the base platform config schema. Define the constant SCAN_INTERVAL
to set default scan interval for this 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.
OK
}) | ||
|
||
|
||
def setup_platform(hass, config, add_entities, disc_info=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.
Please rename disc_info
to discovery_info
to keep variable names consistent all over home assistant.
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.
OK
|
||
import homeassistant.helpers.config_validation as cv | ||
from homeassistant.components.geo_location import GeoLocationEvent | ||
from homeassistant.components.sensor.rest import RestData |
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.
We shouldn't depend on another platform. Service I/O code should be hosted in a standalone library published on pypi.
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.
OK, I understand the direction the project is taking here.
However, at this point there would really not be much more than what is currently implemented in the RestData
class that would need to be outsourced.
And before I go down that path of an external library, could you please have a look at the GeoJsonDistanceHelper
inside the platform. Would you expect that to be outsourced, too, or does this still count as data transformation and can stay inside the 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.
GeoJsonDistanceHelper
certainly looks general enough to fit in a standalone library. I think that's a good idea.
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.
Alright, let me take a look at moving the code.
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.
In the meantime I moved all code that interacts with the external GeoJSON feed as well as the code that calculates distances into a separate library: https://pypi.org/project/geojson-client/
def setup_platform(hass, config, add_entities, disc_info=None): | ||
"""Set up the GeoJSON Events platform.""" | ||
url = config.get(CONF_URL) | ||
scan_interval = config.get(CONF_SCAN_INTERVAL) |
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.
scan_interval = config.get(CONF_SCAN_INTERVAL, SCAN_INTERVAL)
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.
OK
# Update existing device's details with event data. | ||
latitude, longitude, _, name, category = \ | ||
self._extract_data(feature) | ||
device.distance = entry[ATTR_DISTANCE] |
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.
We should invert the flow here so that the entity fetches the new state from a data holding instance in async_update
. That's our standard. Use schedule_update_ha_state(True)
on the entity.
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.
OK. The manager class I implemented is currently fetching the data from the new library and can keep a copy of all entries. Each entity then fetches the original entry on async_update
and updates its values.
"""Return the name of the entity.""" | ||
return self._name | ||
|
||
@name.setter |
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 all the setters and invert the flow as commented 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.
OK
return DEFAULT_UNIT_OF_MEASUREMENT | ||
|
||
@property | ||
def external_id(self): |
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.
This can be made a regular instance attribute.
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.
OK
return self._external_id | ||
|
||
@property | ||
def category(self): |
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.
Same as 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.
I removed the category
altogether for this generic platform since there is no real standard defining categories in GeoJSON feeds.
vol.Optional(CONF_SCAN_INTERVAL, default=DEFAULT_SCAN_INTERVAL): | ||
cv.time_period, | ||
vol.Optional(CONF_CATEGORIES, 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.
Please validate possible categories.
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.
That won't be possible because the external GeoJSON feed can basically make up any category it wants.
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.
Ok. How will the user know what to put here?
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 user would need to look at what categories the provider of the GeoJSON feed has documented, or do a bit of reverse-engineering.
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.
Is there an example of categories from some established feed?
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.
Sure, for example this feed http://www.rfs.nsw.gov.au/feeds/majorIncidents.json uses the following categories:
- Emergency Warning
- Watch and Act
- Advice
- Not Applicable
Documented on the provider's overview page when you scroll down to the table "Alert Level".
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.
I removed categories from this, and move this into a more specific platform, including validation.
@MartinHjelmare : Sorry, I just realised from some of your questions that it may make sense to briefly discuss the general direction for new platforms in the geo location component. Could you please have a look at the last comment in here: home-assistant/architecture#42 |
Those are good questions. I don't have an opinion/answer at the moment. |
@MartinHjelmare : As suggested I moved all code that accesses the external GeoJSON feed into a separate library. I refactored the code in this PR as requested and to integrate with the new library. |
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 ok.
"""No polling needed for GeoJSON location events.""" | ||
return False | ||
|
||
@asyncio.coroutine |
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 Python 3.5 async syntax, ie async def
.
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.
OK
|
||
def setup_platform(hass, config, add_entities, discovery_info=None): | ||
"""Set up the GeoJSON Events platform.""" | ||
url = config.get(CONF_URL) |
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 dict[key]
for required config keys.
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.
OK
…actored platform and tests to work with that new library
6209ff4
to
29d2ffa
Compare
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!
Maybe update the PR description about the category filter. |
Updated the PR description. Doco will be added tonight. |
Description:
This is the first platform of the new geo location component. It fetches data from a GeoJSON feed and generates entities for each external event that is in the vicinity of the Home Assistant server. The radius around Home Assistant is configurable, and so is the scan interval.
I tried to keep this as simple as possible. Future enhancements may include the ability to access other properties of the feed or the ability to define additional filters.
More platforms for specific GeoJSON feeds are in the making, and so are similar platforms for GeoRSS feeds.
Related issue (if applicable): evolving #15953
Pull request in home-assistant.github.io with documentation (if applicable): home-assistant/home-assistant.io#6316
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
.