""" Support for Tado Smart Thermostat. Device tracker platform that supports presence detection. The detection is based on geofencing enabled devices used with Tado. """ import logging from datetime import timedelta from collections import namedtuple import asyncio import aiohttp import async_timeout import voluptuous as vol from homeassistant.const import CONF_USERNAME, CONF_PASSWORD import homeassistant.helpers.config_validation as cv from homeassistant.util import Throttle from homeassistant.components.device_tracker import \ DOMAIN, PLATFORM_SCHEMA, DeviceScanner from homeassistant.helpers.aiohttp_client import async_create_clientsession # Return cached results if last scan was less then this time ago MIN_TIME_BETWEEN_SCANS = timedelta(seconds=30) _LOGGER = logging.getLogger(__name__) PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ vol.Required(CONF_PASSWORD): cv.string, vol.Required(CONF_USERNAME): cv.string }) def get_scanner(hass, config): """Return a Tado scanner.""" scanner = TadoDeviceScanner(hass, config[DOMAIN]) return scanner if scanner.success_init else None Device = namedtuple("Device", ["mac", "name"]) class TadoDeviceScanner(DeviceScanner): """This class gets geofenced devices from Tado.""" def __init__(self, hass, config): """Initialize the scanner.""" self.last_results = [] self.username = config[CONF_USERNAME] self.password = config[CONF_PASSWORD] self.tadoapiurl = 'https://my.tado.com/api/v2/me' \ '?username={}&password={}' self.websession = async_create_clientsession( hass, cookie_jar=aiohttp.CookieJar(unsafe=True, loop=hass.loop)) self.success_init = self._update_info() _LOGGER.info("Tado scanner initialized") @asyncio.coroutine def async_scan_devices(self): """Scan for devices and return a list containing found device ids.""" yield from self._update_info() return [device.mac for device in self.last_results] @asyncio.coroutine def async_get_device_name(self, mac): """Return the name of the given device or None if we don't know.""" filter_named = [device.name for device in self.last_results if device.mac == mac] if filter_named: return filter_named[0] else: return None @Throttle(MIN_TIME_BETWEEN_SCANS) def _update_info(self): """ Query Tado for device marked as at home. Returns boolean if scanning successful. """ _LOGGER.debug("Requesting Tado") last_results = [] response = None tadojson = None try: # get first token with async_timeout.timeout(10, loop=self.hass.loop): url = self.tadoapiurl.format(self.username, self.password) response = yield from self.websession.get( url ) # error on Tado webservice if response.status != 200: _LOGGER.warning( "Error %d on %s.", response.status, self.tadoapiurl) self.token = None return tadojson = yield from response.json() except (asyncio.TimeoutError, aiohttp.errors.ClientError): _LOGGER.error("Can not load Tado data") return False finally: if response is not None: yield from response.release() # Find devices that have geofencing enabled, and are currently at home for mobiledevice in tadojson['mobileDevices']: if 'location' in mobiledevice: if mobiledevice['location']['atHome']: deviceid = mobiledevice['id'] devicename = mobiledevice['name'] last_results.append(Device(deviceid, devicename)) self.last_results = last_results _LOGGER.info("Tado presence query successful") return True