3 from pydeconz.utils
import normalize_bridge_id
4 import voluptuous
as vol
8 config_validation
as cv,
10 entity_registry
as er,
15 from .config_flow
import get_master_hub
16 from .const
import CONF_BRIDGE_ID, DOMAIN, LOGGER
17 from .hub
import DeconzHub
19 DECONZ_SERVICES =
"deconz_services"
21 SERVICE_FIELD =
"field"
22 SERVICE_ENTITY =
"entity"
25 SERVICE_CONFIGURE_DEVICE =
"configure"
26 SERVICE_CONFIGURE_DEVICE_SCHEMA = vol.All(
29 vol.Optional(SERVICE_ENTITY): cv.entity_id,
30 vol.Optional(SERVICE_FIELD): cv.matches_regex(
"/.*"),
31 vol.Required(SERVICE_DATA): dict,
32 vol.Optional(CONF_BRIDGE_ID): str,
35 cv.has_at_least_one_key(SERVICE_ENTITY, SERVICE_FIELD),
38 SERVICE_DEVICE_REFRESH =
"device_refresh"
39 SERVICE_REMOVE_ORPHANED_ENTRIES =
"remove_orphaned_entries"
40 SELECT_GATEWAY_SCHEMA = vol.All(vol.Schema({vol.Optional(CONF_BRIDGE_ID): str}))
42 SUPPORTED_SERVICES = (
43 SERVICE_CONFIGURE_DEVICE,
44 SERVICE_DEVICE_REFRESH,
45 SERVICE_REMOVE_ORPHANED_ENTRIES,
49 SERVICE_CONFIGURE_DEVICE: SERVICE_CONFIGURE_DEVICE_SCHEMA,
50 SERVICE_DEVICE_REFRESH: SELECT_GATEWAY_SCHEMA,
51 SERVICE_REMOVE_ORPHANED_ENTRIES: SELECT_GATEWAY_SCHEMA,
57 """Set up services for deCONZ integration."""
59 async
def async_call_deconz_service(service_call: ServiceCall) ->
None:
60 """Call correct deCONZ service."""
61 service = service_call.service
62 service_data = service_call.data
64 if CONF_BRIDGE_ID
in service_data:
66 bridge_id = normalize_bridge_id(service_data[CONF_BRIDGE_ID])
68 for possible_hub
in hass.data[DOMAIN].values():
69 if possible_hub.bridgeid == bridge_id:
75 LOGGER.error(
"Could not find the gateway %s", bridge_id)
81 LOGGER.error(
"No master gateway available")
84 if service == SERVICE_CONFIGURE_DEVICE:
87 elif service == SERVICE_DEVICE_REFRESH:
90 elif service == SERVICE_REMOVE_ORPHANED_ENTRIES:
93 for service
in SUPPORTED_SERVICES:
94 hass.services.async_register(
97 async_call_deconz_service,
98 schema=SERVICE_TO_SCHEMA[service],
103 """Set attribute of device in deCONZ.
105 Entity is used to resolve to a device path (e.g. '/lights/1').
106 Field is a string representing either a full path
107 (e.g. '/lights/1/state') when entity is not specified, or a
108 subpath (e.g. '/state') when used together with entity.
109 Data is a json object with what data you want to alter
110 e.g. data={'on': true}.
112 "field": "/lights/1/state",
115 See Dresden Elektroniks REST API documentation for details:
116 http://dresden-elektronik.github.io/deconz-rest-doc/rest/
118 field = data.get(SERVICE_FIELD,
"")
119 entity_id = data.get(SERVICE_ENTITY)
120 data = data[SERVICE_DATA]
124 field = hub.deconz_ids[entity_id] + field
126 LOGGER.error(
"Could not find the entity %s", entity_id)
129 await hub.api.request(
"put", field, json=data)
133 """Refresh available devices from deCONZ."""
134 hub.ignore_state_updates =
True
135 await hub.api.refresh_state()
136 hub.load_ignored_devices()
137 hub.ignore_state_updates =
False
141 """Remove orphaned deCONZ entries from device and entity registries."""
142 device_registry = dr.async_get(hub.hass)
143 entity_registry = er.async_get(hub.hass)
145 entity_entries = er.async_entries_for_config_entry(
146 entity_registry, hub.config_entry.entry_id
149 entities_to_be_removed = []
150 devices_to_be_removed = [
152 for entry
in device_registry.devices.get_devices_for_config_entry_id(
153 hub.config_entry.entry_id
158 if hub.api.config.mac:
159 hub_host = device_registry.async_get_device(
160 connections={(CONNECTION_NETWORK_MAC, hub.api.config.mac)},
162 if hub_host
and hub_host.id
in devices_to_be_removed:
163 devices_to_be_removed.remove(hub_host.id)
166 hub_service = device_registry.async_get_device(
167 identifiers={(DOMAIN, hub.api.config.bridge_id)}
169 if hub_service
and hub_service.id
in devices_to_be_removed:
170 devices_to_be_removed.remove(hub_service.id)
173 for event
in hub.events:
174 if event.device_id
in devices_to_be_removed:
175 devices_to_be_removed.remove(event.device_id)
177 for entry
in entity_entries:
179 if entry.unique_id
in hub.entities[entry.domain]:
181 if entry.device_id
in devices_to_be_removed:
182 devices_to_be_removed.remove(entry.device_id)
185 entities_to_be_removed.append(entry.entity_id)
188 for entity_id
in entities_to_be_removed:
189 entity_registry.async_remove(entity_id)
192 for device_id
in devices_to_be_removed:
195 er.async_entries_for_device(
196 entity_registry, device_id, include_disabled_entities=
True
201 device_registry.async_remove_device(device_id)
DeconzHub get_master_hub(HomeAssistant hass)
None async_setup_services(HomeAssistant hass)
None async_configure_service(DeconzHub hub, ReadOnlyDict data)
None async_refresh_devices_service(DeconzHub hub)
None async_remove_orphaned_entries_service(DeconzHub hub)