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
Ejemplo n.º 2
0
    def on_attributes_update(self, content):
        for attr_name, attr_value in content["data"].items():
            attr_config = self.__shared_attributes.get(content["device"],
                                                       {}).get(attr_name)
            if attr_config is None:
                log.warn(
                    "[%s] No configuration for '%s' attribute, ignore its update",
                    self.get_name(), attr_name)
                return

            log.debug(
                "[%s] Processing attribute update for '%s' device: attribute=%s,value=%s",
                self.get_name(), content["device"], attr_name, attr_value)

            # Converter expects dictionary as the second parameter so pack an attribute value to a dictionary
            data = self.__converters[content["device"]]["downlink"].convert(
                attr_config, {"value": attr_value})
            if data is None:
                log.error(
                    "[%s] Failed to update '%s' attribute for '%s' device: data conversion failure",
                    self.get_name(), attr_name, content["device"])
                return

            done = self.send_data_to_bus(
                attr_config.get("nodeId", self.UNKNOWN_ARBITRATION_ID), data,
                attr_config.get("isExtendedId", False),
                attr_config.get("isFd", False),
                attr_config.get("bitrateSwitch", False), True)
            if not done:
                log.error(
                    "[%s] Failed to update '%s' attribute for '%s' device",
                    self.get_name(), attr_name, content["device"])
            else:
                log.debug("[%s] Updated '%s' attribute for '%s' device",
                          self.get_name(), attr_name, content["device"])
    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 __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 __search_node(self,
                   current_node,
                   fullpath,
                   search_method=False,
                   result=[]):
     try:
         if regex.match("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.warn("NODE NOT FOUND - using configuration %s",
                          fullpath)
             else:
                 log.debug("Found in %s", node)
                 result.append(node)
         else:
             fullpath_pattern = regex.compile(fullpath)
             for child_node in current_node.get_children():
                 new_node = self.client.get_node(child_node)
                 new_node_path = '\\\\.'.join(
                     char.split(":")[1]
                     for char in new_node.get_path(200000, True))
                 if self.__show_map:
                     log.debug("SHOW MAP: Current node path: %s",
                               new_node_path)
                 new_node_class = new_node.get_node_class()
                 # regex_fullmatch = re.fullmatch(fullpath, new_node_path.replace('\\\\.', '.')) or new_node_path.replace('\\\\', '\\') == fullpath
                 regex_fullmatch = regex.fullmatch(fullpath_pattern, new_node_path.replace('\\\\.', '.')) or \
                                   new_node_path.replace('\\\\', '\\') == fullpath.replace('\\\\', '\\') or \
                                   new_node_path.replace('\\\\', '\\') == fullpath
                 regex_search = fullpath_pattern.fullmatch(new_node_path.replace('\\\\.', '.'), partial=True) or \
                                   new_node_path.replace('\\\\', '\\') in fullpath.replace('\\\\', '\\')
                 # regex_search = re.search(new_node_path, fullpath.replace('\\\\', '\\'))
                 if regex_fullmatch:
                     if self.__show_map:
                         log.debug(
                             "SHOW MAP: Current node path: %s - NODE FOUND",
                             new_node_path.replace('\\\\', '\\'))
                     result.append(new_node)
                 elif 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(new_node,
                                            fullpath,
                                            result=result)
                     elif new_node_class == ua.NodeClass.Variable:
                         log.debug("Found in %s", new_node_path)
                         result.append(new_node)
                     elif new_node_class == ua.NodeClass.Method and search_method:
                         log.debug("Found in %s", new_node_path)
                         result.append(new_node)
     except Exception as e:
         log.exception(e)
 def __connect_to_current_master(self, device=None):
     connect_attempt_count = 5
     connect_attempt_time_ms = 100
     wait_after_failed_attempts_ms = 300000
     if device is None:
         device = list(self.__devices.keys())[0]
     if self.__devices[device].get(MASTER_PARAMETER) is None:
         self.__devices[device][MASTER_PARAMETER], self.__devices[device][
             AVAILABLE_FUNCTIONS_PARAMETER] = self.__configure_master(
                 self.__devices[device][CONFIG_SECTION_PARAMETER])
     if self.__devices[device][MASTER_PARAMETER] != self.__current_master:
         self.__current_master = self.__devices[device][MASTER_PARAMETER]
         self.__available_functions = self.__devices[device][
             AVAILABLE_FUNCTIONS_PARAMETER]
     connect_attempt_count = self.__devices[device][
         CONFIG_SECTION_PARAMETER].get(CONNECT_ATTEMPT_COUNT_PARAMETER,
                                       connect_attempt_count)
     if connect_attempt_count < 1:
         connect_attempt_count = 1
     connect_attempt_time_ms = self.__devices[device][
         CONFIG_SECTION_PARAMETER].get(CONNECT_ATTEMPT_TIME_MS_PARAMETER,
                                       connect_attempt_time_ms)
     if connect_attempt_time_ms < 500:
         connect_attempt_time_ms = 500
     wait_after_failed_attempts_ms = self.__devices[device][
         CONFIG_SECTION_PARAMETER].get(
             WAIT_AFTER_FAILED_ATTEMPTS_MS_PARAMETER,
             wait_after_failed_attempts_ms)
     if wait_after_failed_attempts_ms < 1000:
         wait_after_failed_attempts_ms = 1000
     current_time = time.time() * 1000
     if not self.__current_master.is_socket_open():
         if self.__devices[device][CONNECTION_ATTEMPT_PARAMETER] >= connect_attempt_count and \
                 current_time - self.__devices[device][LAST_CONNECTION_ATTEMPT_TIME_PARAMETER] >= wait_after_failed_attempts_ms:
             self.__devices[device][CONNECTION_ATTEMPT_PARAMETER] = 0
         while not self.__current_master.is_socket_open() \
                 and self.__devices[device][CONNECTION_ATTEMPT_PARAMETER] < connect_attempt_count \
                 and current_time - self.__devices[device].get(LAST_CONNECTION_ATTEMPT_TIME_PARAMETER, 0) >= connect_attempt_time_ms:
             self.__devices[device][
                 CONNECTION_ATTEMPT_PARAMETER] = self.__devices[device][
                     CONNECTION_ATTEMPT_PARAMETER] + 1
             self.__devices[device][
                 LAST_CONNECTION_ATTEMPT_TIME_PARAMETER] = current_time
             log.debug("Modbus trying connect to %s", device)
             self.__current_master.connect()
             if self.__devices[device][
                     CONNECTION_ATTEMPT_PARAMETER] == connect_attempt_count:
                 log.warn(
                     "Maximum attempt count (%i) for device \"%s\" - encountered.",
                     connect_attempt_count, device)
             #     time.sleep(connect_attempt_time_ms / 1000)
             # if not self.__current_master.is_socket_open():
     if self.__devices[device][
             CONNECTION_ATTEMPT_PARAMETER] >= 0 and self.__current_master.is_socket_open(
             ):
         self.__devices[device][CONNECTION_ATTEMPT_PARAMETER] = 0
         self.__devices[device][
             LAST_CONNECTION_ATTEMPT_TIME_PARAMETER] = current_time
         log.debug("Modbus connected to device %s.", device)
Ejemplo n.º 7
0
    def __connect_to_current_master(self, device=None):
        # TODO: write documentation
        connect_attempt_count = 5
        connect_attempt_time_ms = 100
        wait_after_failed_attempts_ms = 300000

        if device.config.get('master') is None:
            device.config['master'], device.config[
                'available_functions'] = self.__configure_master(device.config)

        if connect_attempt_count < 1:
            connect_attempt_count = 1

        connect_attempt_time_ms = device.config.get('connectAttemptTimeMs',
                                                    connect_attempt_time_ms)

        if connect_attempt_time_ms < 500:
            connect_attempt_time_ms = 500

        wait_after_failed_attempts_ms = device.config.get(
            'waitAfterFailedAttemptsMs', wait_after_failed_attempts_ms)

        if wait_after_failed_attempts_ms < 1000:
            wait_after_failed_attempts_ms = 1000

        current_time = time() * 1000

        if not device.config['master'].is_socket_open():
            if device.config[
                    'connection_attempt'] >= connect_attempt_count and current_time - device.config[
                        'last_connection_attempt_time'] >= wait_after_failed_attempts_ms:
                device.config['connection_attempt'] = 0

            while not device.config['master'].is_socket_open() \
                    and device.config['connection_attempt'] < connect_attempt_count \
                    and current_time - device.config.get('last_connection_attempt_time',
                                                         0) >= connect_attempt_time_ms:
                device.config['connection_attempt'] = device.config[
                    'connection_attempt'] + 1
                device.config['last_connection_attempt_time'] = current_time
                log.debug("Modbus trying connect to %s", device)
                device.config['master'].connect()

                if device.config[
                        'connection_attempt'] == connect_attempt_count:
                    log.warn(
                        "Maximum attempt count (%i) for device \"%s\" - encountered.",
                        connect_attempt_count, device)

        if device.config['connection_attempt'] >= 0 and device.config[
                'master'].is_socket_open():
            device.config['connection_attempt'] = 0
            device.config['last_connection_attempt_time'] = current_time
    def __resolve_iterator_file(self):
        file_name = ""
        try:
            # The algorithm of resolving iterator file name is described in
            # https://thingsboard.io/docs/iot-gateway/config/odbc/#subsection-iterator
            # Edit that description whether algorithm is changed.
            file_name += self.__connection.getinfo(pyodbc.SQL_DRIVER_NAME)
            file_name += self.__connection.getinfo(pyodbc.SQL_SERVER_NAME)
            file_name += self.__connection.getinfo(pyodbc.SQL_DATABASE_NAME)
            file_name += self.__config["polling"]["iterator"]["column"]

            self.__iterator_file_name = sha1(file_name.encode()).hexdigest() + ".json"
            log.debug("[%s] Iterator file name resolved to %s", self.get_name(), self.__iterator_file_name)
        except Exception as e:
            log.warn("[%s] Failed to resolve iterator file name: %s", self.get_name(), str(e))
        return bool(self.__iterator_file_name)
    def 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 __process_row(self, row):
        try:
            data = {}
            for column in self.__column_names:
                data[column] = getattr(row, column)

            to_send = {"attributes": {} if "attributes" not in self.__config["mapping"] else
            self.__converter.convert(self.__config["mapping"]["attributes"], data),
                       "telemetry": {} if "timeseries" not in self.__config["mapping"] else
                       self.__converter.convert(self.__config["mapping"]["timeseries"], data)}

            device_name = eval(self.__config["mapping"]["device"]["name"], globals(), data)
            if device_name not in self.__devices:
                self.__devices[device_name] = {"attributes": {}, "telemetry": {}}
                self.__gateway.add_device(device_name, {"connector": self})

            self.__iterator["value"] = getattr(row, self.__iterator["name"])
            self.__check_and_send(device_name,
                                  self.__config["mapping"]["device"].get("type", self.__connector_type),
                                  to_send)
        except Exception as e:
            log.warn("[%s] Failed to process database row: %s", self.get_name(), str(e))
    def server_side_rpc_handler(self, content):
        done = False
        try:
            if not self.is_connected():
                log.warn("[%s] Cannot process RPC request: not connected to database", self.get_name())
                raise Exception("no connection")

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

            log.debug("[%s] Processing '%s' RPC request (id=%s) for '%s' device: params=%s",
                      self.get_name(), content["data"]["method"], content["data"]["id"],
                      content["device"], content["data"].get("params"))

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

            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.warn("[%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:
            self.__gateway.send_rpc_reply(content["device"], content["data"]["id"], {"success": done})
Ejemplo n.º 12
0
 def __on_bus_error(self, e):
     log.warn(
         "[%s] Notified about CAN bus error. Store it to later processing",
         self.get_name())
     self.__bus_error = e
Ejemplo n.º 13
0
    def server_side_rpc_handler(self, content):
        rpc_config = self.__rpc_calls.get(content["device"],
                                          {}).get(content["data"]["method"])
        if rpc_config is None:
            if not self.__devices[content["device"]]["enableUnknownRpc"]:
                log.warn(
                    "[%s] No configuration for '%s' RPC request (id=%s), ignore it",
                    self.get_name(), content["data"]["method"],
                    content["data"]["id"])
                return
            else:
                rpc_config = {}

        log.debug(
            "[%s] Processing %s '%s' RPC request (id=%s) for '%s' device: params=%s",
            self.get_name(), "pre-configured" if rpc_config else "UNKNOWN",
            content["data"]["method"], content["data"]["id"],
            content["device"], content["data"].get("params"))

        if self.__devices[content["device"]]["overrideRpcConfig"]:
            if rpc_config:
                conversion_config = self.__merge_rpc_configs(
                    content["data"].get("params", {}), rpc_config)
                log.debug(
                    "[%s] RPC request (id=%s) params and connector config merged to conversion config %s",
                    self.get_name(), content["data"]["id"], conversion_config)
            else:
                log.debug(
                    "[%s] RPC request (id=%s) will use its params as conversion config",
                    self.get_name(), content["data"]["id"])
                conversion_config = content["data"].get("params", {})
        else:
            conversion_config = rpc_config

        data = self.__converters[content["device"]]["downlink"].convert(
            conversion_config, content["data"].get("params", {}))
        if data is None:
            log.error(
                "[%s] Failed to process '%s' RPC request (id=%s) for '%s' device: data conversion failure",
                self.get_name(), content["data"]["method"],
                content["data"]["id"], content["device"])
            return

        done = self.send_data_to_bus(
            conversion_config.get("nodeId", self.UNKNOWN_ARBITRATION_ID), data,
            conversion_config.get("isExtendedId"),
            conversion_config.get("isFd"),
            conversion_config.get("bitrateSwitch"), True)
        if not done:
            log.error(
                "[%s] Failed to process '%s' RPC request (id=%s) for '%s' device",
                self.get_name(), content["data"]["method"],
                content["data"]["id"], content["device"])
        else:
            log.debug(
                "[%s] Processed '%s' RPC request (id=%s) for '%s' device",
                self.get_name(), content["data"]["method"],
                content["data"]["id"], content["device"])

        if conversion_config.get("response", True):
            self.__gateway.send_rpc_reply(content["device"],
                                          content["data"]["id"],
                                          {"success": done})
Ejemplo n.º 14
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")
                 device_name_from_node = ""
                 if name_expression == "$DisplayName":
                     device_name_from_node = device_node.get_display_name(
                     ).Text
                 elif name_expression == "$BrowseName":
                     device_name_from_node = device_node.get_browse_name(
                     ).Name
                 elif name_expression == "$NodeId.Identifier":
                     device_name_from_node = str(
                         device_node.nodeid.Identifier)
                 else:
                     name_path = self._check_path(name_expression,
                                                  device_node)
                     device_name_node = []
                     self.__search_node(device_node,
                                        name_path,
                                        result=device_name_node)
                     if len(device_name_node) == 0:
                         log.warn(
                             "Device name node - not found, skipping device..."
                         )
                         continue
                     device_name_node = device_name_node[0]
                     if device_name_node is not None:
                         device_name_from_node = device_name_node.get_value(
                         )
                 if device_name_from_node == "":
                     log.error(
                         "Device name node not found with expression: %s",
                         name_expression)
                     return None
                 full_device_name = name_pattern_config.replace(
                     "${" + name_expression + "}",
                     str(device_name_from_node)).replace(
                         name_expression, str(device_name_from_node))
             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
    def __process_devices(self):
        for device in self.__devices:
            current_time = time.time()
            device_responses = {
                TIMESERIES_PARAMETER: {},
                ATTRIBUTES_PARAMETER: {},
            }
            to_send = {}
            try:
                for config_section in device_responses:
                    if self.__devices[device][CONFIG_SECTION_PARAMETER].get(
                            config_section) is not None:
                        current_device_config = self.__devices[device][
                            CONFIG_SECTION_PARAMETER]
                        unit_id = current_device_config[UNIT_ID_PARAMETER]
                        if self.__devices[device][
                                NEXT_PREFIX + config_section +
                                CHECK_POSTFIX] < current_time:
                            self.__connect_to_current_master(device)
                            if not self.__current_master.is_socket_open(
                            ) or not len(
                                    current_device_config[config_section]):
                                continue
                            #  Reading data from device
                            for interested_data in range(
                                    len(current_device_config[config_section])
                            ):
                                current_data = current_device_config[
                                    config_section][interested_data]
                                current_data[DEVICE_NAME_PARAMETER] = device
                                input_data = self.__function_to_device(
                                    current_data, unit_id)
                                device_responses[config_section][
                                    current_data[TAG_PARAMETER]] = {
                                        "data_sent": current_data,
                                        "input_data": input_data
                                    }

                            log.debug("Checking %s for device %s",
                                      config_section, device)
                            self.__devices[device][
                                NEXT_PREFIX + config_section +
                                CHECK_POSTFIX] = current_time + current_device_config[
                                    config_section +
                                    POLL_PERIOD_POSTFIX] / 1000
                            log.debug(device_responses)
                            converted_data = {}
                            try:
                                converted_data = self.__devices[device][
                                    UPLINK_PREFIX +
                                    CONVERTER_PARAMETER].convert(config={
                                        **current_device_config, BYTE_ORDER_PARAMETER:
                                        current_device_config.get(
                                            BYTE_ORDER_PARAMETER,
                                            self.__byte_order),
                                        WORD_ORDER_PARAMETER:
                                        current_device_config.get(
                                            WORD_ORDER_PARAMETER,
                                            self.__word_order)
                                    },
                                                                 data=
                                                                 device_responses
                                                                 )
                            except Exception as e:
                                log.error(e)
                            if len(
                                    converted_data[ATTRIBUTES_PARAMETER]
                            ) == 0 and len(
                                    converted_data[TELEMETRY_PARAMETER]) == 0:
                                log.warn("Converted data is empty!")
                                continue
                            to_send = {
                                DEVICE_NAME_PARAMETER:
                                converted_data[DEVICE_NAME_PARAMETER],
                                DEVICE_TYPE_PARAMETER:
                                converted_data[DEVICE_TYPE_PARAMETER],
                                TELEMETRY_PARAMETER: [],
                                ATTRIBUTES_PARAMETER: []
                            }
                            if current_device_config.get(
                                    SEND_DATA_ONLY_ON_CHANGE_PARAMETER):
                                self.statistics[
                                    STATISTIC_MESSAGE_RECEIVED_PARAMETER] += 1
                                for converted_data_section in CONVERTED_DATA_SECTIONS:
                                    for current_section_dict in converted_data[
                                            converted_data_section]:
                                        for key, value in current_section_dict.items(
                                        ):
                                            if self.__devices[device][LAST_PREFIX + converted_data_section].get(key) is None or \
                                                    self.__devices[device][LAST_PREFIX + converted_data_section][key] != value:
                                                self.__devices[device][
                                                    LAST_PREFIX +
                                                    converted_data_section][
                                                        key] = value
                                                to_send[
                                                    converted_data_section].append(
                                                        {key: value})
                                if not to_send.get(ATTRIBUTES_PARAMETER
                                                   ) and not to_send.get(
                                                       TELEMETRY_PARAMETER):
                                    log.debug("Data has not been changed.")
                                    continue
                            elif converted_data and current_device_config.get(SEND_DATA_ONLY_ON_CHANGE_PARAMETER) is None or \
                                    not current_device_config.get(SEND_DATA_ONLY_ON_CHANGE_PARAMETER):
                                self.statistics[
                                    STATISTIC_MESSAGE_RECEIVED_PARAMETER] += 1
                                for converted_data_section in CONVERTED_DATA_SECTIONS:
                                    self.__devices[device][
                                        LAST_PREFIX +
                                        converted_data_section] = converted_data[
                                            converted_data_section]
                                    to_send[
                                        converted_data_section] = converted_data[
                                            converted_data_section]

                if to_send.get(ATTRIBUTES_PARAMETER) or to_send.get(
                        TELEMETRY_PARAMETER):
                    self.__gateway.send_to_storage(self.get_name(), to_send)
                    self.statistics[STATISTIC_MESSAGE_SENT_PARAMETER] += 1
            except ConnectionException:
                time.sleep(5)
                log.error("Connection lost! Reconnecting...")
            except Exception as e:
                log.exception(e)