text: """Support for deCONZ devices."""
  import voluptuous as vol
  
  from homeassistant import config_entries
  from homeassistant.const import (
      CONF_API_KEY,
      CONF_HOST,
      CONF_PORT,
      EVENT_HOMEASSISTANT_STOP,
  )
  from homeassistant.helpers import config_validation as cv
  
  # Loading the config flow file will register the flow
  from .config_flow import get_master_gateway
  from .const import CONF_BRIDGEID, CONF_MASTER_GATEWAY, DEFAULT_PORT, DOMAIN, _LOGGER
  from .gateway import DeconzGateway
  
  CONFIG_SCHEMA = vol.Schema(
      {
          DOMAIN: vol.Schema(
              {
                  vol.Optional(CONF_API_KEY): cv.string,
                  vol.Optional(CONF_HOST): cv.string,
                  vol.Optional(CONF_PORT, default=DEFAULT_PORT): cv.port,
              }
          )
      },
      extra=vol.ALLOW_EXTRA,
  )
  
  SERVICE_DECONZ = "configure"
  
  SERVICE_FIELD = "field"
  SERVICE_ENTITY = "entity"
  SERVICE_DATA = "data"
  
  SERVICE_SCHEMA = vol.All(
      vol.Schema(
          {
              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 not hass.config_entries.async_entries(DOMAIN) and DOMAIN in config:
          deconz_config = config[DOMAIN]
          hass.async_create_task(
              hass.config_entries.flow.async_init(
                  DOMAIN,
                  context={"source": config_entries.SOURCE_IMPORT},
                  data=deconz_config,
              )
          )
      return True
  
  
  async def async_setup_entry(hass, config_entry):
      """Set up a deCONZ bridge for a config entry.
  
      Load config, group, light and sensor data for server information.
      Start websocket for push notification of state changes from deCONZ.
      """
      if DOMAIN not in hass.data:
          hass.data[DOMAIN] = {}
  
      if not config_entry.options:
          await async_update_master_gateway(hass, config_entry)
  
      gateway = DeconzGateway(hass, config_entry)
  
      if not await gateway.async_setup():
          return False
  
      hass.data[DOMAIN][gateway.bridgeid] = gateway
  
      await gateway.async_update_device_registry()
  
      async def async_configure(call):
          """Set attribute of device in deCONZ.
  
          Entity is used to resolve to a device path (e.g. '/lights/1').
          Field is a string representing either a full path
          (e.g. '/lights/1/state') when entity is not specified, or a
          subpath (e.g. '/state') when used together with entity.
          Data is a json object with what data you want to alter
          e.g. data={'on': true}.
          {
              "field": "/lights/1/state",
              "data": {"on": true}
          }
          See Dresden Elektroniks REST API documentation for details:
          http://dresden-elektronik.github.io/deconz-rest-doc/rest/
          """
          field = call.data.get(SERVICE_FIELD, "")
          entity_id = call.data.get(SERVICE_ENTITY)
          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:
                  field = gateway.deconz_ids[entity_id] + field
              except KeyError:
                  _LOGGER.error("Could not find the entity %s", entity_id)
                  return
  
          await gateway.api.async_put_state(field, data)
  
      hass.services.async_register(
          DOMAIN, SERVICE_DECONZ, async_configure, schema=SERVICE_SCHEMA
      )
  
      async def async_refresh_devices(call):
          """Refresh available devices from deCONZ."""
          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())
          scenes = set(gateway.api.scenes.keys())
          sensors = set(gateway.api.sensors.keys())
  
          await gateway.api.async_load_parameters()
  
          gateway.async_add_device_callback(
              "group",
              [
                  group
                  for group_id, group in gateway.api.groups.items()
                  if group_id not in groups
              ],
          )
  
          gateway.async_add_device_callback(
              "light",
              [
                  light
                  for light_id, light in gateway.api.lights.items()
                  if light_id not in lights
              ],
          )
  
          gateway.async_add_device_callback(
              "scene",
              [
                  scene
                  for scene_id, scene in gateway.api.scenes.items()
                  if scene_id not in scenes
              ],
          )
  
          gateway.async_add_device_callback(
              "sensor",
              [
                  sensor
                  for sensor_id, sensor in gateway.api.sensors.items()
                  if sensor_id not in sensors
              ],
          )
  
      hass.services.async_register(
          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[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_update_master_gateway(hass, config_entry)
          new_master_gateway = next(iter(hass.data[DOMAIN].values()))
          await async_update_master_gateway(hass, new_master_gateway.config_entry)
  
      return await gateway.async_reset()
  
  
  async def async_update_master_gateway(hass, config_entry):
      """Update master gateway boolean.
  
      Called by setup_entry and unload_entry.
      Makes sure there is always one master available.
      """
      master = not get_master_gateway(hass)
  
      old_options = dict(config_entry.options)
  
      new_options = {CONF_MASTER_GATEWAY: master}
  
      options = {**old_options, **new_options}
  
      hass.config_entries.async_update_entry(config_entry, options=options)
  