Example #1
0
    def server_side_rpc_handler(self, content):
        try:
            if content.get("device") is not None:

                log.debug("Modbus connector received rpc request for %s with content: %s", content["device"], content)
                if isinstance(self.__devices[content["device"]]["config"]["rpc"], dict):
                    rpc_command_config = self.__devices[content["device"]]["config"]["rpc"].get(content["data"]["method"])
                    if rpc_command_config is not None:
                        self.__process_rpc_request(content, rpc_command_config)
                elif isinstance(self.__devices[content["device"]]["config"]["rpc"], list):
                    for rpc_command_config in self.__devices[content["device"]]["config"]["rpc"]:
                        if rpc_command_config["tag"] == content["data"]["method"]:
                            self.__process_rpc_request(content, rpc_command_config)
                            break
                else:
                    log.error("Received rpc request, but method %s not found in config for %s.",
                              content["data"].get("method"),
                              self.get_name())
                    self.__gateway.send_rpc_reply(content["device"],
                                                  content["data"]["id"],
                                                  {content["data"]["method"]: "METHOD NOT FOUND!"})
            else:
                log.debug("Received RPC to connector: %r", content)
        except Exception as e:
            log.exception(e)
Example #2
0
 def __function_to_device(self, config, unit_id):
     function_code = config.get('functionCode')
     result = None
     if function_code in (1, 2, 3, 4):
         result = self.__available_functions[function_code](config["address"],
                                                            config.get("objectsCount", config.get("registersCount",  config.get("registerCount", 1))),
                                                            unit=unit_id)
     elif function_code in (5, 6, 15, 16):
         result = self.__available_functions[function_code](config["address"],
                                                            config["payload"],
                                                            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)
         result = str(result)
     return result
Example #3
0
    def convert(self, config, data):
        self.__result["telemetry"] = []
        self.__result["attributes"] = []
        for config_data in data:
            if self.__result.get(config_data) is None:
                self.__result[config_data] = []
            for tag in data[config_data]:
                log.debug(tag)
                data_sent = data[config_data][tag]["data_sent"]
                input_data = data[config_data][tag]["input_data"]
                log.debug("Called convert function from %s with args",
                          self.__class__.__name__)
                log.debug(data_sent)
                log.debug(input_data)
                result = None
                if data_sent.get("functionCode") == 1 or data_sent.get(
                        "functionCode") == 2:
                    result = input_data.bits
                    log.debug(result)
                    if "registerCount" in data_sent:
                        result = result[:data_sent["registerCount"]]
                    else:
                        result = result[0]
                elif data_sent.get("functionCode") == 3 or data_sent.get(
                        "functionCode") == 4:
                    result = input_data.registers
                    byte_order = data_sent.get("byteOrder", "LITTLE")
                    reg_count = data_sent.get("registerCount", 1)
                    type_of_data = data_sent["type"]
                    try:
                        if byte_order == "LITTLE":
                            decoder = BinaryPayloadDecoder.fromRegisters(
                                result, byteorder=Endian.Little)
                        elif byte_order == "BIG":
                            decoder = BinaryPayloadDecoder.fromRegisters(
                                result, byteorder=Endian.Big)
                        else:
                            log.warning("byte order is not BIG or LITTLE")
                            continue
                    except Exception as e:
                        log.error(e)
                    if type_of_data == "string":
                        result = decoder.decode_string(2 * reg_count)
                    elif type_of_data == "long":
                        if reg_count == 1:
                            result = decoder.decode_16bit_int()
                        elif reg_count == 2:
                            result = decoder.decode_32bit_int()
                        elif reg_count == 4:
                            result = decoder.decode_64bit_int()
                        else:
                            log.warning(
                                "unsupported register count for long data type in response for tag %s",
                                data_sent["tag"])
                            continue
                    elif type_of_data == "double":
                        if reg_count == 2:
                            result = decoder.decode_32bit_float()
                        elif reg_count == 4:
                            result = decoder.decode_64bit_float()
                        else:
                            log.warning(
                                "unsupported register count for double data type in response for tag %s",
                                data_sent["tag"])
                            continue
                    elif type_of_data == "bit":
                        if "bit" in data_sent:
                            if type(result) == list:
                                if len(result) > 1:
                                    log.warning(
                                        "with bit parameter only one register is expected, got more then one in response for tag %s",
                                        data_sent["tag"])
                                    continue
                                result = result[0]
                            position = 15 - data_sent["bit"]  # reverse order
                            # transform result to string representation of a bit sequence, add "0" to make it longer >16
                            result = "0000000000000000" + str(bin(result)[2:])
                            # get length of 16, then get bit, then cast it to int(0||1 from "0"||"1", then cast to boolean)
                            result = bool(
                                int((result[len(result) - 16:])[15 -
                                                                position]))
                        else:
                            log.error(
                                "Bit address not found in config for modbus connector for tag: %s",
                                data_sent["tag"])

                    else:
                        log.warning(
                            "unknown data type, not string, long or double in response for tag %s",
                            data_sent["tag"])
                        continue
                try:
                    self.__result[config_data].append({tag: int(result)})
                except ValueError:
                    self.__result[config_data].append({tag: int(result, 16)})
        self.__result["telemetry"] = self.__result.pop("timeseries")
        log.debug(self.__result)
        return self.__result
Example #4
0
    def convert(self, config, data):
        byte_order_str = config.get("byteOrder", "LITTLE")
        byte_order = Endian.Big if byte_order_str.upper(
        ) == "BIG" else Endian.Little
        builder = BinaryPayloadBuilder(byteorder=byte_order)
        builder_functions = {
            "string": builder.add_string,
            "bits": builder.add_bits,
            "8int": builder.add_8bit_int,
            "16int": builder.add_16bit_int,
            "32int": builder.add_32bit_int,
            "64int": builder.add_64bit_int,
            "8uint": builder.add_8bit_uint,
            "16uint": builder.add_16bit_uint,
            "32uint": builder.add_32bit_uint,
            "64uint": builder.add_64bit_uint,
            "16float": builder.add_16bit_float,
            "32float": builder.add_32bit_float,
            "64float": builder.add_64bit_float
        }
        value = None
        if data.get("data") and data["data"].get("params") is not None:
            value = data["data"]["params"]
        else:
            value = config["value"]
        lower_type = config.get("type", config.get("tag", "error")).lower()
        if lower_type == "error":
            log.error('"type" and "tag" - not found in configuration.')
        variable_size = config.get("registerCount", 1) * 8
        if lower_type in ["integer", "dword", "dword/integer", "word", "int"]:
            lower_type = str(variable_size) + "int"
            assert builder_functions.get(lower_type) is not None
            builder_functions[lower_type](value)
        elif lower_type in [
                "uint", "unsigned", "unsigned integer", "unsigned int"
        ]:
            lower_type = str(variable_size) + "uint"
            assert builder_functions.get(lower_type) is not None
            builder_functions[lower_type](value)
        elif lower_type in ["float", "double"]:
            lower_type = str(variable_size) + "float"
            assert builder_functions.get(lower_type) is not None
            builder_functions[lower_type](value)
        elif lower_type in ["coil", "bits"]:
            assert builder_functions.get("bits") is not None
            builder_functions["bits"](value)
        elif lower_type in ["string"]:
            assert builder_functions.get("string") is not None
            builder_functions[lower_type](value)
        elif lower_type in ["bit"]:
            bits = [0 for _ in range(8)]
            bits[config["bit"] - 1] = int(value)
            log.debug(bits)
            builder.add_bits(bits)
            return builder.to_string()
        else:
            log.error("Unknown variable type")

        builder_converting_functions = {
            5: builder.to_coils,
            15: builder.to_coils,
            6: builder.to_registers,
            16: builder.to_registers
        }

        function_code = config["functionCode"]

        if function_code in builder_converting_functions:
            builder = builder_converting_functions[function_code]()
            if "Exception" in str(builder):
                log.exception(builder)
                builder = str(builder)
            return builder
        log.warning(
            "Unsupported function code, for the device %s in the Modbus Downlink converter",
            config["device"])
        return None
Example #5
0
    def __decode_from_registers(decoder, configuration):
        type_ = configuration["type"]
        registers_count = configuration.get("registerCount", 1)
        lower_type = type_.lower()

        decoder_functions = {
            'string': decoder.decode_string,
            'bit': decoder.decode_bits,
            'bits': decoder.decode_bits,
            '8int': decoder.decode_8bit_int,
            '8uint': decoder.decode_8bit_uint,
            '16int': decoder.decode_16bit_int,
            '16uint': decoder.decode_16bit_uint,
            '16float': decoder.decode_16bit_float,
            '32int': decoder.decode_32bit_int,
            '32uint': decoder.decode_32bit_uint,
            '32float': decoder.decode_32bit_float,
            '64int': decoder.decode_64bit_int,
            '64uint': decoder.decode_64bit_uint,
            '64float': decoder.decode_64bit_float,
        }

        decoded = None
        if lower_type in ['int', 'long', 'integer']:
            type_ = str(registers_count * 16) + "int"
            assert decoder_functions.get(type_) is not None
            decoded = decoder_functions[type_]()

        elif lower_type in ["double", "float"]:
            type_ = str(registers_count * 16) + "float"
            assert decoder_functions.get(type_) is not None
            decoded = decoder_functions[type_]()

        elif lower_type == 'uint':
            type_ = str(registers_count * 16) + "uint"
            assert decoder_functions.get(type_) is not None
            decoded = decoder_functions[type_]()

        elif lower_type == "string":
            decoded = decoder_functions[type_](registers_count * 2)

        elif lower_type == 'bit':
            bit_address = configuration["bit"]
            decoded = decoder_functions[type_]()[bit_address]

        elif lower_type == 'bits':
            decoded = decoder_functions[type_]()

        elif decoder_functions.get(lower_type) is not None:
            decoded = decoder_functions[lower_type]()

        else:
            log.error("Unknown type: %s", type_)

        if isinstance(decoded, int):
            result_data = decoded
        elif isinstance(decoded, bytes):
            result_data = decoded.decode('UTF-8')
        elif isinstance(decoded, list):
            result_data = str(decoded)
        elif isinstance(decoded, float):
            result_data = decoded
        elif decoded is not None:
            result_data = int(decoded, 16)
        else:
            result_data = decoded

        return result_data
Example #6
0
    def convert(self, config, data):
        byte_order_str = config.get("byteOrder", "LITTLE")
        word_order_str = config.get("wordOrder", "LITTLE")
        byte_order = Endian.Big if byte_order_str.upper(
        ) == "BIG" else Endian.Little
        word_order = Endian.Big if word_order_str.upper(
        ) == "BIG" else Endian.Little
        repack = config.get("repack", False)
        builder = BinaryPayloadBuilder(byteorder=byte_order,
                                       wordorder=word_order,
                                       repack=repack)
        builder_functions = {
            "string": builder.add_string,
            "bits": builder.add_bits,
            "8int": builder.add_8bit_int,
            "16int": builder.add_16bit_int,
            "32int": builder.add_32bit_int,
            "64int": builder.add_64bit_int,
            "8uint": builder.add_8bit_uint,
            "16uint": builder.add_16bit_uint,
            "32uint": builder.add_32bit_uint,
            "64uint": builder.add_64bit_uint,
            "16float": builder.add_16bit_float,
            "32float": builder.add_32bit_float,
            "64float": builder.add_64bit_float
        }
        value = None
        if data.get("data") and data["data"].get("params") is not None:
            value = data["data"]["params"]
        else:
            value = config.get("value", 0)

        lower_type = config.get("type", config.get("tag", "error")).lower()

        if lower_type == "error":
            log.error('"type" and "tag" - not found in configuration.')
        variable_size = config.get(
            "objectsCount",
            config.get("registersCount", config.get("registerCount", 1))) * 16

        if lower_type in ["integer", "dword", "dword/integer", "word", "int"]:
            lower_type = str(variable_size) + "int"
            assert builder_functions.get(lower_type) is not None
            builder_functions[lower_type](int(value))
        elif lower_type in [
                "uint", "unsigned", "unsigned integer", "unsigned int"
        ]:
            lower_type = str(variable_size) + "uint"
            assert builder_functions.get(lower_type) is not None
            builder_functions[lower_type](int(value))
        elif lower_type in ["float", "double"]:
            lower_type = str(variable_size) + "float"
            assert builder_functions.get(lower_type) is not None
            builder_functions[lower_type](float(value))
        elif lower_type in ["coil", "bits", "coils", "bit"]:
            assert builder_functions.get("bits") is not None
            if variable_size / 8 > 1.0:
                builder_functions["bits"](bytes(value, encoding='UTF-8')) if isinstance(value, str) else \
                    builder_functions["bits"](bytes(value))
            else:
                return bytes(int(value))
        elif lower_type in ["string"]:
            assert builder_functions.get("string") is not None
            builder_functions[lower_type](value)
        elif lower_type in builder_functions and 'int' in lower_type:
            builder_functions[lower_type](int(value))
        elif lower_type in builder_functions and 'float' in lower_type:
            builder_functions[lower_type](float(value))
        elif lower_type in builder_functions:
            builder_functions[lower_type](value)
        else:
            log.error("Unknown variable type")

        builder_converting_functions = {
            5: builder.to_coils,
            15: builder.to_coils,
            6: builder.to_registers,
            16: builder.to_registers
        }

        function_code = config["functionCode"]

        if function_code in builder_converting_functions:
            builder = builder_converting_functions[function_code]()
            log.debug(builder)
            if "Exception" in str(builder):
                log.exception(builder)
                builder = str(builder)
            if variable_size <= 16:
                if isinstance(builder,
                              list) and len(builder) not in (8, 16, 32, 64):
                    builder = builder[0]
            else:
                if isinstance(builder, list) and len(builder) not in (2, 4):
                    log.warning(
                        "There is a problem with the value builder. Only the first register is written."
                    )
                    builder = builder[0]
            return builder
        log.warning(
            "Unsupported function code, for the device %s in the Modbus Downlink converter",
            config["device"])
        return None
    def __decode_from_registers(decoder, configuration):
        type_ = configuration["type"]
        objects_count = configuration.get(
            "objectsCount",
            configuration.get("registersCount",
                              configuration.get("registerCount", 1)))
        lower_type = type_.lower()

        decoder_functions = {
            'string': decoder.decode_string,
            'bytes': decoder.decode_string,
            'bit': decoder.decode_bits,
            'bits': decoder.decode_bits,
            '8int': decoder.decode_8bit_int,
            '8uint': decoder.decode_8bit_uint,
            '16int': decoder.decode_16bit_int,
            '16uint': decoder.decode_16bit_uint,
            '16float': decoder.decode_16bit_float,
            '32int': decoder.decode_32bit_int,
            '32uint': decoder.decode_32bit_uint,
            '32float': decoder.decode_32bit_float,
            '64int': decoder.decode_64bit_int,
            '64uint': decoder.decode_64bit_uint,
            '64float': decoder.decode_64bit_float,
        }

        decoded = None

        if lower_type == "string":
            decoded = decoder_functions[type_](objects_count * 2)

        elif lower_type == "bytes":
            decoded = decoder_functions[type_](size=objects_count * 2)

        elif decoder_functions.get(lower_type) is not None:
            decoded = decoder_functions[lower_type]()

        elif lower_type in ['int', 'long', 'integer']:
            type_ = str(objects_count * 16) + "int"
            assert decoder_functions.get(type_) is not None
            decoded = decoder_functions[type_]()

        elif lower_type in ["double", "float"]:
            type_ = str(objects_count * 16) + "float"
            assert decoder_functions.get(type_) is not None
            decoded = decoder_functions[type_]()

        elif lower_type == 'uint':
            type_ = str(objects_count * 16) + "uint"
            assert decoder_functions.get(type_) is not None
            decoded = decoder_functions[type_]()

        else:
            log.error("Unknown type: %s", type_)

        if isinstance(decoded, int):
            result_data = decoded
        elif isinstance(decoded, bytes) and lower_type == "string":
            result_data = decoded.decode('UTF-8')
        elif isinstance(decoded, bytes) and lower_type == "bytes":
            result_data = decoded.hex()
        elif isinstance(decoded, list):
            if configuration.get('bit') is not None:
                result_data = int(decoded[configuration['bit']])
            else:
                result_data = [int(bit) for bit in decoded]
        elif isinstance(decoded, float):
            result_data = decoded
        elif decoded is not None:
            result_data = int(decoded, 16)
        else:
            result_data = decoded

        return result_data
Example #8
0
    def __process_devices(self):
        for device in self.__devices:
            current_time = time.time()
            device_responses = {"timeseries": {},
                                "attributes": {},
                                }
            to_send = {}
            try:
                for config_data in device_responses:
                    #log.info(config_data)
                    if self.__devices[device]["config"].get(config_data) is not None:
                        unit_id = self.__devices[device]["config"]["unitId"]
                        if self.__devices[device]["next_"+config_data+"_check"] < current_time:
                            self.__connect_to_current_master(device)
                            #  Reading data from device
                            for interested_data in range(len(self.__devices[device]["config"][config_data])):
                                current_data = self.__devices[device]["config"][config_data][interested_data]
                                current_data["deviceName"] = device
                                input_data = self.__function_to_device(current_data, unit_id)
                                # if not isinstance(input_data, ReadRegistersResponseBase) and input_data.isError():
                                #     log.exception(input_data)
                                #     continue
                                device_responses[config_data][current_data["tag"]] = {"data_sent": current_data,
                                                                                      "input_data": input_data}

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

                            if converted_data and self.__devices[device]["config"].get("sendDataOnlyOnChange"):
                                self.statistics['MessagesReceived'] += 1
                                to_send = {"deviceName": converted_data["deviceName"], "deviceType": converted_data["deviceType"]}
                                if to_send.get("telemetry") is None:
                                    to_send["telemetry"] = []
                                if to_send.get("attributes") is None:
                                    to_send["attributes"] = []
                                for telemetry_dict in converted_data["telemetry"]:
                                    for key, value in telemetry_dict.items():
                                        if self.__devices[device]["last_telemetry"].get(key) is None or \
                                           self.__devices[device]["last_telemetry"][key] != value:
                                            self.__devices[device]["last_telemetry"][key] = value
                                            to_send["telemetry"].append({key: value})
                                for attribute_dict in converted_data["attributes"]:
                                    for key, value in attribute_dict.items():
                                        if self.__devices[device]["last_attributes"].get(key) is None or \
                                           self.__devices[device]["last_attributes"][key] != value:
                                            self.__devices[device]["last_attributes"][key] = value
                                            to_send["attributes"].append({key: value})
                                        # to_send["telemetry"] = converted_data["telemetry"]
                                # if converted_data["attributes"] != self.__devices[device]["attributes"]:
                                    # self.__devices[device]["last_attributes"] = converted_data["attributes"]
                                    # to_send["attributes"] = converted_data["attributes"]
                                if not to_send.get("attributes") and not to_send.get("telemetry"):
                                    # self.__gateway.send_to_storage(self.get_name(), to_send)
                                    # self.statistics['MessagesSent'] += 1
                                    log.debug("Data has not been changed.")
                            elif converted_data and self.__devices[device]["config"].get("sendDataOnlyOnChange") is None or not self.__devices[device]["config"].get("sendDataOnlyOnChange"):
                                self.statistics['MessagesReceived'] += 1
                                to_send = {"deviceName": converted_data["deviceName"],
                                           "deviceType": converted_data["deviceType"]}
                                # if converted_data["telemetry"] != self.__devices[device]["telemetry"]:
                                self.__devices[device]["last_telemetry"] = converted_data["telemetry"]
                                to_send["telemetry"] = converted_data["telemetry"]
                                # if converted_data["attributes"] != self.__devices[device]["attributes"]:
                                self.__devices[device]["last_attributes"] = converted_data["attributes"]
                                to_send["attributes"] = converted_data["attributes"]
                                # self.__gateway.send_to_storage(self.get_name(), to_send)
                                # self.statistics['MessagesSent'] += 1
                #log.info(to_send)
                # 数据添加到存储队列?
                if to_send.get("attributes") or to_send.get("telemetry"):
                    self.__gateway.send_to_storage(self.get_name(), to_send)
                    self.statistics['MessagesSent'] += 1
            except ConnectionException:
                time.sleep(5)
                log.error("Connection lost! Reconnecting...")
            except Exception as e:
                log.exception(e)