async def __call__(self, request: web.Request): auth = aiohttp.BasicAuth.decode(request.headers.get('Authorization')) if self.verify(auth.login, auth.password): json_data = await request.json() if not json_data: return web.Response(status=415) endpoint_config = self.__endpoint['config'] if request.method.upper() not in [ method.upper() for method in endpoint_config['HTTPMethods'] ]: return web.Response(status=405) try: log.info("CONVERTER CONFIG: %r", endpoint_config['converter']) converter = self.__endpoint['converter']( endpoint_config['converter']) converted_data = converter.convert( config=endpoint_config['converter'], data=json_data) self.send_to_storage(self.__name, converted_data) log.info("CONVERTED_DATA: %r", converted_data) return web.Response(status=200) except Exception as e: log.exception("Error while post to basic handler: %s", e) return web.Response(status=500) return web.Response(status=401)
def __process_data(self): while not self.__stopped: if not BLEConnector.process_data.empty(): device_config = BLEConnector.process_data.get() data = device_config.pop('data') config = device_config.pop('config') converter = device_config.pop('converter') try: converter = converter(device_config) converted_data = converter.convert(config, data) self.statistics['MessagesReceived'] = self.statistics[ 'MessagesReceived'] + 1 log.debug(converted_data) if converted_data is not None: self.__gateway.send_to_storage(self.get_name(), converted_data) self.statistics['MessagesSent'] = self.statistics[ 'MessagesSent'] + 1 log.info('Data to ThingsBoard %s', converted_data) except Exception as e: log.exception(e) else: sleep(.2)
def run(self): while not self.__connected: try: self.__connected = self.client.connect() self.client.load_type_definitions() 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) 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)
async def __show_map(self, return_result=False): result = f'MAP FOR {self.name.upper()}' for service in self.client.services: result += f'\n| [Service] {service}' for char in service.characteristics: if "read" in char.properties: try: value = bytes(await self.client.read_gatt_char(char.uuid)) result += f"\n| \t[Characteristic] {char} ({','.join(char.properties)}), Value: {value}" except Exception as e: result += f"\n| \t[Characteristic] {char} ({','.join(char.properties)}), Value: {e}" else: value = None result += f"\n| \t[Characteristic] {char} ({','.join(char.properties)}), Value: {value}" for descriptor in char.descriptors: try: value = bytes( await self.client.read_gatt_descriptor(descriptor.handle) ) result += f"\n| \t\t[Descriptor] {descriptor}) | Value: {value}" except Exception as e: result += f"| \t\t[Descriptor] {descriptor}) | Value: {e}" if return_result: return result else: log.info(result)
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 __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.warn("[%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 __parse_rpc_config(self): if "enableUnknownRpc" not in self.__config["serverSideRpc"]: self.__config["serverSideRpc"]["enableUnknownRpc"] = self.DEFAULT_ENABLE_UNKNOWN_RPC log.info("[%s] Processing unknown RPC %s", self.get_name(), "enabled" if self.__config["serverSideRpc"]["enableUnknownRpc"] else "disabled") if "overrideRpcConfig" not in self.__config["serverSideRpc"]: self.__config["serverSideRpc"]["overrideRpcConfig"] = self.DEFAULT_OVERRIDE_RPC_PARAMS log.info("[%s] Overriding RPC config %s", self.get_name(), "enabled" if self.__config["serverSideRpc"]["overrideRpcConfig"] else "disabled") if "serverSideRpc" not in self.__config or not self.__config["serverSideRpc"].get("methods", []): self.__config["serverSideRpc"] = {"methods": {}} return reformatted_config = {} for rpc_config in self.__config["serverSideRpc"]["methods"]: if isinstance(rpc_config, str): reformatted_config[rpc_config] = [] elif isinstance(rpc_config, dict): reformatted_config[rpc_config["name"]] = rpc_config.get("params", []) else: log.warn("[%s] Wrong RPC config format. Expected str or dict, get %s", self.get_name(), type(rpc_config)) self.__config["serverSideRpc"]["methods"] = reformatted_config
def __init__(self, connector: CanConnector): super().__init__() self.connector = connector self.scheduler = sched.scheduler(time.time, time.sleep) self.events = [] self.daemon = True log.info("[%s] Starting poller", self.connector.get_name())
def __convert_data(self): while not self.__stopped: if not self.__converting_requests.empty(): (address, port), data = self.__converting_requests.get() device = self.__devices.get(f'{address}:{port}', None) if not device: self.__log.error('Can\'t convert data from %s:%s - not in config file', address, port) converter = device['converter'] if not converter: self.__log.error('Converter not found for %s:%s', address, port) try: device_config = { 'encoding': device.get('encoding', 'utf-8').lower(), 'telemetry': device.get('telemetry', []), 'attributes': device.get('attributes', []) } converted_data = converter.convert(device_config, data) self.statistics['MessagesReceived'] = self.statistics['MessagesReceived'] + 1 if converted_data is not None: self.__gateway.send_to_storage(self.get_name(), converted_data) self.statistics['MessagesSent'] = self.statistics['MessagesSent'] + 1 log.info('Data to ThingsBoard %s', converted_data) except Exception as e: self.__log.exception(e) sleep(.2)
def poll_once(self): log.info("[%s] Starting one time poll", self.connector.get_name()) for polling_config in self.connector.get_polling_messages(): self.connector.send_data_to_bus( polling_config["nodeId"], bytearray.fromhex(polling_config["dataInHex"]), polling_config["isExtendedId"], polling_config["isFd"], polling_config["bitrateSwitch"])
def __close(self): if self.is_connected(): try: self.__connection.close() finally: log.info("[%s] Connection to database closed", self.get_name()) self.__connection = None self.__cursor = None
def __configure_pyodbc(self): pyodbc_config = self.__config.get("pyodbc", {}) if not pyodbc_config: return for name, value in pyodbc_config.items(): pyodbc.__dict__[name] = value log.info("[%s] Set pyodbc attributes: %s", self.get_name(), pyodbc_config)
def run(self): while not self.__connected: try: self.client.connect() try: self.client.load_type_definitions() except Exception as e: log.debug(e) log.debug("Error on loading 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 OSError: 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.__initialize_client() while not self.__stopped: try: time.sleep(.1) self.__check_connection() if not self.__connected and not self.__stopped: self.client.connect() self.__initialize_client() log.info("Reconnected to the OPC-UA server - %s", self.__server_conf.get("url")) elif not self.__stopped: if self.__server_conf.get("disableSubscriptions", False) and time.time()*1000 - self.__previous_scan_time > self.__server_conf.get("scanPeriodInMillis", 60000): self.scan_nodes_from_config() self.__previous_scan_time = time.time() * 1000 if self.data_to_send: self.__gateway.send_to_storage(self.get_name(), self.data_to_send.pop()) if self.__stopped: self.close() break except (KeyboardInterrupt, SystemExit): self.close() raise except ConnectionRefusedError: log.error("Connection refused on connection to OPC-UA server with url %s", self.__server_conf.get("url")) self.client = Client(self.__opcua_url, timeout=self.__server_conf.get("timeoutInMillis", 4000)/1000) # self.__sub_handler = SubHandler(self) self._subscribed = {} self.__available_object_resources = {} time.sleep(10) except FuturesTimeoutError: self.__check_connection() except Exception as e: self.close() log.exception(e)
def run(self): while not self.__master.connect(): time.sleep(5) log.warning("Modbus trying reconnect to %s", self.__config.get("name")) log.info("Modbus connected.") self.__connected = True while True: time.sleep(.01) self.__process_devices() if self.__stopped: break
async def run_client(self): while not self.stopped and not self.client.is_connected: await self.connect_to_device() sleep(.2) if self.client and self.client.is_connected: log.info('Connected to %s device', self.name) if self.show_map: await self.__show_map() await self.timer()
def __init_iterator(self): save_iterator = self.__config["polling"]["iterator"].get("persistent", self.DEFAULT_SAVE_ITERATOR) log.info("[%s] Iterator saving %s", self.get_name(), "enabled" if save_iterator else "disabled") if save_iterator and self.__load_iterator_config(): log.info("[%s] Init iterator from file '%s': column=%s, start_value=%s", self.get_name(), self.__iterator_file_name, self.__iterator["name"], self.__iterator["value"]) return True self.__iterator = {"name": self.__config["polling"]["iterator"]["column"], "total": 0} if "value" in self.__config["polling"]["iterator"]: self.__iterator["value"] = self.__config["polling"]["iterator"]["value"] log.info("[%s] Init iterator from configuration: column=%s, start_value=%s", self.get_name(), self.__iterator["name"], self.__iterator["value"]) elif "query" in self.__config["polling"]["iterator"]: try: self.__iterator["value"] = \ self.__cursor.execute(self.__config["polling"]["iterator"]["query"]).fetchone()[0] log.info("[%s] Init iterator from database: column=%s, start_value=%s", self.get_name(), self.__iterator["name"], self.__iterator["value"]) except pyodbc.Warning as w: log.warn("[%s] Warning on init iterator from database: %s", self.get_name(), str(w)) except pyodbc.Error as e: log.error("[%s] Failed to init iterator from database: %s", self.get_name(), str(e)) else: log.error("[%s] Failed to init iterator: value/query param is absent", self.get_name()) return "value" in self.__iterator
def _on_subscribe(self, _, __, mid, granted_qos, *args): log.info(args) try: if granted_qos[0] == 128: self.__log.error( '"%s" subscription failed to topic %s subscription message id = %i', self.get_name(), self.__subscribes_sent.get(mid), mid) else: self.__log.info( '"%s" subscription success to topic %s, subscription message id = %i', self.get_name(), self.__subscribes_sent.get(mid), mid) if self.__subscribes_sent.get(mid) is not None: del self.__subscribes_sent[mid] except Exception as e: self.__log.exception(e)
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_subscribe(self, _, __, mid, granted_qos, *args): log.info(args) try: if granted_qos[0] == 128: self.__log.error( '"%s" subscription failed to topic %s subscription message id = %i', self.get_name(), self.__subscribes_sent.get(mid), mid) else: self.__log.info( '"%s" subscription success to topic %s, subscription message id = %i', self.get_name(), self.__subscribes_sent.get(mid), mid) except Exception as e: self.__log.exception(e) # Success or not, remove this topic from the list of pending subscription requests if self.__subscribes_sent.get(mid) is not None: del self.__subscribes_sent[mid]
def __poll(self): rows = self.__cursor.execute(self.__config["polling"]["query"], self.__iterator["value"]) if not self.__column_names and self.__cursor.rowcount > 0: for column in self.__cursor.description: self.__column_names.append(column[0]) log.info("[%s] Fetch column names: %s", self.get_name(), self.__column_names) for row in rows: # log.debug("[%s] Fetch row: %s", self.get_name(), row) self.__process_row(row) self.__iterator["total"] += self.__cursor.rowcount log.info("[%s] Polling iteration finished. Processed rows: current %d, total %d", self.get_name(), self.__cursor.rowcount, self.__iterator["total"]) if self.__config["polling"]["iterator"].get("persistent", self.DEFAULT_SAVE_ITERATOR) and self.__cursor.rowcount > 0: self.__save_iterator_config()
def process_data(self, request): if not request.json: abort(415) endpoint_config = self.__endpoint['config'] if request.method.upper() not in [ method.upper() for method in endpoint_config['HTTPMethods'] ]: abort(405) try: log.info("CONVERTER CONFIG: %r", endpoint_config['converter']) converter = self.__endpoint['converter']( endpoint_config['converter']) converted_data = converter.convert( config=endpoint_config['converter'], data=request.get_json()) self.send_to_storage(self.__name, converted_data) log.info("CONVERTED_DATA: %r", converted_data) return "OK", 200 except Exception as e: log.exception("Error while post to basic handler: %s", e) return "", 500
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()) self.__stopped = True 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() # self.server_side_rpc_handler({"device": "RPC test", # "data": { # "id": 777, # "method": "usp_NoParameters", # "params": [ 8, True, "Three" ] # }}) 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.warn("[%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() log.info("[%s] Stopped", self.get_name())
def __init__(self, gateway, config, connector_type): super().__init__() # Initialize parents classes self.statistics = { 'MessagesReceived': 0, 'MessagesSent': 0 } # Dictionary, will save information about count received and sent messages. self.__config = config # Save configuration from the configuration file. self.__gateway = gateway # Save gateway object, we will use some gateway methods for adding devices and saving data from them. self.__connector_type = connector_type # Saving type for connector, need for loading converter self.setName( self.__config.get( "name", "Custom %s connector " % self.get_name() + ''.join(choice(ascii_lowercase) for _ in range(5))) ) # get from the configuration or create name for logs. log.info("Starting Custom %s connector", self.get_name()) # Send message to logger 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 = { } # Dictionary with devices, will contain devices configurations, converters for devices and serial port objects self.load_converters( ) # Call function to load converters and save it into devices dictionary self.__connect_to_devices() # Call function for connect to devices 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 __init__(self, gateway, config, connector_type): super().__init__() # Initialize parents classes # Dictionary, will save information about count received and sent messages. self.statistics = {'MessagesReceived': 0, 'MessagesSent': 0} self.__config = config self.__gateway = gateway self.__connector_type = connector_type # get from the configuration or create name for logs. self.setName( self.__config.get( "name", "Custom %s connector " % self.get_name() + ''.join(choice(ascii_lowercase) for _ in range(5)))) # Send message to logger log.info("Starting Custom %s connector", self.get_name()) 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 = { } # Dictionary with devices, will contain devices configurations, converters for devices and serial port objects self.load_converters() self._consumer_threads = [] self._rabbit_connection = None self._rabbit_channels = [] self._rabbit_consumers = [] 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
async def __call__(self, request: web.Request): json_data = await request.json() if not json_data and not len(request.query): return web.Response(status=415) endpoint_config = self.__endpoint['config'] if request.method.upper() not in [ method.upper() for method in endpoint_config['HTTPMethods'] ]: return web.Response(status=405) try: log.info("CONVERTER CONFIG: %r", endpoint_config['converter']) converter = self.__endpoint['converter']( endpoint_config['converter']) data = json_data if json_data else dict(request.query) converted_data = converter.convert( config=endpoint_config['converter'], data=data) self.send_to_storage(self.__name, converted_data) log.info("CONVERTED_DATA: %r", converted_data) return web.Response(status=200) except Exception as e: log.exception("Error while post to anonymous handler: %s", e) return web.Response(status=500)
def __poll(self): rows = self.__cursor.execute(self.__config["polling"]["query"], self.__iterator["value"]) if not self.__column_names: for column in self.__cursor.description: self.__column_names.append(column[0]) log.info("[%s] Fetch column names: %s", self.get_name(), self.__column_names) # For some reason pyodbc.Cursor.rowcount may be 0 (sqlite) so use our own row counter row_count = 0 for row in rows: log.debug("[%s] Fetch row: %s", self.get_name(), row) self.__process_row(row) row_count += 1 self.__iterator["total"] += row_count log.info( "[%s] Polling iteration finished. Processed rows: current %d, total %d", self.get_name(), row_count, self.__iterator["total"]) if self.__config["polling"]["iterator"]["persistent"] and row_count > 0: self.__save_iterator_config()
async def __show_map(self): scanner = self.__config.get('scanner', {}) devices = await BleakScanner( scanning_mode='active' if self.__config. get('passiveScanMode', True) else 'passive' ).discover(timeout=scanner.get('timeout', 10000) / 1000) log.info('FOUND DEVICES') if scanner.get('deviceName'): found_devices = [ x.__str__() for x in filter( lambda x: x.name == scanner['deviceName'], devices) ] if found_devices: log.info(', '.join(found_devices)) else: log.info('nothing to show') else: for device in devices: log.info(device)
def poll(self): if self.first_run: log.info("[%s] Starting poller", self.connector.get_name()) for polling_config in self.connector.get_polling_messages(): key = polling_config["key"] if polling_config["type"] == "always": log.info("[%s] Polling '%s' key every %f sec", self.connector.get_name(), key, polling_config["period"]) self.__poll_and_schedule(bytearray.fromhex(polling_config["dataInHex"]), polling_config) elif self.first_run: log.info("[%s] Polling '%s' key once", self.connector.get_name(), key) self.connector.send_data_to_bus(bytearray.fromhex(polling_config["dataInHex"]), polling_config, raise_exception=self.first_run) if self.first_run: self.first_run = False self.start()
def run(self): for polling_config in self.connector.get_polling_messages(): key = polling_config["key"] if polling_config["type"] == "always": log.info("[%s] Polling '%s' key every %f sec", self.connector.get_name(), key, polling_config["period"]) self.__poll_and_schedule( polling_config["period"], polling_config["nodeId"], bytearray.fromhex(polling_config["dataInHex"]), polling_config["isExtendedId"], polling_config["isFd"], polling_config["bitrateSwitch"]) else: log.info("[%s] Polling '%s' key once", self.connector.get_name(), key) self.connector.send_data_to_bus( polling_config["nodeId"], bytearray.fromhex(polling_config["dataInHex"]), polling_config["isExtendedId"], polling_config["isFd"], polling_config["bitrateSwitch"]) self.scheduler.run() log.info("[%s] Poller stopped", self.connector.get_name())
def open(self): self.__stopped = False self.start() log.info("Starting Modbus connector")