def __function_to_device(self, config, unit_id): function_code = config.get(FUNCTION_CODE_PARAMETER) result = None if function_code in (1, 2, 3, 4): result = self.__available_functions[function_code]( address=config[ADDRESS_PARAMETER], count=config.get( OBJECTS_COUNT_PARAMETER, config.get("registersCount", config.get("registerCount", 1))), unit=unit_id) elif function_code in (5, 6): result = self.__available_functions[function_code]( address=config[ADDRESS_PARAMETER], value=config[PAYLOAD_PARAMETER], unit=unit_id) elif function_code in (15, 16): result = self.__available_functions[function_code]( address=config[ADDRESS_PARAMETER], values=config[PAYLOAD_PARAMETER], unit=unit_id) else: log.error("Unknown Modbus function with code: %i", function_code) log.debug("With result %s", str(result)) if "Exception" in str(result): log.exception(result) return result
def __general_cb(self, iocb, callback_params=None, value=None): try: if callback_params is None: callback_params = self.requests_in_progress[iocb] if iocb.ioResponse: apdu = iocb.ioResponse if isinstance(apdu, SimpleAckPDU): log.debug("Write to %s - successfully.", str(apdu.pduSource)) else: log.debug("Received response: %r", apdu) elif iocb.ioError: log.exception(iocb.ioError) else: log.error("There are no data in response and no errors.") if isinstance(callback_params, dict) and callback_params.get("callback"): try: callback_params["callback"](iocb, callback_params) except TypeError: callback_params["callback"](iocb) except Exception as e: log.exception( "During processing callback, exception has been raised:") log.exception(e) if self.requests_in_progress.get(iocb) is not None: del self.requests_in_progress[iocb]
def on_attributes_update(self, content): for attr_name, attr_value in content["data"].items(): attr_config = self.__shared_attributes.get(content["device"], {}).get(attr_name) if attr_config is None: log.warning( "[%s] No configuration for '%s' attribute, ignore its update", self.get_name(), attr_name) return log.debug( "[%s] Processing attribute update for '%s' device: attribute=%s,value=%s", self.get_name(), content["device"], attr_name, attr_value) # Converter expects dictionary as the second parameter so pack an attribute value to a dictionary data = self.__converters[content["device"]]["downlink"].convert( attr_config, {"value": attr_value}) if data is None: log.error( "[%s] Failed to update '%s' attribute for '%s' device: data conversion failure", self.get_name(), attr_name, content["device"]) return done = self.send_data_to_bus(data, attr_config, data_check=True) if done: log.debug("[%s] Updated '%s' attribute for '%s' device", self.get_name(), attr_name, content["device"]) else: log.error( "[%s] Failed to update '%s' attribute for '%s' device", self.get_name(), attr_name, content["device"])
def __initialize_client(self): self.__opcua_nodes["root"] = self.client.get_objects_node() self.__opcua_nodes["objects"] = self.client.get_objects_node() self.scan_nodes_from_config() self.__previous_scan_time = time.time() * 1000 log.debug('Subscriptions: %s', self.subscribed) log.debug("Available methods: %s", self.__available_object_resources)
def on_attributes_update(self, content): try: for attribute_request in self.__attribute_updates: if fullmatch(attribute_request["deviceNameFilter"], content["device"]) and \ fullmatch(attribute_request["attributeFilter"], list(content["data"].keys())[0]): converted_data = attribute_request[ "downlink_converter"].convert(attribute_request, content) response_queue = Queue(1) request_dict = { "config": { **attribute_request, **converted_data }, "request": regular_request } with self._app.test_request_context(): attribute_update_request_thread = Thread( target=self.__send_request, args=(request_dict, response_queue, log), daemon=True, name="Attribute request to %s" % (converted_data["url"])) attribute_update_request_thread.start() attribute_update_request_thread.join() if not response_queue.empty(): response = response_queue.get_nowait() log.debug(response) del response_queue except Exception as e: log.exception(e)
def on_attributes_update(self, content): try: log.debug('Recieved Attribute Update Request: %r', str(content)) for device in self.__devices: if device["deviceName"] == content["device"]: for request in device["attribute_updates"]: if request["config"].get("requestType") is not None: for attribute in content["data"]: if attribute == request["key"]: request["iocb"][1]["config"].update({ "propertyValue": content["data"][attribute] }) kwargs = request["iocb"][1] iocb = request["iocb"][0](device, **kwargs) self.__request_functions[ request["config"]["requestType"]](iocb) return else: log.error( "\"requestType\" not found in request configuration for key %s device: %s", request.get("key", "[KEY IS EMPTY]"), device["deviceName"]) except Exception as e: log.exception(e)
def __check_and_send(self, device_name, device_type, new_data): self.statistics['MessagesReceived'] += 1 to_send = {"attributes": [], "telemetry": []} send_on_change = self.__config["mapping"].get( "sendDataOnlyOnChange", self.DEFAULT_SEND_IF_CHANGED) for tb_key in to_send.keys(): for key, new_value in new_data[tb_key].items(): if not send_on_change or self.__devices[device_name][ tb_key].get(key, None) != new_value: self.__devices[device_name][tb_key][key] = new_value to_send[tb_key].append({key: new_value}) if to_send["attributes"] or to_send["telemetry"]: to_send["deviceName"] = device_name to_send["deviceType"] = device_type log.debug("[%s] Pushing to TB server '%s' device data: %s", self.get_name(), device_name, to_send) self.__gateway.send_to_storage(self.get_name(), to_send) self.statistics['MessagesSent'] += 1 else: log.debug("[%s] '%s' device data has not been changed", self.get_name(), device_name)
def __service_processing(self, device, characteristic_processing_conf): for service in self.__devices_around[device]['services']: characteristic_uuid_from_config = characteristic_processing_conf.get( 'characteristicUUID') if self.__devices_around[device]['services'][service].get( characteristic_uuid_from_config.upper()) is None: continue characteristic = self.__devices_around[device]['services'][ service][characteristic_uuid_from_config]['characteristic'] self.__check_and_reconnect(device) data = None if characteristic_processing_conf.get( 'method', '_').upper().split()[0] == "READ": if characteristic.supportsRead(): self.__check_and_reconnect(device) data = characteristic.read() log.debug(data) else: log.error( 'This characteristic doesn\'t support "READ" method.') if characteristic_processing_conf.get( 'method', '_').upper().split()[0] == "NOTIFY": self.__check_and_reconnect(device) descriptor = characteristic.getDescriptors(forUUID=0x2902)[0] handle = descriptor.handle if self.__notify_delegators.get(device) is None: self.__notify_delegators[device] = {} if self.__notify_delegators[device].get(handle) is None: self.__notify_delegators[device][handle] = { 'function': self.__notify_handler, 'args': (self.__devices_around[device], handle, self.__notify_delegators[device].get(handle)), 'delegate': None } self.__notify_delegators[device][handle][ 'delegate'] = self.__notify_delegators[device][handle][ 'function'](*self.__notify_delegators[device] [handle]['args']) data = self.__notify_delegators[device][handle][ 'delegate'].data else: self.__notify_delegators[device][handle]['args'] = ( self.__devices_around[device], handle, self.__notify_delegators[device][handle]['delegate']) self.__notify_delegators[device][handle][ 'delegate'] = self.__notify_delegators[device][handle][ 'function'](*self.__notify_delegators[device] [handle]['args']) data = self.__notify_delegators[device][handle][ 'delegate'].data if data is None: log.error('Cannot process characteristic: %s with config:\n%s', str(characteristic.uuid).upper(), pformat(characteristic_processing_conf)) else: log.debug('data: %s', data) return data
def __connect_to_current_master(self, device=None): connect_attempt_count = 5 connect_attempt_time_ms = 100 wait_after_failed_attempts_ms = 300000 if device is None: device = list(self.__devices.keys())[0] if self.__devices[device].get(MASTER_PARAMETER) is None: self.__devices[device][MASTER_PARAMETER], self.__devices[device][ AVAILABLE_FUNCTIONS_PARAMETER] = self.__configure_master( self.__devices[device][CONFIG_SECTION_PARAMETER]) if self.__devices[device][MASTER_PARAMETER] != self.__current_master: self.__current_master = self.__devices[device][MASTER_PARAMETER] self.__available_functions = self.__devices[device][ AVAILABLE_FUNCTIONS_PARAMETER] connect_attempt_count = self.__devices[device][ CONFIG_SECTION_PARAMETER].get(CONNECT_ATTEMPT_COUNT_PARAMETER, connect_attempt_count) if connect_attempt_count < 1: connect_attempt_count = 1 connect_attempt_time_ms = self.__devices[device][ CONFIG_SECTION_PARAMETER].get(CONNECT_ATTEMPT_TIME_MS_PARAMETER, connect_attempt_time_ms) if connect_attempt_time_ms < 500: connect_attempt_time_ms = 500 wait_after_failed_attempts_ms = self.__devices[device][ CONFIG_SECTION_PARAMETER].get( WAIT_AFTER_FAILED_ATTEMPTS_MS_PARAMETER, wait_after_failed_attempts_ms) if wait_after_failed_attempts_ms < 1000: wait_after_failed_attempts_ms = 1000 current_time = time.time() * 1000 if not self.__current_master.is_socket_open(): if self.__devices[device][CONNECTION_ATTEMPT_PARAMETER] >= connect_attempt_count and \ current_time - self.__devices[device][LAST_CONNECTION_ATTEMPT_TIME_PARAMETER] >= wait_after_failed_attempts_ms: self.__devices[device][CONNECTION_ATTEMPT_PARAMETER] = 0 while not self.__current_master.is_socket_open() \ and self.__devices[device][CONNECTION_ATTEMPT_PARAMETER] < connect_attempt_count \ and current_time - self.__devices[device].get(LAST_CONNECTION_ATTEMPT_TIME_PARAMETER, 0) >= connect_attempt_time_ms: self.__devices[device][ CONNECTION_ATTEMPT_PARAMETER] = self.__devices[device][ CONNECTION_ATTEMPT_PARAMETER] + 1 self.__devices[device][ LAST_CONNECTION_ATTEMPT_TIME_PARAMETER] = current_time log.debug("Modbus trying connect to %s", device) self.__current_master.connect() if self.__devices[device][ CONNECTION_ATTEMPT_PARAMETER] == connect_attempt_count: log.warn( "Maximum attempt count (%i) for device \"%s\" - encountered.", connect_attempt_count, device) # time.sleep(connect_attempt_time_ms / 1000) # if not self.__current_master.is_socket_open(): if self.__devices[device][ CONNECTION_ATTEMPT_PARAMETER] >= 0 and self.__current_master.is_socket_open( ): self.__devices[device][CONNECTION_ATTEMPT_PARAMETER] = 0 self.__devices[device][ LAST_CONNECTION_ATTEMPT_TIME_PARAMETER] = current_time log.debug("Modbus connected to device %s.", device)
def device_add(self, device): for interested_device in self.__devices_around: if device.addr.upper( ) == interested_device and self.__devices_around[ interested_device].get('scanned_device') is None: self.__devices_around[interested_device][ 'scanned_device'] = device self.__devices_around[interested_device][ 'is_new_device'] = True log.debug('Device with address: %s - found.', device.addr.upper())
def __save_iterator_config(self): try: Path(self.__config_dir).mkdir(exist_ok=True) with Path(self.__config_dir + self.__iterator_file_name).open("w") as iterator_file: iterator_file.write( dumps(self.__iterator, indent=2, sort_keys=True)) log.debug("[%s] Saved iterator configuration to %s", self.get_name(), self.__iterator_file_name) except Exception as e: log.error("[%s] Failed to save iterator configuration to %s: %s", self.get_name(), self.__iterator_file_name, str(e))
def server_side_rpc_handler(self, content): try: rpc_method = content["data"].get("method") for method in self.__available_object_resources[ content["device"]]['methods']: if rpc_method is not None and method.get( rpc_method) is not None: arguments_from_config = method["arguments"] arguments = content["data"].get( "params") if content["data"].get( "params") is not None else arguments_from_config try: if isinstance(arguments, list): result = method["node"].call_method( method[rpc_method], *arguments) elif arguments is not None: try: result = method["node"].call_method( method[rpc_method], arguments) except ua.UaStatusCodeError as e: if "BadTypeMismatch" in str(e) and isinstance( arguments, int): result = method["node"].call_method( method[rpc_method], float(arguments)) else: result = method["node"].call_method( method[rpc_method]) self.__gateway.send_rpc_reply( content["device"], content["data"]["id"], { content["data"]["method"]: result, "code": 200 }) log.debug("method %s result is: %s", method[rpc_method], result) except Exception as e: log.exception(e) self.__gateway.send_rpc_reply(content["device"], content["data"]["id"], { "error": str(e), "code": 500 }) else: log.error("Method %s not found for device %s", rpc_method, content["device"]) self.__gateway.send_rpc_reply( content["device"], content["data"]["id"], { "error": "%s - Method not found" % (rpc_method), "code": 404 }) except Exception as e: log.exception(e)
def server_side_rpc_handler(self, server_rpc_request): try: if server_rpc_request.get(DEVICE_SECTION_PARAMETER) is not None: log.debug( "Modbus connector received rpc request for %s with server_rpc_request: %s", server_rpc_request[DEVICE_SECTION_PARAMETER], server_rpc_request) if isinstance( self.__devices[ server_rpc_request[DEVICE_SECTION_PARAMETER]] [CONFIG_SECTION_PARAMETER][RPC_SECTION], dict): rpc_command_config = self.__devices[ server_rpc_request[DEVICE_SECTION_PARAMETER]][ CONFIG_SECTION_PARAMETER][RPC_SECTION].get( server_rpc_request[DATA_PARAMETER] [RPC_METHOD_PARAMETER]) if rpc_command_config is not None: self.__process_rpc_request(server_rpc_request, rpc_command_config) elif isinstance( self.__devices[ server_rpc_request[DEVICE_SECTION_PARAMETER]] [CONFIG_SECTION_PARAMETER][RPC_SECTION], list): for rpc_command_config in self.__devices[ server_rpc_request[DEVICE_SECTION_PARAMETER]][ CONFIG_SECTION_PARAMETER][RPC_SECTION]: if rpc_command_config[ TAG_PARAMETER] == server_rpc_request[ DATA_PARAMETER][RPC_METHOD_PARAMETER]: self.__process_rpc_request(server_rpc_request, rpc_command_config) break else: log.error( "Received rpc request, but method %s not found in config for %s.", server_rpc_request[DATA_PARAMETER].get( RPC_METHOD_PARAMETER), self.get_name()) self.__gateway.send_rpc_reply( server_rpc_request[DEVICE_SECTION_PARAMETER], server_rpc_request[DATA_PARAMETER][RPC_ID_PARAMETER], { server_rpc_request[DATA_PARAMETER][RPC_METHOD_PARAMETER]: "METHOD NOT FOUND!" }) else: log.debug("Received RPC to connector: %r", server_rpc_request) except Exception as e: log.exception(e)
def run(self): while True: if time.time( ) - self.__previous_scan_time >= self.__rescan_time != 0: self.__scan_ble() self.__previous_scan_time = time.time() if time.time( ) - self.__previous_read_time >= self.__check_interval_seconds: self.__get_services_and_chars() self.__previous_read_time = time.time() time.sleep(.1) if self.__stopped: log.debug('STOPPED') break
def form_iocb(device, config=None, request_type="readProperty"): config = config if config is not None else device address = device["address"] if isinstance( device["address"], Address) else Address(device["address"]) object_id = ObjectIdentifier(config["objectId"]) property_id = config.get("propertyId") value = config.get("propertyValue") property_index = config.get("propertyIndex") priority = config.get("priority") vendor = device.get("vendor", config.get("vendorId", 0)) request = None iocb = None if request_type == "readProperty": try: request = ReadPropertyRequest(objectIdentifier=object_id, propertyIdentifier=property_id) request.pduDestination = address if property_index is not None: request.propertyArrayIndex = int(property_index) iocb = IOCB(request) except Exception as e: log.exception(e) elif request_type == "writeProperty": datatype = get_datatype(object_id.value[0], property_id, vendor) if (isinstance(value, str) and value.lower() == 'null') or value is None: value = Null() request = WritePropertyRequest(objectIdentifier=object_id, propertyIdentifier=property_id) request.pduDestination = address request.propertyValue = Any() try: value = datatype(value) request.propertyValue = Any(value) except AttributeError as e: log.debug(e) except Exception as error: log.exception("WriteProperty cast error: %r", error) if property_index is not None: request.propertyArrayIndex = property_index if priority is not None: request.priority = priority iocb = IOCB(request) else: log.error("Request type is not found or not implemented") return iocb
def __on_mapping_response_cb(self, iocb: IOCB): try: if self.requests_in_progress.get(iocb) is not None: log.debug(iocb) log.debug(self.requests_in_progress[iocb]) if iocb.ioResponse: apdu = iocb.ioResponse value = self.__property_value_from_apdu(apdu) callback_params = self.requests_in_progress[iocb] if callback_params.get("callback") is not None: self.__general_cb(iocb, callback_params, value) elif iocb.ioError: log.exception(iocb.ioError) except Exception as e: log.exception(e) if self.requests_in_progress.get(iocb) is not None: del self.requests_in_progress[iocb]
def run(self): while not self.__stopped: # Initialization phase if not self.is_connected(): while not self.__stopped and \ not self.__init_connection() and \ self.__config["connection"].get("reconnect", self.DEFAULT_RECONNECT_STATE): reconnect_period = self.__config["connection"].get( "reconnectPeriod", self.DEFAULT_RECONNECT_PERIOD) log.info("[%s] Will reconnect to database in %d second(s)", self.get_name(), reconnect_period) sleep(reconnect_period) if not self.is_connected(): log.error( "[%s] Cannot connect to database so exit from main loop", self.get_name()) break if not self.__init_iterator(): log.error( "[%s] Cannot init database iterator so exit from main loop", self.get_name()) break # Polling phase try: self.__poll() if not self.__stopped: polling_period = self.__config["polling"].get( "period", self.DEFAULT_POLL_PERIOD) log.debug( "[%s] Next polling iteration will be in %d second(s)", self.get_name(), polling_period) sleep(polling_period) except pyodbc.Warning as w: log.warning("[%s] Warning while polling database: %s", self.get_name(), str(w)) except pyodbc.Error as e: log.error("[%s] Error while polling database: %s", self.get_name(), str(e)) self.__close() self.__close() self.__stopped = False log.info("[%s] Stopped", self.get_name())
def on_attributes_update(self, content): log.debug(content) try: for server_variables in self.__available_object_resources[ content["device"]]['variables']: for attribute in content["data"]: for variable in server_variables: if attribute == variable: try: server_variables[variable].set_value( content["data"][variable]) except Exception: server_variables[variable].set_attribute( ua.AttributeIds.Value, ua.DataValue(content["data"][variable])) except Exception as e: log.exception(e)
def server_side_rpc_handler(self, content): try: log.debug('Recieved RPC Request: %r', str(content)) for device in self.__devices: if device["deviceName"] == content["device"]: method_found = False for request in device["server_side_rpc"]: if request["config"].get("requestType") is not None: if content["data"]["method"] == request["method"]: method_found = True kwargs = request["iocb"][1] timeout = time() * 1000 + request[ "config"].get("requestTimeout", 200) if content["data"].get("params") is not None: kwargs["config"].update({ "propertyValue": content["data"]["params"] }) iocb = request["iocb"][0](device, **kwargs) self.__request_functions[ request["config"]["requestType"]]( device=iocb, callback=self.__rpc_response_cb) self.rpc_requests_in_progress[iocb] = { "content": content, "uplink_converter": request["uplink_converter"] } # self.__gateway.register_rpc_request_timeout(content, # timeout, # iocb, # self.__rpc_cancel_processing) else: log.error( "\"requestType\" not found in request configuration for key %s device: %s", request.get("key", "[KEY IS EMPTY]"), device["deviceName"]) if not method_found: log.error("RPC method %s not found in configuration", content["data"]["method"]) self.__gateway.send_rpc_reply(content["device"], content["data"]["id"], success_sent=False) except Exception as e: log.exception(e)
def __init_connection(self): try: log.debug("[%s] Opening connection to database", self.get_name()) connection_config = self.__config["connection"] self.__connection = pyodbc.connect( connection_config["str"], **connection_config.get("attributes", {})) if connection_config.get("encoding", ""): log.info("[%s] Setting encoding to %s", self.get_name(), connection_config["encoding"]) self.__connection.setencoding(connection_config["encoding"]) decoding_config = connection_config.get("decoding") if decoding_config is not None: if isinstance(decoding_config, dict): if decoding_config.get("char", ""): log.info("[%s] Setting SQL_CHAR decoding to %s", self.get_name(), decoding_config["char"]) self.__connection.setdecoding(pyodbc.SQL_CHAR, decoding_config["char"]) if decoding_config.get("wchar", ""): log.info("[%s] Setting SQL_WCHAR decoding to %s", self.get_name(), decoding_config["wchar"]) self.__connection.setdecoding(pyodbc.SQL_WCHAR, decoding_config["wchar"]) if decoding_config.get("metadata", ""): log.info("[%s] Setting SQL_WMETADATA decoding to %s", self.get_name(), decoding_config["metadata"]) self.__connection.setdecoding( pyodbc.SQL_WMETADATA, decoding_config["metadata"]) else: log.warning( "[%s] Unknown decoding configuration %s. Read data may be misdecoded", self.get_name(), decoding_config) self.__cursor = self.__connection.cursor() log.info("[%s] Connection to database opened, attributes %s", self.get_name(), connection_config.get("attributes", {})) except pyodbc.Error as e: log.error("[%s] Failed to connect to database: %s", self.get_name(), str(e)) self.__close() return self.is_connected()
def server_side_rpc_handler(self, content): try: for rpc_request in self.__rpc_requests: if fullmatch(rpc_request["deviceNameFilter"], content["device"]) and \ fullmatch(rpc_request["methodFilter"], content["data"]["method"]): converted_data = rpc_request["downlink_converter"].convert( rpc_request, content) response_queue = Queue(1) request_dict = { "config": { **rpc_request, **converted_data }, "request": regular_request } request_dict["converter"] = request_dict["config"].get( "uplink_converter") with self._app.test_request_context(): from flask import request as flask_request rpc_request_thread = Thread( target=self.__send_request, args=(request_dict, response_queue, log, flask_request), daemon=True, name="RPC request to %s" % (converted_data["url"])) rpc_request_thread.start() rpc_request_thread.join() if not response_queue.empty(): response = response_queue.get_nowait() log.debug(response) self.__gateway.send_rpc_reply( device=content["device"], req_id=content["data"]["id"], content=response[2]) else: self.__gateway.send_rpc_reply( device=content["device"], req_id=content["data"]["id"], success_sent=True) del response_queue except Exception as e: log.exception(e)
def datachange_notification(self, node, val, data): try: log.debug( "Python: New data change event on node %s, with val: %s and data %s", node, val, str(data)) subscription = self.connector.subscribed[node] converted_data = subscription["converter"].convert( (subscription["config_path"], subscription["path"]), val) self.connector.statistics[ 'MessagesReceived'] = self.connector.statistics[ 'MessagesReceived'] + 1 self.connector.data_to_send.append(converted_data) self.connector.statistics[ 'MessagesSent'] = self.connector.statistics['MessagesSent'] + 1 log.debug("[SUBSCRIPTION] Data to ThingsBoard: %s", converted_data) except KeyError: self.connector.scan_nodes_from_config() except Exception as e: log.exception(e)
def __poll_and_schedule(self, data, config): if self.connector.is_stopped(): return if self.events: self.events.pop(0) log.debug( "[%s] Sending periodic (%f sec) CAN message (arbitration_id=%d, data=%s)", self.connector.get_name(), config["period"], config["nodeId"], data) self.connector.send_data_to_bus(data, config, raise_exception=self.first_run) event = self.scheduler.enter(config["period"], 1, self.__poll_and_schedule, argument=(data, config)) self.events.append(event)
def indication(self, apdu: APDU): if isinstance(apdu, IAmRequest): log.debug( "Received IAmRequest from device with ID: %i and address %s:%i", apdu.iAmDeviceIdentifier[1], apdu.pduSource.addrTuple[0], apdu.pduSource.addrTuple[1]) log.debug(apdu.pduSource) request = ReadPropertyRequest( destination=apdu.pduSource, objectIdentifier=apdu.iAmDeviceIdentifier, propertyIdentifier='objectName', ) iocb = IOCB(request) deferred(self.request_io, iocb) iocb.add_callback(self.__iam_cb, vendor_id=apdu.vendorID) self.requests_in_progress.update( {iocb: { "callback": self.__iam_cb }})
def __new_device_processing(self, device): default_services_on_device = [ service for service in self.__devices_around[device]['services'].keys() if int(service.split('-')[0], 16) in self.__default_services ] log.debug('Default services found on device %s :%s', device, default_services_on_device) converter = BytesBLEUplinkConverter( self.__devices_around[device]['device_config']) converted_data = None for service in default_services_on_device: characteristics = [ char for char in self.__devices_around[device]['services'] [service].keys() if self.__devices_around[device]['services'] [service][char]['characteristic'].supportsRead() ] for char in characteristics: read_config = { 'characteristicUUID': char, 'method': 'READ', } try: self.__check_and_reconnect(device) data = self.__service_processing(device, read_config) attribute = capitaliseName(UUID(char).getCommonName()) read_config['key'] = attribute read_config['byteFrom'] = 0 read_config['byteTo'] = -1 converter_config = [{ "type": "attributes", "clean": False, "section_config": read_config }] for interest_information in converter_config: try: converted_data = converter.convert( interest_information, data) self.statistics[ 'MessagesReceived'] = self.statistics[ 'MessagesReceived'] + 1 log.debug(converted_data) except Exception as e: log.debug(e) except Exception as e: log.debug('Cannot process %s', e) continue if converted_data is not None: # self.__gateway.add_device(converted_data["deviceName"], {"connector": self}) self.__gateway.send_to_storage(self.get_name(), converted_data) self.statistics[ 'MessagesSent'] = self.statistics['MessagesSent'] + 1
def on_attributes_update(self, content): log.debug(content) for device in self.__devices_around: if self.__devices_around[device]['device_config'].get( 'name') == content['device']: for requests in self.__devices_around[device]['device_config'][ "attributeUpdates"]: for service in self.__devices_around[device]['services']: if requests[ 'characteristicUUID'] in self.__devices_around[ device]['services'][service]: characteristic = self.__devices_around[device][ 'services'][service][requests[ 'characteristicUUID']]['characteristic'] if 'WRITE' in characteristic.propertiesToString(): if content['data'].get( requests['attributeOnThingsBoard'] ) is not None: try: self.__check_and_reconnect(device) content_to_write = content['data'][ requests[ 'attributeOnThingsBoard']].encode( 'UTF-8') characteristic.write( content_to_write, True) except BTLEDisconnectError: self.__check_and_reconnect(device) content_to_write = content['data'][ requests[ 'attributeOnThingsBoard']].encode( 'UTF-8') characteristic.write( content_to_write, True) except Exception as e: log.exception(e) else: log.error( 'Cannot process attribute update request for device: %s with data: %s and config: %s', device, content, self.__devices_around[device] ['device_config']["attributeUpdates"])
def __scan_ble(self): log.debug("Scanning for devices...") try: self.__scanner.scan(self.__config.get('scanTimeSeconds', 5), passive=self.__config.get( 'passiveScanMode', False)) except BTLEManagementError as e: log.error('BLE working only with root user.') log.error( 'Or you can try this command:\nsudo setcap ' '\'cap_net_raw,cap_net_admin+eip\' %s' '\n====== Attention! ====== ' '\nCommand above - provided access to ble devices to any user.' '\n========================', str(bluepy_path[0] + '/bluepy-helper')) self._connected = False raise e except Exception as e: log.exception(e) time.sleep(10)
def __iam_cb(self, iocb: IOCB, vendor_id=None): if iocb.ioResponse: apdu = iocb.ioResponse log.debug("Received IAm Response: %s", str(apdu)) if self.discovered_devices.get(apdu.pduSource) is None: self.discovered_devices[apdu.pduSource] = {} value = self.__connector.default_converters["uplink_converter"]( "{}").convert(None, apdu) log.debug("Property: %s is %s", apdu.propertyIdentifier, value) self.discovered_devices[apdu.pduSource].update( {apdu.propertyIdentifier: value}) data_to_connector = { "address": apdu.pduSource, "objectId": apdu.objectIdentifier, "name": value, "vendor": vendor_id if vendor_id is not None else 0 } self.__connector.add_device(data_to_connector) elif iocb.ioError: log.exception(iocb.ioError)
def __resolve_iterator_file(self): file_name = "" try: # The algorithm of resolving iterator file name is described in # https://thingsboard.io/docs/iot-gateway/config/odbc/#subsection-iterator # Edit that description whether algorithm is changed. file_name += self.__connection.getinfo(pyodbc.SQL_DRIVER_NAME) file_name += self.__connection.getinfo(pyodbc.SQL_SERVER_NAME) file_name += self.__connection.getinfo(pyodbc.SQL_DATABASE_NAME) file_name += self.get_name() file_name += self.__config["polling"]["iterator"]["column"] self.__iterator_file_name = sha1( file_name.encode()).hexdigest() + ".json" log.debug("[%s] Iterator file name resolved to %s", self.get_name(), self.__iterator_file_name) except Exception as e: log.warning("[%s] Failed to resolve iterator file name: %s", self.get_name(), str(e)) return bool(self.__iterator_file_name)
def __notify_handler(self, device, notify_handle, delegate=None): class NotifyDelegate(DefaultDelegate): def __init__(self): DefaultDelegate.__init__(self) self.device = device self.data = {} def handleNotification(self, handle, data): self.data = data log.debug( 'Notification received from device %s handle: %i, data: %s', self.device, handle, data) if delegate is None: delegate = NotifyDelegate() device['peripheral'].withDelegate(delegate) device['peripheral'].writeCharacteristic(notify_handle, b'\x01\x00', True) if device['peripheral'].waitForNotifications(1): log.debug("Data received from notification: %s", delegate.data) return delegate