├── .github ├── CODEOWNERS ├── ISSUE_TEMPLATE │ ├── feature_request.md │ └── issue.md ├── settings.yml └── stale.yml ├── LICENSE ├── README.md ├── custom_components └── yandex_maps │ ├── __init__.py │ ├── manifest.json │ └── sensor.py └── example.png /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | * @ludeeus -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | 5 | --- 6 | 7 | **Is your feature request related to a problem? Please describe.** 8 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 9 | 10 | **Describe the solution you'd like** 11 | A clear and concise description of what you want to happen. 12 | 13 | **Describe alternatives you've considered** 14 | A clear and concise description of any alternative solutions or features you've considered. 15 | 16 | **Additional context** 17 | Add any other context or screenshots about the feature request here. -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/issue.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Issue 3 | about: Create a report to help us improve 4 | 5 | --- 6 | 7 | **Version of the custom_component** 8 | 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **log** 14 | 15 | ``` 16 | Add your logs here. 17 | ``` -------------------------------------------------------------------------------- /.github/settings.yml: -------------------------------------------------------------------------------- 1 | repository: 2 | private: false 3 | has_issues: true 4 | has_projects: false 5 | has_wiki: false 6 | has_downloads: false 7 | default_branch: master 8 | allow_squash_merge: true 9 | allow_merge_commit: false 10 | allow_rebase_merge: false 11 | labels: 12 | - name: "Feature Request" 13 | color: "fbca04" 14 | - name: "Bug" 15 | color: "b60205" 16 | - name: "Wont Fix" 17 | color: "ffffff" 18 | - name: "Enhancement" 19 | color: a2eeef 20 | - name: "Documentation" 21 | color: "008672" 22 | - name: "Stale" 23 | color: "930191" -------------------------------------------------------------------------------- /.github/stale.yml: -------------------------------------------------------------------------------- 1 | # Number of days of inactivity before an issue becomes stale 2 | daysUntilStale: 14 3 | # Number of days of inactivity before a stale issue is closed 4 | daysUntilClose: 7 5 | # Issues with these labels will never be considered stale 6 | #exemptLabels: 7 | # - pinned 8 | # - security 9 | # Label to use when marking an issue as stale 10 | staleLabel: Stale 11 | # Comment to post when marking an issue as stale. Set to `false` to disable 12 | markComment: > 13 | This issue has been automatically marked as stale because it has not had 14 | recent activity. It will be closed if no further activity occurs. Thank you 15 | for your contributions. 16 | # Comment to post when closing a stale issue. Set to `false` to disable 17 | closeComment: false -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Joakim Sørensen @ludeeus 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # sensor.yandex_maps 2 | 3 | [![BuyMeCoffee][buymecoffeebedge]][buymecoffee] 4 | [![custom_updater](https://img.shields.io/badge/custom__updater-true-success.svg)](https://github.com/custom-components/custom_updater) 5 | 6 | _A platform which give you the time it will take to drive._ 7 | 8 | **Data is fetched from yandex.ru.** 9 | 10 | ![example][exampleimg] 11 | 12 | ## Installation 13 | 14 | To get started put `/custom_components/yandex_maps/sensor.py` here: 15 | `/custom_components/yandex_maps/sensor.py` 16 | 17 | ## Example configuration.yaml 18 | 19 | ```yaml 20 | sensor: 21 | platform: yandex_maps 22 | start: 'device_tracker.my_phone' 23 | destination: '29.361133,54.991133' 24 | name: Time to work 25 | ``` 26 | 27 | ## Configuration variables 28 | 29 | key | type | description 30 | :--- | :--- | :--- 31 | **platform (Required)** | string | The platform name. 32 | **start (Required)** | string | ID of an entity which have `latitude` and `longitude` attributes, or GPS coordinates like `'29.361133,54.991133'`. 33 | **destination (Required)** | string | ID of an entity which have `latitude` and `longitude` attributes, or GPS coordinates like `'29.361133,54.991133'`. 34 | **name (Required)** | string | Name of the sensor. 35 | 36 | *** 37 | 38 | [exampleimg]: example.png 39 | [buymecoffee]: https://www.buymeacoffee.com/ludeeus 40 | [buymecoffeebedge]: https://camo.githubusercontent.com/cd005dca0ef55d7725912ec03a936d3a7c8de5b5/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f6275792532306d6525323061253230636f666665652d646f6e6174652d79656c6c6f772e737667 41 | -------------------------------------------------------------------------------- /custom_components/yandex_maps/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/custom-components/sensor.yandex_maps/bdd76a8cc448afdef35fac9b53cb600cc63ae145/custom_components/yandex_maps/__init__.py -------------------------------------------------------------------------------- /custom_components/yandex_maps/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "domain": "yandex_maps", 3 | "name": "Yandex Maps", 4 | "version": "1.1", 5 | "documentation": "https://github.com/custom-components/sensor.yandex_maps", 6 | "dependencies": [], 7 | "codeowners": [], 8 | "requirements": [] 9 | } 10 | 11 | -------------------------------------------------------------------------------- /custom_components/yandex_maps/sensor.py: -------------------------------------------------------------------------------- 1 | """ 2 | A platform which give you the time it will take to drive. 3 | 4 | For more details about this component, please refer to the documentation at 5 | https://github.com/custom-components/sensor.yandex_maps 6 | """ 7 | import logging 8 | 9 | import re 10 | 11 | import aiohttp 12 | import voluptuous as vol 13 | import homeassistant.helpers.config_validation as cv 14 | from homeassistant.components.sensor import PLATFORM_SCHEMA 15 | from homeassistant.helpers.entity import Entity 16 | 17 | coords_re = re.compile(r'-?\d{1,2}\.\d{1,6},\s?-?\d{1,3}\.\d{1,6}') 18 | 19 | __version__ = '0.0.6' 20 | 21 | CONF_NAME = 'name' 22 | CONF_START = 'start' 23 | CONF_DESTINATION = 'destination' 24 | 25 | ICON = 'mdi:car' 26 | 27 | BASE_URL = 'https://yandex.ru/geohelper/api/v1/router?points={}~{}' 28 | 29 | PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ 30 | vol.Required(CONF_NAME): cv.string, 31 | vol.Required(CONF_START): cv.string, 32 | vol.Required(CONF_DESTINATION): cv.string, 33 | }) 34 | 35 | _LOGGER = logging.getLogger(__name__) 36 | 37 | 38 | async def async_setup_platform( 39 | hass, config, async_add_entities, discovery_info=None): # pylint: disable=unused-argument 40 | """Setup sensor platform.""" 41 | name = config['name'] 42 | start = config['start'] 43 | destination = config['destination'] 44 | 45 | async_add_entities( 46 | [YandexMapsSensor(hass, name, start, destination)], True) 47 | 48 | 49 | class YandexMapsSensor(Entity): 50 | """YandexMap Sensor class""" 51 | 52 | def __init__(self, hass, name, start, destination): 53 | self.hass = hass 54 | self._state = None 55 | self._name = name 56 | self._start = start 57 | self._destination = destination 58 | self.attr = {} 59 | _LOGGER.debug('Initialized sensor %s with %s, %s', self._name, self._start, self._destination) 60 | 61 | async def async_update(self): 62 | """Update sensor.""" 63 | _LOGGER.debug('%s - Running update', self._name) 64 | 65 | try: 66 | url = BASE_URL.format(self.start, self.destination) 67 | 68 | _LOGGER.debug('Requesting url %s', url) 69 | async with aiohttp.ClientSession() as client: 70 | async with client.get(url) as resp: 71 | assert resp.status == 200 72 | info = await resp.json() 73 | 74 | self._state = info.get('direct', {}).get('time') 75 | self.attr = { 76 | 'mapurl': info.get('direct', {}).get('mapUrl'), 77 | 'jamsrate': info.get('jamsRate'), 78 | 'jamsmeasure': info.get('jamsMeasure') 79 | } 80 | except Exception as error: # pylint: disable=broad-except 81 | _LOGGER.debug('%s - Could not update - %s', self._name, error) 82 | 83 | @classmethod 84 | def is_coord(cls, data: str) -> bool: 85 | return bool(coords_re.fullmatch(data)) 86 | 87 | @property 88 | def start(self): 89 | return self.point_to_coords(self._start) 90 | 91 | @property 92 | def destination(self): 93 | return self.point_to_coords(self._destination) 94 | 95 | def point_to_coords(self, point: str) -> str: 96 | if YandexMapsSensor.is_coord(point): 97 | return point 98 | 99 | state = self.hass.states.get(point) 100 | if state: 101 | latitude = state.attributes.get('latitude') 102 | longitude = state.attributes.get('longitude') 103 | if latitude and longitude: 104 | return "{},{}".format(longitude, latitude) 105 | else: 106 | raise AttributeError 107 | 108 | @property 109 | def name(self): 110 | """Name.""" 111 | return self._name 112 | 113 | @property 114 | def state(self): 115 | """State.""" 116 | return self._state 117 | 118 | @property 119 | def icon(self): 120 | """Icon.""" 121 | return ICON 122 | 123 | @property 124 | def unit_of_measurement(self): 125 | """unit_of_measurement.""" 126 | return 'мин' 127 | 128 | @property 129 | def extra_state_attributes(self): 130 | """Attributes.""" 131 | return self.attr 132 | -------------------------------------------------------------------------------- /example.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/custom-components/sensor.yandex_maps/bdd76a8cc448afdef35fac9b53cb600cc63ae145/example.png --------------------------------------------------------------------------------