示例#1
0
 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)
         except Exception as e:
             log.exception(e)
         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
示例#2
0
 def __fill_requests(self):
     log.debug(self.__config["mapping"])
     for endpoint in self.__config["mapping"]:
         try:
             log.debug(endpoint)
             converter = None
             if endpoint["converter"]["type"] == "custom":
                 module = TBModuleLoader.import_module(
                     self.__connector_type,
                     endpoint["converter"]["extension"])
                 if module is not None:
                     log.debug('Custom converter for url %s - found!',
                               endpoint["url"])
                     converter = module(endpoint)
                 else:
                     log.error(
                         "\n\nCannot find extension module for %s url.\nPlease check your configuration.\n",
                         endpoint["url"])
             else:
                 converter = JsonRequestUplinkConverter(endpoint)
             self.__requests_in_progress.append({
                 "config": endpoint,
                 "converter": converter,
                 "next_time": time(),
                 "request": request
             })
         except Exception as e:
             log.exception(e)
示例#3
0
 def __search_attribute_update_variables(self, device_info):
     try:
         if device_info["configuration"].get("attributes_updates", []):
             node = device_info["deviceNode"]
             device_name = device_info["deviceName"]
             if self.__available_object_resources.get(device_name) is None:
                 self.__available_object_resources[device_name] = {}
             if self.__available_object_resources[device_name].get(
                     "variables") is None:
                 self.__available_object_resources[device_name][
                     "variables"] = []
             for attribute_update in device_info["configuration"][
                     "attributes_updates"]:
                 attribute_path = self._check_path(
                     attribute_update["attributeOnDevice"], node)
                 attribute_nodes = []
                 self.__search_node(node,
                                    attribute_path,
                                    result=attribute_nodes)
                 for attribute_node in attribute_nodes:
                     if attribute_node is not None:
                         self.__available_object_resources[device_name][
                             "variables"].append({
                                 attribute_update["attributeOnThingsBoard"]:
                                 attribute_node
                             })
                     else:
                         log.error(
                             "Attribute update node with path \"%s\" - NOT FOUND!",
                             attribute_path)
     except Exception as e:
         log.exception(e)
示例#4
0
 def send_data_to_bus(self,
                      data,
                      config,
                      data_check=True,
                      raise_exception=False):
     try:
         self.__bus.send(
             Message(arbitration_id=config["nodeId"],
                     is_extended_id=config.get(
                         "isExtendedId", self.DEFAULT_EXTENDED_ID_FLAG),
                     is_fd=config.get("isFd", self.DEFAULT_FD_FLAG),
                     bitrate_switch=config.get(
                         "bitrateSwitch", self.DEFAULT_BITRATE_SWITCH_FLAG),
                     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))
         if raise_exception:
             raise e
         else:
             self.__on_bus_error(e)
     return False
示例#5
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.warning(
                    "[%s] No configuration for '%s' attribute, ignore its update",
                    self.get_name(), attr_name)
                return

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

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

            done = self.send_data_to_bus(data, attr_config, data_check=True)
            if done:
                log.debug("[%s] Updated '%s' attribute for '%s' device",
                          self.get_name(), attr_name, content["device"])
            else:
                log.error(
                    "[%s] Failed to update '%s' attribute for '%s' device",
                    self.get_name(), attr_name, content["device"])
示例#6
0
 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]
示例#7
0
 def __function_to_device(self, config, unit_id):
     function_code = config.get(FUNCTION_CODE_PARAMETER)
     result = None
     if function_code in (1, 2, 3, 4):
         result = self.__available_functions[function_code](
             address=config[ADDRESS_PARAMETER],
             count=config.get(
                 OBJECTS_COUNT_PARAMETER,
                 config.get("registersCount",
                            config.get("registerCount", 1))),
             unit=unit_id)
     elif function_code in (5, 6):
         result = self.__available_functions[function_code](
             address=config[ADDRESS_PARAMETER],
             value=config[PAYLOAD_PARAMETER],
             unit=unit_id)
     elif function_code in (15, 16):
         result = self.__available_functions[function_code](
             address=config[ADDRESS_PARAMETER],
             values=config[PAYLOAD_PARAMETER],
             unit=unit_id)
     else:
         log.error("Unknown Modbus function with code: %i", function_code)
     log.debug("With result %s", str(result))
     if "Exception" in str(result):
         log.exception(result)
     return result
示例#8
0
 def on_attributes_update(self, content):
     try:
         log.debug('Recieved Attribute Update Request: %r', str(content))
         for device in self.__devices:
             if device["deviceName"] == content["device"]:
                 for request in device["attribute_updates"]:
                     if request["config"].get("requestType") is not None:
                         for attribute in content["data"]:
                             if attribute == request["key"]:
                                 request["iocb"][1]["config"].update({
                                     "propertyValue":
                                     content["data"][attribute]
                                 })
                                 kwargs = request["iocb"][1]
                                 iocb = request["iocb"][0](device, **kwargs)
                                 self.__request_functions[
                                     request["config"]["requestType"]](iocb)
                                 return
                     else:
                         log.error(
                             "\"requestType\" not found in request configuration for key %s device: %s",
                             request.get("key", "[KEY IS EMPTY]"),
                             device["deviceName"])
     except Exception as e:
         log.exception(e)
示例#9
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 self.__devices_around[device]['services'][service].get(
                 characteristic_uuid_from_config.upper()) is None:
             continue
         characteristic = self.__devices_around[device]['services'][
             service][characteristic_uuid_from_config]['characteristic']
         self.__check_and_reconnect(device)
         data = None
         if characteristic_processing_conf.get(
                 'method', '_').upper().split()[0] == "READ":
             if characteristic.supportsRead():
                 self.__check_and_reconnect(device)
                 data = characteristic.read()
                 log.debug(data)
             else:
                 log.error(
                     'This characteristic doesn\'t support "READ" method.')
         if characteristic_processing_conf.get(
                 'method', '_').upper().split()[0] == "NOTIFY":
             self.__check_and_reconnect(device)
             descriptor = characteristic.getDescriptors(forUUID=0x2902)[0]
             handle = descriptor.handle
             if self.__notify_delegators.get(device) is None:
                 self.__notify_delegators[device] = {}
             if self.__notify_delegators[device].get(handle) is None:
                 self.__notify_delegators[device][handle] = {
                     'function':
                     self.__notify_handler,
                     'args': (self.__devices_around[device], handle,
                              self.__notify_delegators[device].get(handle)),
                     'delegate':
                     None
                 }
                 self.__notify_delegators[device][handle][
                     'delegate'] = self.__notify_delegators[device][handle][
                         'function'](*self.__notify_delegators[device]
                                     [handle]['args'])
                 data = self.__notify_delegators[device][handle][
                     'delegate'].data
             else:
                 self.__notify_delegators[device][handle]['args'] = (
                     self.__devices_around[device], handle,
                     self.__notify_delegators[device][handle]['delegate'])
                 self.__notify_delegators[device][handle][
                     'delegate'] = self.__notify_delegators[device][handle][
                         'function'](*self.__notify_delegators[device]
                                     [handle]['args'])
                 data = self.__notify_delegators[device][handle][
                     'delegate'].data
         if data is None:
             log.error('Cannot process characteristic: %s with config:\n%s',
                       str(characteristic.uuid).upper(),
                       pformat(characteristic_processing_conf))
         else:
             log.debug('data: %s', data)
         return data
示例#10
0
 def __save_iterator_config(self):
     try:
         Path(self.__config_dir).mkdir(exist_ok=True)
         with Path(self.__config_dir +
                   self.__iterator_file_name).open("w") as iterator_file:
             iterator_file.write(
                 dumps(self.__iterator, indent=2, sort_keys=True))
         log.debug("[%s] Saved iterator configuration to %s",
                   self.get_name(), self.__iterator_file_name)
     except Exception as e:
         log.error("[%s] Failed to save iterator configuration to %s: %s",
                   self.get_name(), self.__iterator_file_name, str(e))
示例#11
0
    def server_side_rpc_handler(self, content):
        try:
            rpc_method = content["data"].get("method")
            for method in self.__available_object_resources[
                    content["device"]]['methods']:
                if rpc_method is not None and method.get(
                        rpc_method) is not None:
                    arguments_from_config = method["arguments"]
                    arguments = content["data"].get(
                        "params") if content["data"].get(
                            "params") is not None else arguments_from_config
                    try:
                        if isinstance(arguments, list):
                            result = method["node"].call_method(
                                method[rpc_method], *arguments)
                        elif arguments is not None:
                            try:
                                result = method["node"].call_method(
                                    method[rpc_method], arguments)
                            except ua.UaStatusCodeError as e:
                                if "BadTypeMismatch" in str(e) and isinstance(
                                        arguments, int):
                                    result = method["node"].call_method(
                                        method[rpc_method], float(arguments))
                        else:
                            result = method["node"].call_method(
                                method[rpc_method])

                        self.__gateway.send_rpc_reply(
                            content["device"], content["data"]["id"], {
                                content["data"]["method"]: result,
                                "code": 200
                            })
                        log.debug("method %s result is: %s",
                                  method[rpc_method], result)
                    except Exception as e:
                        log.exception(e)
                        self.__gateway.send_rpc_reply(content["device"],
                                                      content["data"]["id"], {
                                                          "error": str(e),
                                                          "code": 500
                                                      })
                else:
                    log.error("Method %s not found for device %s", rpc_method,
                              content["device"])
                    self.__gateway.send_rpc_reply(
                        content["device"], content["data"]["id"], {
                            "error": "%s - Method not found" % (rpc_method),
                            "code": 404
                        })
        except Exception as e:
            log.exception(e)
示例#12
0
    def __init_iterator(self):
        save_iterator = self.DEFAULT_SAVE_ITERATOR
        if "persistent" not in self.__config["polling"]["iterator"]:
            self.__config["polling"]["iterator"]["persistent"] = save_iterator
        else:
            save_iterator = self.__config["polling"]["iterator"]["persistent"]

        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.warning("[%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
示例#13
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)
                if isinstance(
                        self.__devices[
                            server_rpc_request[DEVICE_SECTION_PARAMETER]]
                    [CONFIG_SECTION_PARAMETER][RPC_SECTION], dict):
                    rpc_command_config = self.__devices[
                        server_rpc_request[DEVICE_SECTION_PARAMETER]][
                            CONFIG_SECTION_PARAMETER][RPC_SECTION].get(
                                server_rpc_request[DATA_PARAMETER]
                                [RPC_METHOD_PARAMETER])
                    if rpc_command_config is not None:
                        self.__process_rpc_request(server_rpc_request,
                                                   rpc_command_config)
                elif isinstance(
                        self.__devices[
                            server_rpc_request[DEVICE_SECTION_PARAMETER]]
                    [CONFIG_SECTION_PARAMETER][RPC_SECTION], list):
                    for rpc_command_config in self.__devices[
                            server_rpc_request[DEVICE_SECTION_PARAMETER]][
                                CONFIG_SECTION_PARAMETER][RPC_SECTION]:
                        if rpc_command_config[
                                TAG_PARAMETER] == server_rpc_request[
                                    DATA_PARAMETER][RPC_METHOD_PARAMETER]:
                            self.__process_rpc_request(server_rpc_request,
                                                       rpc_command_config)
                            break
                else:
                    log.error(
                        "Received rpc request, but method %s not found in config for %s.",
                        server_rpc_request[DATA_PARAMETER].get(
                            RPC_METHOD_PARAMETER), self.get_name())
                    self.__gateway.send_rpc_reply(
                        server_rpc_request[DEVICE_SECTION_PARAMETER],
                        server_rpc_request[DATA_PARAMETER][RPC_ID_PARAMETER], {
                            server_rpc_request[DATA_PARAMETER][RPC_METHOD_PARAMETER]:
                            "METHOD NOT FOUND!"
                        })
            else:
                log.debug("Received RPC to connector: %r", server_rpc_request)
        except Exception as e:
            log.exception(e)
示例#14
0
 def __load_converters(self, connector_type):    # Function for search a converter and save it.
     devices_config = self.__config.get('devices')
     try:
         if devices_config is not None:
             for device_config in devices_config:
                 if device_config.get('converter') is not None:
                     converter = TBModuleLoader.import_module(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)
示例#15
0
 def form_iocb(device, config=None, request_type="readProperty"):
     config = config if config is not None else device
     address = device["address"] if isinstance(
         device["address"], Address) else Address(device["address"])
     object_id = ObjectIdentifier(config["objectId"])
     property_id = config.get("propertyId")
     value = config.get("propertyValue")
     property_index = config.get("propertyIndex")
     priority = config.get("priority")
     vendor = device.get("vendor", config.get("vendorId", 0))
     request = None
     iocb = None
     if request_type == "readProperty":
         try:
             request = ReadPropertyRequest(objectIdentifier=object_id,
                                           propertyIdentifier=property_id)
             request.pduDestination = address
             if property_index is not None:
                 request.propertyArrayIndex = int(property_index)
             iocb = IOCB(request)
         except Exception as e:
             log.exception(e)
     elif request_type == "writeProperty":
         datatype = get_datatype(object_id.value[0], property_id, vendor)
         if (isinstance(value, str)
                 and value.lower() == 'null') or value is None:
             value = Null()
         request = WritePropertyRequest(objectIdentifier=object_id,
                                        propertyIdentifier=property_id)
         request.pduDestination = address
         request.propertyValue = Any()
         try:
             value = datatype(value)
             request.propertyValue = Any(value)
         except AttributeError as e:
             log.debug(e)
         except Exception as error:
             log.exception("WriteProperty cast error: %r", error)
         if property_index is not None:
             request.propertyArrayIndex = property_index
         if priority is not None:
             request.priority = priority
         iocb = IOCB(request)
     else:
         log.error("Request type is not found or not implemented")
     return iocb
示例#16
0
 def server_side_rpc_handler(self, content):
     try:
         log.debug('Recieved RPC Request: %r', str(content))
         for device in self.__devices:
             if device["deviceName"] == content["device"]:
                 method_found = False
                 for request in device["server_side_rpc"]:
                     if request["config"].get("requestType") is not None:
                         if content["data"]["method"] == request["method"]:
                             method_found = True
                             kwargs = request["iocb"][1]
                             timeout = time() * 1000 + request[
                                 "config"].get("requestTimeout", 200)
                             if content["data"].get("params") is not None:
                                 kwargs["config"].update({
                                     "propertyValue":
                                     content["data"]["params"]
                                 })
                             iocb = request["iocb"][0](device, **kwargs)
                             self.__request_functions[
                                 request["config"]["requestType"]](
                                     device=iocb,
                                     callback=self.__rpc_response_cb)
                             self.rpc_requests_in_progress[iocb] = {
                                 "content": content,
                                 "uplink_converter":
                                 request["uplink_converter"]
                             }
                             # self.__gateway.register_rpc_request_timeout(content,
                             #                                             timeout,
                             #                                             iocb,
                             #                                             self.__rpc_cancel_processing)
                     else:
                         log.error(
                             "\"requestType\" not found in request configuration for key %s device: %s",
                             request.get("key", "[KEY IS EMPTY]"),
                             device["deviceName"])
                 if not method_found:
                     log.error("RPC method %s not found in configuration",
                               content["data"]["method"])
                     self.__gateway.send_rpc_reply(content["device"],
                                                   content["data"]["id"],
                                                   success_sent=False)
     except Exception as e:
         log.exception(e)
示例#17
0
    def __init_connection(self):
        try:
            log.debug("[%s] Opening connection to database", self.get_name())
            connection_config = self.__config["connection"]
            self.__connection = pyodbc.connect(
                connection_config["str"],
                **connection_config.get("attributes", {}))
            if connection_config.get("encoding", ""):
                log.info("[%s] Setting encoding to %s", self.get_name(),
                         connection_config["encoding"])
                self.__connection.setencoding(connection_config["encoding"])

            decoding_config = connection_config.get("decoding")
            if decoding_config is not None:
                if isinstance(decoding_config, dict):
                    if decoding_config.get("char", ""):
                        log.info("[%s] Setting SQL_CHAR decoding to %s",
                                 self.get_name(), decoding_config["char"])
                        self.__connection.setdecoding(pyodbc.SQL_CHAR,
                                                      decoding_config["char"])
                    if decoding_config.get("wchar", ""):
                        log.info("[%s] Setting SQL_WCHAR decoding to %s",
                                 self.get_name(), decoding_config["wchar"])
                        self.__connection.setdecoding(pyodbc.SQL_WCHAR,
                                                      decoding_config["wchar"])
                    if decoding_config.get("metadata", ""):
                        log.info("[%s] Setting SQL_WMETADATA decoding to %s",
                                 self.get_name(), decoding_config["metadata"])
                        self.__connection.setdecoding(
                            pyodbc.SQL_WMETADATA, decoding_config["metadata"])
                else:
                    log.warning(
                        "[%s] Unknown decoding configuration %s. Read data may be misdecoded",
                        self.get_name(), decoding_config)

            self.__cursor = self.__connection.cursor()
            log.info("[%s] Connection to database opened, attributes %s",
                     self.get_name(), connection_config.get("attributes", {}))
        except pyodbc.Error as e:
            log.error("[%s] Failed to connect to database: %s",
                      self.get_name(), str(e))
            self.__close()

        return self.is_connected()
示例#18
0
 def on_attributes_update(self, content):
     log.debug(content)
     for device in self.__devices_around:
         if self.__devices_around[device]['device_config'].get(
                 'name') == content['device']:
             for requests in self.__devices_around[device]['device_config'][
                     "attributeUpdates"]:
                 for service in self.__devices_around[device]['services']:
                     if requests[
                             'characteristicUUID'] in self.__devices_around[
                                 device]['services'][service]:
                         characteristic = self.__devices_around[device][
                             'services'][service][requests[
                                 'characteristicUUID']]['characteristic']
                         if 'WRITE' in characteristic.propertiesToString():
                             if content['data'].get(
                                     requests['attributeOnThingsBoard']
                             ) is not None:
                                 try:
                                     self.__check_and_reconnect(device)
                                     content_to_write = content['data'][
                                         requests[
                                             'attributeOnThingsBoard']].encode(
                                                 'UTF-8')
                                     characteristic.write(
                                         content_to_write, True)
                                 except BTLEDisconnectError:
                                     self.__check_and_reconnect(device)
                                     content_to_write = content['data'][
                                         requests[
                                             'attributeOnThingsBoard']].encode(
                                                 'UTF-8')
                                     characteristic.write(
                                         content_to_write, True)
                                 except Exception as e:
                                     log.exception(e)
                         else:
                             log.error(
                                 'Cannot process attribute update request for device: %s with data: %s and config: %s',
                                 device, content,
                                 self.__devices_around[device]
                                 ['device_config']["attributeUpdates"])
示例#19
0
 def __scan_ble(self):
     log.debug("Scanning for devices...")
     try:
         self.__scanner.scan(self.__config.get('scanTimeSeconds', 5),
                             passive=self.__config.get(
                                 'passiveScanMode', False))
     except BTLEManagementError as e:
         log.error('BLE working only with root user.')
         log.error(
             'Or you can try this command:\nsudo setcap '
             '\'cap_net_raw,cap_net_admin+eip\' %s'
             '\n====== Attention! ====== '
             '\nCommand above - provided access to ble devices to any user.'
             '\n========================',
             str(bluepy_path[0] + '/bluepy-helper'))
         self._connected = False
         raise e
     except Exception as e:
         log.exception(e)
         time.sleep(10)
示例#20
0
 def __process_data(self, device):
     common_parameters = self.__get_common_parameters(device)
     converted_data = {}
     for datatype in self.__datatypes:
         for datatype_config in device[datatype]:
             try:
                 response = None
                 method = datatype_config.get("method")
                 if method is None:
                     log.error("Method not found in configuration: %r",
                               datatype_config)
                     continue
                 else:
                     method = method.lower()
                 if method not in self.__methods:
                     log.error("Unknown method: %s, configuration is: %r",
                               method, datatype_config)
                 response = self.__process_methods(method,
                                                   common_parameters,
                                                   datatype_config)
                 converted_data.update(
                     **device["uplink_converter"].convert((
                         datatype, datatype_config), response))
             except SNMPTimeoutException:
                 log.error(
                     "Timeout exception on connection to device \"%s\" with ip: \"%s\"",
                     device["deviceName"], device["ip"])
                 return
             except Exception as e:
                 log.exception(e)
             if isinstance(converted_data,
                           dict) and (converted_data.get("attributes")
                                      or converted_data.get("telemetry")):
                 self.collect_statistic_and_send(self.get_name(),
                                                 converted_data)
示例#21
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 FuturesTimeoutError:
                         self.__check_connection()
                     except Exception as e:
                         log.exception(e)
             log.debug(self.__interest_nodes)
     except Exception as e:
         log.exception(e)
示例#22
0
 def __save_methods(self, device_info):
     try:
         if self.__available_object_resources.get(
                 device_info["deviceName"]) is None:
             self.__available_object_resources[
                 device_info["deviceName"]] = {}
         if self.__available_object_resources[
                 device_info["deviceName"]].get("methods") is None:
             self.__available_object_resources[
                 device_info["deviceName"]]["methods"] = []
         if device_info["configuration"].get("rpc_methods", []):
             node = device_info["deviceNode"]
             for method_object in device_info["configuration"][
                     "rpc_methods"]:
                 method_node_path = self._check_path(
                     method_object["method"], node)
                 methods = []
                 self.__search_node(node,
                                    method_node_path,
                                    True,
                                    result=methods)
                 for method in methods:
                     if method is not None:
                         node_method_name = method.get_display_name().Text
                         self.__available_object_resources[
                             device_info["deviceName"]]["methods"].append({
                                 node_method_name:
                                 method,
                                 "node":
                                 node,
                                 "arguments":
                                 method_object.get("arguments")
                             })
                     else:
                         log.error(
                             "Node for method with path %s - NOT FOUND!",
                             method_node_path)
     except Exception as e:
         log.exception(e)
示例#23
0
 def __rpc_response_cb(self, iocb, callback_params=None):
     device = self.rpc_requests_in_progress[iocb]
     converter = device["uplink_converter"]
     content = device["content"]
     if iocb.ioResponse:
         apdu = iocb.ioResponse
         log.debug("Received callback with Response: %r", apdu)
         converted_data = converter.convert(None, apdu)
         if converted_data is None:
             converted_data = {"success": True}
         self.__gateway.send_rpc_reply(content["device"],
                                       content["data"]["id"],
                                       converted_data)
         # self.__gateway.rpc_with_reply_processing(iocb, converted_data or {"success": True})
     elif iocb.ioError:
         log.exception("Received callback with Error: %r", iocb.ioError)
         data = {"error": str(iocb.ioError)}
         self.__gateway.send_rpc_reply(content["device"],
                                       content["data"]["id"], data)
         log.debug(iocb.ioError)
     else:
         log.error("Received unknown RPC response callback from device: %r",
                   iocb)
示例#24
0
    def __load_iterator_config(self):
        if not self.__iterator_file_name:
            if not self.__resolve_iterator_file():
                log.error(
                    "[%s] Unable to load iterator configuration from file: file name is not resolved",
                    self.get_name())
                return False

        try:
            iterator_file_path = Path(self.__config_dir +
                                      self.__iterator_file_name)
            if not iterator_file_path.exists():
                return False

            with iterator_file_path.open("r") as iterator_file:
                self.__iterator = load(iterator_file)
            log.debug("[%s] Loaded iterator configuration from %s",
                      self.get_name(), self.__iterator_file_name)
        except Exception as e:
            log.error("[%s] Failed to load iterator configuration from %s: %s",
                      self.get_name(), self.__iterator_file_name, str(e))

        return bool(self.__iterator)
示例#25
0
 def load_handlers(self):
     data_handlers = {
         "basic": BasicDataHandler,
         "anonymous": AnonymousDataHandler,
     }
     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'])
             self._api.add_resource(
                 data_handlers[security_type],
                 mapping['endpoint'],
                 endpoint=mapping['endpoint'],
                 resource_class_args=(self.collect_statistic_and_send,
                                      self.get_name(),
                                      self.endpoints[mapping["endpoint"]]))
         except Exception as e:
             log.error("Error on creating handlers - %s", str(e))
示例#26
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())
示例#27
0
 def __search_nodes_and_subscribe(self, device_info):
     sub_nodes = []
     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:
                     try:
                         information_value = information_node.get_value()
                     except:
                         log.error("Err get_value: %s",
                                   str(information_node))
                         continue
                     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 = TBModuleLoader.import_module(
                                 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'] = self.statistics[
                         'MessagesReceived'] + 1
                     self.data_to_send.append(converted_data)
                     self.statistics['MessagesSent'] = self.statistics[
                         'MessagesSent'] + 1
                     log.debug("Data to ThingsBoard: %s", converted_data)
                     if not self.__server_conf.get("disableSubscriptions",
                                                   False):
                         sub_nodes.append(information_node)
                 else:
                     log.error(
                         "Node for %s \"%s\" with path %s - NOT FOUND!",
                         information_type, information_key,
                         information_path)
     if not self.__server_conf.get("disableSubscriptions", False):
         if self.__sub is None:
             self.__sub = self.client.create_subscription(
                 self.__server_conf.get("subCheckPeriodInMillis", 500),
                 self.__sub_handler)
         if sub_nodes:
             self.__sub.subscribe_data_change(sub_nodes)
             log.debug("Added subscription to nodes: %s", str(sub_nodes))
示例#28
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('\\\\.', '.')
             #current_node_path = '\\.'.join(char.split(":")[1] for char in current_node.get_path(200000, True))
             current_node_path = self.get_node_path(current_node)
             # we are allways the parent
             child_node_parent_class = current_node.get_node_class()
             new_parent = current_node
             for child_node in current_node.get_children():
                 new_node_class = child_node.get_node_class()
                 # this will not change you can do it outside th loop
                 # 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))
                 new_node_path = self.get_node_path(child_node)
                 if child_node_parent_class == ua.NodeClass.View and new_parent is not None:
                     parent_path = self.get_node_path(new_parent)
                     #parent_path = '\\.'.join(char.split(":")[1] for char in new_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)
示例#29
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)
                     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
示例#30
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"):
            self.__opcua_url = "opc.tcp://" + self.__server_conf.get("url")
        else:
            self.__opcua_url = self.__server_conf.get("url")
        self.client = Client(
            self.__opcua_url,
            timeout=self.__server_conf.get("timeoutInMillis", 4000) / 1000)
        if self.__server_conf["identity"].get("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 RuntimeError(
                        "Error in ssl configuration - cert or privateKey parameter not found"
                    )
                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.__sub = None
        self.__sub_handler = SubHandler(self)
        self.data_to_send = []
        self.__stopped = False
        self.__connected = False
        self.daemon = True