def datachange_notification(self, node, val, data): try: log.debug("Python: New data change event on node %s, with val: %s", node, val) subscription = self.connector.subscribed[node] converted_data = subscription["converter"].convert( (subscription["config_path"], subscription["path"]), val) self.connector.statistics['MessagesReceived'] += 1 self.connector.data_to_send.append(converted_data) self.connector.statistics['MessagesSent'] += 1 log.debug("Data to ThingsBoard: %s", converted_data) except Exception as e: log.exception(e)
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 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 __initialize_client(self): self.__opcua_nodes["root"] = self.client.get_objects_node() self.__opcua_nodes["objects"] = self.client.get_objects_node() if not self.__server_conf.get("disableSubscriptions", False): self.__sub = self.client.create_subscription( self.__server_conf.get("subCheckPeriodInMillis", 500), self.__sub_handler) else: self.__sub = False 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 __process_slaves(self): # TODO: write documentation device = ModbusConnector.process_requests.get() device_responses = {'timeseries': {}, 'attributes': {}} current_device_config = {} try: for config_section in device_responses: if device.config.get(config_section) is not None: current_device_config = device.config self.__connect_to_current_master(device) if not device.config['master'].is_socket_open() or not len( current_device_config[config_section]): continue # Reading data from device for interested_data in range( len(current_device_config[config_section])): current_data = current_device_config[config_section][ interested_data] current_data[DEVICE_NAME_PARAMETER] = device input_data = self.__function_to_device( device, current_data) device_responses[config_section][ current_data[TAG_PARAMETER]] = { "data_sent": current_data, "input_data": input_data } log.debug("Checking %s for device %s", config_section, device) log.debug('Device response: ', device_responses) if device_responses.get('timeseries') or device_responses.get( 'attributes'): self.__convert_and_save_data((device, current_device_config, { **current_device_config, BYTE_ORDER_PARAMETER: current_device_config.get(BYTE_ORDER_PARAMETER, device.byte_order), WORD_ORDER_PARAMETER: current_device_config.get(WORD_ORDER_PARAMETER, device.word_order) }, device_responses)) except ConnectionException: sleep(5) log.error("Connection lost! Reconnecting...") except Exception as e: log.exception(e)
def on_attributes_update( self, content ): # Function used for processing attribute update requests from ThingsBoard log.debug(content) if self.devices.get(content["device"]) is not None: device_config = self.devices[content["device"]].get( "device_config") if device_config is not None: log.debug(device_config) if device_config.get("attributeUpdates") is not None: requests = device_config["attributeUpdates"] for request in requests: attribute = request.get("attributeOnThingsBoard") log.debug(attribute) if attribute is not None and attribute in content[ "data"]: try: value = content["data"][attribute] str_to_send = str( request["stringToDevice"].replace( "${" + attribute + "}", str(value))).encode("UTF-8") self.devices[content["device"]][ "serial"].write(str_to_send) log.debug( "Attribute update request to device %s : %s", content["device"], str_to_send) time.sleep(.01) except Exception as e: log.exception(e)
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) 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)
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 scan_nodes_from_config(self): try: if self.__interest_nodes: for device_object in self.__interest_nodes: for current_device in device_object: try: device_configuration = device_object[current_device] devices_info_array = self.__search_general_info(device_configuration) for device_info in devices_info_array: if device_info is not None and device_info.get("deviceNode") is not None: self.__search_nodes_and_subscribe(device_info) self.__save_methods(device_info) self.__search_attribute_update_variables(device_info) else: log.error("Device node is None, please check your configuration.") log.debug("Current device node is: %s", str(device_configuration.get("deviceNodePattern"))) break except BrokenPipeError: log.debug("Broken Pipe. Connection lost.") except OSError: log.debug("Stop on scanning.") except FuturesTimeoutError: self.__check_connection() except Exception as e: log.exception(e) log.debug(self.__interest_nodes) except Exception as e: log.exception(e)
def connectionMade(self): # 初始化Framer self.framer = self.factory.framer # 初始化TransactionT if isinstance(self.framer, ModbusSocketFramer): self.transaction = DictTransactionManager(self) else: self.transaction = FifoTransactionManager(self) self._addr = '%s:%d' % (self.transport.getPeer().host, self.transport.getPeer().port) self.factory.addClient(self._addr, self, None) log.debug("Client Connected [%s]" % self._addr) self._connected = True
def __init__(self, gateway, config, connector_type): super().__init__() self.statistics = { 'MessagesReceived': 0, 'MessagesSent': 0 } # Dictionary, will save information about count received and sent messages. log.debug(type(config)) log.debug(config) self.__config = config # Save configuration from the configuration file. log.debug(type(gateway)) log.debug(gateway) self.__gateway = gateway # Save gateway object, we will use some gateway methods for adding devices and saving data from them. self.daemon = True # Set self thread as daemon self.stopped = True # Service variable for check state #self.__connected = False # Service variable for check connection to device self.__devices = {} self.setName( self.__config.get( "name", 'IGT GPIO Default ' + ''.join(choice(ascii_lowercase) for _ in range(5)))) self.__load_converters() log.info('Custom connector %s initialization success.', self.get_name()) # Message to logger log.info("Devices in configuration file found: %s ", '\n'.join(device for device in self.__devices)) # Message to logger
def __fill_interest_devices(self): if self.__config.get('devices') is None: log.error('Devices not found in configuration file. BLE Connector stopped.') self._connected = False return None for interest_device in self.__config.get('devices'): keys_in_config = ['attributes', 'telemetry'] if interest_device.get('MACAddress') is not None: default_converter = BytesBLEUplinkConverter(interest_device) interest_uuid = {} for key_type in keys_in_config: for type_section in interest_device.get(key_type): if type_section.get("characteristicUUID") is not None: converter = None if type_section.get('converter') is not None: try: module = TBUtility.check_and_import(self.__connector_type, type_section['converter']) if module is not None: log.debug('Custom converter for device %s - found!', interest_device['MACAddress']) converter = module(interest_device) else: log.error( "\n\nCannot find extension module for device %s .\nPlease check your configuration.\n", interest_device['MACAddress']) except Exception as e: log.exception(e) else: converter = default_converter if converter is not None: if interest_uuid.get(type_section["characteristicUUID"].upper()) is None: interest_uuid[type_section["characteristicUUID"].upper()] = [ {'section_config': type_section, 'type': key_type, 'converter': converter}] else: interest_uuid[type_section["characteristicUUID"].upper()].append( {'section_config': type_section, 'type': key_type, 'converter': converter}) else: log.error("No characteristicUUID found in configuration section for %s:\n%s\n", key_type, pformat(type_section)) if self.__devices_around.get(interest_device['MACAddress'].upper()) is None: self.__devices_around[interest_device['MACAddress'].upper()] = {} self.__devices_around[interest_device['MACAddress'].upper()]['device_config'] = interest_device self.__devices_around[interest_device['MACAddress'].upper()]['interest_uuid'] = interest_uuid else: log.error("Device address not found, please check your settings.")
def run(self): while not self.__connected: try: self.__connected = self.client.connect() self.client.load_type_definitions() log.debug(self.client.get_namespace_array()[-1]) log.debug( self.client.get_namespace_index( self.client.get_namespace_array()[-1])) except ConnectionRefusedError: log.error( "Connection refused on connection to OPC-UA server with url %s", self.__server_conf.get("url")) time.sleep(10) except Exception as e: log.debug("error on connection to OPC-UA server.") log.error(e) time.sleep(10) else: self.__connected = True log.info("OPC-UA connector %s connected to server %s", self.get_name(), self.__server_conf.get("url")) self.__opcua_nodes["root"] = self.client.get_root_node() self.__opcua_nodes["objects"] = self.client.get_objects_node() sub = self.client.create_subscription( self.__server_conf.get("scanPeriodInMillis", 500), self.__sub_handler) # self.__search_name(self.__opcua_nodes["objects"], 2) # self.__search_tags(self.__opcua_nodes["objects"], 2, sub) self.__search_name(self.__opcua_nodes["root"], 0) self.__search_tags(self.__opcua_nodes["root"], 0, sub) log.debug('Subscriptions: %s', self.subscribed) log.debug("Available methods: %s", self.__available_object_resources) while True: try: time.sleep(1) if self.data_to_send: self.__gateway.send_to_storage(self.get_name(), self.data_to_send.pop()) if self.__stopped: break except (KeyboardInterrupt, SystemExit): self.close() raise except Exception as e: self.close() log.exception(e)
def server_side_rpc_handler(self, content): if content.get("device") is not None: log.debug( "Modbus connector received rpc request for %s with content: %s", content["device"], content) rpc_command_config = self.__devices[ content["device"]]["config"]["rpc"].get( content["data"].get("method")) if rpc_command_config is not None: rpc_command_config["unitId"] = self.__devices[ content["device"]]["config"]["unitId"] if rpc_command_config.get('bit') is not None: rpc_command_config["functionCode"] = 6 if rpc_command_config.get("functionCode") in (5, 6, 15, 16): rpc_command_config["payload"] = self.__devices[ content["device"]]["downlink_converter"].convert( rpc_command_config, content) response = None try: response = self.__function_to_device( rpc_command_config, rpc_command_config["unitId"]) except Exception as e: log.exception(e) if isinstance(response, ReadRegistersResponseBase): to_converter = { "rpc": { content["data"]["method"]: { "data_sent": rpc_command_config, "input_data": response } } } response = self.__devices[ content["device"]]["converter"].convert( config=None, data=to_converter) log.debug("Received RPC method: %s, result: %r", content["data"]["method"], response) elif isinstance( response, (WriteMultipleRegistersResponse, WriteMultipleCoilsResponse, WriteSingleCoilResponse, WriteSingleRegisterResponse)): response = str(response) log.debug("Write %r", response) response = False if response is None else response response = str(response) if isinstance(response, Exception) else response self.__gateway.send_rpc_reply( content["device"], content["data"]["id"], {content["data"]["method"]: response}) else: log.error( "Received rpc request, but method %s not found in config for %s.", content["data"].get("method"), self.get_name()) self.__gateway.send_rpc_reply( content["device"], content["data"]["id"], {content["data"]["method"]: "METHOD NOT FOUND!"}) else: log.debug("Received RPC to connector: %r", content)
def dataReceived(self, data): log.debug("Received data: " + " ".join([hex(byte2int(x)) for x in data])) self._timeoutDeffer.callback('dataReceived') if self._is_valid: # 验证成功 unit = self.framer.decode_data(data).get("uid", 0) self.framer.processIncomingPacket(data, self._handleResponse, unit=unit) else: # 首次获取数据,验证注册码 data_str = str(data, encoding='ascii') if data_str is not None and len(data_str) > 0: self._handlerToken(data_str)
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 characteristic_uuid_from_config is None: log.error('Characteristic not found in config: %s', pformat(characteristic_processing_conf)) return None if self.__devices_around[device]['services'][service].get(characteristic_uuid_from_config) 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 __send_request(self, request, converter_queue, log): url = "" try: request["next_time"] = time() + request["config"].get( "scanPeriod", 10) request_url_from_config = request["config"]["url"] request_url_from_config = str( '/' + request_url_from_config ) if request_url_from_config[0] != '/' else request_url_from_config log.debug(request_url_from_config) url = self.__host + request_url_from_config log.debug(url) request_timeout = request["config"].get("timeout", 1) params = { "method": request["config"].get("httpMethod", "GET"), "url": url, "timeout": request_timeout, "allow_redirects": request["config"].get("allowRedirects", False), "verify": self.__ssl_verify, "auth": self.__security } log.debug(url) if request["config"].get("httpHeaders") is not None: params["headers"] = request["config"]["httpHeaders"] log.debug("Request to %s will be sent", url) response = request["request"](**params) if response and response.ok: if not converter_queue.full(): data_to_storage = [url, request["converter"]] try: data_to_storage.append(response.json()) except UnicodeDecodeError: data_to_storage.append(response.content()) if len(data_to_storage) == 3: converter_queue.put(data_to_storage) else: log.error("Request to URL: %s finished with code: %i", url, response.status_code) except Timeout: log.error("Timeout error on request %s.", url) except RequestException as e: log.error("Cannot connect to %s. Connection error.", url) log.debug(e) except ConnectionError: log.error("Cannot connect to %s. Connection error.", url) 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 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 __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 __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.__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.warn("[%s] Failed to resolve iterator file name: %s", self.get_name(), str(e)) return bool(self.__iterator_file_name)
def __search_general_info(self, device): result = {"deviceName": None, "deviceType": None, "deviceNode": None} result["deviceNode"] = self.__search_node( self.__opcua_nodes["root"], TBUtility.get_value(device["deviceNodePattern"], get_tag=True)) if result["deviceNode"] is not None: name_pattern_config = device["deviceNamePattern"] name_expression = TBUtility.get_value(name_pattern_config, get_tag=True) device_name_node = self.__search_node(self.__opcua_nodes["root"], name_expression) if device_name_node is not None: device_name_from_node = device_name_node.get_value() full_device_name = name_pattern_config.replace( "${" + name_expression + "}", device_name_from_node).replace(name_expression, device_name_from_node) result["deviceName"] = full_device_name log.debug("Device name: %s", full_device_name) if device.get("deviceTypePattern"): device_type_expression = TBUtility.get_value( device["deviceTypePattern"], get_tag=True) device_type_node = self.__search_node( self.__opcua_nodes["root"], device_type_expression) if device_type_node is not None: device_type = device_type_node.get_value() full_device_type = device_type_expression.replace( "${" + device_type_expression + "}", device_type).replace(device_type_expression, device_type) result["deviceType"] = full_device_type log.debug("Device type: %s", full_device_type) else: log.error( "Device type node not found with expression: %s", device_type_expression) else: result["deviceType"] = "default" return result else: log.error("Device name node not found with expression: %s", name_expression) return else: log.error( "Device node not found with expression: %s", TBUtility.get_value(device["deviceNodePattern"], get_tag=True))
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 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 server_side_rpc_handler(self, content): try: for method in self.__available_object_resources[ content["device"]]['methods']: rpc_method = content["data"].get("method") 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 type(arguments) is list: result = method["node"].call_method( method[rpc_method], *arguments) elif arguments is not None: result = method["node"].call_method( method[rpc_method], 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 __function_to_device(self, config, unit_id): function_code = config.get('functionCode') result = None if function_code in (1, 2, 3, 4): result = self.__available_functions[function_code]( config["address"], config.get("registerCount", 1), unit=unit_id) elif function_code in (5, 6, 15, 16): result = self.__available_functions[function_code]( config["address"], config["payload"], unit=unit_id) else: log.error("Unknown Modbus function with code: %i", function_code) log.debug("To modbus device %s, \n%s", config["deviceName"], config) log.debug("With result %s", result) return result
def __connect_to_current_master(self, device=None): # TODO: write documentation connect_attempt_count = 5 connect_attempt_time_ms = 100 wait_after_failed_attempts_ms = 300000 if device.config.get('master') is None: device.config['master'], device.config['available_functions'] = self.__configure_master(device.config) if connect_attempt_count < 1: connect_attempt_count = 1 connect_attempt_time_ms = device.config.get('connectAttemptTimeMs', connect_attempt_time_ms) if connect_attempt_time_ms < 500: connect_attempt_time_ms = 500 wait_after_failed_attempts_ms = device.config.get('waitAfterFailedAttemptsMs', wait_after_failed_attempts_ms) if wait_after_failed_attempts_ms < 1000: wait_after_failed_attempts_ms = 1000 current_time = time() * 1000 if not device.config['master'].is_socket_open(): if device.config['connection_attempt'] >= connect_attempt_count and current_time - device.config[ 'last_connection_attempt_time'] >= wait_after_failed_attempts_ms: device.config['connection_attempt'] = 0 while not device.config['master'].is_socket_open() \ and device.config['connection_attempt'] < connect_attempt_count \ and current_time - device.config.get('last_connection_attempt_time', 0) >= connect_attempt_time_ms: device.config['connection_attempt'] = device.config[ 'connection_attempt'] + 1 device.config['last_connection_attempt_time'] = current_time log.debug("Modbus trying connect to %s", device) device.config['master'].connect() if device.config['connection_attempt'] == connect_attempt_count: log.warn("Maximum attempt count (%i) for device \"%s\" - encountered.", connect_attempt_count, device) if device.config['connection_attempt'] >= 0 and device.config['master'].is_socket_open(): device.config['connection_attempt'] = 0 device.config['last_connection_attempt_time'] = current_time
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 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 run(self): self.__connected = True self.scan_network() self._application.do_whois() log.debug("WhoIsRequest has been sent.") self.scan_network() while not self.__stopped: sleep(.1) for device in self.__devices: try: if device.get("previous_check") is None or time( ) * 1000 - device["previous_check"] >= device[ "poll_period"]: for mapping_type in ["attributes", "telemetry"]: for config in device[mapping_type]: if config.get( "uplink_converter" ) is None or config.get( "downlink_converter") is None: self.__load_converters(device) data_to_application = { "device": device, "mapping_type": mapping_type, "config": config, "callback": self.__bacnet_device_mapping_response_cb } self._application.do_read_property( **data_to_application) device["previous_check"] = time() * 1000 else: sleep(.1) except Exception as e: log.exception(e) if not self.__convert_and_save_data_queue.empty(): for _ in range(self.__convert_and_save_data_queue.qsize()): thread = Thread( target=self.__convert_and_save_data, args=(self.__convert_and_save_data_queue, ), daemon=True) thread.start()