2019-02-14 15:01:46 +00:00
""" Support for the Philips Hue system. """
2018-03-17 03:27:05 +00:00
import ipaddress
2017-12-10 18:15:01 +00:00
import logging
2019-12-16 18:45:09 +00:00
from aiohue . util import normalize_bridge_id
2017-12-10 18:15:01 +00:00
import voluptuous as vol
2019-12-16 11:27:43 +00:00
from homeassistant import config_entries , core
2020-02-05 21:57:17 +00:00
from homeassistant . components import persistent_notification
2019-12-16 18:45:09 +00:00
from homeassistant . const import CONF_HOST
2019-07-31 19:25:30 +00:00
from homeassistant . helpers import config_validation as cv , device_registry as dr
2018-03-30 03:15:40 +00:00
2019-12-16 18:45:09 +00:00
from . bridge import HueBridge
2020-02-11 16:50:07 +00:00
from . const import (
CONF_ALLOW_HUE_GROUPS ,
CONF_ALLOW_UNREACHABLE ,
DEFAULT_ALLOW_HUE_GROUPS ,
DEFAULT_ALLOW_UNREACHABLE ,
DOMAIN ,
)
2017-12-10 18:15:01 +00:00
_LOGGER = logging . getLogger ( __name__ )
CONF_BRIDGES = " bridges "
2019-07-31 19:25:30 +00:00
DATA_CONFIGS = " hue_configs "
2019-02-15 16:43:30 +00:00
2019-07-31 19:25:30 +00:00
PHUE_CONFIG_FILE = " phue.conf "
2017-12-10 18:15:01 +00:00
2019-07-31 19:25:30 +00:00
BRIDGE_CONFIG_SCHEMA = vol . Schema (
{
# Validate as IP address and then convert back to a string.
vol . Required ( CONF_HOST ) : vol . All ( ipaddress . ip_address , cv . string ) ,
vol . Optional (
CONF_ALLOW_UNREACHABLE , default = DEFAULT_ALLOW_UNREACHABLE
) : cv . boolean ,
vol . Optional (
CONF_ALLOW_HUE_GROUPS , default = DEFAULT_ALLOW_HUE_GROUPS
) : cv . boolean ,
2020-01-17 23:38:38 +00:00
vol . Optional ( " filename " ) : str ,
2019-07-31 19:25:30 +00:00
}
)
CONFIG_SCHEMA = vol . Schema (
{
DOMAIN : vol . Schema (
{
vol . Optional ( CONF_BRIDGES ) : vol . All (
2020-02-20 16:11:27 +00:00
cv . ensure_list , [ BRIDGE_CONFIG_SCHEMA ] ,
2019-07-31 19:25:30 +00:00
)
}
)
} ,
extra = vol . ALLOW_EXTRA ,
)
2017-12-10 18:15:01 +00:00
2018-03-17 03:27:05 +00:00
async def async_setup ( hass , config ) :
2017-12-10 18:15:01 +00:00
""" Set up the Hue platform. """
2018-01-25 13:55:14 +00:00
conf = config . get ( DOMAIN )
if conf is None :
conf = { }
2017-12-10 18:15:01 +00:00
2018-03-30 03:15:40 +00:00
hass . data [ DOMAIN ] = { }
2019-02-15 16:43:30 +00:00
hass . data [ DATA_CONFIGS ] = { }
2017-12-10 18:15:01 +00:00
2018-01-25 13:55:14 +00:00
# User has configured bridges
2018-10-04 14:04:44 +00:00
if CONF_BRIDGES not in conf :
2018-03-17 03:27:05 +00:00
return True
2017-12-10 18:15:01 +00:00
2018-10-04 14:04:44 +00:00
bridges = conf [ CONF_BRIDGES ]
2019-12-16 18:45:09 +00:00
configured_hosts = set (
2020-01-16 09:19:38 +00:00
entry . data . get ( " host " ) for entry in hass . config_entries . async_entries ( DOMAIN )
2019-12-16 18:45:09 +00:00
)
2018-03-30 03:15:40 +00:00
for bridge_conf in bridges :
host = bridge_conf [ CONF_HOST ]
2017-12-10 18:15:01 +00:00
2018-03-30 03:15:40 +00:00
# Store config in hass.data so the config entry can find it
2019-02-15 16:43:30 +00:00
hass . data [ DATA_CONFIGS ] [ host ] = bridge_conf
2017-12-10 18:15:01 +00:00
2019-12-16 18:45:09 +00:00
if host in configured_hosts :
2018-03-30 03:15:40 +00:00
continue
2018-03-17 03:27:05 +00:00
2019-12-16 18:45:09 +00:00
# No existing config entry found, trigger link config flow. Because we're
# inside the setup of this component we'll have to use hass.async_add_job
# to avoid a deadlock: creating a config entry will set up the component
# but the setup would block till the entry is created!
2019-07-31 19:25:30 +00:00
hass . async_create_task (
hass . config_entries . flow . async_init (
DOMAIN ,
context = { " source " : config_entries . SOURCE_IMPORT } ,
2019-12-16 18:45:09 +00:00
data = { " host " : bridge_conf [ CONF_HOST ] } ,
2019-07-31 19:25:30 +00:00
)
)
2018-03-17 03:27:05 +00:00
2018-03-30 03:15:40 +00:00
return True
2018-03-04 05:28:04 +00:00
2019-12-16 11:27:43 +00:00
async def async_setup_entry (
hass : core . HomeAssistant , entry : config_entries . ConfigEntry
) :
2018-03-30 03:15:40 +00:00
""" Set up a bridge from a config entry. """
2019-07-31 19:25:30 +00:00
host = entry . data [ " host " ]
2019-02-15 16:43:30 +00:00
config = hass . data [ DATA_CONFIGS ] . get ( host )
2018-03-04 05:28:04 +00:00
2018-03-30 03:15:40 +00:00
if config is None :
2020-02-11 16:50:07 +00:00
allow_unreachable = entry . data . get (
CONF_ALLOW_UNREACHABLE , DEFAULT_ALLOW_UNREACHABLE
)
allow_groups = entry . data . get ( CONF_ALLOW_HUE_GROUPS , DEFAULT_ALLOW_HUE_GROUPS )
2018-03-30 03:15:40 +00:00
else :
allow_unreachable = config [ CONF_ALLOW_UNREACHABLE ]
allow_groups = config [ CONF_ALLOW_HUE_GROUPS ]
2018-03-04 05:28:04 +00:00
2018-03-30 03:15:40 +00:00
bridge = HueBridge ( hass , entry , allow_unreachable , allow_groups )
2018-08-29 15:04:04 +00:00
if not await bridge . async_setup ( ) :
return False
2020-01-31 22:47:40 +00:00
hass . data [ DOMAIN ] [ entry . entry_id ] = bridge
2018-08-29 15:04:04 +00:00
config = bridge . api . config
2019-12-16 11:27:43 +00:00
# For backwards compat
if entry . unique_id is None :
hass . config_entries . async_update_entry (
entry , unique_id = normalize_bridge_id ( config . bridgeid )
)
2018-08-29 15:04:04 +00:00
device_registry = await dr . async_get_registry ( hass )
device_registry . async_get_or_create (
2018-09-17 11:39:30 +00:00
config_entry_id = entry . entry_id ,
2019-07-31 19:25:30 +00:00
connections = { ( dr . CONNECTION_NETWORK_MAC , config . mac ) } ,
identifiers = { ( DOMAIN , config . bridgeid ) } ,
manufacturer = " Signify " ,
2018-08-29 15:04:04 +00:00
name = config . name ,
2019-02-19 05:31:42 +00:00
model = config . modelid ,
sw_version = config . swversion ,
2018-08-29 15:04:04 +00:00
)
2020-02-05 21:57:17 +00:00
if config . modelid == " BSB002 " and config . swversion < " 1935144040 " :
persistent_notification . async_create (
hass ,
" Your Hue hub has a known security vulnerability ([CVE-2020-6007](https://cve.circl.lu/cve/CVE-2020-6007)). Go to the Hue app and check for software updates. " ,
" Signify Hue " ,
" hue_hub_firmware " ,
)
elif config . swupdate2_bridge_state == " readytoinstall " :
err = (
" Please check for software updates of the bridge in the Philips Hue App. " ,
" Signify Hue " ,
" hue_hub_firmware " ,
)
2019-02-19 05:31:42 +00:00
_LOGGER . warning ( err )
2018-08-29 15:04:04 +00:00
return True
2018-04-12 12:28:54 +00:00
async def async_unload_entry ( hass , entry ) :
""" Unload a config entry. """
2020-01-31 22:47:40 +00:00
bridge = hass . data [ DOMAIN ] . pop ( entry . entry_id )
2018-04-12 12:28:54 +00:00
return await bridge . async_reset ( )