Beispiel #1
0
    def getChildTableInformationString(self):
        childTypeDict = {ezsp.EMBER_UNKNOWN_DEVICE: 'Unknown',
         ezsp.EMBER_COORDINATOR: 'Coordinator',
         ezsp.EMBER_ROUTER: 'Router',
         ezsp.EMBER_END_DEVICE: 'End device',
         ezsp.EMBER_SLEEPY_END_DEVICE: 'Sleepy end device',
         ezsp.EMBER_MOBILE_END_DEVICE: 'Mobile end device '}
        (childTableSize, parentEui64, parentNodeId,) = self.ezspGetParentChildParameters()
        s = "This node's parent (if applicable):\n"
        s += '0x%04x (%s)\n\n' % (parentNodeId, byte_tuple.eui64ToHexString(parentEui64))
        s += 'Child table:\n'
        if childTableSize == 0:
            s += 'Empty\n'
            return s
        s += 'Indx ShortID LongID             Type\n'
        i = 0
        while i < childTableSize:
            try:
                (childId, childEui64, childType,) = self.ezspGetChildData(i)
            except ezsp.EmberStatus as e:
                if e.value == ezsp.EMBER_NOT_JOINED:
                    s += '0x%02x EMBER_NOT_JOINED\n' % i
                else:
                    raise 
            else:
                s += '0x%02x 0x%04x  %s %s\n' % (i,
                 childId,
                 byte_tuple.eui64ToHexString(childEui64),
                 childTypeDict[childType])
            i += 1

        return s
Beispiel #2
0
 def _weminucheLinkKeyRequiredCallback(self, eui64):
     event_payload = {'name': 'encryption_key_required',
      'device_address': byte_tuple.eui64ToHexString(eui64, False)}
     event = bridge_event.BridgeEvent(self.getHostEui64(), event_payload)
     try:
         self.event_queue.put(event, False)
     except Queue.Full:
         self.logger.warning('Received bridge event, but the event queue full')
     self.logger.info('Link key required for %s' % byte_tuple.eui64ToHexString(eui64))
     return True
 def callback_ezspChildJoinHandler(self, index, joining, childID,
                                   childEui64, childType):
     if joining:
         self.logger.debug(
             'Node 0x%04x (%s) joined the network.' %
             (childID, byte_tuple.eui64ToHexString(childEui64)))
     else:
         self.logger.debug(
             'Node 0x%04x (%s) left the network.' %
             (childID, byte_tuple.eui64ToHexString(childEui64)))
     ezsp.EZSPInterface.callback_ezspChildJoinHandler(
         self, index, joining, childID, childEui64, childType)
    def getChildTableInformationArray(self):
        childTypeDict = {
            ezsp.EMBER_UNKNOWN_DEVICE: 'Unknown',
            ezsp.EMBER_COORDINATOR: 'Coordinator',
            ezsp.EMBER_ROUTER: 'Router',
            ezsp.EMBER_END_DEVICE: 'End device',
            ezsp.EMBER_SLEEPY_END_DEVICE: 'Sleepy end device',
            ezsp.EMBER_MOBILE_END_DEVICE: 'Mobile end device '
        }
        children = []
        (
            childTableSize,
            parentEui64,
            parentNodeId,
        ) = self.ezspGetParentChildParameters()
        i = 0
        while i < childTableSize:
            (
                childId,
                childEui64,
                childType,
            ) = self.ezspGetChildData(i)
            child_data = {
                'eui64': byte_tuple.eui64ToHexString(childEui64, False),
                'childType': childTypeDict[childType],
                'nodeId': self.emberLookupNodeIdByEui64(childEui64)
            }
            children.append(child_data)
            i += 1

        return children
    def getKeyTableInformationString(self):
        keyTypeDict = {ezsp.EMBER_TRUST_CENTER_LINK_KEY: 'TC_LINK_KEY',
         ezsp.EMBER_TRUST_CENTER_MASTER_KEY: 'TC_MASTER_KEY',
         ezsp.EMBER_CURRENT_NETWORK_KEY: 'CURRENT_NWK_KEY',
         ezsp.EMBER_NEXT_NETWORK_KEY: 'NEXT_NWK_KEY',
         ezsp.EMBER_APPLICATION_LINK_KEY: 'APP_LINK_KEY',
         ezsp.EMBER_APPLICATION_MASTER_KEY: 'APP_MASTER_KEY'}
        keyStruct = ezsp.EmberKeyStruct()
        s = 'Keys:\n'
        for key in keyTypeDict:
            s += '%16s' % keyTypeDict[key]
            s += ' : '
            try:
                self.emberGetKey(key, keyStruct)
                s += byte_tuple.tupleToHexString(keyStruct.key.contents, 16)
            except ezsp.EmberStatus as e:
                s += str(e)
            s += '\n'

        s += '\nLink keys:\n'
        s += 'Indx Address            Key                                Type\n'
        i = 0
        while i < self.EMBER_KEY_TABLE_SIZE:
            s += '0x%02x ' % i
            try:
                self.emberGetKeyTableEntry(i, keyStruct)
                s += '%s ' % byte_tuple.eui64ToHexString(keyStruct.partnerEUI64)
                s += '%s ' % byte_tuple.tupleToHexString(keyStruct.key.contents, 16)
                s += '%s' % keyTypeDict[keyStruct.type]
                s += '\n'
            except ezsp.EmberStatus as e:
                s += '%s\n' % str(e)
            i += 1

        return s
Beispiel #6
0
 def packetsReceived(self, eui64, packetStatsList):
     if eui64 != None:
         eui64Hex = byte_tuple.eui64ToHexString(eui64, False)
         if self.loggedPacketsStatistics.has_key(eui64Hex):
             self.loggedPacketsStatistics[eui64Hex] += packetStatsList
         else:
             self.loggedPacketsStatistics[eui64Hex] = packetStatsList
         overflow = len(self.loggedPacketsStatistics[eui64Hex]) - self.packetLimit
         if overflow > 0:
             del self.loggedPacketsStatistics[eui64Hex][0:overflow]
Beispiel #7
0
    def getAddressTableInformationArray(self):
        address_table = []
        i = 0
        while i < self.EMBER_AF_ADDRESS_TABLE_SIZE:
            address_info = {}
            address_info['index'] = '0x%02x ' % i
            NodeId = self.emberGetAddressTableRemoteNodeId(i)
            if NodeId != ezsp.EMBER_TABLE_ENTRY_UNUSED_NODE_ID:
                Eui64 = self.emberGetAddressTableRemoteEui64(i)
                address_info['nodeId'] = '0x%04x' % NodeId
                address_info['eui64'] = byte_tuple.eui64ToHexString(Eui64)
            address_table.append(address_info)
            i += 1

        return address_table
Beispiel #8
0
 def getNetworkInformationDict(self):
     networkStatusDict = {ezsp.EMBER_NO_NETWORK: 'EMBER_NO_NETWORK',
      ezsp.EMBER_JOINING_NETWORK: 'EMBER_JOINING_NETWORK',
      ezsp.EMBER_JOINED_NETWORK: 'EMBER_JOINED_NETWORK',
      ezsp.EMBER_JOINED_NETWORK_NO_PARENT: 'EMBER_JOINED_NETWORK_NO_PARENT',
      ezsp.EMBER_LEAVING_NETWORK: 'EMBER_LEAVING_NETWORK'}
     securityProfileDict = {security_config.NONE_SECURITY_PROFILE: 'No Security',
      security_config.HA_SECURITY_PROFILE: 'HA',
      security_config.SE_SECURITY_PROFILE_TEST: 'SE Test',
      security_config.SE_SECURITY_PROFILE_FULL: 'SE Full'}
     nodeTypeDict = {ezsp.EMBER_UNKNOWN_DEVICE: 'EMBER_UNKNOWN_DEVICE',
      ezsp.EMBER_COORDINATOR: 'EMBER_COORDINATOR',
      ezsp.EMBER_ROUTER: 'EMBER_ROUTER',
      ezsp.EMBER_END_DEVICE: 'EMBER_END_DEVICE',
      ezsp.EMBER_SLEEPY_END_DEVICE: 'EMBER_SLEEPY_END_DEVICE',
      ezsp.EMBER_MOBILE_END_DEVICE: 'EMBER_MOBILE_END_DEVICE'}
     powerModeDict = {ezsp.EMBER_TX_POWER_MODE_DEFAULT: 'EMBER_TX_POWER_MODE_DEFAULT',
      ezsp.EMBER_TX_POWER_MODE_BOOST: 'EMBER_TX_POWER_MODE_BOOST',
      ezsp.EMBER_TX_POWER_MODE_ALTERNATE: 'EMBER_TX_POWER_MODE_ALTERNATE',
      ezsp.EMBER_TX_POWER_MODE_BOOST_AND_ALTERNATE: 'EMBER_TX_POWER_MODE_BOOST_AND_ALTERNATE'}
     return_dict = {}
     state = self.emberNetworkState()
     return_dict['node_eui64'] = byte_tuple.eui64ToHexString(self._eui64)
     return_dict['network_status'] = networkStatusDict[state]
     power_mode_value = self.ezspGetConfigurationValue(ezsp.EZSP_CONFIG_TX_POWER_MODE)
     return_dict['radio_power_mode'] = powerModeDict[power_mode_value]
     if state == ezsp.EMBER_JOINED_NETWORK or state == ezsp.EMBER_JOINED_NETWORK_NO_PARENT:
         parameters = ezsp.EmberNetworkParameters()
         node = self.ezspGetNetworkParameters(parameters)
         if node in nodeTypeDict:
             nodeType = nodeTypeDict[node]
         else:
             nodeType = 'Unknown'
         securityLevel = self.ezspGetConfigurationValue(ezsp.EZSP_CONFIG_SECURITY_LEVEL)
         if self.EMBER_AF_SECURITY_PROFILE == security_config.CUSTOM_SECURITY_PROFILE:
             securityProfile = self.CUSTOM_PROFILE_STRING
         else:
             securityProfile = securityProfileDict[self.EMBER_AF_SECURITY_PROFILE]
         return_dict['node_type'] = nodeType
         return_dict['pan_id'] = '0x%04X' % parameters.panId
         return_dict['extended_pan_id'] = byte_tuple.extPanToHexString(parameters.extendedPanId)
         return_dict['node_id'] = '0x%04X' % self.emberGetNodeId()
         return_dict['channel'] = parameters.radioChannel
         return_dict['power'] = parameters.radioTxPower
         return_dict['security_level'] = securityLevel
         return_dict['security_profile'] = securityProfile
     return return_dict
 def postFromEventQueue(self):
     try:
         event = self.event_queue.get(False)
         if isinstance(event, device_event.DeviceEvent) and event.device_address == None:
             self.logger.warning('Device Event has no device_address! Cannot post to cloud!')
             return 
         if isinstance(event, device_event.DeviceEvent):
             source_eui64_hex = byte_tuple.eui64ToHexString(event.device_address, False)
             self._register_active_device(source_eui64_hex)
             event.rssi_stats = self.sm.rssiStatsForEui64(source_eui64_hex)
         self.current_json_message = event.to_json()
         self.logger.info('Posting event JSON %s' % self.current_json_message)
         result = self.sendJson(self.current_json_message)
         if result:
             self.current_json_message = None
     except Queue.Empty:
         pass
 def callback_ezspTrustCenterJoinHandler(self, newNodeId, newNodeEui64, status, policyDecision, parentOfNewNodeId):
     policyDict = {ezsp.EMBER_USE_PRECONFIGURED_KEY: 'Allow (USE_PRECONFIGURED_KEY)',
      ezsp.EMBER_SEND_KEY_IN_THE_CLEAR: 'Allow (SEND_KEY_IN_THE_CLEAR)',
      ezsp.EMBER_DENY_JOIN: 'DENY_JOIN',
      ezsp.EMBER_NO_ACTION: 'NO_ACTION'}
     statusDict = {ezsp.EMBER_STANDARD_SECURITY_SECURED_REJOIN: 'STANDARD_SECURITY_SECURED_REJOIN',
      ezsp.EMBER_STANDARD_SECURITY_UNSECURED_JOIN: 'STANDARD_SECURITY_UNSECURED_JOIN',
      ezsp.EMBER_DEVICE_LEFT: 'DEVICE_LEFT',
      ezsp.EMBER_STANDARD_SECURITY_UNSECURED_REJOIN: 'STANDARD_SECURITY_UNSECURED_REJOIN',
      ezsp.EMBER_HIGH_SECURITY_SECURED_REJOIN: 'HIGH_SECURITY_SECURED_REJOIN',
      ezsp.EMBER_HIGH_SECURITY_UNSECURED_REJOIN: 'HIGH_SECURITY_UNSECURED_REJOIN'}
     try:
         self.logger.info('Trust Center: %s %s: %s' % (byte_tuple.eui64ToHexString(newNodeEui64), statusDict[status], policyDict[policyDecision]))
     except KeyError:
         self.logger.info('Trust Center: %s status = 0x%02x: decision = 0x%02x' % (byte_tuple.eui64ToHexString(newNodeEui64), status, policyDecision))
     if status == ezsp.EMBER_STANDARD_SECURITY_UNSECURED_JOIN and policyDecision == ezsp.EMBER_USE_PRECONFIGURED_KEY:
         self._weminucheLinkKeyRequiredCallback(newNodeEui64)
Beispiel #11
0
    def executeCommand(self, command):
        nodeId = self.emberLookupNodeIdByEui64(command.device_address)
        if nodeId == 0:
            return device_command.RSP_EUI64_NOT_FOUND
        infile = command.payload
        sending = True
        blockID = 0
        length = command.payload_length
        if self.telemetry_delegate:
            self.telemetry_delegate.commandTransferStarted(
                byte_tuple.eui64ToHexString(command.device_address), length)
        while sending:
            self.logger.debug('Command progress: %d bytes remaining' %
                              max(length, 0))
            if self.watchdog_delegate:
                self.watchdog_delegate.updateKey('commandThread')
            fileData = infile.read(512)
            if len(fileData) != 0:
                data = struct.pack('>B', blockID)
                data += fileData
                blockID += 1
                if blockID > 255:
                    blockID = 1
                try:
                    result = self._blockingWrite(nodeId, data)
                except:
                    if self.telemetry_delegate:
                        self.telemetry_delegate.commandTransferEnded(False)
                    infile.close()
                    raise
                if result != device_command.RSP_SUCCESS:
                    if self.telemetry_delegate:
                        self.telemetry_delegate.commandTransferEnded(False)
                    infile.close()
                    return result
            else:
                sending = False
            if self.telemetry_delegate:
                self.telemetry_delegate.incrementCommandBytesTransferred(512)
            length = length - 512

        if self.telemetry_delegate:
            self.telemetry_delegate.commandTransferEnded(True)
        infile.close()
        return device_command.RSP_SUCCESS
Beispiel #12
0
    def getAddressTableInformationString(self):
        s = 'Address table:\n'
        if self.EMBER_AF_ADDRESS_TABLE_SIZE == 0:
            s += 'Empty\n'
            return s
        s += 'Indx NodeID EUI64\n'
        i = 0
        while i < self.EMBER_AF_ADDRESS_TABLE_SIZE:
            NodeId = self.emberGetAddressTableRemoteNodeId(i)
            s += '0x%02x ' % i
            if NodeId == ezsp.EMBER_TABLE_ENTRY_UNUSED_NODE_ID:
                s += 'Unused\n'
            else:
                Eui64 = self.emberGetAddressTableRemoteEui64(i)
                s += '0x%04x %s\n' % (NodeId, byte_tuple.eui64ToHexString(Eui64))
            i += 1

        return s
Beispiel #13
0
    def executeCommand(self, command):
        nodeId = self.emberLookupNodeIdByEui64(command.device_address)
        if nodeId == 0:
            return device_command.RSP_EUI64_NOT_FOUND
        infile = command.payload
        sending = True
        blockID = 0
        length = command.payload_length
        if self.telemetry_delegate:
            self.telemetry_delegate.commandTransferStarted(byte_tuple.eui64ToHexString(command.device_address), length)
        while sending:
            self.logger.debug('Command progress: %d bytes remaining' % max(length, 0))
            if self.watchdog_delegate:
                self.watchdog_delegate.updateKey('commandThread')
            fileData = infile.read(512)
            if len(fileData) != 0:
                data = struct.pack('>B', blockID)
                data += fileData
                blockID += 1
                if blockID > 255:
                    blockID = 1
                try:
                    result = self._blockingWrite(nodeId, data)
                except:
                    if self.telemetry_delegate:
                        self.telemetry_delegate.commandTransferEnded(False)
                    infile.close()
                    raise 
                if result != device_command.RSP_SUCCESS:
                    if self.telemetry_delegate:
                        self.telemetry_delegate.commandTransferEnded(False)
                    infile.close()
                    return result
            else:
                sending = False
            if self.telemetry_delegate:
                self.telemetry_delegate.incrementCommandBytesTransferred(512)
            length = length - 512

        if self.telemetry_delegate:
            self.telemetry_delegate.commandTransferEnded(True)
        infile.close()
        return device_command.RSP_SUCCESS
    def getChildTableInformationArray(self):
        childTypeDict = {ezsp.EMBER_UNKNOWN_DEVICE: 'Unknown',
         ezsp.EMBER_COORDINATOR: 'Coordinator',
         ezsp.EMBER_ROUTER: 'Router',
         ezsp.EMBER_END_DEVICE: 'End device',
         ezsp.EMBER_SLEEPY_END_DEVICE: 'Sleepy end device',
         ezsp.EMBER_MOBILE_END_DEVICE: 'Mobile end device '}
        children = []
        (childTableSize, parentEui64, parentNodeId,) = self.ezspGetParentChildParameters()
        i = 0
        while i < childTableSize:
            (childId, childEui64, childType,) = self.ezspGetChildData(i)
            child_data = {'eui64': byte_tuple.eui64ToHexString(childEui64, False),
             'childType': childTypeDict[childType],
             'nodeId': self.emberLookupNodeIdByEui64(childEui64)}
            children.append(child_data)
            i += 1

        return children
 def device_address_hex(self):
     return byte_tuple.eui64ToHexString(self.device_address, False)
 def bridge_address_hex(self):
     if self.bridge_address != None:
         return byte_tuple.eui64ToHexString(self.bridge_address, False)
     else:
         return 
    def run(self):
        global app
        linux_hub.setup_gpio()
        linux_hub.reset_ncp()
        linux_hub.set_up_ipv4_timeouts()
        bridge_config = {'extended_pan_id_prefix': 1111839303L,
         'radio_power': 8,
         'network_create': True,
         'network_permit_joining': True,
         'print_progress_dots': False,
         'purge_link_keys': True}
        random.seed()
        bridge_config['extended_pan_id'] = (bridge_config['extended_pan_id_prefix'] << 32) + random.getrandbits(32)
        try:
            self.device = api.WeminucheApi(self.event_queue, bridge_config)
        except:
            self.logger.critical('Failed to initialise the NCP')
            self.shutdown(14)
            return 
        self.device.energyScanRequest(0)
        while not app.device.channelScanResultsReady():
            time.sleep(0.1)

        (total, failed, energies,) = app.device.collectAndClearChannelScanResults()
        lowest_energy = 0
        selected_channel = 0
        for energy in energies:
            (channel, dbm,) = energy
            if dbm < lowest_energy:
                selected_channel = channel
                lowest_energy = dbm

        self.logger.info('Switching to channel %d with lowest energy %d' % (selected_channel, lowest_energy))
        app.device.channelChangeRequest(selected_channel)
        self.system_environment = self.collectEnvironment()
        self.host_eui64 = self.device.getHostEui64()
        self.host_eui64_hex = byte_tuple.eui64ToHexString(self.host_eui64, False)
        self.watchdog_thread_exit_event = threading.Event()
        self.watchdog_delegate = watchdog_monitor.WatchdogMonitor(self.options.watchdog, self.watchdog_thread_exit_event)
        self.watchdog_thread = threading.Thread(target=self.watchdog_delegate.patWatchdog)
        self.watchdog_thread.start()
        self.device.setTelemetryDelegate(statistics_monitor.StatisticsMonitor(self))
        self.berg_cloud_thread_exit_event = threading.Event()
        self.berg_cloud_api = berg_cloud_socket_api.BergCloudSocketApi(self, self.host_eui64_hex, self.berg_cloud_thread_exit_event, self.command_queue, self.event_queue, self.log_queue, self.watchdog_delegate)
        self.berg_cloud_thread = threading.Thread(target=self.berg_cloud_api.start)
        self.berg_cloud_thread.start()
        self.ver_info = version.Version()
        self.ver_info.ncp_stack_version = self.device.getStackVersionString()
        self.logger.info('Starting webserver')
        self.httpd = status_server.BottleStats()
        self.httpd.set_bridge(self)
        self.webserver_thread = threading.Thread(target=self.httpd.run)
        self.webserver_thread.start()
        self.device.setWatchdogDelegate(self.watchdog_delegate)
        self.command_thread_exit_event = threading.Event()
        self.command_thread = threading.Thread(target=self.runQueuedCommands)
        self.command_thread.start()
        self.zigbee_led_thread_exit_event = threading.Event()
        self.zigbee_led_thread = threading.Thread(target=self.checkConnectedDevices)
        self.zigbee_led_thread.start()
        if self.options.daemon:
            while self.shutdown_triggered == False:
                try:
                    time.sleep(1)
                except KeyboardInterrupt:
                    self.logger.critical('Shutdown triggered in app.run() with KeyboardInterrupt')
                    self.shutdown()
Beispiel #18
0
    def run(self):
        global app
        linux_hub.setup_gpio()
        linux_hub.reset_ncp()
        linux_hub.set_up_ipv4_timeouts()
        bridge_config = {
            'extended_pan_id_prefix': 1111839303L,
            'radio_power': 8,
            'network_create': True,
            'network_permit_joining': True,
            'print_progress_dots': False,
            'purge_link_keys': True
        }
        random.seed()
        bridge_config['extended_pan_id'] = (
            bridge_config['extended_pan_id_prefix'] <<
            32) + random.getrandbits(32)
        try:
            self.device = api.WeminucheApi(self.event_queue, bridge_config)
        except:
            self.logger.critical('Failed to initialise the NCP')
            self.shutdown(14)
            return
        self.device.energyScanRequest(0)
        while not app.device.channelScanResultsReady():
            time.sleep(0.1)

        (
            total,
            failed,
            energies,
        ) = app.device.collectAndClearChannelScanResults()
        lowest_energy = 0
        selected_channel = 0
        for energy in energies:
            (
                channel,
                dbm,
            ) = energy
            if dbm < lowest_energy:
                selected_channel = channel
                lowest_energy = dbm

        self.logger.info('Switching to channel %d with lowest energy %d' %
                         (selected_channel, lowest_energy))
        app.device.channelChangeRequest(selected_channel)
        self.system_environment = self.collectEnvironment()
        self.host_eui64 = self.device.getHostEui64()
        self.host_eui64_hex = byte_tuple.eui64ToHexString(
            self.host_eui64, False)
        self.watchdog_thread_exit_event = threading.Event()
        self.watchdog_delegate = watchdog_monitor.WatchdogMonitor(
            self.options.watchdog, self.watchdog_thread_exit_event)
        self.watchdog_thread = threading.Thread(
            target=self.watchdog_delegate.patWatchdog)
        self.watchdog_thread.start()
        self.device.setTelemetryDelegate(
            statistics_monitor.StatisticsMonitor(self))
        self.berg_cloud_thread_exit_event = threading.Event()
        self.berg_cloud_api = berg_cloud_socket_api.BergCloudSocketApi(
            self, self.host_eui64_hex, self.berg_cloud_thread_exit_event,
            self.command_queue, self.event_queue, self.log_queue,
            self.watchdog_delegate)
        self.berg_cloud_thread = threading.Thread(
            target=self.berg_cloud_api.start)
        self.berg_cloud_thread.start()
        self.ver_info = version.Version()
        self.ver_info.ncp_stack_version = self.device.getStackVersionString()
        self.logger.info('Starting webserver')
        self.httpd = status_server.BottleStats()
        self.httpd.set_bridge(self)
        self.webserver_thread = threading.Thread(target=self.httpd.run)
        self.webserver_thread.start()
        self.device.setWatchdogDelegate(self.watchdog_delegate)
        self.command_thread_exit_event = threading.Event()
        self.command_thread = threading.Thread(target=self.runQueuedCommands)
        self.command_thread.start()
        self.zigbee_led_thread_exit_event = threading.Event()
        self.zigbee_led_thread = threading.Thread(
            target=self.checkConnectedDevices)
        self.zigbee_led_thread.start()
        if self.options.daemon:
            while self.shutdown_triggered == False:
                try:
                    time.sleep(1)
                except KeyboardInterrupt:
                    self.logger.critical(
                        'Shutdown triggered in app.run() with KeyboardInterrupt'
                    )
                    self.shutdown()
 def callback_ezspChildJoinHandler(self, index, joining, childID, childEui64, childType):
     if joining:
         self.logger.debug('Node 0x%04x (%s) joined the network.' % (childID, byte_tuple.eui64ToHexString(childEui64)))
     else:
         self.logger.debug('Node 0x%04x (%s) left the network.' % (childID, byte_tuple.eui64ToHexString(childEui64)))
     ezsp.EZSPInterface.callback_ezspChildJoinHandler(self, index, joining, childID, childEui64, childType)