mirror of
https://github.com/home-assistant/core.git
synced 2025-07-21 20:27:08 +00:00
Update Tile platform to be async (#15073)
* Updated * Updated requirements * Added expired session handling * Changes * Member-requested changes * Bump to 2.0.2 * Bumping requirements * Better exception handling and tidying * Move asyncio stuff to HASS built-ins * Revising re-initi * Hound * Hound
This commit is contained in:
parent
b2df199674
commit
2525fc52b3
@ -5,24 +5,22 @@ For more details about this platform, please refer to the documentation at
|
|||||||
https://home-assistant.io/components/device_tracker.tile/
|
https://home-assistant.io/components/device_tracker.tile/
|
||||||
"""
|
"""
|
||||||
import logging
|
import logging
|
||||||
|
from datetime import timedelta
|
||||||
|
|
||||||
import voluptuous as vol
|
import voluptuous as vol
|
||||||
|
|
||||||
import homeassistant.helpers.config_validation as cv
|
from homeassistant.components.device_tracker import PLATFORM_SCHEMA
|
||||||
from homeassistant.components.device_tracker import (
|
|
||||||
PLATFORM_SCHEMA, DeviceScanner)
|
|
||||||
from homeassistant.const import (
|
from homeassistant.const import (
|
||||||
CONF_USERNAME, CONF_MONITORED_VARIABLES, CONF_PASSWORD)
|
CONF_USERNAME, CONF_MONITORED_VARIABLES, CONF_PASSWORD)
|
||||||
from homeassistant.helpers.event import track_utc_time_change
|
from homeassistant.helpers import aiohttp_client, config_validation as cv
|
||||||
|
from homeassistant.helpers.event import async_track_time_interval
|
||||||
from homeassistant.util import slugify
|
from homeassistant.util import slugify
|
||||||
from homeassistant.util.json import load_json, save_json
|
from homeassistant.util.json import load_json, save_json
|
||||||
|
|
||||||
_LOGGER = logging.getLogger(__name__)
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
REQUIREMENTS = ['pytile==2.0.2']
|
||||||
REQUIREMENTS = ['pytile==1.1.0']
|
|
||||||
|
|
||||||
CLIENT_UUID_CONFIG_FILE = '.tile.conf'
|
CLIENT_UUID_CONFIG_FILE = '.tile.conf'
|
||||||
DEFAULT_ICON = 'mdi:bluetooth'
|
|
||||||
DEVICE_TYPES = ['PHONE', 'TILE']
|
DEVICE_TYPES = ['PHONE', 'TILE']
|
||||||
|
|
||||||
ATTR_ALTITUDE = 'altitude'
|
ATTR_ALTITUDE = 'altitude'
|
||||||
@ -34,89 +32,111 @@ ATTR_VOIP_STATE = 'voip_state'
|
|||||||
|
|
||||||
CONF_SHOW_INACTIVE = 'show_inactive'
|
CONF_SHOW_INACTIVE = 'show_inactive'
|
||||||
|
|
||||||
|
DEFAULT_ICON = 'mdi:bluetooth'
|
||||||
|
DEFAULT_SCAN_INTERVAL = timedelta(minutes=2)
|
||||||
|
|
||||||
PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
|
PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
|
||||||
vol.Required(CONF_USERNAME): cv.string,
|
vol.Required(CONF_USERNAME): cv.string,
|
||||||
vol.Required(CONF_PASSWORD): cv.string,
|
vol.Required(CONF_PASSWORD): cv.string,
|
||||||
vol.Optional(CONF_SHOW_INACTIVE, default=False): cv.boolean,
|
vol.Optional(CONF_SHOW_INACTIVE, default=False): cv.boolean,
|
||||||
vol.Optional(CONF_MONITORED_VARIABLES):
|
vol.Optional(CONF_MONITORED_VARIABLES, default=DEVICE_TYPES):
|
||||||
vol.All(cv.ensure_list, [vol.In(DEVICE_TYPES)]),
|
vol.All(cv.ensure_list, [vol.In(DEVICE_TYPES)]),
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
def setup_scanner(hass, config: dict, see, discovery_info=None):
|
async def async_setup_scanner(hass, config, async_see, discovery_info=None):
|
||||||
"""Validate the configuration and return a Tile scanner."""
|
"""Validate the configuration and return a Tile scanner."""
|
||||||
TileDeviceScanner(hass, config, see)
|
from pytile import Client
|
||||||
return True
|
|
||||||
|
websession = aiohttp_client.async_get_clientsession(hass)
|
||||||
|
|
||||||
|
config_data = await hass.async_add_job(
|
||||||
|
load_json, hass.config.path(CLIENT_UUID_CONFIG_FILE))
|
||||||
|
if config_data:
|
||||||
|
client = Client(
|
||||||
|
config[CONF_USERNAME],
|
||||||
|
config[CONF_PASSWORD],
|
||||||
|
websession,
|
||||||
|
client_uuid=config_data['client_uuid'])
|
||||||
|
else:
|
||||||
|
client = Client(
|
||||||
|
config[CONF_USERNAME], config[CONF_PASSWORD], websession)
|
||||||
|
|
||||||
|
config_data = {'client_uuid': client.client_uuid}
|
||||||
|
config_saved = await hass.async_add_job(
|
||||||
|
save_json, hass.config.path(CLIENT_UUID_CONFIG_FILE), config_data)
|
||||||
|
if not config_saved:
|
||||||
|
_LOGGER.error('Failed to save the client UUID')
|
||||||
|
|
||||||
|
scanner = TileScanner(
|
||||||
|
client, hass, async_see, config[CONF_MONITORED_VARIABLES],
|
||||||
|
config[CONF_SHOW_INACTIVE])
|
||||||
|
return await scanner.async_init()
|
||||||
|
|
||||||
|
|
||||||
class TileDeviceScanner(DeviceScanner):
|
class TileScanner(object):
|
||||||
"""Define a device scanner for Tiles."""
|
"""Define an object to retrieve Tile data."""
|
||||||
|
|
||||||
def __init__(self, hass, config, see):
|
def __init__(self, client, hass, async_see, types, show_inactive):
|
||||||
"""Initialize."""
|
"""Initialize."""
|
||||||
from pytile import Client
|
self._async_see = async_see
|
||||||
|
self._client = client
|
||||||
|
self._hass = hass
|
||||||
|
self._show_inactive = show_inactive
|
||||||
|
self._types = types
|
||||||
|
|
||||||
_LOGGER.debug('Received configuration data: %s', config)
|
async def async_init(self):
|
||||||
|
"""Further initialize connection to the Tile servers."""
|
||||||
|
from pytile.errors import TileError
|
||||||
|
|
||||||
# Load the client UUID (if it exists):
|
try:
|
||||||
config_data = load_json(hass.config.path(CLIENT_UUID_CONFIG_FILE))
|
await self._client.async_init()
|
||||||
if config_data:
|
except TileError as err:
|
||||||
_LOGGER.debug('Using existing client UUID')
|
_LOGGER.error('Unable to set up Tile scanner: %s', err)
|
||||||
self._client = Client(
|
return False
|
||||||
config[CONF_USERNAME],
|
|
||||||
config[CONF_PASSWORD],
|
|
||||||
config_data['client_uuid'])
|
|
||||||
else:
|
|
||||||
_LOGGER.debug('Generating new client UUID')
|
|
||||||
self._client = Client(
|
|
||||||
config[CONF_USERNAME],
|
|
||||||
config[CONF_PASSWORD])
|
|
||||||
|
|
||||||
if not save_json(
|
await self._async_update()
|
||||||
hass.config.path(CLIENT_UUID_CONFIG_FILE),
|
|
||||||
{'client_uuid': self._client.client_uuid}):
|
|
||||||
_LOGGER.error("Failed to save configuration file")
|
|
||||||
|
|
||||||
_LOGGER.debug('Client UUID: %s', self._client.client_uuid)
|
async_track_time_interval(
|
||||||
_LOGGER.debug('User UUID: %s', self._client.user_uuid)
|
self._hass, self._async_update, DEFAULT_SCAN_INTERVAL)
|
||||||
|
|
||||||
self._show_inactive = config.get(CONF_SHOW_INACTIVE)
|
return True
|
||||||
self._types = config.get(CONF_MONITORED_VARIABLES)
|
|
||||||
|
|
||||||
self.devices = {}
|
async def _async_update(self, now=None):
|
||||||
self.see = see
|
"""Update info from Tile."""
|
||||||
|
from pytile.errors import SessionExpiredError, TileError
|
||||||
|
|
||||||
track_utc_time_change(
|
_LOGGER.debug('Updating Tile data')
|
||||||
hass, self._update_info, second=range(0, 60, 30))
|
|
||||||
|
|
||||||
self._update_info()
|
try:
|
||||||
|
await self._client.asayn_init()
|
||||||
|
tiles = await self._client.tiles.all(
|
||||||
|
whitelist=self._types, show_inactive=self._show_inactive)
|
||||||
|
except SessionExpiredError:
|
||||||
|
_LOGGER.info('Session expired; trying again shortly')
|
||||||
|
return
|
||||||
|
except TileError as err:
|
||||||
|
_LOGGER.error('There was an error while updating: %s', err)
|
||||||
|
return
|
||||||
|
|
||||||
def _update_info(self, now=None) -> None:
|
if not tiles:
|
||||||
"""Update the device info."""
|
|
||||||
self.devices = self._client.get_tiles(
|
|
||||||
type_whitelist=self._types, show_inactive=self._show_inactive)
|
|
||||||
|
|
||||||
if not self.devices:
|
|
||||||
_LOGGER.warning('No Tiles found')
|
_LOGGER.warning('No Tiles found')
|
||||||
return
|
return
|
||||||
|
|
||||||
for dev in self.devices:
|
for tile in tiles:
|
||||||
dev_id = 'tile_{0}'.format(slugify(dev['name']))
|
await self._async_see(
|
||||||
lat = dev['tileState']['latitude']
|
dev_id='tile_{0}'.format(slugify(tile['name'])),
|
||||||
lon = dev['tileState']['longitude']
|
gps=(
|
||||||
|
tile['tileState']['latitude'],
|
||||||
attrs = {
|
tile['tileState']['longitude']
|
||||||
ATTR_ALTITUDE: dev['tileState']['altitude'],
|
),
|
||||||
ATTR_CONNECTION_STATE: dev['tileState']['connection_state'],
|
attributes={
|
||||||
ATTR_IS_DEAD: dev['is_dead'],
|
ATTR_ALTITUDE: tile['tileState']['altitude'],
|
||||||
ATTR_IS_LOST: dev['tileState']['is_lost'],
|
ATTR_CONNECTION_STATE:
|
||||||
ATTR_RING_STATE: dev['tileState']['ring_state'],
|
tile['tileState']['connection_state'],
|
||||||
ATTR_VOIP_STATE: dev['tileState']['voip_state'],
|
ATTR_IS_DEAD: tile['is_dead'],
|
||||||
}
|
ATTR_IS_LOST: tile['tileState']['is_lost'],
|
||||||
|
ATTR_RING_STATE: tile['tileState']['ring_state'],
|
||||||
self.see(
|
ATTR_VOIP_STATE: tile['tileState']['voip_state'],
|
||||||
dev_id=dev_id,
|
},
|
||||||
gps=(lat, lon),
|
icon=DEFAULT_ICON)
|
||||||
attributes=attrs,
|
|
||||||
icon=DEFAULT_ICON
|
|
||||||
)
|
|
||||||
|
@ -1113,7 +1113,7 @@ pythonegardia==1.0.39
|
|||||||
pythonwhois==2.4.3
|
pythonwhois==2.4.3
|
||||||
|
|
||||||
# homeassistant.components.device_tracker.tile
|
# homeassistant.components.device_tracker.tile
|
||||||
pytile==1.1.0
|
pytile==2.0.2
|
||||||
|
|
||||||
# homeassistant.components.climate.touchline
|
# homeassistant.components.climate.touchline
|
||||||
pytouchline==0.7
|
pytouchline==0.7
|
||||||
|
Loading…
x
Reference in New Issue
Block a user