Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
16255da
Store gateways inside a dict in deconz domain
Kane610 Mar 26, 2019
1448ddc
Make reachable events gateway specific
Kane610 Mar 27, 2019
14c864d
Gateway shall always exist
Kane610 Mar 28, 2019
7080ba3
Adapt new device signalling to support multiple gateways
Kane610 Mar 28, 2019
9fc43cd
Services follow gateway master
Kane610 Mar 28, 2019
9efe4db
Working on unload entry
Kane610 Mar 29, 2019
6828693
Make unload and master handover work
Kane610 Mar 29, 2019
7245e48
Fix config flow
Kane610 Mar 30, 2019
b510737
Fix linting
Kane610 Mar 30, 2019
47f9d74
Clean up init tests
Kane610 Mar 30, 2019
eb0e7f3
Clean up hassio discovery to fit with the rest
Kane610 Apr 3, 2019
afc2cdb
Store gateways inside a dict in deconz domain
Kane610 Mar 26, 2019
8989ef9
Make reachable events gateway specific
Kane610 Mar 27, 2019
61b3c19
Gateway shall always exist
Kane610 Mar 28, 2019
20c736a
Adapt new device signalling to support multiple gateways
Kane610 Mar 28, 2019
bb25660
Services follow gateway master
Kane610 Mar 28, 2019
d8163a9
Working on unload entry
Kane610 Mar 29, 2019
8163402
Make unload and master handover work
Kane610 Mar 29, 2019
7bc00e0
Fix config flow
Kane610 Mar 30, 2019
7cb0fe9
Fix linting
Kane610 Mar 30, 2019
79fac2b
Clean up init tests
Kane610 Mar 30, 2019
94e4daf
Clean up hassio discovery to fit with the rest
Kane610 Apr 3, 2019
67062ee
Add support for services to specify bridgeid
Kane610 Apr 3, 2019
70a558b
Merge branch 'deconz-support-multiple-gateways' of github.com:Kane610…
Kane610 Apr 3, 2019
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
96 changes: 63 additions & 33 deletions homeassistant/components/deconz/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,14 @@
from homeassistant import config_entries
from homeassistant.const import (
CONF_API_KEY, CONF_HOST, CONF_PORT, EVENT_HOMEASSISTANT_STOP)
from homeassistant.core import callback
from homeassistant.helpers import config_validation as cv
from homeassistant.helpers.device_registry import CONNECTION_NETWORK_MAC

# Loading the config flow file will register the flow
from .config_flow import configured_hosts
from .const import DEFAULT_PORT, DOMAIN, _LOGGER
from .config_flow import get_master_gateway
from .const import (
CONF_ALLOW_CLIP_SENSOR, CONF_ALLOW_DECONZ_GROUPS, CONF_BRIDGEID,
CONF_MASTER_GATEWAY, DEFAULT_PORT, DOMAIN, _LOGGER)
from .gateway import DeconzGateway

REQUIREMENTS = ['pydeconz==54']
Expand All @@ -32,26 +34,27 @@
vol.Optional(SERVICE_ENTITY): cv.entity_id,
vol.Optional(SERVICE_FIELD): cv.matches_regex('/.*'),
vol.Required(SERVICE_DATA): dict,
vol.Optional(CONF_BRIDGEID): str
}), cv.has_at_least_one_key(SERVICE_ENTITY, SERVICE_FIELD))

SERVICE_DEVICE_REFRESH = 'device_refresh'

SERVICE_DEVICE_REFRESCH_SCHEMA = vol.All(vol.Schema({
vol.Optional(CONF_BRIDGEID): str
}))


async def async_setup(hass, config):
"""Load configuration for deCONZ component.

Discovery has loaded the component if DOMAIN is not present in config.
"""
if DOMAIN in config:
deconz_config = None
if CONF_HOST in config[DOMAIN]:
deconz_config = config[DOMAIN]
if deconz_config and not configured_hosts(hass):
hass.async_add_job(hass.config_entries.flow.async_init(
DOMAIN,
context={'source': config_entries.SOURCE_IMPORT},
data=deconz_config
))
if not hass.config_entries.async_entries(DOMAIN) and DOMAIN in config:
deconz_config = config[DOMAIN]
hass.async_add_job(hass.config_entries.flow.async_init(
Comment thread
Kane610 marked this conversation as resolved.
DOMAIN, context={'source': config_entries.SOURCE_IMPORT},
data=deconz_config
))
return True


Expand All @@ -61,26 +64,20 @@ async def async_setup_entry(hass, config_entry):
Load config, group, light and sensor data for server information.
Start websocket for push notification of state changes from deCONZ.
"""
if DOMAIN in hass.data:
_LOGGER.error(
"Config entry failed since one deCONZ instance already exists")
return False
if DOMAIN not in hass.data:
hass.data[DOMAIN] = {}

if not config_entry.options:
await async_populate_options(hass, config_entry)

gateway = DeconzGateway(hass, config_entry)

if not await gateway.async_setup():
return False

hass.data[DOMAIN] = gateway
hass.data[DOMAIN][gateway.bridgeid] = gateway

device_registry = await \
hass.helpers.device_registry.async_get_registry()
device_registry.async_get_or_create(
config_entry_id=config_entry.entry_id,
connections={(CONNECTION_NETWORK_MAC, gateway.api.config.mac)},
identifiers={(DOMAIN, gateway.api.config.bridgeid)},
manufacturer='Dresden Elektronik', model=gateway.api.config.modelid,
name=gateway.api.config.name, sw_version=gateway.api.config.swversion)
await gateway.async_update_device_registry()

async def async_configure(call):
"""Set attribute of device in deCONZ.
Expand All @@ -100,8 +97,11 @@ async def async_configure(call):
"""
field = call.data.get(SERVICE_FIELD, '')
entity_id = call.data.get(SERVICE_ENTITY)
data = call.data.get(SERVICE_DATA)
gateway = hass.data[DOMAIN]
data = call.data[SERVICE_DATA]

gateway = get_master_gateway(hass)
if CONF_BRIDGEID in call.data:
gateway = hass.data[DOMAIN][call.data[CONF_BRIDGEID]]

if entity_id:
try:
Expand All @@ -117,7 +117,9 @@ async def async_configure(call):

async def async_refresh_devices(call):
"""Refresh available devices from deCONZ."""
gateway = hass.data[DOMAIN]
gateway = get_master_gateway(hass)
if CONF_BRIDGEID in call.data:
gateway = hass.data[DOMAIN][call.data[CONF_BRIDGEID]]

groups = set(gateway.api.groups.keys())
lights = set(gateway.api.lights.keys())
Expand Down Expand Up @@ -151,15 +153,43 @@ async def async_refresh_devices(call):
)

hass.services.async_register(
DOMAIN, SERVICE_DEVICE_REFRESH, async_refresh_devices)
DOMAIN, SERVICE_DEVICE_REFRESH, async_refresh_devices,
schema=SERVICE_DEVICE_REFRESCH_SCHEMA)

hass.bus.async_listen_once(EVENT_HOMEASSISTANT_STOP, gateway.shutdown)
return True


async def async_unload_entry(hass, config_entry):
"""Unload deCONZ config entry."""
gateway = hass.data.pop(DOMAIN)
hass.services.async_remove(DOMAIN, SERVICE_DECONZ)
hass.services.async_remove(DOMAIN, SERVICE_DEVICE_REFRESH)
gateway = hass.data[DOMAIN].pop(config_entry.data[CONF_BRIDGEID])

if not hass.data[DOMAIN]:
hass.services.async_remove(DOMAIN, SERVICE_DECONZ)
hass.services.async_remove(DOMAIN, SERVICE_DEVICE_REFRESH)
elif gateway.master:
await async_populate_options(hass, config_entry)
new_master_gateway = next(iter(hass.data[DOMAIN].values()))
await async_populate_options(hass, new_master_gateway.config_entry)

return await gateway.async_reset()


@callback
async def async_populate_options(hass, config_entry):
Comment thread
Kane610 marked this conversation as resolved.
"""Populate default options for gateway.

Called by setup_entry and unload_entry.
Makes sure there is always one master available.
"""
master = not get_master_gateway(hass)

options = {
CONF_MASTER_GATEWAY: master,
CONF_ALLOW_CLIP_SENSOR: config_entry.data.get(
CONF_ALLOW_CLIP_SENSOR, False),
CONF_ALLOW_DECONZ_GROUPS: config_entry.data.get(
CONF_ALLOW_DECONZ_GROUPS, True)
}

hass.config_entries.async_update_entry(config_entry, options=options)
19 changes: 11 additions & 8 deletions homeassistant/components/deconz/binary_sensor.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,9 @@
from homeassistant.core import callback
from homeassistant.helpers.dispatcher import async_dispatcher_connect

from .const import (
ATTR_DARK, ATTR_ON, CONF_ALLOW_CLIP_SENSOR, DOMAIN as DECONZ_DOMAIN,
NEW_SENSOR)
from .const import ATTR_DARK, ATTR_ON, NEW_SENSOR
from .deconz_device import DeconzDevice
from .gateway import get_gateway_from_config_entry

DEPENDENCIES = ['deconz']

Expand All @@ -24,22 +23,26 @@ async def async_setup_platform(

async def async_setup_entry(hass, config_entry, async_add_entities):
"""Set up the deCONZ binary sensor."""
gateway = hass.data[DECONZ_DOMAIN]
gateway = get_gateway_from_config_entry(hass, config_entry)

@callback
def async_add_sensor(sensors):
"""Add binary sensor from deCONZ."""
from pydeconz.sensor import DECONZ_BINARY_SENSOR
entities = []
allow_clip_sensor = config_entry.data.get(CONF_ALLOW_CLIP_SENSOR, True)

for sensor in sensors:

if sensor.type in DECONZ_BINARY_SENSOR and \
not (not allow_clip_sensor and sensor.type.startswith('CLIP')):
not (not gateway.allow_clip_sensor and
sensor.type.startswith('CLIP')):

entities.append(DeconzBinarySensor(sensor, gateway))

async_add_entities(entities, True)

gateway.listeners.append(
async_dispatcher_connect(hass, NEW_SENSOR, async_add_sensor))
gateway.listeners.append(async_dispatcher_connect(
hass, gateway.async_event_new_device(NEW_SENSOR), async_add_sensor))

async_add_sensor(gateway.api.sensors.values())

Expand Down
19 changes: 11 additions & 8 deletions homeassistant/components/deconz/climate.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,9 @@
from homeassistant.core import callback
from homeassistant.helpers.dispatcher import async_dispatcher_connect

from .const import (
ATTR_OFFSET, ATTR_VALVE, CONF_ALLOW_CLIP_SENSOR,
DOMAIN as DECONZ_DOMAIN, NEW_SENSOR)
from .const import ATTR_OFFSET, ATTR_VALVE, NEW_SENSOR
from .deconz_device import DeconzDevice
from .gateway import get_gateway_from_config_entry

DEPENDENCIES = ['deconz']

Expand All @@ -20,22 +19,26 @@ async def async_setup_entry(hass, config_entry, async_add_entities):

Thermostats are based on the same device class as sensors in deCONZ.
"""
gateway = hass.data[DECONZ_DOMAIN]
gateway = get_gateway_from_config_entry(hass, config_entry)

@callback
def async_add_climate(sensors):
"""Add climate devices from deCONZ."""
from pydeconz.sensor import THERMOSTAT
entities = []
allow_clip_sensor = config_entry.data.get(CONF_ALLOW_CLIP_SENSOR, True)

for sensor in sensors:

if sensor.type in THERMOSTAT and \
not (not allow_clip_sensor and sensor.type.startswith('CLIP')):
not (not gateway.allow_clip_sensor and
sensor.type.startswith('CLIP')):

entities.append(DeconzThermostat(sensor, gateway))

async_add_entities(entities, True)

gateway.listeners.append(
async_dispatcher_connect(hass, NEW_SENSOR, async_add_climate))
gateway.listeners.append(async_dispatcher_connect(
hass, gateway.async_event_new_device(NEW_SENSOR), async_add_climate))

async_add_climate(gateway.api.sensors.values())

Expand Down
Loading