-
-
Notifications
You must be signed in to change notification settings - Fork 38.3k
Add transport data from maps.yandex.ru api #26252
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
Merged
Merged
Changes from 2 commits
Commits
Show all changes
19 commits
Select commit
Hold shift + click to select a range
9c681d4
adding feature obtaining Moscow transport data from maps.yandex.ru api
rishatik92 e1e7d46
extracting the YandexMapsRequester to pypi
rishatik92 36ced04
fix code review comments
rishatik92 ccc8ce1
fix stop_name, state in datetime, logger formating
rishatik92 5cc230e
fix comments
rishatik92 612d619
add docstring to init
rishatik92 e409f98
rename, because it works not only Moscow, but many another big cities…
rishatik92 f36bc3c
fix comments
rishatik92 bf62be3
Try to solve relative view in sensor timestamp
rishatik92 65d12e4
back to isoformat
rishatik92 e3b5894
add tests, update external library version
rishatik92 18dd4ed
flake8 and black tests for sensor.py
rishatik92 98fc10b
fix manifest.json
rishatik92 8e2a0e0
update tests, migrate to pytest, async, Using MockDependency
rishatik92 986dabb
move json to tests/fixtures
rishatik92 2609797
script/lint fixes
rishatik92 0d110ea
fix comments
rishatik92 9e135f7
removing check_filter function
rishatik92 1c98ff1
fix typo
rishatik92 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
Empty file.
12 changes: 12 additions & 0 deletions
12
homeassistant/components/moscow_yandex_transport/manifest.json
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,12 @@ | ||
| { | ||
| "domain": "moscow_yandex_transport", | ||
| "name": "Moscow Yandex transport", | ||
| "documentation": "https://www.home-assistant.io/components/moscow_yandex_transport", | ||
| "requirements": [ | ||
| "moscow_yandex_transport==0.2.0" | ||
| ], | ||
| "dependencies": [], | ||
| "codeowners": [ | ||
| "@rishatik92" | ||
| ] | ||
| } |
143 changes: 143 additions & 0 deletions
143
homeassistant/components/moscow_yandex_transport/sensor.py
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,143 @@ | ||
| # -*- coding: utf-8 -*- | ||
| ''' | ||
| Service for obtaining information about closer bus from Transport Yandex Service | ||
| @author: rishatik92@gmail.com | ||
|
rishatik92 marked this conversation as resolved.
Outdated
|
||
| ''' | ||
|
|
||
| import logging | ||
| from datetime import timedelta | ||
| from time import time | ||
|
|
||
| import voluptuous as vol | ||
| from moscow_yandex_transport import YandexMapsRequester | ||
|
|
||
| import homeassistant.helpers.config_validation as cv | ||
| from homeassistant.components.sensor import PLATFORM_SCHEMA | ||
| from homeassistant.const import CONF_NAME, ATTR_ATTRIBUTION | ||
| from homeassistant.helpers.entity import Entity | ||
|
|
||
| _LOGGER = logging.getLogger(__name__) | ||
|
|
||
| STOP_NAME = "Stop name" | ||
|
rishatik92 marked this conversation as resolved.
Outdated
|
||
| USER_AGENT = "Home Assistant" | ||
| ATTRIBUTION = "Data provided by maps.yandex.ru" | ||
|
|
||
| CONF_STOP_ID = "stop_id" | ||
| CONF_ROUTE = "routes" | ||
|
|
||
| DEFAULT_NAME = "Yandex Transport" | ||
| ICON = "mdi:bus" | ||
|
|
||
| SCAN_INTERVAL = timedelta(minutes=1) | ||
| TIME_STR_FORMAT = "%H:%M" | ||
|
rishatik92 marked this conversation as resolved.
Outdated
|
||
|
|
||
| PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend( | ||
| { | ||
| vol.Required(CONF_STOP_ID): cv.string, | ||
| vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string, | ||
| vol.Optional(CONF_ROUTE, default=[]): cv.ensure_list, | ||
|
rishatik92 marked this conversation as resolved.
Outdated
|
||
| } | ||
| ) | ||
|
|
||
|
|
||
| def due_in_minutes(timestamp: int): | ||
| """Get the time in minutes from a timestamp. | ||
|
|
||
| The timestamp should be in the posix time | ||
| """ | ||
| diff = timestamp - time() | ||
| if diff < 0: | ||
|
rishatik92 marked this conversation as resolved.
Outdated
|
||
| diff = 0 | ||
|
|
||
| return str(int(diff / 60)) | ||
|
|
||
|
|
||
| def setup_platform(hass, config, add_entities, discovery_info=None): | ||
| """Set up the Yandex transport sensor.""" | ||
| stop_id = config.get(CONF_STOP_ID) | ||
|
rishatik92 marked this conversation as resolved.
Outdated
|
||
| name = config.get(CONF_NAME) | ||
|
rishatik92 marked this conversation as resolved.
Outdated
|
||
| routes = config.get(CONF_ROUTE) | ||
|
rishatik92 marked this conversation as resolved.
Outdated
|
||
|
|
||
| data = YandexMapsRequester(user_agent=USER_AGENT) | ||
| add_entities([DiscoverMoscowYandexTransport(data, stop_id, routes, name)], True) | ||
|
|
||
|
|
||
| class DiscoverMoscowYandexTransport(Entity): | ||
| def __init__(self, requester, stop_id, routes, name): | ||
| """ | ||
|
|
||
| :type requester: data provider for request to yandex api | ||
|
rishatik92 marked this conversation as resolved.
Outdated
|
||
| """ | ||
| self.requester = requester | ||
| self._stop_id = stop_id | ||
| self._routes = [] | ||
| for route in routes: | ||
| self._routes.append(str(route)) | ||
|
rishatik92 marked this conversation as resolved.
Outdated
|
||
| self._state = None | ||
| self._name = name | ||
| self._attrs = None | ||
| self._next_route = None | ||
|
rishatik92 marked this conversation as resolved.
Outdated
|
||
|
|
||
| def update(self): | ||
| """Get the latest data from maps.yandex.ru and update the states.""" | ||
| result = {} | ||
|
rishatik92 marked this conversation as resolved.
Outdated
|
||
| closer_time = None | ||
| try: | ||
| yandex_reply = self.requester.get_stop_info(self._stop_id) | ||
| data = yandex_reply["data"] | ||
| stop_metadata = data["properties"]["StopMetaData"] | ||
| except KeyError as e: | ||
| _LOGGER.warning(f"Exception KeyError was captured, missing key is {e}. Yandex returned :{yandex_reply}") | ||
|
rishatik92 marked this conversation as resolved.
Outdated
|
||
| self.requester.set_new_session() | ||
| data = self.requester.get_stop_info(self._stop_id)["data"] | ||
| stop_metadata = data["properties"]["StopMetaData"] | ||
| stop_name = data["properties"]["name"] | ||
| transport_list = stop_metadata["Transport"] | ||
| for transport in transport_list: | ||
| route = transport["name"] | ||
| if self._routes and route not in self._routes: | ||
|
rishatik92 marked this conversation as resolved.
|
||
| # skip unnecessary route info | ||
| continue | ||
| if "Events" in transport["BriefSchedule"]: | ||
| for event in transport["BriefSchedule"]["Events"]: | ||
| if "Estimated" in event: | ||
| posix_time_next = int(event["Estimated"]["value"]) | ||
| if closer_time is None or closer_time > posix_time_next: | ||
| closer_time = posix_time_next | ||
| if route not in result: | ||
|
rishatik92 marked this conversation as resolved.
Outdated
|
||
| result[route] = [] | ||
|
rishatik92 marked this conversation as resolved.
Outdated
|
||
| result[route].append(event["Estimated"]["text"]) | ||
|
rishatik92 marked this conversation as resolved.
Outdated
|
||
| for route in result: | ||
|
rishatik92 marked this conversation as resolved.
Outdated
|
||
| result[route] = ", ".join(result[route]) | ||
| result[STOP_NAME] = stop_name | ||
| result[ATTR_ATTRIBUTION] = ATTRIBUTION | ||
| if closer_time is None: | ||
| self._state = "n/a" | ||
|
rishatik92 marked this conversation as resolved.
Outdated
|
||
| else: | ||
| self._state = due_in_minutes(closer_time) | ||
|
rishatik92 marked this conversation as resolved.
Outdated
|
||
| self._attrs = result | ||
|
|
||
| @property | ||
| def state(self): | ||
| """Return the state of the sensor.""" | ||
| return self._state | ||
|
|
||
| @property | ||
| def name(self): | ||
| """Return the name of the sensor.""" | ||
| return self._name | ||
|
|
||
| @property | ||
| def device_state_attributes(self): | ||
| """Return the state attributes.""" | ||
| return self._attrs | ||
|
|
||
| @property | ||
| def unit_of_measurement(self): | ||
| """Return the unit this state is expressed in.""" | ||
| return "min" | ||
|
rishatik92 marked this conversation as resolved.
Outdated
|
||
|
|
||
| @property | ||
| def icon(self): | ||
| """Icon to use in the frontend, if any.""" | ||
| return ICON | ||
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.