From b7aba525cab9a84cbb7b390c652c0db9e72a27f3 Mon Sep 17 00:00:00 2001 From: jeremydk Date: Fri, 27 Jan 2017 23:42:37 -0800 Subject: [PATCH] Emulated Hue "host-ip" fails to bind when running in docker without --net=host (#5550) * UPNP changes to allow a separate advertised IP and Port. * Fixing lint. * UPNP changes to allow a separate advertised IP and Port. * Fixing lint. * Update __init__.py * Moved logic for advertised ip and port into config class. * Commenting change for clarity. * Spacing changes for PEP8 * Spacing Changes for PEP8 * Style Changes --- homeassistant/components/emulated_hue/__init__.py | 15 ++++++++++++++- homeassistant/components/emulated_hue/upnp.py | 11 ++++++----- 2 files changed, 20 insertions(+), 6 deletions(-) diff --git a/homeassistant/components/emulated_hue/__init__.py b/homeassistant/components/emulated_hue/__init__.py index 5d6d6d0e61d..2412b283abe 100644 --- a/homeassistant/components/emulated_hue/__init__.py +++ b/homeassistant/components/emulated_hue/__init__.py @@ -30,6 +30,8 @@ NUMBERS_FILE = 'emulated_hue_ids.json' CONF_HOST_IP = 'host_ip' CONF_LISTEN_PORT = 'listen_port' +CONF_ADVERTISE_IP = 'advertise_ip' +CONF_ADVERTISE_PORT = 'advertise_port' CONF_UPNP_BIND_MULTICAST = 'upnp_bind_multicast' CONF_OFF_MAPS_TO_ON_DOMAINS = 'off_maps_to_on_domains' CONF_EXPOSE_BY_DEFAULT = 'expose_by_default' @@ -53,6 +55,9 @@ CONFIG_SCHEMA = vol.Schema({ vol.Optional(CONF_HOST_IP): cv.string, vol.Optional(CONF_LISTEN_PORT, default=DEFAULT_LISTEN_PORT): vol.All(vol.Coerce(int), vol.Range(min=1, max=65535)), + vol.Optional(CONF_ADVERTISE_IP): cv.string, + vol.Optional(CONF_ADVERTISE_PORT): + vol.All(vol.Coerce(int), vol.Range(min=1, max=65535)), vol.Optional(CONF_UPNP_BIND_MULTICAST): cv.boolean, vol.Optional(CONF_OFF_MAPS_TO_ON_DOMAINS): cv.ensure_list, vol.Optional(CONF_EXPOSE_BY_DEFAULT): cv.boolean, @@ -92,7 +97,8 @@ def setup(hass, yaml_config): upnp_listener = UPNPResponderThread( config.host_ip_addr, config.listen_port, - config.upnp_bind_multicast) + config.upnp_bind_multicast, config.advertise_ip, + config.advertise_port) @asyncio.coroutine def stop_emulated_hue_bridge(event): @@ -169,6 +175,13 @@ class Config(object): self.exposed_domains = conf.get( CONF_EXPOSED_DOMAINS, DEFAULT_EXPOSED_DOMAINS) + # Calculated effective advertised IP and port for network isolation + self.advertise_ip = conf.get( + CONF_ADVERTISE_IP) or self.host_ip_addr + + self.advertise_port = conf.get( + CONF_ADVERTISE_PORT) or self.listen_port + def entity_id_to_number(self, entity_id): """Get a unique number for the entity id.""" if self.type == TYPE_ALEXA: diff --git a/homeassistant/components/emulated_hue/upnp.py b/homeassistant/components/emulated_hue/upnp.py index de3be34e2de..31d8ab60e30 100644 --- a/homeassistant/components/emulated_hue/upnp.py +++ b/homeassistant/components/emulated_hue/upnp.py @@ -50,7 +50,7 @@ class DescriptionXmlView(HomeAssistantView): """ resp_text = xml_template.format( - self.config.host_ip_addr, self.config.listen_port) + self.config.advertise_ip, self.config.advertise_port) return web.Response(text=resp_text, content_type='text/xml') @@ -60,7 +60,8 @@ class UPNPResponderThread(threading.Thread): _interrupted = False - def __init__(self, host_ip_addr, listen_port, upnp_bind_multicast): + def __init__(self, host_ip_addr, listen_port, upnp_bind_multicast, + advertise_ip, advertise_port): """Initialize the class.""" threading.Thread.__init__(self) @@ -81,9 +82,9 @@ USN: uuid:Socket-1_0-221438K0100073::urn:schemas-upnp-org:device:basic:1 """ - self.upnp_response = resp_template.format(host_ip_addr, listen_port) \ - .replace("\n", "\r\n") \ - .encode('utf-8') + self.upnp_response = resp_template.format( + advertise_ip, advertise_port).replace("\n", "\r\n") \ + .encode('utf-8') # Set up a pipe for signaling to the receiver that it's time to # shutdown. Essentially, we place the SSDP socket into nonblocking