From 9c681d47526e9e0530b3f264c801ba737fe6c4b0 Mon Sep 17 00:00:00 2001 From: Rishat Askarov Date: Wed, 28 Aug 2019 21:35:26 +0300 Subject: [PATCH 01/21] adding feature obtaining Moscow transport data from maps.yandex.ru api --- .../moscow_yandex_transport/__init__.py | 0 .../moscow_yandex_transport/manifest.json | 8 + .../moscow_yandex_transport/sensor.py | 178 ++++++++++++++++++ 3 files changed, 186 insertions(+) create mode 100644 homeassistant/components/moscow_yandex_transport/__init__.py create mode 100644 homeassistant/components/moscow_yandex_transport/manifest.json create mode 100644 homeassistant/components/moscow_yandex_transport/sensor.py diff --git a/homeassistant/components/moscow_yandex_transport/__init__.py b/homeassistant/components/moscow_yandex_transport/__init__.py new file mode 100644 index 00000000000000..e69de29bb2d1d6 diff --git a/homeassistant/components/moscow_yandex_transport/manifest.json b/homeassistant/components/moscow_yandex_transport/manifest.json new file mode 100644 index 00000000000000..075791a28432fb --- /dev/null +++ b/homeassistant/components/moscow_yandex_transport/manifest.json @@ -0,0 +1,8 @@ +{ + "domain": "moscow_yandex_transport", + "name": "Moscow Yandex transport", + "documentation": "https://www.home-assistant.io/components/moscow_yandex_transport", + "requirements": [], + "dependencies": [], + "codeowners": [] +} diff --git a/homeassistant/components/moscow_yandex_transport/sensor.py b/homeassistant/components/moscow_yandex_transport/sensor.py new file mode 100644 index 00000000000000..d76136b7f8e0db --- /dev/null +++ b/homeassistant/components/moscow_yandex_transport/sensor.py @@ -0,0 +1,178 @@ +# -*- coding: utf-8 -*- +''' +Service for obtaining information about closer bus from Transport Yandex Service +@author: rishatik92@gmail.com +''' + +RESOURCE = 'https://yandex.ru/maps/api/masstransit/getStopInfo' +CONFIG = { + 'init_url': 'https://maps.yandex.ru', + 'uri': RESOURCE, + 'params': {'ajax': 1, 'lang': 'en', 'locale': 'en_EN', 'mode': 'prognosis'}, + 'headers': {'User-Agent': "Home Assistant"}} +SESSION_KEY = "sessionId" +CSRF_TOKEN_KEY = "csrfToken" +import logging +import re +from datetime import timedelta +from json import loads +from time import time + +import requests +import voluptuous as vol + +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" + +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" + +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, + } +) + + +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: + 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) + name = config.get(CONF_NAME) + routes = config.get(CONF_ROUTE) + + data = YandexMapsRequester(CONFIG) + 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 + """ + self.requester = requester + self._stop_id = stop_id + self._routes = [] + for route in routes: + self._routes.append(str(route)) + self._state = None + self._name = name + self._attrs = None + self._next_route = None + + def update(self): + """Get the latest data from maps.yandex.ru and update the states.""" + result = {} + 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}") + 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: + # 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: + result[route] = [] + result[route].append(event["Estimated"]["text"]) + for route in result: + result[route] = ", ".join(result[route]) + result[STOP_NAME] = stop_name + result[ATTR_ATTRIBUTION] = ATTRIBUTION + if closer_time is None: + self._state = "n/a" + else: + self._state = due_in_minutes(closer_time) + 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" + + @property + def icon(self): + """Icon to use in the frontend, if any.""" + return ICON + + +class YandexMapsRequester(object): + def __init__(self, config): + self._config = config + self.set_new_session() + + def get_stop_info(self, stop_id): + """" + get transport data for stop_id in json + """ + self._config["params"]["id"] = f"stop__{stop_id}" + req = requests.get(self._config["uri"], params=self._config["params"], cookies=self._config["cookies"], + headers=self._config["headers"]) + return loads(req.content.decode('utf8')) + + def set_new_session(self): + """ + Create new http session to Yandex, with valid csrf_token and session_id + """ + ya_request = requests.get(url=self._config["init_url"], headers=self._config["headers"]) + reply = ya_request.content.decode('utf8') + self._config["params"][CSRF_TOKEN_KEY] = re.search(f'"{CSRF_TOKEN_KEY}":"(\w+.\w+)"', reply).group(1) + self._config["cookies"] = dict(ya_request.cookies) + self._config["params"][SESSION_KEY] = re.search(f'"{SESSION_KEY}":"(\d+.\d+)"', reply).group(1) From e1e7d46eb0f5c271e53f43f3c04a4715f1b7e389 Mon Sep 17 00:00:00 2001 From: Rishat Askarov Date: Sat, 31 Aug 2019 20:49:40 +0300 Subject: [PATCH 02/21] extracting the YandexMapsRequester to pypi --- .../moscow_yandex_transport/manifest.json | 8 +++- .../moscow_yandex_transport/sensor.py | 41 ++----------------- 2 files changed, 9 insertions(+), 40 deletions(-) diff --git a/homeassistant/components/moscow_yandex_transport/manifest.json b/homeassistant/components/moscow_yandex_transport/manifest.json index 075791a28432fb..cc4e9d44ecd3f0 100644 --- a/homeassistant/components/moscow_yandex_transport/manifest.json +++ b/homeassistant/components/moscow_yandex_transport/manifest.json @@ -2,7 +2,11 @@ "domain": "moscow_yandex_transport", "name": "Moscow Yandex transport", "documentation": "https://www.home-assistant.io/components/moscow_yandex_transport", - "requirements": [], + "requirements": [ + "moscow_yandex_transport==0.2.0" + ], "dependencies": [], - "codeowners": [] + "codeowners": [ + "@rishatik92" + ] } diff --git a/homeassistant/components/moscow_yandex_transport/sensor.py b/homeassistant/components/moscow_yandex_transport/sensor.py index d76136b7f8e0db..9361770f30b967 100644 --- a/homeassistant/components/moscow_yandex_transport/sensor.py +++ b/homeassistant/components/moscow_yandex_transport/sensor.py @@ -4,22 +4,12 @@ @author: rishatik92@gmail.com ''' -RESOURCE = 'https://yandex.ru/maps/api/masstransit/getStopInfo' -CONFIG = { - 'init_url': 'https://maps.yandex.ru', - 'uri': RESOURCE, - 'params': {'ajax': 1, 'lang': 'en', 'locale': 'en_EN', 'mode': 'prognosis'}, - 'headers': {'User-Agent': "Home Assistant"}} -SESSION_KEY = "sessionId" -CSRF_TOKEN_KEY = "csrfToken" import logging -import re from datetime import timedelta -from json import loads from time import time -import requests import voluptuous as vol +from moscow_yandex_transport import YandexMapsRequester import homeassistant.helpers.config_validation as cv from homeassistant.components.sensor import PLATFORM_SCHEMA @@ -29,7 +19,7 @@ _LOGGER = logging.getLogger(__name__) STOP_NAME = "Stop name" - +USER_AGENT = "Home Assistant" ATTRIBUTION = "Data provided by maps.yandex.ru" CONF_STOP_ID = "stop_id" @@ -68,7 +58,7 @@ def setup_platform(hass, config, add_entities, discovery_info=None): name = config.get(CONF_NAME) routes = config.get(CONF_ROUTE) - data = YandexMapsRequester(CONFIG) + data = YandexMapsRequester(user_agent=USER_AGENT) add_entities([DiscoverMoscowYandexTransport(data, stop_id, routes, name)], True) @@ -151,28 +141,3 @@ def unit_of_measurement(self): def icon(self): """Icon to use in the frontend, if any.""" return ICON - - -class YandexMapsRequester(object): - def __init__(self, config): - self._config = config - self.set_new_session() - - def get_stop_info(self, stop_id): - """" - get transport data for stop_id in json - """ - self._config["params"]["id"] = f"stop__{stop_id}" - req = requests.get(self._config["uri"], params=self._config["params"], cookies=self._config["cookies"], - headers=self._config["headers"]) - return loads(req.content.decode('utf8')) - - def set_new_session(self): - """ - Create new http session to Yandex, with valid csrf_token and session_id - """ - ya_request = requests.get(url=self._config["init_url"], headers=self._config["headers"]) - reply = ya_request.content.decode('utf8') - self._config["params"][CSRF_TOKEN_KEY] = re.search(f'"{CSRF_TOKEN_KEY}":"(\w+.\w+)"', reply).group(1) - self._config["cookies"] = dict(ya_request.cookies) - self._config["params"][SESSION_KEY] = re.search(f'"{SESSION_KEY}":"(\d+.\d+)"', reply).group(1) From 36ced044988a6d0abfb7b3abf0fc958208afc97a Mon Sep 17 00:00:00 2001 From: Rishat Askarov Date: Sun, 1 Sep 2019 21:46:15 +0300 Subject: [PATCH 03/21] fix code review comments --- .../moscow_yandex_transport/sensor.py | 63 +++++++------------ 1 file changed, 22 insertions(+), 41 deletions(-) diff --git a/homeassistant/components/moscow_yandex_transport/sensor.py b/homeassistant/components/moscow_yandex_transport/sensor.py index 9361770f30b967..a5290aaad85177 100644 --- a/homeassistant/components/moscow_yandex_transport/sensor.py +++ b/homeassistant/components/moscow_yandex_transport/sensor.py @@ -1,12 +1,10 @@ # -*- coding: utf-8 -*- -''' +""" Service for obtaining information about closer bus from Transport Yandex Service -@author: rishatik92@gmail.com -''' +""" import logging from datetime import timedelta -from time import time import voluptuous as vol from moscow_yandex_transport import YandexMapsRequester @@ -35,28 +33,17 @@ { vol.Required(CONF_STOP_ID): cv.string, vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string, - vol.Optional(CONF_ROUTE, default=[]): cv.ensure_list, + vol.Optional(CONF_ROUTE, default=[]): vol.All(cv.ensure_list, [cv.string]), + } ) -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: - 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) - name = config.get(CONF_NAME) - routes = config.get(CONF_ROUTE) + stop_id = config[CONF_STOP_ID] + name = config[CONF_NAME] + routes = config[CONF_ROUTE] data = YandexMapsRequester(user_agent=USER_AGENT) add_entities([DiscoverMoscowYandexTransport(data, stop_id, routes, name)], True) @@ -64,30 +51,26 @@ def setup_platform(hass, config, add_entities, discovery_info=None): class DiscoverMoscowYandexTransport(Entity): def __init__(self, requester, stop_id, routes, name): - """ - - :type requester: data provider for request to yandex api - """ + """Initialize sensor.""" self.requester = requester self._stop_id = stop_id self._routes = [] - for route in routes: - self._routes.append(str(route)) + self._routes = routes self._state = None self._name = name self._attrs = None - self._next_route = None def update(self): """Get the latest data from maps.yandex.ru and update the states.""" - result = {} + attrs = {} 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}") + _LOGGER.warning( + "Exception KeyError was captured, missing key is " + str(e) + ". Yandex returned: " + str(yandex_reply)) self.requester.set_new_session() data = self.requester.get_stop_info(self._stop_id)["data"] stop_metadata = data["properties"]["StopMetaData"] @@ -95,7 +78,7 @@ def update(self): transport_list = stop_metadata["Transport"] for transport in transport_list: route = transport["name"] - if self._routes and route not in self._routes: + if route not in self._routes: # skip unnecessary route info continue if "Events" in transport["BriefSchedule"]: @@ -104,18 +87,16 @@ def update(self): 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: - result[route] = [] - result[route].append(event["Estimated"]["text"]) - for route in result: - result[route] = ", ".join(result[route]) - result[STOP_NAME] = stop_name - result[ATTR_ATTRIBUTION] = ATTRIBUTION + if route not in attrs: + attrs[route] = [] + attrs[route].append(event["Estimated"]["text"]) + attrs[STOP_NAME] = stop_name + attrs[ATTR_ATTRIBUTION] = ATTRIBUTION if closer_time is None: - self._state = "n/a" + self._state = None else: - self._state = due_in_minutes(closer_time) - self._attrs = result + self._state = closer_time + self._attrs = attrs @property def state(self): @@ -135,7 +116,7 @@ def device_state_attributes(self): @property def unit_of_measurement(self): """Return the unit this state is expressed in.""" - return "min" + return "timestamp" @property def icon(self): From ccc8ce18cedd4b069fd16fa070ed4439c0d65f61 Mon Sep 17 00:00:00 2001 From: Rishat Askarov Date: Sun, 1 Sep 2019 22:32:23 +0300 Subject: [PATCH 04/21] fix stop_name, state in datetime, logger formating --- .../components/moscow_yandex_transport/sensor.py | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/homeassistant/components/moscow_yandex_transport/sensor.py b/homeassistant/components/moscow_yandex_transport/sensor.py index a5290aaad85177..fb05c921d3e600 100644 --- a/homeassistant/components/moscow_yandex_transport/sensor.py +++ b/homeassistant/components/moscow_yandex_transport/sensor.py @@ -4,7 +4,7 @@ """ import logging -from datetime import timedelta +from datetime import timedelta, datetime import voluptuous as vol from moscow_yandex_transport import YandexMapsRequester @@ -16,7 +16,7 @@ _LOGGER = logging.getLogger(__name__) -STOP_NAME = "Stop name" +STOP_NAME = "stop_name" USER_AGENT = "Home Assistant" ATTRIBUTION = "Data provided by maps.yandex.ru" @@ -27,7 +27,6 @@ ICON = "mdi:bus" SCAN_INTERVAL = timedelta(minutes=1) -TIME_STR_FORMAT = "%H:%M" PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend( { @@ -70,7 +69,7 @@ def update(self): stop_metadata = data["properties"]["StopMetaData"] except KeyError as e: _LOGGER.warning( - "Exception KeyError was captured, missing key is " + str(e) + ". Yandex returned: " + str(yandex_reply)) + "Exception KeyError was captured, missing key is %s. Yandex returned: %s" % (e, yandex_reply)) self.requester.set_new_session() data = self.requester.get_stop_info(self._stop_id)["data"] stop_metadata = data["properties"]["StopMetaData"] @@ -95,7 +94,7 @@ def update(self): if closer_time is None: self._state = None else: - self._state = closer_time + self._state = datetime.utcfromtimestamp(closer_time) self._attrs = attrs @property @@ -113,11 +112,6 @@ 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 "timestamp" - @property def icon(self): """Icon to use in the frontend, if any.""" From 5cc230ec556ff99d255b02d67b3d00fd1dd5de68 Mon Sep 17 00:00:00 2001 From: Rishat Askarov Date: Sun, 1 Sep 2019 23:03:30 +0300 Subject: [PATCH 05/21] fix comments --- .../components/moscow_yandex_transport/sensor.py | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/homeassistant/components/moscow_yandex_transport/sensor.py b/homeassistant/components/moscow_yandex_transport/sensor.py index fb05c921d3e600..234d16a283150a 100644 --- a/homeassistant/components/moscow_yandex_transport/sensor.py +++ b/homeassistant/components/moscow_yandex_transport/sensor.py @@ -69,7 +69,7 @@ def update(self): stop_metadata = data["properties"]["StopMetaData"] except KeyError as e: _LOGGER.warning( - "Exception KeyError was captured, missing key is %s. Yandex returned: %s" % (e, yandex_reply)) + "Exception KeyError was captured, missing key is %s. Yandex returned: %s" % e, yandex_reply) self.requester.set_new_session() data = self.requester.get_stop_info(self._stop_id)["data"] stop_metadata = data["properties"]["StopMetaData"] @@ -77,7 +77,7 @@ def update(self): transport_list = stop_metadata["Transport"] for transport in transport_list: route = transport["name"] - if route not in self._routes: + if self._routes and route not in self._routes: # skip unnecessary route info continue if "Events" in transport["BriefSchedule"]: @@ -94,7 +94,7 @@ def update(self): if closer_time is None: self._state = None else: - self._state = datetime.utcfromtimestamp(closer_time) + self._state = datetime.utcfromtimestamp(closer_time).isoformat(timespec='minutes') self._attrs = attrs @property @@ -102,6 +102,11 @@ def state(self): """Return the state of the sensor.""" return self._state + @property + def device_class(self): + """Return type of the sensor.""" + return "timestamp" + @property def name(self): """Return the name of the sensor.""" From 612d6191e74ab9fb0bc5510d62a64b81351373f7 Mon Sep 17 00:00:00 2001 From: Rishat Askarov Date: Sun, 1 Sep 2019 23:04:42 +0300 Subject: [PATCH 06/21] add docstring to init --- homeassistant/components/moscow_yandex_transport/__init__.py | 1 + 1 file changed, 1 insertion(+) diff --git a/homeassistant/components/moscow_yandex_transport/__init__.py b/homeassistant/components/moscow_yandex_transport/__init__.py index e69de29bb2d1d6..a2586ae4ca6a04 100644 --- a/homeassistant/components/moscow_yandex_transport/__init__.py +++ b/homeassistant/components/moscow_yandex_transport/__init__.py @@ -0,0 +1 @@ +""" Service for obtaining information about closer bus from Transport Yandex Service. """ From e409f9814b123e0914da71f5e73134c1b879a908 Mon Sep 17 00:00:00 2001 From: Rishat Askarov Date: Wed, 4 Sep 2019 22:55:49 +0300 Subject: [PATCH 07/21] rename, because it works not only Moscow, but many another big cities in Russia --- .../components/moscow_yandex_transport/manifest.json | 12 ------------ .../__init__.py | 0 .../components/yandex_transport/manifest.json | 12 ++++++++++++ .../sensor.py | 2 +- 4 files changed, 13 insertions(+), 13 deletions(-) delete mode 100644 homeassistant/components/moscow_yandex_transport/manifest.json rename homeassistant/components/{moscow_yandex_transport => yandex_transport}/__init__.py (100%) create mode 100644 homeassistant/components/yandex_transport/manifest.json rename homeassistant/components/{moscow_yandex_transport => yandex_transport}/sensor.py (98%) diff --git a/homeassistant/components/moscow_yandex_transport/manifest.json b/homeassistant/components/moscow_yandex_transport/manifest.json deleted file mode 100644 index cc4e9d44ecd3f0..00000000000000 --- a/homeassistant/components/moscow_yandex_transport/manifest.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "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" - ] -} diff --git a/homeassistant/components/moscow_yandex_transport/__init__.py b/homeassistant/components/yandex_transport/__init__.py similarity index 100% rename from homeassistant/components/moscow_yandex_transport/__init__.py rename to homeassistant/components/yandex_transport/__init__.py diff --git a/homeassistant/components/yandex_transport/manifest.json b/homeassistant/components/yandex_transport/manifest.json new file mode 100644 index 00000000000000..d6e98989279075 --- /dev/null +++ b/homeassistant/components/yandex_transport/manifest.json @@ -0,0 +1,12 @@ +{ + "domain": "andex_transport", + "name": "Yandex transport", + "documentation": "https://www.home-assistant.io/components/yandex_transport", + "requirements": [ + "ya_ma==0.2.0" + ], + "dependencies": [], + "codeowners": [ + "@rishatik92" + ] +} diff --git a/homeassistant/components/moscow_yandex_transport/sensor.py b/homeassistant/components/yandex_transport/sensor.py similarity index 98% rename from homeassistant/components/moscow_yandex_transport/sensor.py rename to homeassistant/components/yandex_transport/sensor.py index 234d16a283150a..d62104c31efbdb 100644 --- a/homeassistant/components/moscow_yandex_transport/sensor.py +++ b/homeassistant/components/yandex_transport/sensor.py @@ -7,7 +7,7 @@ from datetime import timedelta, datetime import voluptuous as vol -from moscow_yandex_transport import YandexMapsRequester +from ya_ma import YandexMapsRequester import homeassistant.helpers.config_validation as cv from homeassistant.components.sensor import PLATFORM_SCHEMA From f36bc3c7251e319022da3f3010e5d941d83a07d3 Mon Sep 17 00:00:00 2001 From: Rishat Askarov Date: Wed, 4 Sep 2019 23:36:07 +0300 Subject: [PATCH 08/21] fix comments --- .coveragerc | 1 + CODEOWNERS | 1 + homeassistant/components/yandex_transport/manifest.json | 4 ++-- requirements_all.txt | 3 +++ 4 files changed, 7 insertions(+), 2 deletions(-) diff --git a/.coveragerc b/.coveragerc index 02d59b55f5f2a1..23c028278e0e6d 100644 --- a/.coveragerc +++ b/.coveragerc @@ -726,6 +726,7 @@ omit = homeassistant/components/yale_smart_alarm/alarm_control_panel.py homeassistant/components/yamaha/media_player.py homeassistant/components/yamaha_musiccast/media_player.py + homeassistant/components/yandex_transport/* homeassistant/components/yeelight/* homeassistant/components/yeelightsunflower/light.py homeassistant/components/yi/camera.py diff --git a/CODEOWNERS b/CODEOWNERS index d51031486ef7cc..a04a25ec93d9a4 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -309,6 +309,7 @@ homeassistant/components/xiaomi_miio/* @rytilahti @syssi homeassistant/components/xiaomi_tv/* @simse homeassistant/components/xmpp/* @fabaff @flowolf homeassistant/components/yamaha_musiccast/* @jalmeroth +homeassistant/components/yandex_transport/* @rishatik92 homeassistant/components/yeelight/* @rytilahti @zewelor homeassistant/components/yeelightsunflower/* @lindsaymarkward homeassistant/components/yessssms/* @flowolf diff --git a/homeassistant/components/yandex_transport/manifest.json b/homeassistant/components/yandex_transport/manifest.json index d6e98989279075..cae2139183ed93 100644 --- a/homeassistant/components/yandex_transport/manifest.json +++ b/homeassistant/components/yandex_transport/manifest.json @@ -1,9 +1,9 @@ { - "domain": "andex_transport", + "domain": "yandex_transport", "name": "Yandex transport", "documentation": "https://www.home-assistant.io/components/yandex_transport", "requirements": [ - "ya_ma==0.2.0" + "ya_ma==0.3.1" ], "dependencies": [], "codeowners": [ diff --git a/requirements_all.txt b/requirements_all.txt index 147cbb3a8a99a3..c1a2a4ced8eb02 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -1955,6 +1955,9 @@ xmltodict==0.12.0 # homeassistant.components.xs1 xs1-api-client==2.3.5 +# homeassistant.components.yandex_transport +ya_ma==0.3.1 + # homeassistant.components.yweather yahooweather==0.10 From bf62be3d51f0585a16ff97e5a45e61c0c0a7e607 Mon Sep 17 00:00:00 2001 From: Rishat Askarov Date: Thu, 5 Sep 2019 01:52:38 +0300 Subject: [PATCH 09/21] Try to solve relative view in sensor timestamp --- homeassistant/components/yandex_transport/sensor.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/homeassistant/components/yandex_transport/sensor.py b/homeassistant/components/yandex_transport/sensor.py index d62104c31efbdb..71e2f92010ea6e 100644 --- a/homeassistant/components/yandex_transport/sensor.py +++ b/homeassistant/components/yandex_transport/sensor.py @@ -4,14 +4,15 @@ """ import logging -from datetime import timedelta, datetime +from datetime import timedelta import voluptuous as vol from ya_ma import YandexMapsRequester import homeassistant.helpers.config_validation as cv +import homeassistant.util.dt as dt_util from homeassistant.components.sensor import PLATFORM_SCHEMA -from homeassistant.const import CONF_NAME, ATTR_ATTRIBUTION +from homeassistant.const import CONF_NAME, ATTR_ATTRIBUTION, DEVICE_CLASS_TIMESTAMP from homeassistant.helpers.entity import Entity _LOGGER = logging.getLogger(__name__) @@ -94,7 +95,7 @@ def update(self): if closer_time is None: self._state = None else: - self._state = datetime.utcfromtimestamp(closer_time).isoformat(timespec='minutes') + self._state = dt_util.utc_from_timestamp(closer_time) self._attrs = attrs @property @@ -104,8 +105,8 @@ def state(self): @property def device_class(self): - """Return type of the sensor.""" - return "timestamp" + """Return the device class.""" + return DEVICE_CLASS_TIMESTAMP @property def name(self): From 65d12e4ff30a8d28539f883618fd9ed146dc76c0 Mon Sep 17 00:00:00 2001 From: Rishat Askarov Date: Thu, 5 Sep 2019 01:58:42 +0300 Subject: [PATCH 10/21] back to isoformat --- homeassistant/components/yandex_transport/sensor.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/homeassistant/components/yandex_transport/sensor.py b/homeassistant/components/yandex_transport/sensor.py index 71e2f92010ea6e..7ab3a4914f3069 100644 --- a/homeassistant/components/yandex_transport/sensor.py +++ b/homeassistant/components/yandex_transport/sensor.py @@ -95,7 +95,7 @@ def update(self): if closer_time is None: self._state = None else: - self._state = dt_util.utc_from_timestamp(closer_time) + self._state = dt_util.utc_from_timestamp(closer_time).isoformat(timespec="seconds") self._attrs = attrs @property From e3b589457e7b094e2c69d974686ad89b5722af5d Mon Sep 17 00:00:00 2001 From: Rishat Askarov Date: Wed, 18 Sep 2019 23:20:17 +0300 Subject: [PATCH 11/21] add tests, update external library version --- .../components/yandex_transport/manifest.json | 2 +- requirements_all.txt | 2 +- tests/components/yandex_transport/__init__.py | 1 + .../yandex_transport/mock_import.py | 1883 +++++++++++++++++ .../test_yandex_transport_sensor.py | 118 ++ 5 files changed, 2004 insertions(+), 2 deletions(-) create mode 100644 tests/components/yandex_transport/__init__.py create mode 100644 tests/components/yandex_transport/mock_import.py create mode 100644 tests/components/yandex_transport/test_yandex_transport_sensor.py diff --git a/homeassistant/components/yandex_transport/manifest.json b/homeassistant/components/yandex_transport/manifest.json index cae2139183ed93..3187bf670252c4 100644 --- a/homeassistant/components/yandex_transport/manifest.json +++ b/homeassistant/components/yandex_transport/manifest.json @@ -3,7 +3,7 @@ "name": "Yandex transport", "documentation": "https://www.home-assistant.io/components/yandex_transport", "requirements": [ - "ya_ma==0.3.1" + "ya_ma==0.3.4" ], "dependencies": [], "codeowners": [ diff --git a/requirements_all.txt b/requirements_all.txt index c1a2a4ced8eb02..12a429901fca4b 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -1956,7 +1956,7 @@ xmltodict==0.12.0 xs1-api-client==2.3.5 # homeassistant.components.yandex_transport -ya_ma==0.3.1 +ya_ma==0.3.4 # homeassistant.components.yweather yahooweather==0.10 diff --git a/tests/components/yandex_transport/__init__.py b/tests/components/yandex_transport/__init__.py new file mode 100644 index 00000000000000..fe6b0db52d3e05 --- /dev/null +++ b/tests/components/yandex_transport/__init__.py @@ -0,0 +1 @@ +"""Tests for the yandex transport platform.""" diff --git a/tests/components/yandex_transport/mock_import.py b/tests/components/yandex_transport/mock_import.py new file mode 100644 index 00000000000000..b78308c7f5b402 --- /dev/null +++ b/tests/components/yandex_transport/mock_import.py @@ -0,0 +1,1883 @@ +"""Mock import ya_ma library for the tests.""" +import sys +from unittest.mock import Mock + +fake_module = Mock() + +REPLY = { + "data": { + "geometries": [{"type": "Point", "coordinates": [37.565280044, 55.851959656]}], + "geometry": {"type": "Point", "coordinates": [37.565280044, 55.851959656]}, + "properties": { + "name": "7-й автобусный парк", + "description": "7-й автобусный парк", + "currentTime": "Mon Sep 16 2019 21:40:40 GMT+0300 (Moscow Standard Time)", + "StopMetaData": { + "id": "stop__9639579", + "name": "7-й автобусный парк", + "type": "urban", + "region": { + "id": 213, + "type": 6, + "parent_id": 1, + "capital_id": 0, + "geo_parent_id": 0, + "city_id": 213, + "name": "moscow", + "native_name": "", + "iso_name": "RU MOW", + "is_main": True, + "en_name": "Moscow", + "short_en_name": "MSK", + "phone_code": "495 499", + "phone_code_old": "095", + "zip_code": "", + "population": 12506468, + "synonyms": "Moskau, Moskva", + "latitude": 55.753215, + "longitude": 37.622504, + "latitude_size": 0.878654, + "longitude_size": 1.164423, + "zoom": 10, + "tzname": "Europe/Moscow", + "official_languages": "ru", + "widespread_languages": "ru", + "suggest_list": [], + "is_eu": False, + "services_names": [ + "bs", + "yaca", + "weather", + "afisha", + "maps", + "tv", + "ad", + "etrain", + "subway", + "delivery", + "route", + ], + "ename": "moscow", + "bounds": [ + [37.0402925, 55.31141404514547], + [38.2047155, 56.190068045145466], + ], + "names": { + "ablative": "", + "accusative": "Москву", + "dative": "Москве", + "directional": "", + "genitive": "Москвы", + "instrumental": "Москвой", + "locative": "", + "nominative": "Москва", + "preposition": "в", + "prepositional": "Москве", + }, + "parent": { + "id": 1, + "type": 5, + "parent_id": 3, + "capital_id": 213, + "geo_parent_id": 0, + "city_id": 213, + "name": "moscow-and-moscow-oblast", + "native_name": "", + "iso_name": "RU-MOS", + "is_main": True, + "en_name": "Moscow and Moscow Oblast", + "short_en_name": "RU-MOS", + "phone_code": "495 496 498 499", + "phone_code_old": "", + "zip_code": "", + "population": 7503385, + "synonyms": "Московская область, Подмосковье, Podmoskovye", + "latitude": 55.815792, + "longitude": 37.380031, + "latitude_size": 2.705659, + "longitude_size": 5.060749, + "zoom": 8, + "tzname": "Europe/Moscow", + "official_languages": "ru", + "widespread_languages": "ru", + "suggest_list": [ + 213, + 10716, + 10747, + 10758, + 20728, + 10740, + 10738, + 20523, + 10735, + 10734, + 10743, + 21622, + ], + "is_eu": False, + "services_names": ["bs", "yaca", "ad"], + "ename": "moscow-and-moscow-oblast", + "bounds": [ + [34.8496565, 54.439456064325434], + [39.9104055, 57.14511506432543], + ], + "names": { + "ablative": "", + "accusative": "Москву и Московскую область", + "dative": "Москве и Московской области", + "directional": "", + "genitive": "Москвы и Московской области", + "instrumental": "Москвой и Московской областью", + "locative": "", + "nominative": "Москва и Московская область", + "preposition": "в", + "prepositional": "Москве и Московской области", + }, + "parent": { + "id": 225, + "type": 3, + "parent_id": 10001, + "capital_id": 213, + "geo_parent_id": 0, + "city_id": 213, + "name": "russia", + "native_name": "", + "iso_name": "RU", + "is_main": False, + "en_name": "Russia", + "short_en_name": "RU", + "phone_code": "7", + "phone_code_old": "", + "zip_code": "", + "population": 146880432, + "synonyms": "Russian Federation,Российская Федерация", + "latitude": 61.698653, + "longitude": 99.505405, + "latitude_size": 40.700127, + "longitude_size": 171.643239, + "zoom": 3, + "tzname": "", + "official_languages": "ru", + "widespread_languages": "ru", + "suggest_list": [ + 213, + 2, + 65, + 54, + 47, + 43, + 66, + 51, + 56, + 172, + 39, + 62, + ], + "is_eu": False, + "services_names": ["bs", "yaca", "ad"], + "ename": "russia", + "bounds": [ + [13.683785499999999, 35.290400699917846], + [-174.6729755, 75.99052769991785], + ], + "names": { + "ablative": "", + "accusative": "Россию", + "dative": "России", + "directional": "", + "genitive": "России", + "instrumental": "Россией", + "locative": "", + "nominative": "Россия", + "preposition": "в", + "prepositional": "России", + }, + }, + }, + }, + "Transport": [ + { + "lineId": "2036925416", + "name": "194", + "Types": ["bus"], + "type": "bus", + "threads": [ + { + "threadId": "2036927196", + "EssentialStops": [ + { + "id": "stop__9711780", + "name": "Метро Петровско-Разумовская", + }, + {"id": "stop__9648742", "name": "Коровино"}, + ], + "BriefSchedule": { + "Events": [ + { + "Scheduled": { + "value": "1568659860", + "tzOffset": 10800, + "text": "21:51", + } + }, + { + "Scheduled": { + "value": "1568660760", + "tzOffset": 10800, + "text": "22:06", + } + }, + { + "Scheduled": { + "value": "1568661840", + "tzOffset": 10800, + "text": "22:24", + } + }, + ], + "departureTime": "21:51", + }, + } + ], + "threadId": "2036927196", + "EssentialStops": [ + { + "id": "stop__9711780", + "name": "Метро Петровско-Разумовская", + }, + {"id": "stop__9648742", "name": "Коровино"}, + ], + "BriefSchedule": { + "Events": [ + { + "Scheduled": { + "value": "1568659860", + "tzOffset": 10800, + "text": "21:51", + } + }, + { + "Scheduled": { + "value": "1568660760", + "tzOffset": 10800, + "text": "22:06", + } + }, + { + "Scheduled": { + "value": "1568661840", + "tzOffset": 10800, + "text": "22:24", + } + }, + ], + "departureTime": "21:51", + }, + }, + { + "lineId": "213_114_bus_mosgortrans", + "name": "114", + "Types": ["bus"], + "type": "bus", + "threads": [ + { + "threadId": "213B_114_bus_mosgortrans", + "EssentialStops": [ + {"id": "stop__9647199", "name": "Метро Войковская"}, + { + "id": "stop__9639588", + "name": "Коровинское шоссе", + }, + ], + "BriefSchedule": { + "Events": [], + "Frequency": { + "text": "15 мин", + "value": 900, + "begin": { + "value": "1568603405", + "tzOffset": 10800, + "text": "6:10", + }, + "end": { + "value": "1568672165", + "tzOffset": 10800, + "text": "1:16", + }, + }, + }, + } + ], + "threadId": "213B_114_bus_mosgortrans", + "EssentialStops": [ + {"id": "stop__9647199", "name": "Метро Войковская"}, + {"id": "stop__9639588", "name": "Коровинское шоссе"}, + ], + "BriefSchedule": { + "Events": [], + "Frequency": { + "text": "15 мин", + "value": 900, + "begin": { + "value": "1568603405", + "tzOffset": 10800, + "text": "6:10", + }, + "end": { + "value": "1568672165", + "tzOffset": 10800, + "text": "1:16", + }, + }, + }, + }, + { + "lineId": "213_154_bus_mosgortrans", + "name": "154", + "Types": ["bus"], + "type": "bus", + "threads": [ + { + "threadId": "213B_154_bus_mosgortrans", + "EssentialStops": [ + {"id": "stop__9642548", "name": "ВДНХ (южная)"}, + {"id": "stop__9711744", "name": "Станция Ховрино"}, + ], + "BriefSchedule": { + "Events": [ + { + "Scheduled": { + "value": "1568659260", + "tzOffset": 10800, + "text": "21:41", + }, + "Estimated": { + "value": "1568659252", + "tzOffset": 10800, + "text": "21:40", + }, + "vehicleId": "codd%5Fnew|1054764%5F191500", + }, + { + "Scheduled": { + "value": "1568660580", + "tzOffset": 10800, + "text": "22:03", + } + }, + { + "Scheduled": { + "value": "1568661900", + "tzOffset": 10800, + "text": "22:25", + } + }, + ], + "departureTime": "21:41", + }, + } + ], + "threadId": "213B_154_bus_mosgortrans", + "EssentialStops": [ + {"id": "stop__9642548", "name": "ВДНХ (южная)"}, + {"id": "stop__9711744", "name": "Станция Ховрино"}, + ], + "BriefSchedule": { + "Events": [ + { + "Scheduled": { + "value": "1568659260", + "tzOffset": 10800, + "text": "21:41", + }, + "Estimated": { + "value": "1568659252", + "tzOffset": 10800, + "text": "21:40", + }, + "vehicleId": "codd%5Fnew|1054764%5F191500", + }, + { + "Scheduled": { + "value": "1568660580", + "tzOffset": 10800, + "text": "22:03", + } + }, + { + "Scheduled": { + "value": "1568661900", + "tzOffset": 10800, + "text": "22:25", + } + }, + ], + "departureTime": "21:41", + }, + }, + { + "lineId": "213_179_bus_mosgortrans", + "name": "179", + "Types": ["bus"], + "type": "bus", + "threads": [ + { + "threadId": "213B_179_bus_mosgortrans", + "EssentialStops": [ + {"id": "stop__9647199", "name": "Метро Войковская"}, + { + "id": "stop__9639480", + "name": "Платформа Лианозово", + }, + ], + "BriefSchedule": { + "Events": [ + { + "Scheduled": { + "value": "1568659920", + "tzOffset": 10800, + "text": "21:52", + }, + "Estimated": { + "value": "1568659351", + "tzOffset": 10800, + "text": "21:42", + }, + "vehicleId": "codd%5Fnew|59832%5F31359", + }, + { + "Scheduled": { + "value": "1568660760", + "tzOffset": 10800, + "text": "22:06", + } + }, + { + "Scheduled": { + "value": "1568661660", + "tzOffset": 10800, + "text": "22:21", + } + }, + ], + "departureTime": "21:52", + }, + } + ], + "threadId": "213B_179_bus_mosgortrans", + "EssentialStops": [ + {"id": "stop__9647199", "name": "Метро Войковская"}, + {"id": "stop__9639480", "name": "Платформа Лианозово"}, + ], + "BriefSchedule": { + "Events": [ + { + "Scheduled": { + "value": "1568659920", + "tzOffset": 10800, + "text": "21:52", + }, + "Estimated": { + "value": "1568659351", + "tzOffset": 10800, + "text": "21:42", + }, + "vehicleId": "codd%5Fnew|59832%5F31359", + }, + { + "Scheduled": { + "value": "1568660760", + "tzOffset": 10800, + "text": "22:06", + } + }, + { + "Scheduled": { + "value": "1568661660", + "tzOffset": 10800, + "text": "22:21", + } + }, + ], + "departureTime": "21:52", + }, + }, + { + "lineId": "213_191m_minibus_default", + "name": "591", + "Types": ["bus"], + "type": "bus", + "threads": [ + { + "threadId": "213A_191m_minibus_default", + "EssentialStops": [ + {"id": "stop__9647199", "name": "Метро Войковская"}, + {"id": "stop__9711744", "name": "Станция Ховрино"}, + ], + "BriefSchedule": { + "Events": [ + { + "Estimated": { + "value": "1568660525", + "tzOffset": 10800, + "text": "22:02", + }, + "vehicleId": "codd%5Fnew|38278%5F9345312", + } + ], + "Frequency": { + "text": "22 мин", + "value": 1320, + "begin": { + "value": "1568602033", + "tzOffset": 10800, + "text": "5:47", + }, + "end": { + "value": "1568672233", + "tzOffset": 10800, + "text": "1:17", + }, + }, + }, + } + ], + "threadId": "213A_191m_minibus_default", + "EssentialStops": [ + {"id": "stop__9647199", "name": "Метро Войковская"}, + {"id": "stop__9711744", "name": "Станция Ховрино"}, + ], + "BriefSchedule": { + "Events": [ + { + "Estimated": { + "value": "1568660525", + "tzOffset": 10800, + "text": "22:02", + }, + "vehicleId": "codd%5Fnew|38278%5F9345312", + } + ], + "Frequency": { + "text": "22 мин", + "value": 1320, + "begin": { + "value": "1568602033", + "tzOffset": 10800, + "text": "5:47", + }, + "end": { + "value": "1568672233", + "tzOffset": 10800, + "text": "1:17", + }, + }, + }, + }, + { + "lineId": "213_206m_minibus_default", + "name": "206к", + "Types": ["bus"], + "type": "bus", + "threads": [ + { + "threadId": "213A_206m_minibus_default", + "EssentialStops": [ + { + "id": "stop__9640756", + "name": "Метро Петровско-Разумовская", + }, + {"id": "stop__9640553", "name": "Лобненская улица"}, + ], + "BriefSchedule": { + "Events": [], + "Frequency": { + "text": "22 мин", + "value": 1320, + "begin": { + "value": "1568601239", + "tzOffset": 10800, + "text": "5:33", + }, + "end": { + "value": "1568671439", + "tzOffset": 10800, + "text": "1:03", + }, + }, + }, + } + ], + "threadId": "213A_206m_minibus_default", + "EssentialStops": [ + { + "id": "stop__9640756", + "name": "Метро Петровско-Разумовская", + }, + {"id": "stop__9640553", "name": "Лобненская улица"}, + ], + "BriefSchedule": { + "Events": [], + "Frequency": { + "text": "22 мин", + "value": 1320, + "begin": { + "value": "1568601239", + "tzOffset": 10800, + "text": "5:33", + }, + "end": { + "value": "1568671439", + "tzOffset": 10800, + "text": "1:03", + }, + }, + }, + }, + { + "lineId": "213_215_bus_mosgortrans", + "name": "215", + "Types": ["bus"], + "type": "bus", + "threads": [ + { + "threadId": "213B_215_bus_mosgortrans", + "EssentialStops": [ + { + "id": "stop__9711780", + "name": "Метро Петровско-Разумовская", + }, + {"id": "stop__9711744", "name": "Станция Ховрино"}, + ], + "BriefSchedule": { + "Events": [], + "Frequency": { + "text": "27 мин", + "value": 1620, + "begin": { + "value": "1568601276", + "tzOffset": 10800, + "text": "5:34", + }, + "end": { + "value": "1568671476", + "tzOffset": 10800, + "text": "1:04", + }, + }, + }, + } + ], + "threadId": "213B_215_bus_mosgortrans", + "EssentialStops": [ + { + "id": "stop__9711780", + "name": "Метро Петровско-Разумовская", + }, + {"id": "stop__9711744", "name": "Станция Ховрино"}, + ], + "BriefSchedule": { + "Events": [], + "Frequency": { + "text": "27 мин", + "value": 1620, + "begin": { + "value": "1568601276", + "tzOffset": 10800, + "text": "5:34", + }, + "end": { + "value": "1568671476", + "tzOffset": 10800, + "text": "1:04", + }, + }, + }, + }, + { + "lineId": "213_282_bus_mosgortrans", + "name": "282", + "Types": ["bus"], + "type": "bus", + "threads": [ + { + "threadId": "213A_282_bus_mosgortrans", + "EssentialStops": [ + {"id": "stop__9641102", "name": "Улица Корнейчука"}, + {"id": "2532226085", "name": "Метро Войковская"}, + ], + "BriefSchedule": { + "Events": [ + { + "Estimated": { + "value": "1568659888", + "tzOffset": 10800, + "text": "21:51", + }, + "vehicleId": "codd%5Fnew|34874%5F9345408", + } + ], + "Frequency": { + "text": "15 мин", + "value": 900, + "begin": { + "value": "1568602180", + "tzOffset": 10800, + "text": "5:49", + }, + "end": { + "value": "1568673460", + "tzOffset": 10800, + "text": "1:37", + }, + }, + }, + } + ], + "threadId": "213A_282_bus_mosgortrans", + "EssentialStops": [ + {"id": "stop__9641102", "name": "Улица Корнейчука"}, + {"id": "2532226085", "name": "Метро Войковская"}, + ], + "BriefSchedule": { + "Events": [ + { + "Estimated": { + "value": "1568659888", + "tzOffset": 10800, + "text": "21:51", + }, + "vehicleId": "codd%5Fnew|34874%5F9345408", + } + ], + "Frequency": { + "text": "15 мин", + "value": 900, + "begin": { + "value": "1568602180", + "tzOffset": 10800, + "text": "5:49", + }, + "end": { + "value": "1568673460", + "tzOffset": 10800, + "text": "1:37", + }, + }, + }, + }, + { + "lineId": "213_294m_minibus_default", + "name": "994", + "Types": ["bus"], + "type": "bus", + "threads": [ + { + "threadId": "213A_294m_minibus_default", + "EssentialStops": [ + { + "id": "stop__9640756", + "name": "Метро Петровско-Разумовская", + }, + {"id": "stop__9649459", "name": "Метро Алтуфьево"}, + ], + "BriefSchedule": { + "Events": [], + "Frequency": { + "text": "30 мин", + "value": 1800, + "begin": { + "value": "1568601527", + "tzOffset": 10800, + "text": "5:38", + }, + "end": { + "value": "1568671727", + "tzOffset": 10800, + "text": "1:08", + }, + }, + }, + } + ], + "threadId": "213A_294m_minibus_default", + "EssentialStops": [ + { + "id": "stop__9640756", + "name": "Метро Петровско-Разумовская", + }, + {"id": "stop__9649459", "name": "Метро Алтуфьево"}, + ], + "BriefSchedule": { + "Events": [], + "Frequency": { + "text": "30 мин", + "value": 1800, + "begin": { + "value": "1568601527", + "tzOffset": 10800, + "text": "5:38", + }, + "end": { + "value": "1568671727", + "tzOffset": 10800, + "text": "1:08", + }, + }, + }, + }, + { + "lineId": "213_36_trolleybus_mosgortrans", + "name": "т36", + "Types": ["bus"], + "type": "bus", + "threads": [ + { + "threadId": "213A_36_trolleybus_mosgortrans", + "EssentialStops": [ + {"id": "stop__9642550", "name": "ВДНХ (южная)"}, + { + "id": "stop__9640641", + "name": "Дмитровское шоссе, 155", + }, + ], + "BriefSchedule": { + "Events": [ + { + "Scheduled": { + "value": "1568659680", + "tzOffset": 10800, + "text": "21:48", + }, + "Estimated": { + "value": "1568659426", + "tzOffset": 10800, + "text": "21:43", + }, + "vehicleId": "codd%5Fnew|1084829%5F430260", + }, + { + "Scheduled": { + "value": "1568660520", + "tzOffset": 10800, + "text": "22:02", + }, + "Estimated": { + "value": "1568659656", + "tzOffset": 10800, + "text": "21:47", + }, + "vehicleId": "codd%5Fnew|1117016%5F430280", + }, + { + "Scheduled": { + "value": "1568661900", + "tzOffset": 10800, + "text": "22:25", + }, + "Estimated": { + "value": "1568660538", + "tzOffset": 10800, + "text": "22:02", + }, + "vehicleId": "codd%5Fnew|1054576%5F430226", + }, + ], + "departureTime": "21:48", + }, + } + ], + "threadId": "213A_36_trolleybus_mosgortrans", + "EssentialStops": [ + {"id": "stop__9642550", "name": "ВДНХ (южная)"}, + {"id": "stop__9640641", "name": "Дмитровское шоссе, 155"}, + ], + "BriefSchedule": { + "Events": [ + { + "Scheduled": { + "value": "1568659680", + "tzOffset": 10800, + "text": "21:48", + }, + "Estimated": { + "value": "1568659426", + "tzOffset": 10800, + "text": "21:43", + }, + "vehicleId": "codd%5Fnew|1084829%5F430260", + }, + { + "Scheduled": { + "value": "1568660520", + "tzOffset": 10800, + "text": "22:02", + }, + "Estimated": { + "value": "1568659656", + "tzOffset": 10800, + "text": "21:47", + }, + "vehicleId": "codd%5Fnew|1117016%5F430280", + }, + { + "Scheduled": { + "value": "1568661900", + "tzOffset": 10800, + "text": "22:25", + }, + "Estimated": { + "value": "1568660538", + "tzOffset": 10800, + "text": "22:02", + }, + "vehicleId": "codd%5Fnew|1054576%5F430226", + }, + ], + "departureTime": "21:48", + }, + }, + { + "lineId": "213_47_trolleybus_mosgortrans", + "name": "т47", + "Types": ["bus"], + "type": "bus", + "threads": [ + { + "threadId": "213B_47_trolleybus_mosgortrans", + "EssentialStops": [ + { + "id": "stop__9639568", + "name": "Бескудниковский переулок", + }, + { + "id": "stop__9641903", + "name": "Бескудниковский переулок", + }, + ], + "BriefSchedule": { + "Events": [ + { + "Scheduled": { + "value": "1568659980", + "tzOffset": 10800, + "text": "21:53", + }, + "Estimated": { + "value": "1568659253", + "tzOffset": 10800, + "text": "21:40", + }, + "vehicleId": "codd%5Fnew|1112219%5F430329", + }, + { + "Scheduled": { + "value": "1568660940", + "tzOffset": 10800, + "text": "22:09", + }, + "Estimated": { + "value": "1568660519", + "tzOffset": 10800, + "text": "22:01", + }, + "vehicleId": "codd%5Fnew|1139620%5F430382", + }, + { + "Scheduled": { + "value": "1568663580", + "tzOffset": 10800, + "text": "22:53", + } + }, + ], + "departureTime": "21:53", + }, + } + ], + "threadId": "213B_47_trolleybus_mosgortrans", + "EssentialStops": [ + {"id": "stop__9639568", "name": "Бескудниковский переулок"}, + {"id": "stop__9641903", "name": "Бескудниковский переулок"}, + ], + "BriefSchedule": { + "Events": [ + { + "Scheduled": { + "value": "1568659980", + "tzOffset": 10800, + "text": "21:53", + }, + "Estimated": { + "value": "1568659253", + "tzOffset": 10800, + "text": "21:40", + }, + "vehicleId": "codd%5Fnew|1112219%5F430329", + }, + { + "Scheduled": { + "value": "1568660940", + "tzOffset": 10800, + "text": "22:09", + }, + "Estimated": { + "value": "1568660519", + "tzOffset": 10800, + "text": "22:01", + }, + "vehicleId": "codd%5Fnew|1139620%5F430382", + }, + { + "Scheduled": { + "value": "1568663580", + "tzOffset": 10800, + "text": "22:53", + } + }, + ], + "departureTime": "21:53", + }, + }, + { + "lineId": "213_56_trolleybus_mosgortrans", + "name": "т56", + "Types": ["bus"], + "type": "bus", + "threads": [ + { + "threadId": "213A_56_trolleybus_mosgortrans", + "EssentialStops": [ + { + "id": "stop__9639561", + "name": "Коровинское шоссе", + }, + { + "id": "stop__9639588", + "name": "Коровинское шоссе", + }, + ], + "BriefSchedule": { + "Events": [ + { + "Estimated": { + "value": "1568660675", + "tzOffset": 10800, + "text": "22:04", + }, + "vehicleId": "codd%5Fnew|146304%5F31207", + } + ], + "Frequency": { + "text": "8 мин", + "value": 480, + "begin": { + "value": "1568606244", + "tzOffset": 10800, + "text": "6:57", + }, + "end": { + "value": "1568670144", + "tzOffset": 10800, + "text": "0:42", + }, + }, + }, + } + ], + "threadId": "213A_56_trolleybus_mosgortrans", + "EssentialStops": [ + {"id": "stop__9639561", "name": "Коровинское шоссе"}, + {"id": "stop__9639588", "name": "Коровинское шоссе"}, + ], + "BriefSchedule": { + "Events": [ + { + "Estimated": { + "value": "1568660675", + "tzOffset": 10800, + "text": "22:04", + }, + "vehicleId": "codd%5Fnew|146304%5F31207", + } + ], + "Frequency": { + "text": "8 мин", + "value": 480, + "begin": { + "value": "1568606244", + "tzOffset": 10800, + "text": "6:57", + }, + "end": { + "value": "1568670144", + "tzOffset": 10800, + "text": "0:42", + }, + }, + }, + }, + { + "lineId": "213_63_bus_mosgortrans", + "name": "63", + "Types": ["bus"], + "type": "bus", + "threads": [ + { + "threadId": "213A_63_bus_mosgortrans", + "EssentialStops": [ + {"id": "stop__9640554", "name": "Лобненская улица"}, + {"id": "stop__9640553", "name": "Лобненская улица"}, + ], + "BriefSchedule": { + "Events": [ + { + "Estimated": { + "value": "1568659369", + "tzOffset": 10800, + "text": "21:42", + }, + "vehicleId": "codd%5Fnew|38921%5F9215306", + }, + { + "Estimated": { + "value": "1568660136", + "tzOffset": 10800, + "text": "21:55", + }, + "vehicleId": "codd%5Fnew|38918%5F9215303", + }, + ], + "Frequency": { + "text": "17 мин", + "value": 1020, + "begin": { + "value": "1568600987", + "tzOffset": 10800, + "text": "5:29", + }, + "end": { + "value": "1568670227", + "tzOffset": 10800, + "text": "0:43", + }, + }, + }, + } + ], + "threadId": "213A_63_bus_mosgortrans", + "EssentialStops": [ + {"id": "stop__9640554", "name": "Лобненская улица"}, + {"id": "stop__9640553", "name": "Лобненская улица"}, + ], + "BriefSchedule": { + "Events": [ + { + "Estimated": { + "value": "1568659369", + "tzOffset": 10800, + "text": "21:42", + }, + "vehicleId": "codd%5Fnew|38921%5F9215306", + }, + { + "Estimated": { + "value": "1568660136", + "tzOffset": 10800, + "text": "21:55", + }, + "vehicleId": "codd%5Fnew|38918%5F9215303", + }, + ], + "Frequency": { + "text": "17 мин", + "value": 1020, + "begin": { + "value": "1568600987", + "tzOffset": 10800, + "text": "5:29", + }, + "end": { + "value": "1568670227", + "tzOffset": 10800, + "text": "0:43", + }, + }, + }, + }, + { + "lineId": "213_677_bus_mosgortrans", + "name": "677", + "Types": ["bus"], + "type": "bus", + "threads": [ + { + "threadId": "213B_677_bus_mosgortrans", + "EssentialStops": [ + { + "id": "stop__9639495", + "name": "Метро Петровско-Разумовская", + }, + { + "id": "stop__9639480", + "name": "Платформа Лианозово", + }, + ], + "BriefSchedule": { + "Events": [ + { + "Estimated": { + "value": "1568659369", + "tzOffset": 10800, + "text": "21:42", + }, + "vehicleId": "codd%5Fnew|11731%5F31376", + } + ], + "Frequency": { + "text": "4 мин", + "value": 240, + "begin": { + "value": "1568600940", + "tzOffset": 10800, + "text": "5:29", + }, + "end": { + "value": "1568672640", + "tzOffset": 10800, + "text": "1:24", + }, + }, + }, + } + ], + "threadId": "213B_677_bus_mosgortrans", + "EssentialStops": [ + { + "id": "stop__9639495", + "name": "Метро Петровско-Разумовская", + }, + {"id": "stop__9639480", "name": "Платформа Лианозово"}, + ], + "BriefSchedule": { + "Events": [ + { + "Estimated": { + "value": "1568659369", + "tzOffset": 10800, + "text": "21:42", + }, + "vehicleId": "codd%5Fnew|11731%5F31376", + } + ], + "Frequency": { + "text": "4 мин", + "value": 240, + "begin": { + "value": "1568600940", + "tzOffset": 10800, + "text": "5:29", + }, + "end": { + "value": "1568672640", + "tzOffset": 10800, + "text": "1:24", + }, + }, + }, + }, + { + "lineId": "213_692_bus_mosgortrans", + "name": "692", + "Types": ["bus"], + "type": "bus", + "threads": [ + { + "threadId": "2036928706", + "EssentialStops": [ + {"id": "3163417967", "name": "Платформа Дегунино"}, + {"id": "3163417967", "name": "Платформа Дегунино"}, + ], + "BriefSchedule": { + "Events": [ + { + "Scheduled": { + "value": "1568660280", + "tzOffset": 10800, + "text": "21:58", + }, + "Estimated": { + "value": "1568660255", + "tzOffset": 10800, + "text": "21:57", + }, + "vehicleId": "codd%5Fnew|63029%5F31485", + }, + { + "Scheduled": { + "value": "1568693340", + "tzOffset": 10800, + "text": "7:09", + } + }, + { + "Scheduled": { + "value": "1568696940", + "tzOffset": 10800, + "text": "8:09", + } + }, + ], + "departureTime": "21:58", + }, + } + ], + "threadId": "2036928706", + "EssentialStops": [ + {"id": "3163417967", "name": "Платформа Дегунино"}, + {"id": "3163417967", "name": "Платформа Дегунино"}, + ], + "BriefSchedule": { + "Events": [ + { + "Scheduled": { + "value": "1568660280", + "tzOffset": 10800, + "text": "21:58", + }, + "Estimated": { + "value": "1568660255", + "tzOffset": 10800, + "text": "21:57", + }, + "vehicleId": "codd%5Fnew|63029%5F31485", + }, + { + "Scheduled": { + "value": "1568693340", + "tzOffset": 10800, + "text": "7:09", + } + }, + { + "Scheduled": { + "value": "1568696940", + "tzOffset": 10800, + "text": "8:09", + } + }, + ], + "departureTime": "21:58", + }, + }, + { + "lineId": "213_78_trolleybus_mosgortrans", + "name": "т78", + "Types": ["bus"], + "type": "bus", + "threads": [ + { + "threadId": "213A_78_trolleybus_mosgortrans", + "EssentialStops": [ + { + "id": "stop__9887464", + "name": "9-я Северная линия", + }, + { + "id": "stop__9887464", + "name": "9-я Северная линия", + }, + ], + "BriefSchedule": { + "Events": [ + { + "Scheduled": { + "value": "1568659620", + "tzOffset": 10800, + "text": "21:47", + }, + "Estimated": { + "value": "1568659898", + "tzOffset": 10800, + "text": "21:51", + }, + "vehicleId": "codd%5Fnew|147522%5F31184", + }, + { + "Scheduled": { + "value": "1568660760", + "tzOffset": 10800, + "text": "22:06", + } + }, + { + "Scheduled": { + "value": "1568661900", + "tzOffset": 10800, + "text": "22:25", + } + }, + ], + "departureTime": "21:47", + }, + } + ], + "threadId": "213A_78_trolleybus_mosgortrans", + "EssentialStops": [ + {"id": "stop__9887464", "name": "9-я Северная линия"}, + {"id": "stop__9887464", "name": "9-я Северная линия"}, + ], + "BriefSchedule": { + "Events": [ + { + "Scheduled": { + "value": "1568659620", + "tzOffset": 10800, + "text": "21:47", + }, + "Estimated": { + "value": "1568659898", + "tzOffset": 10800, + "text": "21:51", + }, + "vehicleId": "codd%5Fnew|147522%5F31184", + }, + { + "Scheduled": { + "value": "1568660760", + "tzOffset": 10800, + "text": "22:06", + } + }, + { + "Scheduled": { + "value": "1568661900", + "tzOffset": 10800, + "text": "22:25", + } + }, + ], + "departureTime": "21:47", + }, + }, + { + "lineId": "213_82_bus_mosgortrans", + "name": "82", + "Types": ["bus"], + "type": "bus", + "threads": [ + { + "threadId": "2036925244", + "EssentialStops": [ + { + "id": "2310890052", + "name": "Метро Верхние Лихоборы", + }, + { + "id": "2310890052", + "name": "Метро Верхние Лихоборы", + }, + ], + "BriefSchedule": { + "Events": [ + { + "Scheduled": { + "value": "1568659680", + "tzOffset": 10800, + "text": "21:48", + } + }, + { + "Scheduled": { + "value": "1568661780", + "tzOffset": 10800, + "text": "22:23", + } + }, + { + "Scheduled": { + "value": "1568663760", + "tzOffset": 10800, + "text": "22:56", + } + }, + ], + "departureTime": "21:48", + }, + } + ], + "threadId": "2036925244", + "EssentialStops": [ + {"id": "2310890052", "name": "Метро Верхние Лихоборы"}, + {"id": "2310890052", "name": "Метро Верхние Лихоборы"}, + ], + "BriefSchedule": { + "Events": [ + { + "Scheduled": { + "value": "1568659680", + "tzOffset": 10800, + "text": "21:48", + } + }, + { + "Scheduled": { + "value": "1568661780", + "tzOffset": 10800, + "text": "22:23", + } + }, + { + "Scheduled": { + "value": "1568663760", + "tzOffset": 10800, + "text": "22:56", + } + }, + ], + "departureTime": "21:48", + }, + }, + { + "lineId": "2465131598", + "name": "179к", + "Types": ["bus"], + "type": "bus", + "threads": [ + { + "threadId": "2465131758", + "EssentialStops": [ + { + "id": "stop__9640244", + "name": "Платформа Лианозово", + }, + { + "id": "stop__9639480", + "name": "Платформа Лианозово", + }, + ], + "BriefSchedule": { + "Events": [ + { + "Scheduled": { + "value": "1568659500", + "tzOffset": 10800, + "text": "21:45", + } + }, + { + "Scheduled": { + "value": "1568659980", + "tzOffset": 10800, + "text": "21:53", + } + }, + { + "Scheduled": { + "value": "1568660880", + "tzOffset": 10800, + "text": "22:08", + } + }, + ], + "departureTime": "21:45", + }, + } + ], + "threadId": "2465131758", + "EssentialStops": [ + {"id": "stop__9640244", "name": "Платформа Лианозово"}, + {"id": "stop__9639480", "name": "Платформа Лианозово"}, + ], + "BriefSchedule": { + "Events": [ + { + "Scheduled": { + "value": "1568659500", + "tzOffset": 10800, + "text": "21:45", + } + }, + { + "Scheduled": { + "value": "1568659980", + "tzOffset": 10800, + "text": "21:53", + } + }, + { + "Scheduled": { + "value": "1568660880", + "tzOffset": 10800, + "text": "22:08", + } + }, + ], + "departureTime": "21:45", + }, + }, + { + "lineId": "466_bus_default", + "name": "466", + "Types": ["bus"], + "type": "bus", + "threads": [ + { + "threadId": "466B_bus_default", + "EssentialStops": [ + { + "id": "stop__9640546", + "name": "Станция Бескудниково", + }, + { + "id": "stop__9640545", + "name": "Станция Бескудниково", + }, + ], + "BriefSchedule": { + "Events": [], + "Frequency": { + "text": "22 мин", + "value": 1320, + "begin": { + "value": "1568604647", + "tzOffset": 10800, + "text": "6:30", + }, + "end": { + "value": "1568675447", + "tzOffset": 10800, + "text": "2:10", + }, + }, + }, + } + ], + "threadId": "466B_bus_default", + "EssentialStops": [ + {"id": "stop__9640546", "name": "Станция Бескудниково"}, + {"id": "stop__9640545", "name": "Станция Бескудниково"}, + ], + "BriefSchedule": { + "Events": [], + "Frequency": { + "text": "22 мин", + "value": 1320, + "begin": { + "value": "1568604647", + "tzOffset": 10800, + "text": "6:30", + }, + "end": { + "value": "1568675447", + "tzOffset": 10800, + "text": "2:10", + }, + }, + }, + }, + { + "lineId": "677k_bus_default", + "name": "677к", + "Types": ["bus"], + "type": "bus", + "threads": [ + { + "threadId": "677kA_bus_default", + "EssentialStops": [ + { + "id": "stop__9640244", + "name": "Платформа Лианозово", + }, + { + "id": "stop__9639480", + "name": "Платформа Лианозово", + }, + ], + "BriefSchedule": { + "Events": [ + { + "Scheduled": { + "value": "1568659920", + "tzOffset": 10800, + "text": "21:52", + }, + "Estimated": { + "value": "1568660003", + "tzOffset": 10800, + "text": "21:53", + }, + "vehicleId": "codd%5Fnew|130308%5F31319", + }, + { + "Scheduled": { + "value": "1568661240", + "tzOffset": 10800, + "text": "22:14", + } + }, + { + "Scheduled": { + "value": "1568662500", + "tzOffset": 10800, + "text": "22:35", + } + }, + ], + "departureTime": "21:52", + }, + } + ], + "threadId": "677kA_bus_default", + "EssentialStops": [ + {"id": "stop__9640244", "name": "Платформа Лианозово"}, + {"id": "stop__9639480", "name": "Платформа Лианозово"}, + ], + "BriefSchedule": { + "Events": [ + { + "Scheduled": { + "value": "1568659920", + "tzOffset": 10800, + "text": "21:52", + }, + "Estimated": { + "value": "1568660003", + "tzOffset": 10800, + "text": "21:53", + }, + "vehicleId": "codd%5Fnew|130308%5F31319", + }, + { + "Scheduled": { + "value": "1568661240", + "tzOffset": 10800, + "text": "22:14", + } + }, + { + "Scheduled": { + "value": "1568662500", + "tzOffset": 10800, + "text": "22:35", + } + }, + ], + "departureTime": "21:52", + }, + }, + { + "lineId": "m10_bus_default", + "name": "м10", + "Types": ["bus"], + "type": "bus", + "threads": [ + { + "threadId": "2036926048", + "EssentialStops": [ + {"id": "stop__9640554", "name": "Лобненская улица"}, + {"id": "stop__9640553", "name": "Лобненская улица"}, + ], + "BriefSchedule": { + "Events": [ + { + "Estimated": { + "value": "1568659718", + "tzOffset": 10800, + "text": "21:48", + }, + "vehicleId": "codd%5Fnew|146260%5F31212", + }, + { + "Estimated": { + "value": "1568660422", + "tzOffset": 10800, + "text": "22:00", + }, + "vehicleId": "codd%5Fnew|13997%5F31247", + }, + ], + "Frequency": { + "text": "15 мин", + "value": 900, + "begin": { + "value": "1568606903", + "tzOffset": 10800, + "text": "7:08", + }, + "end": { + "value": "1568675183", + "tzOffset": 10800, + "text": "2:06", + }, + }, + }, + } + ], + "threadId": "2036926048", + "EssentialStops": [ + {"id": "stop__9640554", "name": "Лобненская улица"}, + {"id": "stop__9640553", "name": "Лобненская улица"}, + ], + "BriefSchedule": { + "Events": [ + { + "Estimated": { + "value": "1568659718", + "tzOffset": 10800, + "text": "21:48", + }, + "vehicleId": "codd%5Fnew|146260%5F31212", + }, + { + "Estimated": { + "value": "1568660422", + "tzOffset": 10800, + "text": "22:00", + }, + "vehicleId": "codd%5Fnew|13997%5F31247", + }, + ], + "Frequency": { + "text": "15 мин", + "value": 900, + "begin": { + "value": "1568606903", + "tzOffset": 10800, + "text": "7:08", + }, + "end": { + "value": "1568675183", + "tzOffset": 10800, + "text": "2:06", + }, + }, + }, + }, + ], + }, + }, + "toponymSeoname": "dmitrovskoye_shosse", + } +} + + +class MockRequester(object): + """Fake YandexRequester object.""" + + def __init__(self, user_agent=None): + """Create mock module object, for avoid importing ya_ma library.""" + pass + + def get_stop_info(self, stop_id): + """Fake method. Return information about stop_id 9639579.""" + return REPLY + + def set_new_session(self): + """Fake method for reset http session.""" + pass + + +requester = MockRequester() +fake_module.YandexMapsRequester = MockRequester +sys.modules["ya_ma"] = fake_module diff --git a/tests/components/yandex_transport/test_yandex_transport_sensor.py b/tests/components/yandex_transport/test_yandex_transport_sensor.py new file mode 100644 index 00000000000000..143a6f638bc28c --- /dev/null +++ b/tests/components/yandex_transport/test_yandex_transport_sensor.py @@ -0,0 +1,118 @@ +"""Tests for the yandex transport platform.""" + +import unittest +from unittest.mock import Mock + +import homeassistant.util.dt as dt_util +from homeassistant.components.yandex_transport.sensor import ( + DiscoverMoscowYandexTransport, + setup_platform, +) +from homeassistant.const import CONF_NAME, ATTR_ATTRIBUTION +from homeassistant.setup import setup_component +from tests.common import assert_setup_component, get_test_home_assistant +from tests.components.yandex_transport import mock_import + +STOP_ID = 9639579 +ROUTES = ["194", "т36", "т47", "м10"] +NAME = "test_name" +TEST_CONFIG = { + "sensor": { + "platform": "yandex_transport", + "stop_id": 9639579, + "routes": ROUTES, + "name": NAME, + } +} + + +def true_filter(reply, filter_routes=None): + """Check transport filtering by routes list.""" + + closer_time = None + if filter_routes is None: + filter_routes = [] + attrs = {} + ["data"] + stop_metadata = reply["data"]["properties"]["StopMetaData"] + + stop_name = reply["data"]["properties"]["name"] + transport_list = stop_metadata["Transport"] + for transport in transport_list: + route = transport["name"] + if filter_routes and route not in filter_routes: + # 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 attrs: + attrs[route] = [] + attrs[route].append(event["Estimated"]["text"]) + attrs["stop_name"] = stop_name + attrs[ATTR_ATTRIBUTION] = "Data provided by maps.yandex.ru" + if closer_time is None: + state = None + else: + state = dt_util.utc_from_timestamp(closer_time).isoformat(timespec="seconds") + return attrs, state + + +class TestYandexTransportSensor(unittest.TestCase): + """Test yandex transport sensor.""" + + def setup_method(self, method): + """Set up things to be run when tests are started.""" + self.hass = get_test_home_assistant() + + def teardown_method(self, method): + """Stop everything that was started.""" + self.hass.stop() + + def test_setup_platform_valid_config(self): + """Check a valid configuration and call add_entities with sensor.""" + with assert_setup_component(1, "sensor"): + assert setup_component(self.hass, "sensor", TEST_CONFIG) + add_entities = Mock() + setup_platform(None, TEST_CONFIG["sensor"], add_entities) + assert add_entities.called + assert isinstance( + add_entities.call_args[0][0][0], DiscoverMoscowYandexTransport + ) + + def test_setup_platform_invalid_config(self): + """Check an invalid configuration.""" + with assert_setup_component(0): + assert setup_component( + self.hass, + "sensor", + {"sensor": {"platform": "yandex_transport", "stopid": 1234}}, + ) + + def test_name(self): + """Return the name if set in the configuration.""" + sensor = DiscoverMoscowYandexTransport(mock_import.requester, STOP_ID, [], NAME) + assert sensor.name == TEST_CONFIG["sensor"][CONF_NAME] + + def test_state(self): + """Return the contents of _state.""" + sensor = DiscoverMoscowYandexTransport( + mock_import.requester, STOP_ID, ROUTES, NAME + ) + sensor.update() + assert sensor.state == dt_util.utc_from_timestamp(1568659253).isoformat( + timespec="seconds" + ) + + def test_filtered_attributes(self): + """Return the contents of attributes.""" + sensor = DiscoverMoscowYandexTransport( + mock_import.requester, STOP_ID, ROUTES, NAME + ) + sensor.update() + attrs, state = true_filter(mock_import.REPLY, filter_routes=ROUTES) + assert sensor.device_state_attributes == attrs + assert sensor.state == state From 18dd4ed31e437f43eb3bfb603346d5e67b59e113 Mon Sep 17 00:00:00 2001 From: Rishat Askarov Date: Wed, 18 Sep 2019 23:34:07 +0300 Subject: [PATCH 12/21] flake8 and black tests for sensor.py --- .../components/yandex_transport/__init__.py | 2 +- .../components/yandex_transport/manifest.json | 16 ++++++---------- .../components/yandex_transport/sensor.py | 16 ++++++++++------ 3 files changed, 17 insertions(+), 17 deletions(-) diff --git a/homeassistant/components/yandex_transport/__init__.py b/homeassistant/components/yandex_transport/__init__.py index a2586ae4ca6a04..d007b2d3df8581 100644 --- a/homeassistant/components/yandex_transport/__init__.py +++ b/homeassistant/components/yandex_transport/__init__.py @@ -1 +1 @@ -""" Service for obtaining information about closer bus from Transport Yandex Service. """ +"""Service for obtaining information about closer bus from Transport Yandex Service.""" diff --git a/homeassistant/components/yandex_transport/manifest.json b/homeassistant/components/yandex_transport/manifest.json index 3187bf670252c4..739cf14d12f484 100644 --- a/homeassistant/components/yandex_transport/manifest.json +++ b/homeassistant/components/yandex_transport/manifest.json @@ -1,12 +1,8 @@ { - "domain": "yandex_transport", - "name": "Yandex transport", - "documentation": "https://www.home-assistant.io/components/yandex_transport", - "requirements": [ - "ya_ma==0.3.4" - ], - "dependencies": [], - "codeowners": [ - "@rishatik92" - ] + "domain": "yandex_transport", + "name": "Yandex Transport", + "documentation": "https://www.home-assistant.io/components/yandex_transport", + "requirements": ["ya_ma==0.3.4"], + "dependencies": [], + "codeowners": ["@rishatik92"], } diff --git a/homeassistant/components/yandex_transport/sensor.py b/homeassistant/components/yandex_transport/sensor.py index 7ab3a4914f3069..f3430391ff2929 100644 --- a/homeassistant/components/yandex_transport/sensor.py +++ b/homeassistant/components/yandex_transport/sensor.py @@ -1,7 +1,5 @@ # -*- coding: utf-8 -*- -""" -Service for obtaining information about closer bus from Transport Yandex Service -""" +"""Service for obtaining information about closer bus from Transport Yandex Service.""" import logging from datetime import timedelta @@ -34,7 +32,6 @@ vol.Required(CONF_STOP_ID): cv.string, vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string, vol.Optional(CONF_ROUTE, default=[]): vol.All(cv.ensure_list, [cv.string]), - } ) @@ -50,6 +47,8 @@ def setup_platform(hass, config, add_entities, discovery_info=None): class DiscoverMoscowYandexTransport(Entity): + """Implementation of yandex_transport sensor.""" + def __init__(self, requester, stop_id, routes, name): """Initialize sensor.""" self.requester = requester @@ -70,7 +69,10 @@ def update(self): stop_metadata = data["properties"]["StopMetaData"] except KeyError as e: _LOGGER.warning( - "Exception KeyError was captured, missing key is %s. Yandex returned: %s" % e, yandex_reply) + "Exception KeyError was captured, missing key is %s. Yandex returned: %s" + % e, + yandex_reply, + ) self.requester.set_new_session() data = self.requester.get_stop_info(self._stop_id)["data"] stop_metadata = data["properties"]["StopMetaData"] @@ -95,7 +97,9 @@ def update(self): if closer_time is None: self._state = None else: - self._state = dt_util.utc_from_timestamp(closer_time).isoformat(timespec="seconds") + self._state = dt_util.utc_from_timestamp(closer_time).isoformat( + timespec="seconds" + ) self._attrs = attrs @property From 98fc10b567993acd3e3eae676593f2e2d14cc445 Mon Sep 17 00:00:00 2001 From: Rishat Askarov Date: Wed, 18 Sep 2019 23:41:08 +0300 Subject: [PATCH 13/21] fix manifest.json --- .../components/yandex_transport/manifest.json | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/homeassistant/components/yandex_transport/manifest.json b/homeassistant/components/yandex_transport/manifest.json index 739cf14d12f484..54837b2eb0914d 100644 --- a/homeassistant/components/yandex_transport/manifest.json +++ b/homeassistant/components/yandex_transport/manifest.json @@ -1,8 +1,12 @@ { - "domain": "yandex_transport", - "name": "Yandex Transport", - "documentation": "https://www.home-assistant.io/components/yandex_transport", - "requirements": ["ya_ma==0.3.4"], - "dependencies": [], - "codeowners": ["@rishatik92"], + "domain": "yandex_transport", + "name": "Yandex Transport", + "documentation": "https://www.home-assistant.io/components/yandex_transport", + "requirements": [ + "ya_ma==0.3.4" + ], + "dependencies": [], + "codeowners": [ + "@rishatik92" + ] } From 8e2a0e025ffc4be66b63f0b929628a7e0d29a01c Mon Sep 17 00:00:00 2001 From: Rishat Askarov Date: Thu, 19 Sep 2019 01:22:58 +0300 Subject: [PATCH 14/21] update tests, migrate to pytest, async, Using MockDependency --- .../{mock_import.py => reply.json} | 41 +---- .../test_yandex_transport_sensor.py | 148 ++++++++++-------- 2 files changed, 90 insertions(+), 99 deletions(-) rename tests/components/yandex_transport/{mock_import.py => reply.json} (99%) diff --git a/tests/components/yandex_transport/mock_import.py b/tests/components/yandex_transport/reply.json similarity index 99% rename from tests/components/yandex_transport/mock_import.py rename to tests/components/yandex_transport/reply.json index b78308c7f5b402..f50d0365f1c28e 100644 --- a/tests/components/yandex_transport/mock_import.py +++ b/tests/components/yandex_transport/reply.json @@ -1,10 +1,4 @@ -"""Mock import ya_ma library for the tests.""" -import sys -from unittest.mock import Mock - -fake_module = Mock() - -REPLY = { +{ "data": { "geometries": [{"type": "Point", "coordinates": [37.565280044, 55.851959656]}], "geometry": {"type": "Point", "coordinates": [37.565280044, 55.851959656]}, @@ -26,7 +20,7 @@ "name": "moscow", "native_name": "", "iso_name": "RU MOW", - "is_main": True, + "is_main": true, "en_name": "Moscow", "short_en_name": "MSK", "phone_code": "495 499", @@ -43,7 +37,7 @@ "official_languages": "ru", "widespread_languages": "ru", "suggest_list": [], - "is_eu": False, + "is_eu": false, "services_names": [ "bs", "yaca", @@ -84,7 +78,7 @@ "name": "moscow-and-moscow-oblast", "native_name": "", "iso_name": "RU-MOS", - "is_main": True, + "is_main": true, "en_name": "Moscow and Moscow Oblast", "short_en_name": "RU-MOS", "phone_code": "495 496 498 499", @@ -114,7 +108,7 @@ 10743, 21622, ], - "is_eu": False, + "is_eu": false, "services_names": ["bs", "yaca", "ad"], "ename": "moscow-and-moscow-oblast", "bounds": [ @@ -143,7 +137,7 @@ "name": "russia", "native_name": "", "iso_name": "RU", - "is_main": False, + "is_main": false, "en_name": "Russia", "short_en_name": "RU", "phone_code": "7", @@ -173,7 +167,7 @@ 39, 62, ], - "is_eu": False, + "is_eu": false, "services_names": ["bs", "yaca", "ad"], "ename": "russia", "bounds": [ @@ -1860,24 +1854,3 @@ "toponymSeoname": "dmitrovskoye_shosse", } } - - -class MockRequester(object): - """Fake YandexRequester object.""" - - def __init__(self, user_agent=None): - """Create mock module object, for avoid importing ya_ma library.""" - pass - - def get_stop_info(self, stop_id): - """Fake method. Return information about stop_id 9639579.""" - return REPLY - - def set_new_session(self): - """Fake method for reset http session.""" - pass - - -requester = MockRequester() -fake_module.YandexMapsRequester = MockRequester -sys.modules["ya_ma"] = fake_module diff --git a/tests/components/yandex_transport/test_yandex_transport_sensor.py b/tests/components/yandex_transport/test_yandex_transport_sensor.py index 143a6f638bc28c..27be0fb28e2bc8 100644 --- a/tests/components/yandex_transport/test_yandex_transport_sensor.py +++ b/tests/components/yandex_transport/test_yandex_transport_sensor.py @@ -1,17 +1,42 @@ """Tests for the yandex transport platform.""" -import unittest -from unittest.mock import Mock +from json import load +from pathlib import Path +from pytest import fixture + +import homeassistant.components.sensor as sensor import homeassistant.util.dt as dt_util -from homeassistant.components.yandex_transport.sensor import ( - DiscoverMoscowYandexTransport, - setup_platform, -) from homeassistant.const import CONF_NAME, ATTR_ATTRIBUTION -from homeassistant.setup import setup_component -from tests.common import assert_setup_component, get_test_home_assistant -from tests.components.yandex_transport import mock_import +from tests.common import assert_setup_component, async_setup_component, MockDependency + +with open(Path(__file__).parents[0] / "reply.json") as json_file: + REPLY = load(json_file) + + +@fixture +def mock_requester(): + """Create a mock ya_ma module and YandexMapsRequester.""" + with MockDependency("ya_ma") as ya_ma: + + class MockRequester(object): + """Fake YandexRequester object.""" + + def __init__(self, user_agent=None): + """Create mock module object, for avoid importing ya_ma library.""" + pass + + def get_stop_info(self, stop_id): + """Fake method. Return information about stop_id 9639579.""" + return REPLY + + def set_new_session(self): + """Fake method for reset http session.""" + pass + + ya_ma.YandexMapsRequester = MockRequester + yield MockRequester() + STOP_ID = 9639579 ROUTES = ["194", "т36", "т47", "м10"] @@ -33,7 +58,7 @@ def true_filter(reply, filter_routes=None): if filter_routes is None: filter_routes = [] attrs = {} - ["data"] + stop_metadata = reply["data"]["properties"]["StopMetaData"] stop_name = reply["data"]["properties"]["name"] @@ -61,58 +86,51 @@ def true_filter(reply, filter_routes=None): return attrs, state -class TestYandexTransportSensor(unittest.TestCase): - """Test yandex transport sensor.""" - - def setup_method(self, method): - """Set up things to be run when tests are started.""" - self.hass = get_test_home_assistant() - - def teardown_method(self, method): - """Stop everything that was started.""" - self.hass.stop() - - def test_setup_platform_valid_config(self): - """Check a valid configuration and call add_entities with sensor.""" - with assert_setup_component(1, "sensor"): - assert setup_component(self.hass, "sensor", TEST_CONFIG) - add_entities = Mock() - setup_platform(None, TEST_CONFIG["sensor"], add_entities) - assert add_entities.called - assert isinstance( - add_entities.call_args[0][0][0], DiscoverMoscowYandexTransport - ) - - def test_setup_platform_invalid_config(self): - """Check an invalid configuration.""" - with assert_setup_component(0): - assert setup_component( - self.hass, - "sensor", - {"sensor": {"platform": "yandex_transport", "stopid": 1234}}, - ) - - def test_name(self): - """Return the name if set in the configuration.""" - sensor = DiscoverMoscowYandexTransport(mock_import.requester, STOP_ID, [], NAME) - assert sensor.name == TEST_CONFIG["sensor"][CONF_NAME] - - def test_state(self): - """Return the contents of _state.""" - sensor = DiscoverMoscowYandexTransport( - mock_import.requester, STOP_ID, ROUTES, NAME - ) - sensor.update() - assert sensor.state == dt_util.utc_from_timestamp(1568659253).isoformat( - timespec="seconds" - ) - - def test_filtered_attributes(self): - """Return the contents of attributes.""" - sensor = DiscoverMoscowYandexTransport( - mock_import.requester, STOP_ID, ROUTES, NAME - ) - sensor.update() - attrs, state = true_filter(mock_import.REPLY, filter_routes=ROUTES) - assert sensor.device_state_attributes == attrs - assert sensor.state == state +async def assert_setup_sensor(hass, config, count=1): + """Set up the sensor and assert it's been created.""" + with assert_setup_component(count): + assert await async_setup_component(hass, sensor.DOMAIN, config) + + +async def test_setup_platform_valid_config(hass, mock_requester): + """Test that sensor is set up properly with valid config.""" + await assert_setup_sensor(hass, TEST_CONFIG) + + +async def test_setup_platform_invalid_config(hass, mock_requester): + """Check an invalid configuration.""" + await assert_setup_sensor( + hass, {"sensor": {"platform": "yandex_transport", "stopid": 1234}}, count=0 + ) + + +async def test_name(hass, mock_requester): + """Return the name if set in the configuration.""" + await assert_setup_sensor(hass, TEST_CONFIG) + state = hass.states.get("sensor.test_name") + assert state.name == TEST_CONFIG["sensor"][CONF_NAME] + + +async def test_state(hass, mock_requester): + """Return the contents of _state.""" + await assert_setup_sensor(hass, TEST_CONFIG) + state = hass.states.get("sensor.test_name") + assert state.state == dt_util.utc_from_timestamp(1568659253).isoformat( + timespec="seconds" + ) + + +async def test_filtered_attributes(hass, mock_requester): + """Return the contents of attributes.""" + await assert_setup_sensor(hass, TEST_CONFIG) + state = hass.states.get("sensor.test_name") + + true_attrs, true_state = true_filter(REPLY, filter_routes=ROUTES) + assert state.state == true_state + result_key_len = len(true_attrs) + i = 0 + assert i != result_key_len + for key in true_attrs: + i += 1 + assert state.attributes[key] == true_attrs[key] + assert i == result_key_len From 986dabb68bd3b9e2600074eb7b3dac23488e00d6 Mon Sep 17 00:00:00 2001 From: Rishat Askarov Date: Thu, 19 Sep 2019 01:32:16 +0300 Subject: [PATCH 15/21] move json to tests/fixtures --- .../test_yandex_transport_sensor.py | 16 +- .../yandex_transport_reply.json} | 1140 ++++++++++------- 2 files changed, 704 insertions(+), 452 deletions(-) rename tests/{components/yandex_transport/reply.json => fixtures/yandex_transport_reply.json} (70%) diff --git a/tests/components/yandex_transport/test_yandex_transport_sensor.py b/tests/components/yandex_transport/test_yandex_transport_sensor.py index 27be0fb28e2bc8..9ee8aa051ad399 100644 --- a/tests/components/yandex_transport/test_yandex_transport_sensor.py +++ b/tests/components/yandex_transport/test_yandex_transport_sensor.py @@ -1,17 +1,19 @@ """Tests for the yandex transport platform.""" -from json import load -from pathlib import Path - +from json import loads from pytest import fixture import homeassistant.components.sensor as sensor import homeassistant.util.dt as dt_util from homeassistant.const import CONF_NAME, ATTR_ATTRIBUTION -from tests.common import assert_setup_component, async_setup_component, MockDependency - -with open(Path(__file__).parents[0] / "reply.json") as json_file: - REPLY = load(json_file) +from tests.common import ( + assert_setup_component, + async_setup_component, + MockDependency, + load_fixture, +) + +REPLY = loads(load_fixture("yandex_transport_reply.json")) @fixture diff --git a/tests/components/yandex_transport/reply.json b/tests/fixtures/yandex_transport_reply.json similarity index 70% rename from tests/components/yandex_transport/reply.json rename to tests/fixtures/yandex_transport_reply.json index f50d0365f1c28e..c5e4857297aa93 100644 --- a/tests/components/yandex_transport/reply.json +++ b/tests/fixtures/yandex_transport_reply.json @@ -1,7 +1,21 @@ { "data": { - "geometries": [{"type": "Point", "coordinates": [37.565280044, 55.851959656]}], - "geometry": {"type": "Point", "coordinates": [37.565280044, 55.851959656]}, + "geometries": [ + { + "type": "Point", + "coordinates": [ + 37.565280044, + 55.851959656 + ] + } + ], + "geometry": { + "type": "Point", + "coordinates": [ + 37.565280044, + 55.851959656 + ] + }, "properties": { "name": "7-й автобусный парк", "description": "7-й автобусный парк", @@ -49,12 +63,18 @@ "etrain", "subway", "delivery", - "route", + "route" ], "ename": "moscow", "bounds": [ - [37.0402925, 55.31141404514547], - [38.2047155, 56.190068045145466], + [ + 37.0402925, + 55.31141404514547 + ], + [ + 38.2047155, + 56.190068045145466 + ] ], "names": { "ablative": "", @@ -66,7 +86,7 @@ "locative": "", "nominative": "Москва", "preposition": "в", - "prepositional": "Москве", + "prepositional": "Москве" }, "parent": { "id": 1, @@ -106,14 +126,24 @@ 10735, 10734, 10743, - 21622, + 21622 ], "is_eu": false, - "services_names": ["bs", "yaca", "ad"], + "services_names": [ + "bs", + "yaca", + "ad" + ], "ename": "moscow-and-moscow-oblast", "bounds": [ - [34.8496565, 54.439456064325434], - [39.9104055, 57.14511506432543], + [ + 34.8496565, + 54.439456064325434 + ], + [ + 39.9104055, + 57.14511506432543 + ] ], "names": { "ablative": "", @@ -125,7 +155,7 @@ "locative": "", "nominative": "Москва и Московская область", "preposition": "в", - "prepositional": "Москве и Московской области", + "prepositional": "Москве и Московской области" }, "parent": { "id": 225, @@ -165,14 +195,24 @@ 56, 172, 39, - 62, + 62 ], "is_eu": false, - "services_names": ["bs", "yaca", "ad"], + "services_names": [ + "bs", + "yaca", + "ad" + ], "ename": "russia", "bounds": [ - [13.683785499999999, 35.290400699917846], - [-174.6729755, 75.99052769991785], + [ + 13.683785499999999, + 35.290400699917846 + ], + [ + -174.6729755, + 75.99052769991785 + ] ], "names": { "ablative": "", @@ -184,16 +224,18 @@ "locative": "", "nominative": "Россия", "preposition": "в", - "prepositional": "России", - }, - }, - }, + "prepositional": "России" + } + } + } }, "Transport": [ { "lineId": "2036925416", "name": "194", - "Types": ["bus"], + "Types": [ + "bus" + ], "type": "bus", "threads": [ { @@ -201,9 +243,12 @@ "EssentialStops": [ { "id": "stop__9711780", - "name": "Метро Петровско-Разумовская", + "name": "Метро Петровско-Разумовская" }, - {"id": "stop__9648742", "name": "Коровино"}, + { + "id": "stop__9648742", + "name": "Коровино" + } ], "BriefSchedule": { "Events": [ @@ -211,35 +256,38 @@ "Scheduled": { "value": "1568659860", "tzOffset": 10800, - "text": "21:51", + "text": "21:51" } }, { "Scheduled": { "value": "1568660760", "tzOffset": 10800, - "text": "22:06", + "text": "22:06" } }, { "Scheduled": { "value": "1568661840", "tzOffset": 10800, - "text": "22:24", + "text": "22:24" } - }, + } ], - "departureTime": "21:51", - }, + "departureTime": "21:51" + } } ], "threadId": "2036927196", "EssentialStops": [ { "id": "stop__9711780", - "name": "Метро Петровско-Разумовская", + "name": "Метро Петровско-Разумовская" }, - {"id": "stop__9648742", "name": "Коровино"}, + { + "id": "stop__9648742", + "name": "Коровино" + } ], "BriefSchedule": { "Events": [ @@ -247,41 +295,46 @@ "Scheduled": { "value": "1568659860", "tzOffset": 10800, - "text": "21:51", + "text": "21:51" } }, { "Scheduled": { "value": "1568660760", "tzOffset": 10800, - "text": "22:06", + "text": "22:06" } }, { "Scheduled": { "value": "1568661840", "tzOffset": 10800, - "text": "22:24", + "text": "22:24" } - }, + } ], - "departureTime": "21:51", - }, + "departureTime": "21:51" + } }, { "lineId": "213_114_bus_mosgortrans", "name": "114", - "Types": ["bus"], + "Types": [ + "bus" + ], "type": "bus", "threads": [ { "threadId": "213B_114_bus_mosgortrans", "EssentialStops": [ - {"id": "stop__9647199", "name": "Метро Войковская"}, { - "id": "stop__9639588", - "name": "Коровинское шоссе", + "id": "stop__9647199", + "name": "Метро Войковская" }, + { + "id": "stop__9639588", + "name": "Коровинское шоссе" + } ], "BriefSchedule": { "Events": [], @@ -291,21 +344,27 @@ "begin": { "value": "1568603405", "tzOffset": 10800, - "text": "6:10", + "text": "6:10" }, "end": { "value": "1568672165", "tzOffset": 10800, - "text": "1:16", - }, - }, - }, + "text": "1:16" + } + } + } } ], "threadId": "213B_114_bus_mosgortrans", "EssentialStops": [ - {"id": "stop__9647199", "name": "Метро Войковская"}, - {"id": "stop__9639588", "name": "Коровинское шоссе"}, + { + "id": "stop__9647199", + "name": "Метро Войковская" + }, + { + "id": "stop__9639588", + "name": "Коровинское шоссе" + } ], "BriefSchedule": { "Events": [], @@ -315,27 +374,35 @@ "begin": { "value": "1568603405", "tzOffset": 10800, - "text": "6:10", + "text": "6:10" }, "end": { "value": "1568672165", "tzOffset": 10800, - "text": "1:16", - }, - }, - }, + "text": "1:16" + } + } + } }, { "lineId": "213_154_bus_mosgortrans", "name": "154", - "Types": ["bus"], + "Types": [ + "bus" + ], "type": "bus", "threads": [ { "threadId": "213B_154_bus_mosgortrans", "EssentialStops": [ - {"id": "stop__9642548", "name": "ВДНХ (южная)"}, - {"id": "stop__9711744", "name": "Станция Ховрино"}, + { + "id": "stop__9642548", + "name": "ВДНХ (южная)" + }, + { + "id": "stop__9711744", + "name": "Станция Ховрино" + } ], "BriefSchedule": { "Events": [ @@ -343,38 +410,44 @@ "Scheduled": { "value": "1568659260", "tzOffset": 10800, - "text": "21:41", + "text": "21:41" }, "Estimated": { "value": "1568659252", "tzOffset": 10800, - "text": "21:40", + "text": "21:40" }, - "vehicleId": "codd%5Fnew|1054764%5F191500", + "vehicleId": "codd%5Fnew|1054764%5F191500" }, { "Scheduled": { "value": "1568660580", "tzOffset": 10800, - "text": "22:03", + "text": "22:03" } }, { "Scheduled": { "value": "1568661900", "tzOffset": 10800, - "text": "22:25", + "text": "22:25" } - }, + } ], - "departureTime": "21:41", - }, + "departureTime": "21:41" + } } ], "threadId": "213B_154_bus_mosgortrans", "EssentialStops": [ - {"id": "stop__9642548", "name": "ВДНХ (южная)"}, - {"id": "stop__9711744", "name": "Станция Ховрино"}, + { + "id": "stop__9642548", + "name": "ВДНХ (южная)" + }, + { + "id": "stop__9711744", + "name": "Станция Ховрино" + } ], "BriefSchedule": { "Events": [ @@ -382,47 +455,52 @@ "Scheduled": { "value": "1568659260", "tzOffset": 10800, - "text": "21:41", + "text": "21:41" }, "Estimated": { "value": "1568659252", "tzOffset": 10800, - "text": "21:40", + "text": "21:40" }, - "vehicleId": "codd%5Fnew|1054764%5F191500", + "vehicleId": "codd%5Fnew|1054764%5F191500" }, { "Scheduled": { "value": "1568660580", "tzOffset": 10800, - "text": "22:03", + "text": "22:03" } }, { "Scheduled": { "value": "1568661900", "tzOffset": 10800, - "text": "22:25", + "text": "22:25" } - }, + } ], - "departureTime": "21:41", - }, + "departureTime": "21:41" + } }, { "lineId": "213_179_bus_mosgortrans", "name": "179", - "Types": ["bus"], + "Types": [ + "bus" + ], "type": "bus", "threads": [ { "threadId": "213B_179_bus_mosgortrans", "EssentialStops": [ - {"id": "stop__9647199", "name": "Метро Войковская"}, { - "id": "stop__9639480", - "name": "Платформа Лианозово", + "id": "stop__9647199", + "name": "Метро Войковская" }, + { + "id": "stop__9639480", + "name": "Платформа Лианозово" + } ], "BriefSchedule": { "Events": [ @@ -430,38 +508,44 @@ "Scheduled": { "value": "1568659920", "tzOffset": 10800, - "text": "21:52", + "text": "21:52" }, "Estimated": { "value": "1568659351", "tzOffset": 10800, - "text": "21:42", + "text": "21:42" }, - "vehicleId": "codd%5Fnew|59832%5F31359", + "vehicleId": "codd%5Fnew|59832%5F31359" }, { "Scheduled": { "value": "1568660760", "tzOffset": 10800, - "text": "22:06", + "text": "22:06" } }, { "Scheduled": { "value": "1568661660", "tzOffset": 10800, - "text": "22:21", + "text": "22:21" } - }, + } ], - "departureTime": "21:52", - }, + "departureTime": "21:52" + } } ], "threadId": "213B_179_bus_mosgortrans", "EssentialStops": [ - {"id": "stop__9647199", "name": "Метро Войковская"}, - {"id": "stop__9639480", "name": "Платформа Лианозово"}, + { + "id": "stop__9647199", + "name": "Метро Войковская" + }, + { + "id": "stop__9639480", + "name": "Платформа Лианозово" + } ], "BriefSchedule": { "Events": [ @@ -469,44 +553,52 @@ "Scheduled": { "value": "1568659920", "tzOffset": 10800, - "text": "21:52", + "text": "21:52" }, "Estimated": { "value": "1568659351", "tzOffset": 10800, - "text": "21:42", + "text": "21:42" }, - "vehicleId": "codd%5Fnew|59832%5F31359", + "vehicleId": "codd%5Fnew|59832%5F31359" }, { "Scheduled": { "value": "1568660760", "tzOffset": 10800, - "text": "22:06", + "text": "22:06" } }, { "Scheduled": { "value": "1568661660", "tzOffset": 10800, - "text": "22:21", + "text": "22:21" } - }, + } ], - "departureTime": "21:52", - }, + "departureTime": "21:52" + } }, { "lineId": "213_191m_minibus_default", "name": "591", - "Types": ["bus"], + "Types": [ + "bus" + ], "type": "bus", "threads": [ { "threadId": "213A_191m_minibus_default", "EssentialStops": [ - {"id": "stop__9647199", "name": "Метро Войковская"}, - {"id": "stop__9711744", "name": "Станция Ховрино"}, + { + "id": "stop__9647199", + "name": "Метро Войковская" + }, + { + "id": "stop__9711744", + "name": "Станция Ховрино" + } ], "BriefSchedule": { "Events": [ @@ -514,9 +606,9 @@ "Estimated": { "value": "1568660525", "tzOffset": 10800, - "text": "22:02", + "text": "22:02" }, - "vehicleId": "codd%5Fnew|38278%5F9345312", + "vehicleId": "codd%5Fnew|38278%5F9345312" } ], "Frequency": { @@ -525,21 +617,27 @@ "begin": { "value": "1568602033", "tzOffset": 10800, - "text": "5:47", + "text": "5:47" }, "end": { "value": "1568672233", "tzOffset": 10800, - "text": "1:17", - }, - }, - }, + "text": "1:17" + } + } + } } ], "threadId": "213A_191m_minibus_default", "EssentialStops": [ - {"id": "stop__9647199", "name": "Метро Войковская"}, - {"id": "stop__9711744", "name": "Станция Ховрино"}, + { + "id": "stop__9647199", + "name": "Метро Войковская" + }, + { + "id": "stop__9711744", + "name": "Станция Ховрино" + } ], "BriefSchedule": { "Events": [ @@ -547,9 +645,9 @@ "Estimated": { "value": "1568660525", "tzOffset": 10800, - "text": "22:02", + "text": "22:02" }, - "vehicleId": "codd%5Fnew|38278%5F9345312", + "vehicleId": "codd%5Fnew|38278%5F9345312" } ], "Frequency": { @@ -558,20 +656,22 @@ "begin": { "value": "1568602033", "tzOffset": 10800, - "text": "5:47", + "text": "5:47" }, "end": { "value": "1568672233", "tzOffset": 10800, - "text": "1:17", - }, - }, - }, + "text": "1:17" + } + } + } }, { "lineId": "213_206m_minibus_default", "name": "206к", - "Types": ["bus"], + "Types": [ + "bus" + ], "type": "bus", "threads": [ { @@ -579,9 +679,12 @@ "EssentialStops": [ { "id": "stop__9640756", - "name": "Метро Петровско-Разумовская", + "name": "Метро Петровско-Разумовская" }, - {"id": "stop__9640553", "name": "Лобненская улица"}, + { + "id": "stop__9640553", + "name": "Лобненская улица" + } ], "BriefSchedule": { "Events": [], @@ -591,24 +694,27 @@ "begin": { "value": "1568601239", "tzOffset": 10800, - "text": "5:33", + "text": "5:33" }, "end": { "value": "1568671439", "tzOffset": 10800, - "text": "1:03", - }, - }, - }, + "text": "1:03" + } + } + } } ], "threadId": "213A_206m_minibus_default", "EssentialStops": [ { "id": "stop__9640756", - "name": "Метро Петровско-Разумовская", + "name": "Метро Петровско-Разумовская" }, - {"id": "stop__9640553", "name": "Лобненская улица"}, + { + "id": "stop__9640553", + "name": "Лобненская улица" + } ], "BriefSchedule": { "Events": [], @@ -618,20 +724,22 @@ "begin": { "value": "1568601239", "tzOffset": 10800, - "text": "5:33", + "text": "5:33" }, "end": { "value": "1568671439", "tzOffset": 10800, - "text": "1:03", - }, - }, - }, + "text": "1:03" + } + } + } }, { "lineId": "213_215_bus_mosgortrans", "name": "215", - "Types": ["bus"], + "Types": [ + "bus" + ], "type": "bus", "threads": [ { @@ -639,9 +747,12 @@ "EssentialStops": [ { "id": "stop__9711780", - "name": "Метро Петровско-Разумовская", + "name": "Метро Петровско-Разумовская" }, - {"id": "stop__9711744", "name": "Станция Ховрино"}, + { + "id": "stop__9711744", + "name": "Станция Ховрино" + } ], "BriefSchedule": { "Events": [], @@ -651,24 +762,27 @@ "begin": { "value": "1568601276", "tzOffset": 10800, - "text": "5:34", + "text": "5:34" }, "end": { "value": "1568671476", "tzOffset": 10800, - "text": "1:04", - }, - }, - }, + "text": "1:04" + } + } + } } ], "threadId": "213B_215_bus_mosgortrans", "EssentialStops": [ { "id": "stop__9711780", - "name": "Метро Петровско-Разумовская", + "name": "Метро Петровско-Разумовская" }, - {"id": "stop__9711744", "name": "Станция Ховрино"}, + { + "id": "stop__9711744", + "name": "Станция Ховрино" + } ], "BriefSchedule": { "Events": [], @@ -678,27 +792,35 @@ "begin": { "value": "1568601276", "tzOffset": 10800, - "text": "5:34", + "text": "5:34" }, "end": { "value": "1568671476", "tzOffset": 10800, - "text": "1:04", - }, - }, - }, + "text": "1:04" + } + } + } }, { "lineId": "213_282_bus_mosgortrans", "name": "282", - "Types": ["bus"], + "Types": [ + "bus" + ], "type": "bus", "threads": [ { "threadId": "213A_282_bus_mosgortrans", "EssentialStops": [ - {"id": "stop__9641102", "name": "Улица Корнейчука"}, - {"id": "2532226085", "name": "Метро Войковская"}, + { + "id": "stop__9641102", + "name": "Улица Корнейчука" + }, + { + "id": "2532226085", + "name": "Метро Войковская" + } ], "BriefSchedule": { "Events": [ @@ -706,9 +828,9 @@ "Estimated": { "value": "1568659888", "tzOffset": 10800, - "text": "21:51", + "text": "21:51" }, - "vehicleId": "codd%5Fnew|34874%5F9345408", + "vehicleId": "codd%5Fnew|34874%5F9345408" } ], "Frequency": { @@ -717,21 +839,27 @@ "begin": { "value": "1568602180", "tzOffset": 10800, - "text": "5:49", + "text": "5:49" }, "end": { "value": "1568673460", "tzOffset": 10800, - "text": "1:37", - }, - }, - }, + "text": "1:37" + } + } + } } ], "threadId": "213A_282_bus_mosgortrans", "EssentialStops": [ - {"id": "stop__9641102", "name": "Улица Корнейчука"}, - {"id": "2532226085", "name": "Метро Войковская"}, + { + "id": "stop__9641102", + "name": "Улица Корнейчука" + }, + { + "id": "2532226085", + "name": "Метро Войковская" + } ], "BriefSchedule": { "Events": [ @@ -739,9 +867,9 @@ "Estimated": { "value": "1568659888", "tzOffset": 10800, - "text": "21:51", + "text": "21:51" }, - "vehicleId": "codd%5Fnew|34874%5F9345408", + "vehicleId": "codd%5Fnew|34874%5F9345408" } ], "Frequency": { @@ -750,20 +878,22 @@ "begin": { "value": "1568602180", "tzOffset": 10800, - "text": "5:49", + "text": "5:49" }, "end": { "value": "1568673460", "tzOffset": 10800, - "text": "1:37", - }, - }, - }, + "text": "1:37" + } + } + } }, { "lineId": "213_294m_minibus_default", "name": "994", - "Types": ["bus"], + "Types": [ + "bus" + ], "type": "bus", "threads": [ { @@ -771,9 +901,12 @@ "EssentialStops": [ { "id": "stop__9640756", - "name": "Метро Петровско-Разумовская", + "name": "Метро Петровско-Разумовская" }, - {"id": "stop__9649459", "name": "Метро Алтуфьево"}, + { + "id": "stop__9649459", + "name": "Метро Алтуфьево" + } ], "BriefSchedule": { "Events": [], @@ -783,24 +916,27 @@ "begin": { "value": "1568601527", "tzOffset": 10800, - "text": "5:38", + "text": "5:38" }, "end": { "value": "1568671727", "tzOffset": 10800, - "text": "1:08", - }, - }, - }, + "text": "1:08" + } + } + } } ], "threadId": "213A_294m_minibus_default", "EssentialStops": [ { "id": "stop__9640756", - "name": "Метро Петровско-Разумовская", + "name": "Метро Петровско-Разумовская" }, - {"id": "stop__9649459", "name": "Метро Алтуфьево"}, + { + "id": "stop__9649459", + "name": "Метро Алтуфьево" + } ], "BriefSchedule": { "Events": [], @@ -810,30 +946,35 @@ "begin": { "value": "1568601527", "tzOffset": 10800, - "text": "5:38", + "text": "5:38" }, "end": { "value": "1568671727", "tzOffset": 10800, - "text": "1:08", - }, - }, - }, + "text": "1:08" + } + } + } }, { "lineId": "213_36_trolleybus_mosgortrans", "name": "т36", - "Types": ["bus"], + "Types": [ + "bus" + ], "type": "bus", "threads": [ { "threadId": "213A_36_trolleybus_mosgortrans", "EssentialStops": [ - {"id": "stop__9642550", "name": "ВДНХ (южная)"}, { - "id": "stop__9640641", - "name": "Дмитровское шоссе, 155", + "id": "stop__9642550", + "name": "ВДНХ (южная)" }, + { + "id": "stop__9640641", + "name": "Дмитровское шоссе, 155" + } ], "BriefSchedule": { "Events": [ @@ -841,50 +982,56 @@ "Scheduled": { "value": "1568659680", "tzOffset": 10800, - "text": "21:48", + "text": "21:48" }, "Estimated": { "value": "1568659426", "tzOffset": 10800, - "text": "21:43", + "text": "21:43" }, - "vehicleId": "codd%5Fnew|1084829%5F430260", + "vehicleId": "codd%5Fnew|1084829%5F430260" }, { "Scheduled": { "value": "1568660520", "tzOffset": 10800, - "text": "22:02", + "text": "22:02" }, "Estimated": { "value": "1568659656", "tzOffset": 10800, - "text": "21:47", + "text": "21:47" }, - "vehicleId": "codd%5Fnew|1117016%5F430280", + "vehicleId": "codd%5Fnew|1117016%5F430280" }, { "Scheduled": { "value": "1568661900", "tzOffset": 10800, - "text": "22:25", + "text": "22:25" }, "Estimated": { "value": "1568660538", "tzOffset": 10800, - "text": "22:02", + "text": "22:02" }, - "vehicleId": "codd%5Fnew|1054576%5F430226", - }, + "vehicleId": "codd%5Fnew|1054576%5F430226" + } ], - "departureTime": "21:48", - }, + "departureTime": "21:48" + } } ], "threadId": "213A_36_trolleybus_mosgortrans", "EssentialStops": [ - {"id": "stop__9642550", "name": "ВДНХ (южная)"}, - {"id": "stop__9640641", "name": "Дмитровское шоссе, 155"}, + { + "id": "stop__9642550", + "name": "ВДНХ (южная)" + }, + { + "id": "stop__9640641", + "name": "Дмитровское шоссе, 155" + } ], "BriefSchedule": { "Events": [ @@ -892,49 +1039,51 @@ "Scheduled": { "value": "1568659680", "tzOffset": 10800, - "text": "21:48", + "text": "21:48" }, "Estimated": { "value": "1568659426", "tzOffset": 10800, - "text": "21:43", + "text": "21:43" }, - "vehicleId": "codd%5Fnew|1084829%5F430260", + "vehicleId": "codd%5Fnew|1084829%5F430260" }, { "Scheduled": { "value": "1568660520", "tzOffset": 10800, - "text": "22:02", + "text": "22:02" }, "Estimated": { "value": "1568659656", "tzOffset": 10800, - "text": "21:47", + "text": "21:47" }, - "vehicleId": "codd%5Fnew|1117016%5F430280", + "vehicleId": "codd%5Fnew|1117016%5F430280" }, { "Scheduled": { "value": "1568661900", "tzOffset": 10800, - "text": "22:25", + "text": "22:25" }, "Estimated": { "value": "1568660538", "tzOffset": 10800, - "text": "22:02", + "text": "22:02" }, - "vehicleId": "codd%5Fnew|1054576%5F430226", - }, + "vehicleId": "codd%5Fnew|1054576%5F430226" + } ], - "departureTime": "21:48", - }, + "departureTime": "21:48" + } }, { "lineId": "213_47_trolleybus_mosgortrans", "name": "т47", - "Types": ["bus"], + "Types": [ + "bus" + ], "type": "bus", "threads": [ { @@ -942,12 +1091,12 @@ "EssentialStops": [ { "id": "stop__9639568", - "name": "Бескудниковский переулок", + "name": "Бескудниковский переулок" }, { "id": "stop__9641903", - "name": "Бескудниковский переулок", - }, + "name": "Бескудниковский переулок" + } ], "BriefSchedule": { "Events": [ @@ -955,44 +1104,50 @@ "Scheduled": { "value": "1568659980", "tzOffset": 10800, - "text": "21:53", + "text": "21:53" }, "Estimated": { "value": "1568659253", "tzOffset": 10800, - "text": "21:40", + "text": "21:40" }, - "vehicleId": "codd%5Fnew|1112219%5F430329", + "vehicleId": "codd%5Fnew|1112219%5F430329" }, { "Scheduled": { "value": "1568660940", "tzOffset": 10800, - "text": "22:09", + "text": "22:09" }, "Estimated": { "value": "1568660519", "tzOffset": 10800, - "text": "22:01", + "text": "22:01" }, - "vehicleId": "codd%5Fnew|1139620%5F430382", + "vehicleId": "codd%5Fnew|1139620%5F430382" }, { "Scheduled": { "value": "1568663580", "tzOffset": 10800, - "text": "22:53", + "text": "22:53" } - }, + } ], - "departureTime": "21:53", - }, + "departureTime": "21:53" + } } ], "threadId": "213B_47_trolleybus_mosgortrans", "EssentialStops": [ - {"id": "stop__9639568", "name": "Бескудниковский переулок"}, - {"id": "stop__9641903", "name": "Бескудниковский переулок"}, + { + "id": "stop__9639568", + "name": "Бескудниковский переулок" + }, + { + "id": "stop__9641903", + "name": "Бескудниковский переулок" + } ], "BriefSchedule": { "Events": [ @@ -1000,43 +1155,45 @@ "Scheduled": { "value": "1568659980", "tzOffset": 10800, - "text": "21:53", + "text": "21:53" }, "Estimated": { "value": "1568659253", "tzOffset": 10800, - "text": "21:40", + "text": "21:40" }, - "vehicleId": "codd%5Fnew|1112219%5F430329", + "vehicleId": "codd%5Fnew|1112219%5F430329" }, { "Scheduled": { "value": "1568660940", "tzOffset": 10800, - "text": "22:09", + "text": "22:09" }, "Estimated": { "value": "1568660519", "tzOffset": 10800, - "text": "22:01", + "text": "22:01" }, - "vehicleId": "codd%5Fnew|1139620%5F430382", + "vehicleId": "codd%5Fnew|1139620%5F430382" }, { "Scheduled": { "value": "1568663580", "tzOffset": 10800, - "text": "22:53", + "text": "22:53" } - }, + } ], - "departureTime": "21:53", - }, + "departureTime": "21:53" + } }, { "lineId": "213_56_trolleybus_mosgortrans", "name": "т56", - "Types": ["bus"], + "Types": [ + "bus" + ], "type": "bus", "threads": [ { @@ -1044,12 +1201,12 @@ "EssentialStops": [ { "id": "stop__9639561", - "name": "Коровинское шоссе", + "name": "Коровинское шоссе" }, { "id": "stop__9639588", - "name": "Коровинское шоссе", - }, + "name": "Коровинское шоссе" + } ], "BriefSchedule": { "Events": [ @@ -1057,9 +1214,9 @@ "Estimated": { "value": "1568660675", "tzOffset": 10800, - "text": "22:04", + "text": "22:04" }, - "vehicleId": "codd%5Fnew|146304%5F31207", + "vehicleId": "codd%5Fnew|146304%5F31207" } ], "Frequency": { @@ -1068,21 +1225,27 @@ "begin": { "value": "1568606244", "tzOffset": 10800, - "text": "6:57", + "text": "6:57" }, "end": { "value": "1568670144", "tzOffset": 10800, - "text": "0:42", - }, - }, - }, + "text": "0:42" + } + } + } } ], "threadId": "213A_56_trolleybus_mosgortrans", "EssentialStops": [ - {"id": "stop__9639561", "name": "Коровинское шоссе"}, - {"id": "stop__9639588", "name": "Коровинское шоссе"}, + { + "id": "stop__9639561", + "name": "Коровинское шоссе" + }, + { + "id": "stop__9639588", + "name": "Коровинское шоссе" + } ], "BriefSchedule": { "Events": [ @@ -1090,9 +1253,9 @@ "Estimated": { "value": "1568660675", "tzOffset": 10800, - "text": "22:04", + "text": "22:04" }, - "vehicleId": "codd%5Fnew|146304%5F31207", + "vehicleId": "codd%5Fnew|146304%5F31207" } ], "Frequency": { @@ -1101,27 +1264,35 @@ "begin": { "value": "1568606244", "tzOffset": 10800, - "text": "6:57", + "text": "6:57" }, "end": { "value": "1568670144", "tzOffset": 10800, - "text": "0:42", - }, - }, - }, + "text": "0:42" + } + } + } }, { "lineId": "213_63_bus_mosgortrans", "name": "63", - "Types": ["bus"], + "Types": [ + "bus" + ], "type": "bus", "threads": [ { "threadId": "213A_63_bus_mosgortrans", "EssentialStops": [ - {"id": "stop__9640554", "name": "Лобненская улица"}, - {"id": "stop__9640553", "name": "Лобненская улица"}, + { + "id": "stop__9640554", + "name": "Лобненская улица" + }, + { + "id": "stop__9640553", + "name": "Лобненская улица" + } ], "BriefSchedule": { "Events": [ @@ -1129,18 +1300,18 @@ "Estimated": { "value": "1568659369", "tzOffset": 10800, - "text": "21:42", + "text": "21:42" }, - "vehicleId": "codd%5Fnew|38921%5F9215306", + "vehicleId": "codd%5Fnew|38921%5F9215306" }, { "Estimated": { "value": "1568660136", "tzOffset": 10800, - "text": "21:55", + "text": "21:55" }, - "vehicleId": "codd%5Fnew|38918%5F9215303", - }, + "vehicleId": "codd%5Fnew|38918%5F9215303" + } ], "Frequency": { "text": "17 мин", @@ -1148,21 +1319,27 @@ "begin": { "value": "1568600987", "tzOffset": 10800, - "text": "5:29", + "text": "5:29" }, "end": { "value": "1568670227", "tzOffset": 10800, - "text": "0:43", - }, - }, - }, + "text": "0:43" + } + } + } } ], "threadId": "213A_63_bus_mosgortrans", "EssentialStops": [ - {"id": "stop__9640554", "name": "Лобненская улица"}, - {"id": "stop__9640553", "name": "Лобненская улица"}, + { + "id": "stop__9640554", + "name": "Лобненская улица" + }, + { + "id": "stop__9640553", + "name": "Лобненская улица" + } ], "BriefSchedule": { "Events": [ @@ -1170,18 +1347,18 @@ "Estimated": { "value": "1568659369", "tzOffset": 10800, - "text": "21:42", + "text": "21:42" }, - "vehicleId": "codd%5Fnew|38921%5F9215306", + "vehicleId": "codd%5Fnew|38921%5F9215306" }, { "Estimated": { "value": "1568660136", "tzOffset": 10800, - "text": "21:55", + "text": "21:55" }, - "vehicleId": "codd%5Fnew|38918%5F9215303", - }, + "vehicleId": "codd%5Fnew|38918%5F9215303" + } ], "Frequency": { "text": "17 мин", @@ -1189,20 +1366,22 @@ "begin": { "value": "1568600987", "tzOffset": 10800, - "text": "5:29", + "text": "5:29" }, "end": { "value": "1568670227", "tzOffset": 10800, - "text": "0:43", - }, - }, - }, + "text": "0:43" + } + } + } }, { "lineId": "213_677_bus_mosgortrans", "name": "677", - "Types": ["bus"], + "Types": [ + "bus" + ], "type": "bus", "threads": [ { @@ -1210,12 +1389,12 @@ "EssentialStops": [ { "id": "stop__9639495", - "name": "Метро Петровско-Разумовская", + "name": "Метро Петровско-Разумовская" }, { "id": "stop__9639480", - "name": "Платформа Лианозово", - }, + "name": "Платформа Лианозово" + } ], "BriefSchedule": { "Events": [ @@ -1223,9 +1402,9 @@ "Estimated": { "value": "1568659369", "tzOffset": 10800, - "text": "21:42", + "text": "21:42" }, - "vehicleId": "codd%5Fnew|11731%5F31376", + "vehicleId": "codd%5Fnew|11731%5F31376" } ], "Frequency": { @@ -1234,24 +1413,27 @@ "begin": { "value": "1568600940", "tzOffset": 10800, - "text": "5:29", + "text": "5:29" }, "end": { "value": "1568672640", "tzOffset": 10800, - "text": "1:24", - }, - }, - }, + "text": "1:24" + } + } + } } ], "threadId": "213B_677_bus_mosgortrans", "EssentialStops": [ { "id": "stop__9639495", - "name": "Метро Петровско-Разумовская", + "name": "Метро Петровско-Разумовская" }, - {"id": "stop__9639480", "name": "Платформа Лианозово"}, + { + "id": "stop__9639480", + "name": "Платформа Лианозово" + } ], "BriefSchedule": { "Events": [ @@ -1259,9 +1441,9 @@ "Estimated": { "value": "1568659369", "tzOffset": 10800, - "text": "21:42", + "text": "21:42" }, - "vehicleId": "codd%5Fnew|11731%5F31376", + "vehicleId": "codd%5Fnew|11731%5F31376" } ], "Frequency": { @@ -1270,27 +1452,35 @@ "begin": { "value": "1568600940", "tzOffset": 10800, - "text": "5:29", + "text": "5:29" }, "end": { "value": "1568672640", "tzOffset": 10800, - "text": "1:24", - }, - }, - }, + "text": "1:24" + } + } + } }, { "lineId": "213_692_bus_mosgortrans", "name": "692", - "Types": ["bus"], + "Types": [ + "bus" + ], "type": "bus", "threads": [ { "threadId": "2036928706", "EssentialStops": [ - {"id": "3163417967", "name": "Платформа Дегунино"}, - {"id": "3163417967", "name": "Платформа Дегунино"}, + { + "id": "3163417967", + "name": "Платформа Дегунино" + }, + { + "id": "3163417967", + "name": "Платформа Дегунино" + } ], "BriefSchedule": { "Events": [ @@ -1298,38 +1488,44 @@ "Scheduled": { "value": "1568660280", "tzOffset": 10800, - "text": "21:58", + "text": "21:58" }, "Estimated": { "value": "1568660255", "tzOffset": 10800, - "text": "21:57", + "text": "21:57" }, - "vehicleId": "codd%5Fnew|63029%5F31485", + "vehicleId": "codd%5Fnew|63029%5F31485" }, { "Scheduled": { "value": "1568693340", "tzOffset": 10800, - "text": "7:09", + "text": "7:09" } }, { "Scheduled": { "value": "1568696940", "tzOffset": 10800, - "text": "8:09", + "text": "8:09" } - }, + } ], - "departureTime": "21:58", - }, + "departureTime": "21:58" + } } ], "threadId": "2036928706", "EssentialStops": [ - {"id": "3163417967", "name": "Платформа Дегунино"}, - {"id": "3163417967", "name": "Платформа Дегунино"}, + { + "id": "3163417967", + "name": "Платформа Дегунино" + }, + { + "id": "3163417967", + "name": "Платформа Дегунино" + } ], "BriefSchedule": { "Events": [ @@ -1337,37 +1533,39 @@ "Scheduled": { "value": "1568660280", "tzOffset": 10800, - "text": "21:58", + "text": "21:58" }, "Estimated": { "value": "1568660255", "tzOffset": 10800, - "text": "21:57", + "text": "21:57" }, - "vehicleId": "codd%5Fnew|63029%5F31485", + "vehicleId": "codd%5Fnew|63029%5F31485" }, { "Scheduled": { "value": "1568693340", "tzOffset": 10800, - "text": "7:09", + "text": "7:09" } }, { "Scheduled": { "value": "1568696940", "tzOffset": 10800, - "text": "8:09", + "text": "8:09" } - }, + } ], - "departureTime": "21:58", - }, + "departureTime": "21:58" + } }, { "lineId": "213_78_trolleybus_mosgortrans", "name": "т78", - "Types": ["bus"], + "Types": [ + "bus" + ], "type": "bus", "threads": [ { @@ -1375,12 +1573,12 @@ "EssentialStops": [ { "id": "stop__9887464", - "name": "9-я Северная линия", + "name": "9-я Северная линия" }, { "id": "stop__9887464", - "name": "9-я Северная линия", - }, + "name": "9-я Северная линия" + } ], "BriefSchedule": { "Events": [ @@ -1388,38 +1586,44 @@ "Scheduled": { "value": "1568659620", "tzOffset": 10800, - "text": "21:47", + "text": "21:47" }, "Estimated": { "value": "1568659898", "tzOffset": 10800, - "text": "21:51", + "text": "21:51" }, - "vehicleId": "codd%5Fnew|147522%5F31184", + "vehicleId": "codd%5Fnew|147522%5F31184" }, { "Scheduled": { "value": "1568660760", "tzOffset": 10800, - "text": "22:06", + "text": "22:06" } }, { "Scheduled": { "value": "1568661900", "tzOffset": 10800, - "text": "22:25", + "text": "22:25" } - }, + } ], - "departureTime": "21:47", - }, + "departureTime": "21:47" + } } ], "threadId": "213A_78_trolleybus_mosgortrans", "EssentialStops": [ - {"id": "stop__9887464", "name": "9-я Северная линия"}, - {"id": "stop__9887464", "name": "9-я Северная линия"}, + { + "id": "stop__9887464", + "name": "9-я Северная линия" + }, + { + "id": "stop__9887464", + "name": "9-я Северная линия" + } ], "BriefSchedule": { "Events": [ @@ -1427,37 +1631,39 @@ "Scheduled": { "value": "1568659620", "tzOffset": 10800, - "text": "21:47", + "text": "21:47" }, "Estimated": { "value": "1568659898", "tzOffset": 10800, - "text": "21:51", + "text": "21:51" }, - "vehicleId": "codd%5Fnew|147522%5F31184", + "vehicleId": "codd%5Fnew|147522%5F31184" }, { "Scheduled": { "value": "1568660760", "tzOffset": 10800, - "text": "22:06", + "text": "22:06" } }, { "Scheduled": { "value": "1568661900", "tzOffset": 10800, - "text": "22:25", + "text": "22:25" } - }, + } ], - "departureTime": "21:47", - }, + "departureTime": "21:47" + } }, { "lineId": "213_82_bus_mosgortrans", "name": "82", - "Types": ["bus"], + "Types": [ + "bus" + ], "type": "bus", "threads": [ { @@ -1465,12 +1671,12 @@ "EssentialStops": [ { "id": "2310890052", - "name": "Метро Верхние Лихоборы", + "name": "Метро Верхние Лихоборы" }, { "id": "2310890052", - "name": "Метро Верхние Лихоборы", - }, + "name": "Метро Верхние Лихоборы" + } ], "BriefSchedule": { "Events": [ @@ -1478,32 +1684,38 @@ "Scheduled": { "value": "1568659680", "tzOffset": 10800, - "text": "21:48", + "text": "21:48" } }, { "Scheduled": { "value": "1568661780", "tzOffset": 10800, - "text": "22:23", + "text": "22:23" } }, { "Scheduled": { "value": "1568663760", "tzOffset": 10800, - "text": "22:56", + "text": "22:56" } - }, + } ], - "departureTime": "21:48", - }, + "departureTime": "21:48" + } } ], "threadId": "2036925244", "EssentialStops": [ - {"id": "2310890052", "name": "Метро Верхние Лихоборы"}, - {"id": "2310890052", "name": "Метро Верхние Лихоборы"}, + { + "id": "2310890052", + "name": "Метро Верхние Лихоборы" + }, + { + "id": "2310890052", + "name": "Метро Верхние Лихоборы" + } ], "BriefSchedule": { "Events": [ @@ -1511,31 +1723,33 @@ "Scheduled": { "value": "1568659680", "tzOffset": 10800, - "text": "21:48", + "text": "21:48" } }, { "Scheduled": { "value": "1568661780", "tzOffset": 10800, - "text": "22:23", + "text": "22:23" } }, { "Scheduled": { "value": "1568663760", "tzOffset": 10800, - "text": "22:56", + "text": "22:56" } - }, + } ], - "departureTime": "21:48", - }, + "departureTime": "21:48" + } }, { "lineId": "2465131598", "name": "179к", - "Types": ["bus"], + "Types": [ + "bus" + ], "type": "bus", "threads": [ { @@ -1543,12 +1757,12 @@ "EssentialStops": [ { "id": "stop__9640244", - "name": "Платформа Лианозово", + "name": "Платформа Лианозово" }, { "id": "stop__9639480", - "name": "Платформа Лианозово", - }, + "name": "Платформа Лианозово" + } ], "BriefSchedule": { "Events": [ @@ -1556,32 +1770,38 @@ "Scheduled": { "value": "1568659500", "tzOffset": 10800, - "text": "21:45", + "text": "21:45" } }, { "Scheduled": { "value": "1568659980", "tzOffset": 10800, - "text": "21:53", + "text": "21:53" } }, { "Scheduled": { "value": "1568660880", "tzOffset": 10800, - "text": "22:08", + "text": "22:08" } - }, + } ], - "departureTime": "21:45", - }, + "departureTime": "21:45" + } } ], "threadId": "2465131758", "EssentialStops": [ - {"id": "stop__9640244", "name": "Платформа Лианозово"}, - {"id": "stop__9639480", "name": "Платформа Лианозово"}, + { + "id": "stop__9640244", + "name": "Платформа Лианозово" + }, + { + "id": "stop__9639480", + "name": "Платформа Лианозово" + } ], "BriefSchedule": { "Events": [ @@ -1589,31 +1809,33 @@ "Scheduled": { "value": "1568659500", "tzOffset": 10800, - "text": "21:45", + "text": "21:45" } }, { "Scheduled": { "value": "1568659980", "tzOffset": 10800, - "text": "21:53", + "text": "21:53" } }, { "Scheduled": { "value": "1568660880", "tzOffset": 10800, - "text": "22:08", + "text": "22:08" } - }, + } ], - "departureTime": "21:45", - }, + "departureTime": "21:45" + } }, { "lineId": "466_bus_default", "name": "466", - "Types": ["bus"], + "Types": [ + "bus" + ], "type": "bus", "threads": [ { @@ -1621,12 +1843,12 @@ "EssentialStops": [ { "id": "stop__9640546", - "name": "Станция Бескудниково", + "name": "Станция Бескудниково" }, { "id": "stop__9640545", - "name": "Станция Бескудниково", - }, + "name": "Станция Бескудниково" + } ], "BriefSchedule": { "Events": [], @@ -1636,21 +1858,27 @@ "begin": { "value": "1568604647", "tzOffset": 10800, - "text": "6:30", + "text": "6:30" }, "end": { "value": "1568675447", "tzOffset": 10800, - "text": "2:10", - }, - }, - }, + "text": "2:10" + } + } + } } ], "threadId": "466B_bus_default", "EssentialStops": [ - {"id": "stop__9640546", "name": "Станция Бескудниково"}, - {"id": "stop__9640545", "name": "Станция Бескудниково"}, + { + "id": "stop__9640546", + "name": "Станция Бескудниково" + }, + { + "id": "stop__9640545", + "name": "Станция Бескудниково" + } ], "BriefSchedule": { "Events": [], @@ -1660,20 +1888,22 @@ "begin": { "value": "1568604647", "tzOffset": 10800, - "text": "6:30", + "text": "6:30" }, "end": { "value": "1568675447", "tzOffset": 10800, - "text": "2:10", - }, - }, - }, + "text": "2:10" + } + } + } }, { "lineId": "677k_bus_default", "name": "677к", - "Types": ["bus"], + "Types": [ + "bus" + ], "type": "bus", "threads": [ { @@ -1681,12 +1911,12 @@ "EssentialStops": [ { "id": "stop__9640244", - "name": "Платформа Лианозово", + "name": "Платформа Лианозово" }, { "id": "stop__9639480", - "name": "Платформа Лианозово", - }, + "name": "Платформа Лианозово" + } ], "BriefSchedule": { "Events": [ @@ -1694,38 +1924,44 @@ "Scheduled": { "value": "1568659920", "tzOffset": 10800, - "text": "21:52", + "text": "21:52" }, "Estimated": { "value": "1568660003", "tzOffset": 10800, - "text": "21:53", + "text": "21:53" }, - "vehicleId": "codd%5Fnew|130308%5F31319", + "vehicleId": "codd%5Fnew|130308%5F31319" }, { "Scheduled": { "value": "1568661240", "tzOffset": 10800, - "text": "22:14", + "text": "22:14" } }, { "Scheduled": { "value": "1568662500", "tzOffset": 10800, - "text": "22:35", + "text": "22:35" } - }, + } ], - "departureTime": "21:52", - }, + "departureTime": "21:52" + } } ], "threadId": "677kA_bus_default", "EssentialStops": [ - {"id": "stop__9640244", "name": "Платформа Лианозово"}, - {"id": "stop__9639480", "name": "Платформа Лианозово"}, + { + "id": "stop__9640244", + "name": "Платформа Лианозово" + }, + { + "id": "stop__9639480", + "name": "Платформа Лианозово" + } ], "BriefSchedule": { "Events": [ @@ -1733,44 +1969,52 @@ "Scheduled": { "value": "1568659920", "tzOffset": 10800, - "text": "21:52", + "text": "21:52" }, "Estimated": { "value": "1568660003", "tzOffset": 10800, - "text": "21:53", + "text": "21:53" }, - "vehicleId": "codd%5Fnew|130308%5F31319", + "vehicleId": "codd%5Fnew|130308%5F31319" }, { "Scheduled": { "value": "1568661240", "tzOffset": 10800, - "text": "22:14", + "text": "22:14" } }, { "Scheduled": { "value": "1568662500", "tzOffset": 10800, - "text": "22:35", + "text": "22:35" } - }, + } ], - "departureTime": "21:52", - }, + "departureTime": "21:52" + } }, { "lineId": "m10_bus_default", "name": "м10", - "Types": ["bus"], + "Types": [ + "bus" + ], "type": "bus", "threads": [ { "threadId": "2036926048", "EssentialStops": [ - {"id": "stop__9640554", "name": "Лобненская улица"}, - {"id": "stop__9640553", "name": "Лобненская улица"}, + { + "id": "stop__9640554", + "name": "Лобненская улица" + }, + { + "id": "stop__9640553", + "name": "Лобненская улица" + } ], "BriefSchedule": { "Events": [ @@ -1778,18 +2022,18 @@ "Estimated": { "value": "1568659718", "tzOffset": 10800, - "text": "21:48", + "text": "21:48" }, - "vehicleId": "codd%5Fnew|146260%5F31212", + "vehicleId": "codd%5Fnew|146260%5F31212" }, { "Estimated": { "value": "1568660422", "tzOffset": 10800, - "text": "22:00", + "text": "22:00" }, - "vehicleId": "codd%5Fnew|13997%5F31247", - }, + "vehicleId": "codd%5Fnew|13997%5F31247" + } ], "Frequency": { "text": "15 мин", @@ -1797,21 +2041,27 @@ "begin": { "value": "1568606903", "tzOffset": 10800, - "text": "7:08", + "text": "7:08" }, "end": { "value": "1568675183", "tzOffset": 10800, - "text": "2:06", - }, - }, - }, + "text": "2:06" + } + } + } } ], "threadId": "2036926048", "EssentialStops": [ - {"id": "stop__9640554", "name": "Лобненская улица"}, - {"id": "stop__9640553", "name": "Лобненская улица"}, + { + "id": "stop__9640554", + "name": "Лобненская улица" + }, + { + "id": "stop__9640553", + "name": "Лобненская улица" + } ], "BriefSchedule": { "Events": [ @@ -1819,18 +2069,18 @@ "Estimated": { "value": "1568659718", "tzOffset": 10800, - "text": "21:48", + "text": "21:48" }, - "vehicleId": "codd%5Fnew|146260%5F31212", + "vehicleId": "codd%5Fnew|146260%5F31212" }, { "Estimated": { "value": "1568660422", "tzOffset": 10800, - "text": "22:00", + "text": "22:00" }, - "vehicleId": "codd%5Fnew|13997%5F31247", - }, + "vehicleId": "codd%5Fnew|13997%5F31247" + } ], "Frequency": { "text": "15 мин", @@ -1838,19 +2088,19 @@ "begin": { "value": "1568606903", "tzOffset": 10800, - "text": "7:08", + "text": "7:08" }, "end": { "value": "1568675183", "tzOffset": 10800, - "text": "2:06", - }, - }, - }, - }, - ], - }, + "text": "2:06" + } + } + } + } + ] + } }, - "toponymSeoname": "dmitrovskoye_shosse", + "toponymSeoname": "dmitrovskoye_shosse" } } From 260979706664e02198239a82db742f460437995a Mon Sep 17 00:00:00 2001 From: Rishat Askarov Date: Thu, 19 Sep 2019 02:31:47 +0300 Subject: [PATCH 16/21] script/lint fixes --- .../components/yandex_transport/manifest.json | 16 ++++++---------- .../components/yandex_transport/sensor.py | 6 +++--- .../test_yandex_transport_sensor.py | 14 +++++++------- 3 files changed, 16 insertions(+), 20 deletions(-) diff --git a/homeassistant/components/yandex_transport/manifest.json b/homeassistant/components/yandex_transport/manifest.json index 54837b2eb0914d..739cf14d12f484 100644 --- a/homeassistant/components/yandex_transport/manifest.json +++ b/homeassistant/components/yandex_transport/manifest.json @@ -1,12 +1,8 @@ { - "domain": "yandex_transport", - "name": "Yandex Transport", - "documentation": "https://www.home-assistant.io/components/yandex_transport", - "requirements": [ - "ya_ma==0.3.4" - ], - "dependencies": [], - "codeowners": [ - "@rishatik92" - ] + "domain": "yandex_transport", + "name": "Yandex Transport", + "documentation": "https://www.home-assistant.io/components/yandex_transport", + "requirements": ["ya_ma==0.3.4"], + "dependencies": [], + "codeowners": ["@rishatik92"], } diff --git a/homeassistant/components/yandex_transport/sensor.py b/homeassistant/components/yandex_transport/sensor.py index f3430391ff2929..340291807ead98 100644 --- a/homeassistant/components/yandex_transport/sensor.py +++ b/homeassistant/components/yandex_transport/sensor.py @@ -67,10 +67,10 @@ def update(self): yandex_reply = self.requester.get_stop_info(self._stop_id) data = yandex_reply["data"] stop_metadata = data["properties"]["StopMetaData"] - except KeyError as e: + except KeyError as key_error: _LOGGER.warning( - "Exception KeyError was captured, missing key is %s. Yandex returned: %s" - % e, + "Exception KeyError was captured, missing key is %s. Yandex returned: %s", + key_error, yandex_reply, ) self.requester.set_new_session() diff --git a/tests/components/yandex_transport/test_yandex_transport_sensor.py b/tests/components/yandex_transport/test_yandex_transport_sensor.py index 9ee8aa051ad399..32c270187ea946 100644 --- a/tests/components/yandex_transport/test_yandex_transport_sensor.py +++ b/tests/components/yandex_transport/test_yandex_transport_sensor.py @@ -16,21 +16,22 @@ REPLY = loads(load_fixture("yandex_transport_reply.json")) +def get_fake_reply(stop_id): + """Return fake reply.""" + return REPLY + + @fixture def mock_requester(): """Create a mock ya_ma module and YandexMapsRequester.""" with MockDependency("ya_ma") as ya_ma: - class MockRequester(object): + class MockRequester: """Fake YandexRequester object.""" def __init__(self, user_agent=None): """Create mock module object, for avoid importing ya_ma library.""" - pass - - def get_stop_info(self, stop_id): - """Fake method. Return information about stop_id 9639579.""" - return REPLY + self.get_stop_info = get_fake_reply def set_new_session(self): """Fake method for reset http session.""" @@ -55,7 +56,6 @@ def set_new_session(self): def true_filter(reply, filter_routes=None): """Check transport filtering by routes list.""" - closer_time = None if filter_routes is None: filter_routes = [] From 0d110eaa2bead4ec131b699f18cad1bc5d2543c6 Mon Sep 17 00:00:00 2001 From: Rishat Askarov Date: Thu, 19 Sep 2019 20:34:32 +0300 Subject: [PATCH 17/21] fix comments --- .../components/yandex_transport/manifest.json | 16 +++++--- .../test_yandex_transport_sensor.py | 39 +++++-------------- 2 files changed, 19 insertions(+), 36 deletions(-) diff --git a/homeassistant/components/yandex_transport/manifest.json b/homeassistant/components/yandex_transport/manifest.json index 739cf14d12f484..54837b2eb0914d 100644 --- a/homeassistant/components/yandex_transport/manifest.json +++ b/homeassistant/components/yandex_transport/manifest.json @@ -1,8 +1,12 @@ { - "domain": "yandex_transport", - "name": "Yandex Transport", - "documentation": "https://www.home-assistant.io/components/yandex_transport", - "requirements": ["ya_ma==0.3.4"], - "dependencies": [], - "codeowners": ["@rishatik92"], + "domain": "yandex_transport", + "name": "Yandex Transport", + "documentation": "https://www.home-assistant.io/components/yandex_transport", + "requirements": [ + "ya_ma==0.3.4" + ], + "dependencies": [], + "codeowners": [ + "@rishatik92" + ] } diff --git a/tests/components/yandex_transport/test_yandex_transport_sensor.py b/tests/components/yandex_transport/test_yandex_transport_sensor.py index 32c270187ea946..bbd3a8fa163d4e 100644 --- a/tests/components/yandex_transport/test_yandex_transport_sensor.py +++ b/tests/components/yandex_transport/test_yandex_transport_sensor.py @@ -1,7 +1,7 @@ """Tests for the yandex transport platform.""" -from json import loads -from pytest import fixture +import json +import pytest import homeassistant.components.sensor as sensor import homeassistant.util.dt as dt_util @@ -13,32 +13,16 @@ load_fixture, ) -REPLY = loads(load_fixture("yandex_transport_reply.json")) +REPLY = json.loads(load_fixture("yandex_transport_reply.json")) -def get_fake_reply(stop_id): - """Return fake reply.""" - return REPLY - - -@fixture +@pytest.fixture def mock_requester(): """Create a mock ya_ma module and YandexMapsRequester.""" with MockDependency("ya_ma") as ya_ma: - - class MockRequester: - """Fake YandexRequester object.""" - - def __init__(self, user_agent=None): - """Create mock module object, for avoid importing ya_ma library.""" - self.get_stop_info = get_fake_reply - - def set_new_session(self): - """Fake method for reset http session.""" - pass - - ya_ma.YandexMapsRequester = MockRequester - yield MockRequester() + instance = ya_ma.YandexMapsRequester.return_value + instance.get_stop_info.return_value = REPLY + yield instance STOP_ID = 9639579 @@ -129,10 +113,5 @@ async def test_filtered_attributes(hass, mock_requester): true_attrs, true_state = true_filter(REPLY, filter_routes=ROUTES) assert state.state == true_state - result_key_len = len(true_attrs) - i = 0 - assert i != result_key_len - for key in true_attrs: - i += 1 - assert state.attributes[key] == true_attrs[key] - assert i == result_key_len + state_attrs = {key: state.attributes[key] for key in true_attrs} + assert state_attrs == true_attrs From 9e135f73c6c52634c6e0db4c3b37943e4aec0a99 Mon Sep 17 00:00:00 2001 From: Rishat Askarov Date: Thu, 19 Sep 2019 23:26:25 +0300 Subject: [PATCH 18/21] removing check_filter function --- .../test_yandex_transport_sensor.py | 53 +++++-------------- 1 file changed, 12 insertions(+), 41 deletions(-) diff --git a/tests/components/yandex_transport/test_yandex_transport_sensor.py b/tests/components/yandex_transport/test_yandex_transport_sensor.py index bbd3a8fa163d4e..582e8144dc4839 100644 --- a/tests/components/yandex_transport/test_yandex_transport_sensor.py +++ b/tests/components/yandex_transport/test_yandex_transport_sensor.py @@ -5,7 +5,7 @@ import homeassistant.components.sensor as sensor import homeassistant.util.dt as dt_util -from homeassistant.const import CONF_NAME, ATTR_ATTRIBUTION +from homeassistant.const import CONF_NAME from tests.common import ( assert_setup_component, async_setup_component, @@ -37,39 +37,15 @@ def mock_requester(): } } +FILTERED_ATTRS = { + "т36": ["21:43", "21:47", "22:02"], + "т47": ["21:40", "22:01"], + "м10": ["21:48", "22:00"], + "stop_name": "7-й автобусный парк", + "attribution": "Data provided by maps.yandex.ru", +} -def true_filter(reply, filter_routes=None): - """Check transport filtering by routes list.""" - closer_time = None - if filter_routes is None: - filter_routes = [] - attrs = {} - - stop_metadata = reply["data"]["properties"]["StopMetaData"] - - stop_name = reply["data"]["properties"]["name"] - transport_list = stop_metadata["Transport"] - for transport in transport_list: - route = transport["name"] - if filter_routes and route not in filter_routes: - # 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 attrs: - attrs[route] = [] - attrs[route].append(event["Estimated"]["text"]) - attrs["stop_name"] = stop_name - attrs[ATTR_ATTRIBUTION] = "Data provided by maps.yandex.ru" - if closer_time is None: - state = None - else: - state = dt_util.utc_from_timestamp(closer_time).isoformat(timespec="seconds") - return attrs, state +RESULT_STATE = dt_util.utc_from_timestamp(1568659253).isoformat(timespec="seconds") async def assert_setup_sensor(hass, config, count=1): @@ -101,17 +77,12 @@ async def test_state(hass, mock_requester): """Return the contents of _state.""" await assert_setup_sensor(hass, TEST_CONFIG) state = hass.states.get("sensor.test_name") - assert state.state == dt_util.utc_from_timestamp(1568659253).isoformat( - timespec="seconds" - ) + assert state.state == RESULT_STATE async def test_filtered_attributes(hass, mock_requester): """Return the contents of attributes.""" await assert_setup_sensor(hass, TEST_CONFIG) state = hass.states.get("sensor.test_name") - - true_attrs, true_state = true_filter(REPLY, filter_routes=ROUTES) - assert state.state == true_state - state_attrs = {key: state.attributes[key] for key in true_attrs} - assert state_attrs == true_attrs + state_attrs = {key: state.attributes[key] for key in FILTERED_ATTRS} + assert dict(state_attrs) == FILTERED_ATTRS From 1c98ff15869c19f5725943358ca32aaf83f9fba6 Mon Sep 17 00:00:00 2001 From: Rishat Askarov Date: Thu, 19 Sep 2019 23:31:31 +0300 Subject: [PATCH 19/21] fix typo --- .../components/yandex_transport/test_yandex_transport_sensor.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/components/yandex_transport/test_yandex_transport_sensor.py b/tests/components/yandex_transport/test_yandex_transport_sensor.py index 582e8144dc4839..50d945e7fae371 100644 --- a/tests/components/yandex_transport/test_yandex_transport_sensor.py +++ b/tests/components/yandex_transport/test_yandex_transport_sensor.py @@ -85,4 +85,4 @@ async def test_filtered_attributes(hass, mock_requester): await assert_setup_sensor(hass, TEST_CONFIG) state = hass.states.get("sensor.test_name") state_attrs = {key: state.attributes[key] for key in FILTERED_ATTRS} - assert dict(state_attrs) == FILTERED_ATTRS + assert state_attrs == FILTERED_ATTRS From cc4003c4080497630e5dd58e3deb3f0cdd304723 Mon Sep 17 00:00:00 2001 From: Askarov Rishat Date: Fri, 20 Sep 2019 17:46:16 +0300 Subject: [PATCH 20/21] up version on manifest.json --- homeassistant/components/yandex_transport/manifest.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/homeassistant/components/yandex_transport/manifest.json b/homeassistant/components/yandex_transport/manifest.json index 54837b2eb0914d..6c633f848c0c68 100644 --- a/homeassistant/components/yandex_transport/manifest.json +++ b/homeassistant/components/yandex_transport/manifest.json @@ -3,7 +3,7 @@ "name": "Yandex Transport", "documentation": "https://www.home-assistant.io/components/yandex_transport", "requirements": [ - "ya_ma==0.3.4" + "ya_ma==0.3.7" ], "dependencies": [], "codeowners": [ From 8330c8a12ef94531f499c6de4b4e31a08ca3b45a Mon Sep 17 00:00:00 2001 From: Askarov Rishat Date: Fri, 20 Sep 2019 17:47:53 +0300 Subject: [PATCH 21/21] up version to 0.3.7 in requirements_all.txt --- requirements_all.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements_all.txt b/requirements_all.txt index 12a429901fca4b..57d688f81a30b0 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -1956,7 +1956,7 @@ xmltodict==0.12.0 xs1-api-client==2.3.5 # homeassistant.components.yandex_transport -ya_ma==0.3.4 +ya_ma==0.3.7 # homeassistant.components.yweather yahooweather==0.10