2015-01-09 08:07:58 +00:00
|
|
|
"""
|
|
|
|
Starts a service to scan in intervals for new devices.
|
|
|
|
|
2015-01-12 16:21:50 +00:00
|
|
|
Will emit EVENT_PLATFORM_DISCOVERED whenever a new service has been discovered.
|
2015-01-09 08:07:58 +00:00
|
|
|
|
|
|
|
Knows which components handle certain types, will make sure they are
|
2015-01-12 16:21:50 +00:00
|
|
|
loaded before the EVENT_PLATFORM_DISCOVERED is fired.
|
2015-01-09 08:07:58 +00:00
|
|
|
"""
|
2017-03-03 21:11:40 +00:00
|
|
|
import json
|
2017-03-01 15:38:49 +00:00
|
|
|
from datetime import timedelta
|
2015-01-09 08:07:58 +00:00
|
|
|
import logging
|
2017-04-21 01:45:15 +00:00
|
|
|
import os
|
2015-01-09 08:07:58 +00:00
|
|
|
|
2016-09-30 02:02:22 +00:00
|
|
|
import voluptuous as vol
|
|
|
|
|
2018-04-13 14:14:53 +00:00
|
|
|
from homeassistant import data_entry_flow
|
2017-04-09 08:05:34 +00:00
|
|
|
from homeassistant.core import callback
|
2016-06-12 00:43:13 +00:00
|
|
|
from homeassistant.const import EVENT_HOMEASSISTANT_START
|
2017-03-01 15:38:49 +00:00
|
|
|
import homeassistant.helpers.config_validation as cv
|
|
|
|
from homeassistant.helpers.event import async_track_point_in_utc_time
|
|
|
|
from homeassistant.helpers.discovery import async_load_platform, async_discover
|
|
|
|
import homeassistant.util.dt as dt_util
|
2015-01-09 08:07:58 +00:00
|
|
|
|
2018-05-07 14:00:54 +00:00
|
|
|
REQUIREMENTS = ['netdisco==1.4.1']
|
2015-01-09 08:07:58 +00:00
|
|
|
|
2016-08-22 12:19:19 +00:00
|
|
|
DOMAIN = 'discovery'
|
2015-01-09 08:07:58 +00:00
|
|
|
|
2017-03-01 15:38:49 +00:00
|
|
|
SCAN_INTERVAL = timedelta(seconds=300)
|
2015-08-24 00:20:09 +00:00
|
|
|
SERVICE_NETGEAR = 'netgear_router'
|
2016-08-22 12:19:19 +00:00
|
|
|
SERVICE_WEMO = 'belkin_wemo'
|
2016-10-22 06:20:15 +00:00
|
|
|
SERVICE_HASS_IOS_APP = 'hass_ios'
|
2017-04-16 21:37:39 +00:00
|
|
|
SERVICE_IKEA_TRADFRI = 'ikea_tradfri'
|
2017-04-21 01:45:15 +00:00
|
|
|
SERVICE_HASSIO = 'hassio'
|
2017-05-12 15:51:54 +00:00
|
|
|
SERVICE_AXIS = 'axis'
|
2017-07-05 04:37:18 +00:00
|
|
|
SERVICE_APPLE_TV = 'apple_tv'
|
2017-08-01 03:54:07 +00:00
|
|
|
SERVICE_WINK = 'wink'
|
2017-09-13 03:44:42 +00:00
|
|
|
SERVICE_XIAOMI_GW = 'xiaomi_gw'
|
2017-11-28 07:13:30 +00:00
|
|
|
SERVICE_TELLDUSLIVE = 'tellstick'
|
2017-12-10 18:15:01 +00:00
|
|
|
SERVICE_HUE = 'philips_hue'
|
2018-05-15 17:58:00 +00:00
|
|
|
SERVICE_KONNECTED = 'konnected'
|
2018-01-01 16:08:13 +00:00
|
|
|
SERVICE_DECONZ = 'deconz'
|
2018-01-04 10:05:27 +00:00
|
|
|
SERVICE_DAIKIN = 'daikin'
|
2018-05-07 07:35:55 +00:00
|
|
|
SERVICE_SABNZBD = 'sabnzbd'
|
2018-03-18 16:26:33 +00:00
|
|
|
SERVICE_SAMSUNG_PRINTER = 'samsung_printer'
|
2018-04-13 17:25:35 +00:00
|
|
|
SERVICE_HOMEKIT = 'homekit'
|
2015-07-20 07:07:01 +00:00
|
|
|
|
2018-03-30 03:15:40 +00:00
|
|
|
CONFIG_ENTRY_HANDLERS = {
|
2018-04-18 14:27:44 +00:00
|
|
|
SERVICE_DECONZ: 'deconz',
|
2018-03-30 03:15:40 +00:00
|
|
|
SERVICE_HUE: 'hue',
|
|
|
|
}
|
|
|
|
|
2015-01-09 08:07:58 +00:00
|
|
|
SERVICE_HANDLERS = {
|
2016-10-22 06:20:15 +00:00
|
|
|
SERVICE_HASS_IOS_APP: ('ios', None),
|
2016-06-12 00:43:13 +00:00
|
|
|
SERVICE_NETGEAR: ('device_tracker', None),
|
|
|
|
SERVICE_WEMO: ('wemo', None),
|
2017-04-16 21:37:39 +00:00
|
|
|
SERVICE_IKEA_TRADFRI: ('tradfri', None),
|
2017-04-21 01:45:15 +00:00
|
|
|
SERVICE_HASSIO: ('hassio', None),
|
2017-05-12 15:51:54 +00:00
|
|
|
SERVICE_AXIS: ('axis', None),
|
2017-07-05 04:37:18 +00:00
|
|
|
SERVICE_APPLE_TV: ('apple_tv', None),
|
2017-08-01 03:54:07 +00:00
|
|
|
SERVICE_WINK: ('wink', None),
|
2017-09-14 22:49:03 +00:00
|
|
|
SERVICE_XIAOMI_GW: ('xiaomi_aqara', None),
|
2017-11-28 07:13:30 +00:00
|
|
|
SERVICE_TELLDUSLIVE: ('tellduslive', None),
|
2018-01-21 05:08:42 +00:00
|
|
|
SERVICE_DAIKIN: ('daikin', None),
|
2018-05-07 07:35:55 +00:00
|
|
|
SERVICE_SABNZBD: ('sabnzbd', None),
|
2018-03-18 16:26:33 +00:00
|
|
|
SERVICE_SAMSUNG_PRINTER: ('sensor', 'syncthru'),
|
2018-05-15 17:58:00 +00:00
|
|
|
SERVICE_KONNECTED: ('konnected', None),
|
2016-06-12 00:43:13 +00:00
|
|
|
'google_cast': ('media_player', 'cast'),
|
|
|
|
'panasonic_viera': ('media_player', 'panasonic_viera'),
|
|
|
|
'plex_mediaserver': ('media_player', 'plex'),
|
|
|
|
'roku': ('media_player', 'roku'),
|
|
|
|
'sonos': ('media_player', 'sonos'),
|
2016-10-27 06:46:44 +00:00
|
|
|
'yamaha': ('media_player', 'yamaha'),
|
2016-06-12 00:43:13 +00:00
|
|
|
'logitech_mediaserver': ('media_player', 'squeezebox'),
|
2016-07-26 06:20:56 +00:00
|
|
|
'directv': ('media_player', 'directv'),
|
2016-12-14 04:04:40 +00:00
|
|
|
'denonavr': ('media_player', 'denonavr'),
|
2016-12-16 06:20:00 +00:00
|
|
|
'samsung_tv': ('media_player', 'samsungtv'),
|
2017-01-05 22:39:28 +00:00
|
|
|
'yeelight': ('light', 'yeelight'),
|
2017-02-28 14:23:07 +00:00
|
|
|
'frontier_silicon': ('media_player', 'frontier_silicon'),
|
2017-02-22 22:01:06 +00:00
|
|
|
'openhome': ('media_player', 'openhome'),
|
2017-06-22 05:43:35 +00:00
|
|
|
'harmony': ('remote', 'harmony'),
|
2017-04-20 04:52:37 +00:00
|
|
|
'bose_soundtouch': ('media_player', 'soundtouch'),
|
2017-08-02 05:41:51 +00:00
|
|
|
'bluesound': ('media_player', 'bluesound'),
|
2018-02-27 21:21:56 +00:00
|
|
|
'songpal': ('media_player', 'songpal'),
|
2018-04-14 12:31:12 +00:00
|
|
|
'kodi': ('media_player', 'kodi'),
|
2018-05-01 19:20:38 +00:00
|
|
|
'volumio': ('media_player', 'volumio'),
|
2018-05-20 18:53:57 +00:00
|
|
|
'nanoleaf_aurora': ('light', 'nanoleaf_aurora'),
|
2018-06-05 18:38:50 +00:00
|
|
|
'freebox': ('device_tracker', 'freebox'),
|
2015-01-09 08:07:58 +00:00
|
|
|
}
|
|
|
|
|
2018-04-13 17:25:35 +00:00
|
|
|
OPTIONAL_SERVICE_HANDLERS = {
|
|
|
|
SERVICE_HOMEKIT: ('homekit_controller', None),
|
|
|
|
}
|
|
|
|
|
2017-02-23 10:54:35 +00:00
|
|
|
CONF_IGNORE = 'ignore'
|
2018-04-13 17:25:35 +00:00
|
|
|
CONF_ENABLE = 'enable'
|
2017-02-23 10:54:35 +00:00
|
|
|
|
2016-09-30 02:02:22 +00:00
|
|
|
CONFIG_SCHEMA = vol.Schema({
|
2017-03-01 15:38:49 +00:00
|
|
|
vol.Required(DOMAIN): vol.Schema({
|
2017-02-23 10:54:35 +00:00
|
|
|
vol.Optional(CONF_IGNORE, default=[]):
|
2018-04-07 21:18:49 +00:00
|
|
|
vol.All(cv.ensure_list, [
|
2018-04-13 17:25:35 +00:00
|
|
|
vol.In(list(CONFIG_ENTRY_HANDLERS) + list(SERVICE_HANDLERS))]),
|
|
|
|
vol.Optional(CONF_ENABLE, default=[]):
|
|
|
|
vol.All(cv.ensure_list, [vol.In(OPTIONAL_SERVICE_HANDLERS)])
|
2017-02-23 10:54:35 +00:00
|
|
|
}),
|
2016-09-30 02:02:22 +00:00
|
|
|
}, extra=vol.ALLOW_EXTRA)
|
|
|
|
|
2015-01-09 08:07:58 +00:00
|
|
|
|
2018-03-17 03:27:05 +00:00
|
|
|
async def async_setup(hass, config):
|
2016-03-08 16:55:57 +00:00
|
|
|
"""Start a discovery service."""
|
2017-03-01 15:38:49 +00:00
|
|
|
from netdisco.discovery import NetworkDiscovery
|
2015-03-01 05:06:59 +00:00
|
|
|
|
2017-03-01 15:38:49 +00:00
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
netdisco = NetworkDiscovery()
|
2017-03-03 21:11:40 +00:00
|
|
|
already_discovered = set()
|
2015-01-09 08:07:58 +00:00
|
|
|
|
|
|
|
# Disable zeroconf logging, it spams
|
|
|
|
logging.getLogger('zeroconf').setLevel(logging.CRITICAL)
|
|
|
|
|
2017-02-23 10:54:35 +00:00
|
|
|
# Platforms ignore by config
|
|
|
|
ignored_platforms = config[DOMAIN][CONF_IGNORE]
|
|
|
|
|
2018-04-13 17:25:35 +00:00
|
|
|
# Optional platforms enabled by config
|
|
|
|
enabled_platforms = config[DOMAIN][CONF_ENABLE]
|
|
|
|
|
2018-03-17 03:27:05 +00:00
|
|
|
async def new_service_found(service, info):
|
2017-05-02 20:47:20 +00:00
|
|
|
"""Handle a new service if one is found."""
|
2017-02-23 10:54:35 +00:00
|
|
|
if service in ignored_platforms:
|
|
|
|
logger.info("Ignoring service: %s %s", service, info)
|
|
|
|
return
|
|
|
|
|
2018-03-30 03:15:40 +00:00
|
|
|
discovery_hash = json.dumps([service, info], sort_keys=True)
|
|
|
|
if discovery_hash in already_discovered:
|
|
|
|
return
|
|
|
|
|
|
|
|
already_discovered.add(discovery_hash)
|
|
|
|
|
|
|
|
if service in CONFIG_ENTRY_HANDLERS:
|
|
|
|
await hass.config_entries.flow.async_init(
|
|
|
|
CONFIG_ENTRY_HANDLERS[service],
|
2018-04-13 14:14:53 +00:00
|
|
|
source=data_entry_flow.SOURCE_DISCOVERY,
|
2018-03-30 03:15:40 +00:00
|
|
|
data=info
|
|
|
|
)
|
|
|
|
return
|
|
|
|
|
2017-03-01 15:38:49 +00:00
|
|
|
comp_plat = SERVICE_HANDLERS.get(service)
|
2015-03-22 05:02:47 +00:00
|
|
|
|
2018-04-13 17:25:35 +00:00
|
|
|
if not comp_plat and service in enabled_platforms:
|
|
|
|
comp_plat = OPTIONAL_SERVICE_HANDLERS[service]
|
|
|
|
|
2017-03-01 15:38:49 +00:00
|
|
|
# We do not know how to handle this service.
|
|
|
|
if not comp_plat:
|
2017-09-03 20:27:13 +00:00
|
|
|
logger.info("Unknown service discovered: %s %s", service, info)
|
2017-03-01 15:38:49 +00:00
|
|
|
return
|
|
|
|
|
2017-03-03 21:11:40 +00:00
|
|
|
logger.info("Found new service: %s %s", service, info)
|
|
|
|
|
2017-03-01 15:38:49 +00:00
|
|
|
component, platform = comp_plat
|
2015-01-09 08:07:58 +00:00
|
|
|
|
2017-03-01 15:38:49 +00:00
|
|
|
if platform is None:
|
2018-03-17 03:27:05 +00:00
|
|
|
await async_discover(hass, service, info, component, config)
|
2017-03-01 15:38:49 +00:00
|
|
|
else:
|
2018-03-17 03:27:05 +00:00
|
|
|
await async_load_platform(
|
2017-03-01 15:38:49 +00:00
|
|
|
hass, component, platform, info, config)
|
2015-01-09 08:07:58 +00:00
|
|
|
|
2018-03-17 03:27:05 +00:00
|
|
|
async def scan_devices(now):
|
2017-03-01 15:38:49 +00:00
|
|
|
"""Scan for devices."""
|
2018-03-17 03:27:05 +00:00
|
|
|
results = await hass.async_add_job(_discover, netdisco)
|
2015-01-09 08:07:58 +00:00
|
|
|
|
2017-03-01 15:38:49 +00:00
|
|
|
for result in results:
|
|
|
|
hass.async_add_job(new_service_found(*result))
|
2015-01-09 08:07:58 +00:00
|
|
|
|
2017-03-01 15:38:49 +00:00
|
|
|
async_track_point_in_utc_time(hass, scan_devices,
|
|
|
|
dt_util.utcnow() + SCAN_INTERVAL)
|
2015-01-09 08:07:58 +00:00
|
|
|
|
2017-04-09 08:05:34 +00:00
|
|
|
@callback
|
|
|
|
def schedule_first(event):
|
|
|
|
"""Schedule the first discovery when Home Assistant starts up."""
|
|
|
|
async_track_point_in_utc_time(hass, scan_devices, dt_util.utcnow())
|
|
|
|
|
2017-04-21 01:45:15 +00:00
|
|
|
# discovery local services
|
|
|
|
if 'HASSIO' in os.environ:
|
|
|
|
hass.async_add_job(new_service_found(SERVICE_HASSIO, {}))
|
|
|
|
|
2017-04-09 08:05:34 +00:00
|
|
|
hass.bus.async_listen_once(EVENT_HOMEASSISTANT_START, schedule_first)
|
2015-01-09 08:07:58 +00:00
|
|
|
|
|
|
|
return True
|
2017-03-01 15:38:49 +00:00
|
|
|
|
|
|
|
|
|
|
|
def _discover(netdisco):
|
|
|
|
"""Discover devices."""
|
|
|
|
results = []
|
|
|
|
try:
|
|
|
|
netdisco.scan()
|
|
|
|
|
|
|
|
for disc in netdisco.discover():
|
|
|
|
for service in netdisco.get_info(disc):
|
|
|
|
results.append((disc, service))
|
2018-05-15 17:58:00 +00:00
|
|
|
|
2017-03-01 15:38:49 +00:00
|
|
|
finally:
|
|
|
|
netdisco.stop()
|
|
|
|
|
|
|
|
return results
|