async def _make_sensor(device_class, discovery_info): """Create ZHA sensors factory.""" from zigpy.zcl.clusters.general import OnOff from zigpy.zcl.clusters.measurement import OccupancySensing in_clusters = discovery_info['in_clusters'] out_clusters = discovery_info['out_clusters'] endpoint = discovery_info['endpoint'] if endpoint.device_type in (0x0800, 0x0810, 0x0820, 0x0830, 0x0000, 0x0001, 0x0006): sensor = RemoteSensor('remote', **discovery_info) elif (OnOff.cluster_id in in_clusters or OnOff.cluster_id in out_clusters): sensor = OnOffSensor('opening', **discovery_info, cluster_key=OnOff.ep_attribute) elif (OccupancySensing.cluster_id in in_clusters or OccupancySensing.cluster_id in out_clusters): sensor = OccupancySensor('motion', **discovery_info, cluster_key=OccupancySensing.ep_attribute) # try: # result = await zha_new.get_attributes( # endpoint, # OccupancySensing.cluster_id, # ['occupancy', 'occupancy_sensor_type']) # sensor._device_state_attributes['occupancy_sensor_type'] = result[1] # sensor._state = result[0] # except: # _LOGGER.debug("get attributes: failed") elif device_class == 'moisture': sensor = MoistureSensor('moisture', **discovery_info) else: sensor = BinarySensor(device_class, **discovery_info) if discovery_info['new_join']: for cluster in in_clusters.values(): v = await cluster.bind() if v[0]: _LOGGER.error("[0x%04x:%s] bind input-cluster failed %s", endpoint._device.nwk, endpoint.endpoint_id, Status(v[0]).name) _LOGGER.debug("[0x%04x:%s] bind input-cluster %s: %s", endpoint._device.nwk, endpoint.endpoint_id, cluster.cluster_id, v) for cluster in out_clusters.values(): v = await cluster.bind() if v[0]: _LOGGER.error("[0x%04x:%s] bind output-cluster failed %s", endpoint._device.nwk, endpoint.endpoint_id, Status(v[0]).name) _LOGGER.debug("[0x%04x:%s] bind output-cluster %s: %s", endpoint._device.nwk, endpoint.endpoint_id, cluster.cluster_id, v) _LOGGER.debug("[0x%04x:%s] exit make binary-sensor ", endpoint._device.nwk, endpoint.endpoint_id) return sensor
async def _make_sensor(device_class, discovery_info): """Create ZHA sensors factory.""" in_clusters = discovery_info['in_clusters'] out_clusters = discovery_info['out_clusters'] endpoint = discovery_info['endpoint'] if endpoint.device_type in ( 0x0800, 0x0810, 0x0820, 0x0830, 0x0000, 0x0001, 0x0006, ): sensor = RemoteSensor('remote', **discovery_info) elif device_class == 'moisture': sensor = MoistureSensor('moisture', **discovery_info) elif device_class == 'motion': sensor = OccupancySensor('motion', **discovery_info) elif (OnOff.cluster_id in in_clusters or OnOff.cluster_id in out_clusters): sensor = OnOffSensor('opening', **discovery_info, cluster_key=OnOff.ep_attribute) elif (OccupancySensing.cluster_id in in_clusters or OccupancySensing.cluster_id in out_clusters): sensor = OccupancySensor('motion', **discovery_info, cluster_key=OccupancySensing.ep_attribute) else: sensor = BinarySensor(device_class, **discovery_info) if discovery_info['new_join']: for cluster in in_clusters.values(): try: v = await cluster.bind() except Exception: v = [Status.TIMEOUT] if v[0]: _LOGGER.error("[0x%04x:%s] bind input-cluster failed %s", endpoint._device.nwk, endpoint.endpoint_id, Status(v[0]).name) _LOGGER.debug("[0x%04x:%s] bind input-cluster %s: %s", endpoint._device.nwk, endpoint.endpoint_id, cluster.cluster_id, v) _LOGGER.debug("[0x%04x:%s] exit make binary-sensor ", endpoint._device.nwk, endpoint.endpoint_id) return sensor
async def async_device_initialized(self, device, join): """Handle device joined and basic information discovered (async).""" from zigpy.zdo.types import Status import zigpy.profiles populate_data() discovered_info = {} out_clusters = [] model = None # loop over endpoints _LOGGER.debug("[0x%04x] device init for %s -> Endpoints: %s", device.nwk, device.ieee, list(device.endpoints.keys())) for endpoint_id, endpoint in device.endpoints.items(): _LOGGER.debug( "[0x%04x:%s] endpoint init", device.nwk, endpoint_id, ) if endpoint_id == 0: # ZDO continue component = None profile_clusters = [set(), set()] device_key = '%s-%s' % (str(device.ieee), endpoint_id) node_config = self._config[DOMAIN][CONF_DEVICE_CONFIG].get( device_key, {}) _LOGGER.debug("[0x%04x:%s] node config for %s: %s", device.nwk, endpoint_id, device_key, node_config) if CONF_TEMPLATE in node_config: device_model = model = node_config.get(CONF_TEMPLATE, "default") if device_model not in self.custom_devices: self.custom_devices[ device_model] = custom_module = get_custom_device_info( device_model) else: custom_module = self.custom_devices[device_model] if '_custom_endpoint_init' in custom_module: custom_module['_custom_endpoint_init'](endpoint, node_config, device_model) if CONF_MANUFACTURER in node_config: discovered_info[CONF_MANUFACTURER] = node_config[ CONF_MANUFACTURER] if CONF_MODEL in node_config: discovered_info[CONF_MODEL] = node_config[CONF_MODEL] elif 0 in endpoint.in_clusters: # just get device_info if cluster 0 exists # if join: # v = await discover_cluster_values(endpoint, endpoint.in_clusters[0]) discovered_info = await _discover_endpoint_info(endpoint) if model is not None and discovered_info[CONF_MODEL] is None: discovered_info[CONF_MODEL] = model # when a model name is available and not the template already applied, # use it to do custom init if (discovered_info[CONF_MODEL] is not None and CONF_TEMPLATE not in node_config): device_model = model = discovered_info[CONF_MODEL] if device_model not in self.custom_devices: self.custom_devices[ device_model] = custom_module = get_custom_device_info( device_model) else: custom_module = self.custom_devices[device_model] _LOGGER.debug('[0x%04x:%s] pre call _custom_endpoint_init: %s', device.nwk, endpoint_id, custom_module) if custom_module.get('_custom_endpoint_init', None) is not None: _LOGGER.debug('[0x%04x:%s] call _custom_endpoint_init: %s', device.nwk, endpoint_id, device_model) custom_module['_custom_endpoint_init'](endpoint, node_config, device_model) else: _LOGGER.debug( '[0x%04x:%s] no call _custom_endpoint_init: %s', device.nwk, endpoint_id, device_model) _LOGGER.debug("[0x%04x:%s] node config for %s: %s", device.nwk, endpoint_id, device_key, node_config) if endpoint.profile_id in zigpy.profiles.PROFILES: profile = zigpy.profiles.PROFILES[endpoint.profile_id] if DEVICE_CLASS.get(endpoint.profile_id, {}).get(endpoint.device_type, None): profile_clusters[0].update( profile.CLUSTERS[endpoint.device_type][0]) profile_clusters[1].update( profile.CLUSTERS[endpoint.device_type][1]) profile_info = DEVICE_CLASS[endpoint.profile_id] component = profile_info[endpoint.device_type] # _LOGGER.debug("profile for %s: %s", device_key, profile_info) # Override type (switch,light,sensor, binary_sensor,...) from config if ha_const.CONF_TYPE in node_config: component = node_config[ha_const.CONF_TYPE] if component in COMPONENT_CLUSTERS: profile_clusters = list(COMPONENT_CLUSTERS[component]) # Add allowed In_Clusters from config if CONF_IN_CLUSTER in node_config: a = set(node_config.get(CONF_IN_CLUSTER)) # _LOGGER.debug('%s', type(profile_clusters)) profile_clusters[0] = a # Add allowed Out_Clusters from config if CONF_OUT_CLUSTER in node_config: profile_clusters[1] = set(node_config.get(CONF_OUT_CLUSTER)) async def req_conf_report(report_cls, report_attr, report_min, report_max, report_change): try: await report_cls.bind() v = await report_cls.configure_reporting( report_attr, int(report_min), int(report_max), report_change) _LOGGER.debug( "[0x%04x:%s] %s: set config report %s status: %s", device.nwk, endpoint_id, device_key, report_cls.cluster_id, v[0]) except: _LOGGER.error( "[0x%04x:%s] %s:set config report failed: %s", device.nwk, endpoint_id, device_key, report_cls.cluster_id) # if reporting is configured in yaml, # then create cluster if needed and setup reporting if join and CONF_CONFIG_REPORT in node_config: for report in node_config.get(CONF_CONFIG_REPORT): report_cls, report_attr, report_min, report_max, report_change = report if report_cls in endpoint.in_clusters: cluster = endpoint.in_clusters[report_cls] await req_conf_report(cluster, report_attr, report_min, report_max, report_change) # elif report_cls in endpoint.out_clusters: # cluster = endpoint.out_clusters[report_cls] # await req_conf_report( # cluster, # report_attr, # report_min, # report_max, # report_change) else: _LOGGER.debug( "[0x%04x:%s] config reports skipped, already joined %s", device.nwk, endpoint_id, device._ieee) _LOGGER.debug("[0x%04x:%s] 2:profile %s, component: %s cluster:%s", device.nwk, endpoint_id, endpoint.profile_id, component, profile_clusters) if component: # only discovered clusters that are in the profile or configuration listed in_clusters = [ endpoint.in_clusters[c] for c in profile_clusters[0] if c in endpoint.in_clusters ] out_clusters = [ endpoint.out_clusters[c] for c in profile_clusters[1] if c in endpoint.out_clusters ] if in_clusters != [] or out_clusters != []: # create discovery info discovery_info = { 'endpoint': endpoint, 'in_clusters': {c.cluster_id: c for c in in_clusters}, 'out_clusters': {c.cluster_id: c for c in out_clusters}, 'component': component, 'device': device, 'domain': DOMAIN, 'discovery_key': device_key, 'new_join': join, 'application': self } discovery_info.update(discovered_info) self._hass.data[DISCOVERY_KEY][device_key] = discovery_info """ goto to the specific code for switch, light sensor or binary_sensor """ await discovery.async_load_platform( self._hass, component, DOMAIN, {'discovery_key': device_key}, self._config, ) _LOGGER.debug( "[0x%04x:%s] Return from component general entity:%s", device.nwk, endpoint_id, device._ieee) # initialize single clusters for cluster_id, cluster in endpoint.in_clusters.items(): cluster_type = type(cluster) # _LOGGER.debug("[0x%04x:%s] Start single-cluster entity: %s", # device.nwk, # endpoint_id, # cluster_id) if cluster_id in profile_clusters[0]: continue if cluster_type not in SINGLE_CLUSTER_DEVICE_CLASS: continue if ha_const.CONF_TYPE in node_config: component = node_config[ha_const.CONF_TYPE] else: component = SINGLE_CLUSTER_DEVICE_CLASS[cluster_type] cluster_key = '%s-%s' % (device_key, cluster_id) # cluster key -> single cluster discovery_info = { 'discovery_key': cluster_key, 'endpoint': endpoint, 'in_clusters': { cluster.cluster_id: cluster }, 'out_clusters': {}, 'new_join': join, 'domain': DOMAIN, 'component': component, 'application': self } discovery_info.update(discovered_info) self._hass.data[DISCOVERY_KEY][cluster_key] = discovery_info _LOGGER.debug("[0x%04x:%s] Call single-cluster entity: %s", device.nwk, endpoint_id, cluster_id) await discovery.async_load_platform( self._hass, component, DOMAIN, {'discovery_key': cluster_key}, self._config, ) # in_clusters.append(cluster) # _LOGGER.debug("[0x%04x] Return from single-cluster entity:%s", # device.nwk, # discovery_info) # _LOGGER.debug("[0x%04x:%s] Start bind clusters", # device.nwk, # endpoint_id) if join: for cluster in out_clusters: try: v = await cluster.bind() if v[0]: _LOGGER.error( "[0x%04x:%s] bind output-cluster failed %s : %s", device.nwk, endpoint_id, cluster.cluster_id, Status(v[0]).name) except Exception: _LOGGER.error( "[0x%04x:%s] bind output-cluster exception %s ", device.nwk, endpoint_id, cluster.cluster_id) # _LOGGER.debug("[0x%04x:%s] bind output-cluster %s: %s", # device.nwk, # endpoint_id, # cluster.cluster_id, # v) # _LOGGER.debug("[0x%04x] Exit endpoint init: Input:%s Output:%s", # device.nwk, # list(endpoint.in_clusters.keys()), # list(endpoint.out_clusters.keys()) # ) device._application.listener_event('device_updated', device) self.controller._state = 'Run' self.controller._device_state_attributes['no_of_entities'] = len( self._entity_list) self.controller.async_schedule_update_ha_state() _LOGGER.debug( "[0x%04x] Exit device init %s", device.nwk, device.ieee, )