def __connect_to_devices(self):    # Function for opening connection and connecting to devices
     for device in self.devices:
         try:    # Start error handler
             connection_start = time.time()
             if self.devices[device].get("serial") is None \
                     or self.devices[device]["serial"] is None \
                     or not self.devices[device]["serial"].isOpen():    # Connect only if serial not available earlier or it is closed.
                 self.devices[device]["serial"] = None
                 while self.devices[device]["serial"] is None or not self.devices[device]["serial"].isOpen():    # Try connect
                     '''connection to serial port with parameters from configuration file or default'''
                     self.devices[device]["serial"] = serial.Serial(
                              port=self.__config.get('port', '/dev/ttyUSB0'),
                              baudrate=self.__config.get('baudrate', 9600),
                              bytesize=self.__config.get('bytesize', serial.EIGHTBITS),
                              parity=self.__config.get('parity', serial.PARITY_NONE),
                              stopbits=self.__config.get('stopbits', serial.STOPBITS_ONE),
                              timeout=self.__config.get('timeout', 1),
                              xonxoff=self.__config.get('xonxoff', False),
                              rtscts=self.__config.get('rtscts', False),
                              write_timeout=self.__config.get('write_timeout', None),
                              dsrdtr=self.__config.get('dsrdtr', False),
                              inter_byte_timeout=self.__config.get('inter_byte_timeout', None),
                              exclusive=self.__config.get('exclusive', None)
                     )
                     time.sleep(.1)
                     if time.time() - connection_start > 10:    # Break connection try if it setting up for 10 seconds
                         log.error("Connection refused per timeout for device %s", self.devices[device]["device_config"].get("name"))
                         break
         except serial.serialutil.SerialException:
             log.error("Port %s for device %s - not found", self.__config.get('port', '/dev/ttyUSB0'), device)
             time.sleep(10)
         except Exception as e:
             log.exception(e)
             time.sleep(10)
         else:    # if no exception handled - add device and change connection state
             self.__gateway.add_device(self.devices[device]["device_config"]["name"], {"connector": self}, self.devices[device]["device_config"]["type"])
             self.connected = True
    def __run_server(self):
        self.endpoints = self.load_endpoints()

        self._app = web.Application(
            debug=self.__config.get('debugMode', False))

        ssl_context = None
        cert = None
        key = None
        if self.__config.get('SSL', False):
            if not self.__config.get('security'):
                if not os.path.exists('domain_srv.crt'):
                    from thingsboard_gateway.connectors.rest.ssl_generator import SSLGenerator
                    n = SSLGenerator(self.__config['host'])
                    n.generate_certificate()

                cert = 'domain_srv.crt'
                key = 'domain_srv.key'
            else:
                try:
                    cert = self.__config['security']['cert']
                    key = self.__config['security']['key']
                except KeyError as e:
                    log.exception(e)
                    log.error('Provide certificate and key path!')

            ssl_context = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH)
            ssl_context.load_cert_chain(cert, key)

        self.load_handlers()
        web.run_app(self._app,
                    host=self.__config['host'],
                    port=self.__config['port'],
                    handle_signals=False,
                    ssl_context=ssl_context,
                    reuse_port=self.__config['port'],
                    reuse_address=self.__config['host'])
예제 #3
0
    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)
                device = tuple(
                    filter(
                        lambda slave: slave.name == server_rpc_request[DEVICE_SECTION_PARAMETER], self.__slaves
                    )
                )[0]

                if isinstance(device.config[RPC_SECTION], dict):
                    rpc_command_config = device.config[RPC_SECTION].get(
                        server_rpc_request[DATA_PARAMETER][RPC_METHOD_PARAMETER])

                    if rpc_command_config is not None:
                        self.__process_request(server_rpc_request, rpc_command_config)

                elif isinstance(device.config[RPC_SECTION], list):
                    for rpc_command_config in device.config[RPC_SECTION]:
                        if rpc_command_config[TAG_PARAMETER] == server_rpc_request[DATA_PARAMETER][
                                RPC_METHOD_PARAMETER]:
                            self.__process_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)
예제 #4
0
 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 Exception as e:
                         log.exception(e)
             log.debug(self.__interest_nodes)
     except Exception as e:
         log.exception(e)
예제 #5
0
    def __init__(self, config):
        super().__init__()
        self.loop = None
        self.stopped = False
        self.name = config['name']
        self.device_type = config.get('deviceType', 'default')
        self.timeout = config.get('timeout', 10000) / 1000
        self.show_map = config.get('showMap', False)
        self.__connector_type = config['connector_type']

        self.daemon = True

        try:
            self.mac_address = self.validate_mac_address(config['MACAddress'])
            self.client = BleakClient(self.mac_address)
        except ValueError as e:
            self.client = None
            self.stopped = True
            log.error(e)

        self.poll_period = config.get('pollPeriod', 5000) / 1000
        self.config = {
            'extension': config.get('extension', DEFAULT_CONVERTER_CLASS_NAME),
            'telemetry': config.get('telemetry', []),
            'attributes': config.get('attributes', []),
            'attributeUpdates': config.get('attributeUpdates', []),
            'serverSideRpc': config.get('serverSideRpc', [])
        }
        self.callback = config['callback']
        self.last_polled_time = 0

        self.notifying_chars = []

        self.__converter = None
        self.__load_converter()

        self.start()
예제 #6
0
    async def __process_self(self):
        not_converted_data = {'telemetry': [], 'attributes': []}
        for section in ('telemetry', 'attributes'):
            for item in self.config[section]:
                char_id = item['characteristicUUID']

                if item['method'] == 'read':
                    try:
                        data = await self.client.read_gatt_char(char_id)
                        not_converted_data[section].append({
                            'data': data,
                            **item
                        })
                    except BleakError as e:
                        log.error(e)
                elif item[
                        'method'] == 'notify' and char_id not in self.notifying_chars:
                    try:
                        self.__set_char_handle(item, char_id)
                        self.notifying_chars.append(char_id)
                        await self.notify(char_id)
                    except BleakError:
                        log.error(e)

        if len(not_converted_data['telemetry']) > 0 or len(
                not_converted_data['attributes']) > 0:
            data_for_converter = {
                'deviceName': self.name,
                'deviceType': self.device_type,
                'converter': self.__converter,
                'config': {
                    'attributes': self.config['attributes'],
                    'telemetry': self.config['telemetry']
                },
                'data': not_converted_data
            }
            self.callback(data_for_converter)
예제 #7
0
    def server_side_rpc_handler(self, content):
        try:
            if content.get("device") is not None:

                log.debug(
                    "Modbus connector received rpc request for %s with content: %s",
                    content["device"], content)
                if isinstance(
                        self.__devices[content["device"]]["config"]["rpc"],
                        dict):
                    rpc_command_config = self.__devices[
                        content["device"]]["config"]["rpc"].get(
                            content["data"]["method"])
                    if rpc_command_config is not None:
                        self.__process_rpc_request(content, rpc_command_config)
                elif isinstance(
                        self.__devices[content["device"]]["config"]["rpc"],
                        list):
                    for rpc_command_config in self.__devices[
                            content["device"]]["config"]["rpc"]:
                        if rpc_command_config["tag"] == content["data"][
                                "method"]:
                            self.__process_rpc_request(content,
                                                       rpc_command_config)
                            break
                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)
        except Exception as e:
            log.exception(e)
예제 #8
0
 def send_data_to_bus(self,
                      node_id,
                      data,
                      is_extended_id=False,
                      is_fd=False,
                      bitrate_switch=False,
                      data_check=False):
     try:
         self.__bus.send(
             Message(arbitration_id=node_id,
                     is_extended_id=is_extended_id,
                     is_fd=is_fd,
                     bitrate_switch=bitrate_switch,
                     data=data,
                     check=data_check))
         return True
     except (ValueError, TypeError) as e:
         log.error("[%s] Wrong CAN message data: %s", self.get_name(),
                   str(e))
     except CanError as e:
         log.error("[%s] Failed to send CAN message: %s", self.get_name(),
                   str(e))
         self.__on_bus_error(e)
     return False
예제 #9
0
 def load_handlers(self):
     data_handlers = {
         "basic": BasicDataHandler,
         "anonymous": AnonymousDataHandler,
     }
     handlers = []
     for mapping in self.__config.get("mapping"):
         try:
             security_type = "anonymous" if mapping.get(
                 "security") is None else mapping["security"]["type"].lower(
                 )
             if security_type != "anonymous":
                 Users.add_user(mapping['endpoint'],
                                mapping['security']['username'],
                                mapping['security']['password'])
             for http_method in mapping['HTTPMethods']:
                 handler = data_handlers[security_type](
                     self.collect_statistic_and_send, self.get_name(),
                     self.endpoints[mapping["endpoint"]])
                 handlers.append(
                     web.route(http_method, mapping['endpoint'], handler))
         except Exception as e:
             log.error("Error on creating handlers - %s", str(e))
     self._app.add_routes(handlers)
 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]
예제 #11
0
    def server_side_rpc_handler(self,
                                config,
                                content,
                                callback=None,
                                errback=None):
        rpc_command_config = config["config"]["rpc"].get(
            content["data"].get("method"))
        if rpc_command_config.get('bit') is not None:
            rpc_command_config["functionCode"] = 6
            rpc_command_config["unitId"] = config["config"]["unitId"]

        if rpc_command_config is not None:
            rpc_command_config["payload"] = self._devices[
                content["device"]]["downlink_converter"].convert(
                    rpc_command_config, content)
            return self._function_to_device(rpc_command_config,
                                            rpc_command_config['unit_id'],
                                            callback=callback,
                                            errback=errback)
        else:
            log.error(
                "Received rpc request, but method %s not found in config for %s.",
                content["data"].get("method"), config["config"]['deviceName'])
            return None
예제 #12
0
    def server_side_rpc_handler(self, content):
        log.debug(
            "Modbus connector received rpc request for %s with content: %s",
            self.get_name(), content)
        rpc_command_config = self.__devices[
            content["device"]]["config"]["rpc"].get(
                content["data"].get("method"))
        if rpc_command_config.get('bit') is not None:
            rpc_command_config["functionCode"] = 6
            rpc_command_config["unitId"] = self.__devices[
                content["device"]]["config"]["unitId"]

        if rpc_command_config is not None:
            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 response is not None:
                response = isinstance(
                    response,
                    (WriteMultipleRegistersResponse,
                     WriteMultipleCoilsResponse, WriteSingleCoilResponse,
                     WriteSingleRegisterResponse))
                log.debug(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())
예제 #13
0
 def load_converters(self):
     devices_config = self.__config.get('devices')
     try:
         if devices_config is not None:
             print("Devices config part loaded ... ")
             for device_config in devices_config:
                 if device_config.get('converter') is not None:
                     converter = TBUtility.check_and_import(
                         self.__connector_type, device_config['converter'])
                     self.devices[device_config['name']] = {
                         'converter': converter(device_config),
                         'device_config': device_config
                     }
                 else:
                     log.error(
                         'Converter configuration for the custom connector %s -- not found, please check your configuration file.',
                         self.get_name())
         else:
             log.error(
                 'Section "devices" in the configuration not found. A custom connector %s has being stopped.',
                 self.get_name())
             self.close()
     except Exception as e:
         log.exception(e)
예제 #14
0
 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)
         if "${" in name_pattern_config and "}" in name_pattern_config:
             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)
             else:
                 log.error("Device name node not found with expression: %s",
                           name_expression)
                 return
         else:
             full_device_name = name_expression
         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)
             if "${" in device_type_expression and "}" in device_type_expression:
                 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)
                 else:
                     log.error(
                         "Device type node not found with expression: %s",
                         device_type_expression)
                     full_device_type = "default"
             else:
                 full_device_type = device_type_expression
             result["deviceType"] = full_device_type
             log.debug("Device type: %s", full_device_type)
         else:
             result["deviceType"] = "default"
         return result
     else:
         log.error(
             "Device node not found with expression: %s",
             TBUtility.get_value(device["deviceNodePattern"], get_tag=True))
예제 #15
0
 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
     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.")
예제 #16
0
 def __process_rpc_request(self, content, rpc_command_config):
     if rpc_command_config is not None:
         log.debug(rpc_command_config)
         address = rpc_command_config["address"]
         response = None
         try:
             if content["data"].get("params") is not None:
                 params = content["data"]["params"]
                 if not isinstance(params, bool):
                     log.error(
                         "Received rpc request, but params is not bool for method %s!",
                         content["data"].get("method"))
                     self.__gateway.send_rpc_reply(
                         content["device"], content["data"]["id"], {
                             content["data"]["method"]:
                             "Error, params is not bool!"
                         })
                     return
                 inversion = rpc_command_config["inversion"]
                 result = (params != inversion)  # params XOR inversion
                 f = open("/sys/class/gpio/gpio" + str(address) + "/value",
                          "w")
                 if result:
                     ret = f.write("1")
                 else:
                     ret = f.write("0")
                 f.close()
                 response = {"success": True}
             else:
                 log.error(
                     "Received rpc request, but no params found for method %s!",
                     content["data"].get("method"))
                 self.__gateway.send_rpc_reply(
                     content["device"], content["data"]["id"],
                     {content["data"]["method"]: "Error, no params found!"})
                 return
         except Exception as e:
             log.exception(e)
             response = e
         if content.get("id") or (content.get("data") is not None
                                  and content["data"].get("id")):
             if isinstance(response, Exception):
                 log.error(
                     "Received rpc request, but exception happened for method %s!",
                     content["data"].get("method"))
                 self.__gateway.send_rpc_reply(
                     content["device"], content["data"]["id"],
                     {content["data"]["method"]: str(response)})
             else:
                 self.__gateway.send_rpc_reply(content["device"],
                                               content["data"]["id"],
                                               response)
예제 #17
0
 def __search_general_info(self, device):
     result = []
     match_devices = []
     self.__search_node(self.__opcua_nodes["root"], TBUtility.get_value(device["deviceNodePattern"], get_tag=True), result=match_devices)
     for device_node in match_devices:
         if device_node is not None:
             result_device_dict = {"deviceName": None, "deviceType": None, "deviceNode": device_node, "configuration": deepcopy(device)}
             name_pattern_config = device["deviceNamePattern"]
             name_expression = TBUtility.get_value(name_pattern_config, get_tag=True)
             if "${" in name_pattern_config and "}" in name_pattern_config:
                 log.debug("Looking for device name")
                 name_path = self._check_path(name_expression, device_node)
                 device_name_node = []
                 self.__search_node(device_node, name_path, result=device_name_node)
                 device_name_node = device_name_node[0]
                 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 + "}", str(device_name_from_node)).replace(
                         name_expression, str(device_name_from_node))
                 else:
                     log.error("Device name node not found with expression: %s", name_expression)
                     return None
             else:
                 full_device_name = name_expression
             result_device_dict["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)
                 if "${" in device_type_expression and "}" in device_type_expression:
                     type_path = self._check_path(device_type_expression, device_node)
                     device_type_node = []
                     self.__search_node(device_node, type_path, result=device_type_node)
                     device_type_node = device_type_node[0]
                     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)
                     else:
                         log.error("Device type node not found with expression: %s", device_type_expression)
                         full_device_type = "default"
                 else:
                     full_device_type = device_type_expression
                 result_device_dict["deviceType"] = full_device_type
                 log.debug("Device type: %s", full_device_type)
             else:
                 result_device_dict["deviceType"] = "default"
             result.append(result_device_dict)
         else:
             log.error("Device node not found with expression: %s", TBUtility.get_value(device["deviceNodePattern"], get_tag=True))
     return result
예제 #18
0
 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
예제 #19
0
    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 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())
예제 #21
0
 def server_side_rpc_handler(self, content):
     log.debug(content)
     try:
         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']["serverSideRpc"]:
                     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 requests.get(
                                     'methodProcessing'
                             ) and requests['methodProcessing'].upper(
                             ) in characteristic.propertiesToString():
                                 if content['data']['method'] == requests[
                                         'methodRPC']:
                                     response = None
                                     if requests['methodProcessing'].upper(
                                     ) == 'WRITE':
                                         try:
                                             self.__check_and_reconnect(
                                                 device)
                                             response = characteristic.write(
                                                 content['data'].get(
                                                     'params',
                                                     '').encode('UTF-8'),
                                                 requests.get(
                                                     'withResponse', False))
                                         except BTLEDisconnectError:
                                             self.__check_and_reconnect(
                                                 device)
                                             response = characteristic.write(
                                                 content['data'].get(
                                                     'params',
                                                     '').encode('UTF-8'),
                                                 requests.get(
                                                     'withResponse', False))
                                     elif requests[
                                             'methodProcessing'].upper(
                                             ) == 'READ':
                                         try:
                                             self.__check_and_reconnect(
                                                 device)
                                             response = characteristic.read(
                                             )
                                         except BTLEDisconnectError:
                                             self.__check_and_reconnect(
                                                 device)
                                             response = characteristic.read(
                                             )
                                     elif requests[
                                             'methodProcessing'].upper(
                                             ) == 'NOTIFY':
                                         try:
                                             self.__check_and_reconnect(
                                                 device)
                                             delegate = self.__notify_handler(
                                                 self.
                                                 __devices_around[device],
                                                 characteristic.handle)
                                             response = delegate.data
                                         except BTLEDisconnectError:
                                             self.__check_and_reconnect(
                                                 device)
                                             delegate = self.__notify_handler(
                                                 self.
                                                 __devices_around[device],
                                                 characteristic.handle)
                                             response = delegate.data
                                     if response is not None:
                                         log.debug(
                                             'Response from device: %s',
                                             response)
                                         if requests['withResponse']:
                                             response = 'success'
                                         self.__gateway.send_rpc_reply(
                                             content['device'],
                                             content['data']['id'],
                                             str(response))
                             else:
                                 log.error(
                                     'Method for rpc request - not supported by characteristic or not found in the config.\nDevice: %s with data: %s and config: %s',
                                     device, content,
                                     self.__devices_around[device]
                                     ['device_config']["serverSideRpc"])
     except Exception as e:
         log.exception(e)
예제 #22
0
    def __get_services_and_chars(self):
        for device in self.__devices_around:
            try:
                if self.__devices_around.get(
                        device) is not None and self.__devices_around[
                            device].get('scanned_device') is not None:
                    log.debug('Connecting to device: %s', device)
                    if self.__devices_around[device].get('peripheral') is None:
                        address_type = self.__devices_around[device][
                            'device_config'].get('addrType', "public")
                        peripheral = Peripheral(
                            self.__devices_around[device]['scanned_device'],
                            address_type)
                        self.__devices_around[device][
                            'peripheral'] = peripheral
                    else:
                        peripheral = self.__devices_around[device][
                            'peripheral']
                    try:
                        log.info(peripheral.getState())
                    except BTLEInternalError:
                        peripheral.connect(
                            self.__devices_around[device]['scanned_device'])
                    try:
                        services = peripheral.getServices()
                    except BTLEDisconnectError:
                        self.__check_and_reconnect(device)
                        services = peripheral.getServices()
                    for service in services:
                        if self.__devices_around[device].get(
                                'services') is None:
                            log.debug(
                                'Building device %s map, it may take a time, please wait...',
                                device)
                            self.__devices_around[device]['services'] = {}
                        service_uuid = str(service.uuid).upper()
                        if self.__devices_around[device]['services'].get(
                                service_uuid) is None:
                            self.__devices_around[device]['services'][
                                service_uuid] = {}

                            try:
                                characteristics = service.getCharacteristics()
                            except BTLEDisconnectError:
                                self.__check_and_reconnect(device)
                                characteristics = service.getCharacteristics()

                            if self.__config.get('buildDevicesMap', False):
                                for characteristic in characteristics:
                                    descriptors = []
                                    self.__check_and_reconnect(device)
                                    try:
                                        descriptors = characteristic.getDescriptors(
                                        )
                                    except BTLEDisconnectError:
                                        self.__check_and_reconnect(device)
                                        descriptors = characteristic.getDescriptors(
                                        )
                                    except BTLEGattError as e:
                                        log.debug(e)
                                    except Exception as e:
                                        log.exception(e)
                                    characteristic_uuid = str(
                                        characteristic.uuid).upper()
                                    if self.__devices_around[device][
                                            'services'][service_uuid].get(
                                                characteristic_uuid) is None:
                                        self.__check_and_reconnect(device)
                                        self.__devices_around[device][
                                            'services'][service_uuid][
                                                characteristic_uuid] = {
                                                    'characteristic':
                                                    characteristic,
                                                    'handle':
                                                    characteristic.handle,
                                                    'descriptors': {}
                                                }
                                    for descriptor in descriptors:
                                        log.debug(descriptor.handle)
                                        log.debug(str(descriptor.uuid))
                                        log.debug(str(descriptor))
                                        self.__devices_around[device][
                                            'services'][service_uuid][
                                                characteristic_uuid][
                                                    'descriptors'][
                                                        descriptor.
                                                        handle] = descriptor
                            else:
                                for characteristic in characteristics:
                                    characteristic_uuid = str(
                                        characteristic.uuid).upper()
                                    self.__devices_around[device]['services'][
                                        service_uuid][characteristic_uuid] = {
                                            'characteristic': characteristic,
                                            'handle': characteristic.handle
                                        }

                    if self.__devices_around[device]['is_new_device']:
                        log.debug('New device %s - processing.', device)
                        self.__devices_around[device]['is_new_device'] = False
                        self.__new_device_processing(device)
                    for interest_char in self.__devices_around[device][
                            'interest_uuid']:
                        characteristics_configs_for_processing_by_methods = {}

                        for configuration_section in self.__devices_around[
                                device]['interest_uuid'][interest_char]:
                            characteristic_uuid_from_config = configuration_section[
                                'section_config'].get("characteristicUUID")
                            if characteristic_uuid_from_config is None:
                                log.error(
                                    'Characteristic not found in config: %s',
                                    pformat(configuration_section))
                                continue
                            method = configuration_section[
                                'section_config'].get('method')
                            if method is None:
                                log.error('Method not found in config: %s',
                                          pformat(configuration_section))
                                continue
                            characteristics_configs_for_processing_by_methods[
                                method.upper()] = {
                                    "method":
                                    method,
                                    "characteristicUUID":
                                    characteristic_uuid_from_config
                                }
                        for method in characteristics_configs_for_processing_by_methods:
                            data = self.__service_processing(
                                device,
                                characteristics_configs_for_processing_by_methods[
                                    method])
                            for section in self.__devices_around[device][
                                    'interest_uuid'][interest_char]:
                                converter = section['converter']
                                converted_data = converter.convert(
                                    section, data)
                                self.statistics[
                                    'MessagesReceived'] = self.statistics[
                                        'MessagesReceived'] + 1
                                log.debug(data)
                                log.debug(converted_data)
                                self.__gateway.send_to_storage(
                                    self.get_name(), converted_data)
                                self.statistics[
                                    'MessagesSent'] = self.statistics[
                                        'MessagesSent'] + 1
            except BTLEDisconnectError:
                log.debug('Connection lost. Device %s', device)
                continue
            except Exception as e:
                log.exception(e)
예제 #23
0
    def __process_devices(self):
        for device in self.__devices:
            current_time = time.time()
            device_responses = {"timeseries": {},
                                "attributes": {},
                                }
            to_send = {}
            try:
                for config_data in device_responses:
                    if self.__devices[device]["config"].get(config_data) is not None:
                        unit_id = self.__devices[device]["config"]["unitId"]
                        if self.__devices[device]["next_"+config_data+"_check"] < current_time:
                            self.__connect_to_current_master(device)
                            #  Reading data from device
                            for interested_data in range(len(self.__devices[device]["config"][config_data])):
                                current_data = self.__devices[device]["config"][config_data][interested_data]
                                current_data["deviceName"] = device
                                input_data = self.__function_to_device(current_data, unit_id)
                                # if not isinstance(input_data, ReadRegistersResponseBase) and input_data.isError():
                                #     log.exception(input_data)
                                #     continue
                                device_responses[config_data][current_data["tag"]] = {"data_sent": current_data,
                                                                                      "input_data": input_data}

                            log.debug("Checking %s for device %s", config_data, device)
                            self.__devices[device]["next_"+config_data+"_check"] = current_time + self.__devices[device]["config"][config_data+"PollPeriod"]/1000
                            log.debug(device_responses)
                            converted_data = {}
                            try:
                                converted_data = self.__devices[device]["converter"].convert(config={"byteOrder": self.__devices[device]["config"].get("byteOrder", self.__byte_order),
                                                                                                     "wordOrder": self.__devices[device]["config"].get("wordOrder", self.__word_order)},
                                                                                             data=device_responses)
                            except Exception as e:
                                log.error(e)

                            if converted_data and self.__devices[device]["config"].get("sendDataOnlyOnChange"):
                                self.statistics['MessagesReceived'] += 1
                                to_send = {"deviceName": converted_data["deviceName"], "deviceType": converted_data["deviceType"]}
                                if to_send.get("telemetry") is None:
                                    to_send["telemetry"] = []
                                if to_send.get("attributes") is None:
                                    to_send["attributes"] = []
                                for telemetry_dict in converted_data["telemetry"]:
                                    for key, value in telemetry_dict.items():
                                        if self.__devices[device]["last_telemetry"].get(key) is None or \
                                           self.__devices[device]["last_telemetry"][key] != value:
                                            self.__devices[device]["last_telemetry"][key] = value
                                            to_send["telemetry"].append({key: value})
                                for attribute_dict in converted_data["attributes"]:
                                    for key, value in attribute_dict.items():
                                        if self.__devices[device]["last_attributes"].get(key) is None or \
                                           self.__devices[device]["last_attributes"][key] != value:
                                            self.__devices[device]["last_attributes"][key] = value
                                            to_send["attributes"].append({key: value})
                                        # to_send["telemetry"] = converted_data["telemetry"]
                                # if converted_data["attributes"] != self.__devices[device]["attributes"]:
                                    # self.__devices[device]["last_attributes"] = converted_data["attributes"]
                                    # to_send["attributes"] = converted_data["attributes"]
                                if not to_send.get("attributes") and not to_send.get("telemetry"):
                                    # self.__gateway.send_to_storage(self.get_name(), to_send)
                                    # self.statistics['MessagesSent'] += 1
                                    log.debug("Data has not been changed.")
                            elif converted_data and self.__devices[device]["config"].get("sendDataOnlyOnChange") is None or not self.__devices[device]["config"].get("sendDataOnlyOnChange"):
                                self.statistics['MessagesReceived'] += 1
                                to_send = {"deviceName": converted_data["deviceName"],
                                           "deviceType": converted_data["deviceType"]}
                                # if converted_data["telemetry"] != self.__devices[device]["telemetry"]:
                                self.__devices[device]["last_telemetry"] = converted_data["telemetry"]
                                to_send["telemetry"] = converted_data["telemetry"]
                                # if converted_data["attributes"] != self.__devices[device]["attributes"]:
                                self.__devices[device]["last_attributes"] = converted_data["attributes"]
                                to_send["attributes"] = converted_data["attributes"]
                                # self.__gateway.send_to_storage(self.get_name(), to_send)
                                # self.statistics['MessagesSent'] += 1

                if to_send.get("attributes") or to_send.get("telemetry"):
                    self.__gateway.send_to_storage(self.get_name(), to_send)
                    self.statistics['MessagesSent'] += 1
            except ConnectionException:
                time.sleep(5)
                log.error("Connection lost! Reconnecting...")
            except Exception as e:
                log.exception(e)
예제 #24
0
 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
                 # giusguerrini, 2020-09-24: Fix: flush event set and send all data to platform,
                 # so data_to_send doesn't grow indefinitely in case of more than one value change
                 # per cycle, and platform doesn't lose events.
                 # NOTE: possible performance improvement: use a map to store only one event per
                 # variable to reduce frequency of messages to platform.
                 while 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 FuturesTimeoutError:
             self.__check_connection()
         except Exception as e:
             log.error(
                 "Connection failed on connection to OPC-UA server with url %s",
                 self.__server_conf.get("url"))
             log.exception(e)
             self.client = Client(
                 self.__opcua_url,
                 timeout=self.__server_conf.get("timeoutInMillis", 4000) /
                 1000)
             self._subscribed = {}
             self.__available_object_resources = {}
             time.sleep(10)
예제 #25
0
    def server_side_rpc_handler(self, content):
        done = False
        try:
            if not self.is_connected():
                log.warning(
                    "[%s] Cannot process RPC request: not connected to database",
                    self.get_name())
                raise Exception("no connection")

            is_rpc_unknown = False
            rpc_config = self.__config["serverSideRpc"]["methods"].get(
                content["data"]["method"])
            if rpc_config is None:
                if not self.__config["serverSideRpc"]["enableUnknownRpc"]:
                    log.warning("[%s] Ignore unknown RPC request '%s' (id=%s)",
                                self.get_name(), content["data"]["method"],
                                content["data"]["id"])
                    raise Exception("unknown RPC request")
                else:
                    is_rpc_unknown = True
                    rpc_config = content["data"].get("params", {})
                    sql_params = rpc_config.get("args", [])
                    query = rpc_config.get("query", "")
            else:
                if self.__config["serverSideRpc"]["overrideRpcConfig"]:
                    rpc_config = {
                        **rpc_config,
                        **content["data"].get("params", {})
                    }

                # The params attribute is obsolete but leave for backward configuration compatibility
                sql_params = rpc_config.get("args") or rpc_config.get(
                    "params", [])
                query = rpc_config.get("query", "")

            log.debug(
                "[%s] Processing %s '%s' RPC request (id=%s) for '%s' device: params=%s, query=%s",
                self.get_name(), "unknown" if is_rpc_unknown else "",
                content["data"]["method"], content["data"]["id"],
                content["device"], sql_params, query)

            if self.__rpc_cursor is None:
                self.__rpc_cursor = self.__connection.cursor()

            if query:
                if sql_params:
                    self.__rpc_cursor.execute(query, sql_params)
                else:
                    self.__rpc_cursor.execute(query)
            else:
                if sql_params:
                    self.__rpc_cursor.execute(
                        "{{CALL {} ({})}}".format(
                            content["data"]["method"],
                            ("?," * len(sql_params))[0:-1]), sql_params)
                else:
                    self.__rpc_cursor.execute("{{CALL {}}}".format(
                        content["data"]["method"]))

            done = True
            log.debug(
                "[%s] Processed '%s' RPC request (id=%s) for '%s' device",
                self.get_name(), content["data"]["method"],
                content["data"]["id"], content["device"])
        except pyodbc.Warning as w:
            log.warning(
                "[%s] Warning while processing '%s' RPC request (id=%s) for '%s' device: %s",
                self.get_name(), content["data"]["method"],
                content["data"]["id"], content["device"], str(w))
        except Exception as e:
            log.error(
                "[%s] Failed to process '%s' RPC request (id=%s) for '%s' device: %s",
                self.get_name(), content["data"]["method"],
                content["data"]["id"], content["device"], str(e))
        finally:
            if done and rpc_config.get("result",
                                       self.DEFAULT_PROCESS_RPC_RESULT):
                response = self.row_to_dict(self.__rpc_cursor.fetchone())
                self.__gateway.send_rpc_reply(content["device"],
                                              content["data"]["id"], response)
            else:
                self.__gateway.send_rpc_reply(content["device"],
                                              content["data"]["id"],
                                              {"success": done})
예제 #26
0
 def __search_nodes_and_subscribe(self, device_info):
     information_types = {
         "attributes": "attributes",
         "timeseries": "telemetry"
     }
     for information_type in information_types:
         for information in device_info["configuration"][information_type]:
             information_key = information["key"]
             config_path = TBUtility.get_value(information["path"],
                                               get_tag=True)
             information_path = self._check_path(config_path,
                                                 device_info["deviceNode"])
             information["path"] = '${%s}' % information_path
             information_nodes = []
             self.__search_node(device_info["deviceNode"],
                                information_path,
                                result=information_nodes)
             for information_node in information_nodes:
                 if information_node is not None:
                     information_value = information_node.get_value()
                     log.debug(
                         "Node for %s \"%s\" with path: %s - FOUND! Current values is: %s",
                         information_type, information_key,
                         information_path, str(information_value))
                     if device_info.get("uplink_converter") is None:
                         configuration = {
                             **device_info["configuration"], "deviceName":
                             device_info["deviceName"],
                             "deviceType":
                             device_info["deviceType"]
                         }
                         if device_info["configuration"].get(
                                 'converter') is None:
                             converter = OpcUaUplinkConverter(configuration)
                         else:
                             converter = TBUtility.check_and_import(
                                 self._connector_type, configuration)
                         device_info["uplink_converter"] = converter
                     else:
                         converter = device_info["uplink_converter"]
                     self.subscribed[information_node] = {
                         "converter": converter,
                         "path": information_path,
                         "config_path": config_path
                     }
                     if not device_info.get(
                             information_types[information_type]):
                         device_info[
                             information_types[information_type]] = []
                     converted_data = converter.convert(
                         (config_path, information_path), information_value)
                     self.statistics['MessagesReceived'] += 1
                     self.data_to_send.append(converted_data)
                     self.statistics['MessagesSent'] += 1
                     if self.__sub is None:
                         self.__sub = self.client.create_subscription(
                             self.__server_conf.get(
                                 "subCheckPeriodInMillis", 500),
                             self.__sub_handler)
                     if self.__sub:
                         self.__sub.subscribe_data_change(information_node)
                     log.debug("Added subscription to node: %s",
                               str(information_node))
                     log.debug("Data to ThingsBoard: %s", converted_data)
                 else:
                     log.error(
                         "Node for %s \"%s\" with path %s - NOT FOUND!",
                         information_type, information_key,
                         information_path)
예제 #27
0
    def __init__(self, gateway, config, connector_type):
        self._connector_type = connector_type
        self.statistics = {'MessagesReceived': 0, 'MessagesSent': 0}
        super().__init__()
        self.__gateway = gateway
        self.__server_conf = config.get("server")
        self.__interest_nodes = []
        self.__available_object_resources = {}
        self.__show_map = self.__server_conf.get("showMap", False)
        self.__previous_scan_time = 0
        for mapping in self.__server_conf["mapping"]:
            if mapping.get("deviceNodePattern") is not None:
                self.__interest_nodes.append(
                    {mapping["deviceNodePattern"]: mapping})
            else:
                log.error(
                    "deviceNodePattern in mapping: %s - not found, add property deviceNodePattern to processing this mapping",
                    dumps(mapping))
        if "opc.tcp" not in self.__server_conf.get("url"):
            opcua_url = "opc.tcp://" + self.__server_conf.get("url")
        else:
            opcua_url = self.__server_conf.get("url")
        self.client = Client(
            opcua_url,
            timeout=self.__server_conf.get("timeoutInMillis", 4000) / 1000)
        if self.__server_conf["identity"]["type"] == "cert.PEM":
            try:
                ca_cert = self.__server_conf["identity"].get("caCert")
                private_key = self.__server_conf["identity"].get("privateKey")
                cert = self.__server_conf["identity"].get("cert")
                security_mode = self.__server_conf["identity"].get(
                    "mode", "SignAndEncrypt")
                policy = self.__server_conf["security"]
                if cert is None or private_key is None:
                    log.exception(
                        "Error in ssl configuration - cert or privateKey parameter not found"
                    )
                    raise
                security_string = policy + ',' + security_mode + ',' + cert + ',' + private_key
                if ca_cert is not None:
                    security_string = security_string + ',' + ca_cert
                self.client.set_security_string(security_string)

            except Exception as e:
                log.exception(e)
        if self.__server_conf["identity"].get("username"):
            self.client.set_user(
                self.__server_conf["identity"].get("username"))
            if self.__server_conf["identity"].get("password"):
                self.client.set_password(
                    self.__server_conf["identity"].get("password"))

        self.setName(
            self.__server_conf.get(
                "name", 'OPC-UA ' +
                ''.join(choice(ascii_lowercase)
                        for _ in range(5))) + " Connector")
        self.__opcua_nodes = {}
        self._subscribed = {}
        self.data_to_send = []
        self.__sub_handler = SubHandler(self)
        self.__stopped = False
        self.__connected = False
        self.daemon = True
예제 #28
0
    def run(self):
        while not self.__connected:
            try:
                self.__connected = 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.__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)
        while not self.__stopped:
            try:
                time.sleep(.1)
                self.__check_connection()
                if not self.__connected and not self.__stopped:
                    self.client.connect()
                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"))
                time.sleep(10)
            except Exception as e:
                self.close()
                log.exception(e)
예제 #29
0
 def __search_node(self,
                   current_node,
                   fullpath,
                   search_method=False,
                   result=None):
     if result is None:
         result = []
     try:
         if regex.match(r"ns=\d*;[isgb]=.*", fullpath, regex.IGNORECASE):
             if self.__show_map:
                 log.debug("Looking for node with config")
             node = self.client.get_node(fullpath)
             if node is None:
                 log.warning("NODE NOT FOUND - using configuration %s",
                             fullpath)
             else:
                 log.debug("Found in %s", node)
                 result.append(node)
         else:
             fullpath_pattern = regex.compile(fullpath)
             full1 = fullpath.replace('\\\\.', '.')
             for child_node in current_node.get_children():
                 new_node_class = child_node.get_node_class()
                 #basis Description of node.get_parent() function, sometime child_node.get_parent() return None
                 new_parent = child_node.get_parent()
                 if (new_parent is None):
                     child_node_parent_class = current_node.get_node_class()
                 else:
                     child_node_parent_class = child_node.get_parent(
                     ).get_node_class()
                 current_node_path = '\\.'.join(
                     char.split(":")[1]
                     for char in current_node.get_path(200000, True))
                 new_node_path = '\\\\.'.join(
                     char.split(":")[1]
                     for char in child_node.get_path(200000, True))
                 if child_node_parent_class == ua.NodeClass.View and new_parent is not None:
                     parent_path = '\\.'.join(
                         char.split(":")[1]
                         for char in child_node.get_parent().get_path(
                             200000, True))
                     fullpath = fullpath.replace(current_node_path,
                                                 parent_path)
                 nnp1 = new_node_path.replace('\\\\.', '.')
                 nnp2 = new_node_path.replace('\\\\', '\\')
                 if self.__show_map:
                     log.debug("SHOW MAP: Current node path: %s",
                               new_node_path)
                 regex_fullmatch = regex.fullmatch(fullpath_pattern,  nnp1) or \
                                   nnp2 == full1 or \
                                   nnp2 == fullpath or \
                                   nnp1 == full1
                 if regex_fullmatch:
                     if self.__show_map:
                         log.debug(
                             "SHOW MAP: Current node path: %s - NODE FOUND",
                             nnp2)
                     result.append(child_node)
                 else:
                     regex_search = fullpath_pattern.fullmatch(nnp1, partial=True) or \
                                       nnp2 in full1 or \
                                       nnp1 in full1
                     if regex_search:
                         if self.__show_map:
                             log.debug(
                                 "SHOW MAP: Current node path: %s - NODE FOUND",
                                 new_node_path)
                         if new_node_class == ua.NodeClass.Object:
                             if self.__show_map:
                                 log.debug("SHOW MAP: Search in %s",
                                           new_node_path)
                             self.__search_node(child_node,
                                                fullpath,
                                                result=result)
                         elif new_node_class == ua.NodeClass.Variable:
                             log.debug("Found in %s", new_node_path)
                             result.append(child_node)
                         elif new_node_class == ua.NodeClass.Method and search_method:
                             log.debug("Found in %s", new_node_path)
                             result.append(child_node)
     except CancelledError:
         log.error(
             "Request during search has been canceled by the OPC-UA server."
         )
     except BrokenPipeError:
         log.error("Broken Pipe. Connection lost.")
     except OSError:
         log.debug("Stop on scanning.")
     except Exception as e:
         log.exception(e)
예제 #30
0
 async def connect_to_device(self):
     try:
         log.info('Trying to connect to %s with %s MAC address', self.name, self.mac_address)
         await self.client.connect(timeout=self.timeout)
     except Exception as e:
         log.error(e)