Пример #1
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
Пример #2
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]
Пример #3
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"])
Пример #4
0
 def __initialize_client(self):
     self.__opcua_nodes["root"] = self.client.get_objects_node()
     self.__opcua_nodes["objects"] = self.client.get_objects_node()
     self.scan_nodes_from_config()
     self.__previous_scan_time = time.time() * 1000
     log.debug('Subscriptions: %s', self.subscribed)
     log.debug("Available methods: %s", self.__available_object_resources)
Пример #5
0
 def on_attributes_update(self, content):
     try:
         for attribute_request in self.__attribute_updates:
             if fullmatch(attribute_request["deviceNameFilter"], content["device"]) and \
                     fullmatch(attribute_request["attributeFilter"], list(content["data"].keys())[0]):
                 converted_data = attribute_request[
                     "downlink_converter"].convert(attribute_request,
                                                   content)
                 response_queue = Queue(1)
                 request_dict = {
                     "config": {
                         **attribute_request,
                         **converted_data
                     },
                     "request": regular_request
                 }
                 with self._app.test_request_context():
                     attribute_update_request_thread = Thread(
                         target=self.__send_request,
                         args=(request_dict, response_queue, log),
                         daemon=True,
                         name="Attribute request to %s" %
                         (converted_data["url"]))
                     attribute_update_request_thread.start()
                     attribute_update_request_thread.join()
                 if not response_queue.empty():
                     response = response_queue.get_nowait()
                     log.debug(response)
                 del response_queue
     except Exception as e:
         log.exception(e)
Пример #6
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)
Пример #7
0
    def __check_and_send(self, device_name, device_type, new_data):
        self.statistics['MessagesReceived'] += 1
        to_send = {"attributes": [], "telemetry": []}
        send_on_change = self.__config["mapping"].get(
            "sendDataOnlyOnChange", self.DEFAULT_SEND_IF_CHANGED)

        for tb_key in to_send.keys():
            for key, new_value in new_data[tb_key].items():
                if not send_on_change or self.__devices[device_name][
                        tb_key].get(key, None) != new_value:
                    self.__devices[device_name][tb_key][key] = new_value
                    to_send[tb_key].append({key: new_value})

        if to_send["attributes"] or to_send["telemetry"]:
            to_send["deviceName"] = device_name
            to_send["deviceType"] = device_type

            log.debug("[%s] Pushing to TB server '%s' device data: %s",
                      self.get_name(), device_name, to_send)

            self.__gateway.send_to_storage(self.get_name(), to_send)
            self.statistics['MessagesSent'] += 1
        else:
            log.debug("[%s] '%s' device data has not been changed",
                      self.get_name(), device_name)
Пример #8
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
Пример #9
0
 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)
Пример #10
0
 def device_add(self, device):
     for interested_device in self.__devices_around:
         if device.addr.upper(
         ) == interested_device and self.__devices_around[
                 interested_device].get('scanned_device') is None:
             self.__devices_around[interested_device][
                 'scanned_device'] = device
             self.__devices_around[interested_device][
                 'is_new_device'] = True
         log.debug('Device with address: %s - found.', device.addr.upper())
Пример #11
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))
Пример #12
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)
Пример #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 run(self):
        while True:
            if time.time(
            ) - self.__previous_scan_time >= self.__rescan_time != 0:
                self.__scan_ble()
                self.__previous_scan_time = time.time()

            if time.time(
            ) - self.__previous_read_time >= self.__check_interval_seconds:
                self.__get_services_and_chars()
                self.__previous_read_time = time.time()

            time.sleep(.1)
            if self.__stopped:
                log.debug('STOPPED')
                break
Пример #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 __on_mapping_response_cb(self, iocb: IOCB):
     try:
         if self.requests_in_progress.get(iocb) is not None:
             log.debug(iocb)
             log.debug(self.requests_in_progress[iocb])
             if iocb.ioResponse:
                 apdu = iocb.ioResponse
                 value = self.__property_value_from_apdu(apdu)
                 callback_params = self.requests_in_progress[iocb]
                 if callback_params.get("callback") is not None:
                     self.__general_cb(iocb, callback_params, value)
             elif iocb.ioError:
                 log.exception(iocb.ioError)
     except Exception as e:
         log.exception(e)
     if self.requests_in_progress.get(iocb) is not None:
         del self.requests_in_progress[iocb]
Пример #17
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())
Пример #18
0
 def on_attributes_update(self, content):
     log.debug(content)
     try:
         for server_variables in self.__available_object_resources[
                 content["device"]]['variables']:
             for attribute in content["data"]:
                 for variable in server_variables:
                     if attribute == variable:
                         try:
                             server_variables[variable].set_value(
                                 content["data"][variable])
                         except Exception:
                             server_variables[variable].set_attribute(
                                 ua.AttributeIds.Value,
                                 ua.DataValue(content["data"][variable]))
     except Exception as e:
         log.exception(e)
Пример #19
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)
Пример #20
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()
Пример #21
0
    def server_side_rpc_handler(self, content):
        try:
            for rpc_request in self.__rpc_requests:
                if fullmatch(rpc_request["deviceNameFilter"], content["device"]) and \
                        fullmatch(rpc_request["methodFilter"], content["data"]["method"]):
                    converted_data = rpc_request["downlink_converter"].convert(
                        rpc_request, content)
                    response_queue = Queue(1)
                    request_dict = {
                        "config": {
                            **rpc_request,
                            **converted_data
                        },
                        "request": regular_request
                    }
                    request_dict["converter"] = request_dict["config"].get(
                        "uplink_converter")
                    with self._app.test_request_context():
                        from flask import request as flask_request
                        rpc_request_thread = Thread(
                            target=self.__send_request,
                            args=(request_dict, response_queue, log,
                                  flask_request),
                            daemon=True,
                            name="RPC request to %s" % (converted_data["url"]))
                        rpc_request_thread.start()
                        rpc_request_thread.join()
                    if not response_queue.empty():
                        response = response_queue.get_nowait()
                        log.debug(response)
                        self.__gateway.send_rpc_reply(
                            device=content["device"],
                            req_id=content["data"]["id"],
                            content=response[2])
                    else:
                        self.__gateway.send_rpc_reply(
                            device=content["device"],
                            req_id=content["data"]["id"],
                            success_sent=True)

                    del response_queue
        except Exception as e:
            log.exception(e)
Пример #22
0
 def datachange_notification(self, node, val, data):
     try:
         log.debug(
             "Python: New data change event on node %s, with val: %s and data %s",
             node, val, str(data))
         subscription = self.connector.subscribed[node]
         converted_data = subscription["converter"].convert(
             (subscription["config_path"], subscription["path"]), val)
         self.connector.statistics[
             'MessagesReceived'] = self.connector.statistics[
                 'MessagesReceived'] + 1
         self.connector.data_to_send.append(converted_data)
         self.connector.statistics[
             'MessagesSent'] = self.connector.statistics['MessagesSent'] + 1
         log.debug("[SUBSCRIPTION] Data to ThingsBoard: %s", converted_data)
     except KeyError:
         self.connector.scan_nodes_from_config()
     except Exception as e:
         log.exception(e)
Пример #23
0
    def __poll_and_schedule(self, data, config):
        if self.connector.is_stopped():
            return
        if self.events:
            self.events.pop(0)

        log.debug(
            "[%s] Sending periodic (%f sec) CAN message (arbitration_id=%d, data=%s)",
            self.connector.get_name(), config["period"], config["nodeId"],
            data)
        self.connector.send_data_to_bus(data,
                                        config,
                                        raise_exception=self.first_run)

        event = self.scheduler.enter(config["period"],
                                     1,
                                     self.__poll_and_schedule,
                                     argument=(data, config))
        self.events.append(event)
Пример #24
0
 def indication(self, apdu: APDU):
     if isinstance(apdu, IAmRequest):
         log.debug(
             "Received IAmRequest from device with ID: %i and address %s:%i",
             apdu.iAmDeviceIdentifier[1], apdu.pduSource.addrTuple[0],
             apdu.pduSource.addrTuple[1])
         log.debug(apdu.pduSource)
         request = ReadPropertyRequest(
             destination=apdu.pduSource,
             objectIdentifier=apdu.iAmDeviceIdentifier,
             propertyIdentifier='objectName',
         )
         iocb = IOCB(request)
         deferred(self.request_io, iocb)
         iocb.add_callback(self.__iam_cb, vendor_id=apdu.vendorID)
         self.requests_in_progress.update(
             {iocb: {
                 "callback": self.__iam_cb
             }})
Пример #25
0
 def __new_device_processing(self, device):
     default_services_on_device = [
         service
         for service in self.__devices_around[device]['services'].keys()
         if int(service.split('-')[0], 16) in self.__default_services
     ]
     log.debug('Default services found on device %s :%s', device,
               default_services_on_device)
     converter = BytesBLEUplinkConverter(
         self.__devices_around[device]['device_config'])
     converted_data = None
     for service in default_services_on_device:
         characteristics = [
             char for char in self.__devices_around[device]['services']
             [service].keys() if self.__devices_around[device]['services']
             [service][char]['characteristic'].supportsRead()
         ]
         for char in characteristics:
             read_config = {
                 'characteristicUUID': char,
                 'method': 'READ',
             }
             try:
                 self.__check_and_reconnect(device)
                 data = self.__service_processing(device, read_config)
                 attribute = capitaliseName(UUID(char).getCommonName())
                 read_config['key'] = attribute
                 read_config['byteFrom'] = 0
                 read_config['byteTo'] = -1
                 converter_config = [{
                     "type": "attributes",
                     "clean": False,
                     "section_config": read_config
                 }]
                 for interest_information in converter_config:
                     try:
                         converted_data = converter.convert(
                             interest_information, data)
                         self.statistics[
                             'MessagesReceived'] = self.statistics[
                                 'MessagesReceived'] + 1
                         log.debug(converted_data)
                     except Exception as e:
                         log.debug(e)
             except Exception as e:
                 log.debug('Cannot process %s', e)
                 continue
     if converted_data is not None:
         # self.__gateway.add_device(converted_data["deviceName"], {"connector": self})
         self.__gateway.send_to_storage(self.get_name(), converted_data)
         self.statistics[
             'MessagesSent'] = self.statistics['MessagesSent'] + 1
Пример #26
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"])
Пример #27
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)
Пример #28
0
 def __iam_cb(self, iocb: IOCB, vendor_id=None):
     if iocb.ioResponse:
         apdu = iocb.ioResponse
         log.debug("Received IAm Response: %s", str(apdu))
         if self.discovered_devices.get(apdu.pduSource) is None:
             self.discovered_devices[apdu.pduSource] = {}
         value = self.__connector.default_converters["uplink_converter"](
             "{}").convert(None, apdu)
         log.debug("Property: %s is %s", apdu.propertyIdentifier, value)
         self.discovered_devices[apdu.pduSource].update(
             {apdu.propertyIdentifier: value})
         data_to_connector = {
             "address": apdu.pduSource,
             "objectId": apdu.objectIdentifier,
             "name": value,
             "vendor": vendor_id if vendor_id is not None else 0
         }
         self.__connector.add_device(data_to_connector)
     elif iocb.ioError:
         log.exception(iocb.ioError)
Пример #29
0
    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.get_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.warning("[%s] Failed to resolve iterator file name: %s",
                        self.get_name(), str(e))
        return bool(self.__iterator_file_name)
Пример #30
0
    def __notify_handler(self, device, notify_handle, delegate=None):
        class NotifyDelegate(DefaultDelegate):
            def __init__(self):
                DefaultDelegate.__init__(self)
                self.device = device
                self.data = {}

            def handleNotification(self, handle, data):
                self.data = data
                log.debug(
                    'Notification received from device %s handle: %i, data: %s',
                    self.device, handle, data)

        if delegate is None:
            delegate = NotifyDelegate()
        device['peripheral'].withDelegate(delegate)
        device['peripheral'].writeCharacteristic(notify_handle, b'\x01\x00',
                                                 True)
        if device['peripheral'].waitForNotifications(1):
            log.debug("Data received from notification: %s", delegate.data)
        return delegate