Browse Source

+ Completed minimal functionality to nbus revision 2

DLIMIKO 11 months ago
parent
commit
8e6beb3c22

+ 1 - 1
.idea/nbus_api.iml

@@ -4,7 +4,7 @@
     <content url="file://$MODULE_DIR$">
     <content url="file://$MODULE_DIR$">
       <excludeFolder url="file://$MODULE_DIR$/im" />
       <excludeFolder url="file://$MODULE_DIR$/im" />
     </content>
     </content>
-    <orderEntry type="inheritedJdk" />
+    <orderEntry type="jdk" jdkName="Python 3.9 (nbus_api)" jdkType="Python SDK" />
     <orderEntry type="sourceFolder" forTests="false" />
     <orderEntry type="sourceFolder" forTests="false" />
   </component>
   </component>
   <component name="PackageRequirementsSettings">
   <component name="PackageRequirementsSettings">

+ 73 - 63
main.py

@@ -1,9 +1,8 @@
 from nbus_hal.nbus_serial.serial_port import *
 from nbus_hal.nbus_serial.serial_port import *
-from nbus_api.nbus_slave_module import NBusSlaveModule
-from nbus_api.nbus_slave_device import NBusSlaveDevice
+from nbus_api.nbus_module_slave import NBusSlaveModule
 from nbus_hal.nbus_serial.serial_config import *
 from nbus_hal.nbus_serial.serial_config import *
-from nbus_types.nbus_data_fomat import NBusDataValue
-from nbus_types.nbus_parameter_type import NBusParameterID, NBusParameterValue
+from nbus_sensor_drivers.generic_sensor_driver import NBusGenericSensor
+from nbus_types.nbus_parameter_type import NBusParameterID
 
 
 # example config
 # example config
 config = {
 config = {
@@ -15,65 +14,76 @@ config = {
     "enable_log": False
     "enable_log": False
 }
 }
 
 
-
-class DummySlave(NBusSlaveDevice):
-    def data_parameters_loaded(self) -> bool:
-        return True
-
-    def map_parameter_get(self, param_id: NBusParameterID, param_value: int) -> NBusParameterValue:
-        return param_value
-
-    def map_parameter_set(self, param_id: NBusParameterID, param_value: NBusParameterValue) -> int:
-        return param_value
-
-    def map_data_get(self, values: list[int]) -> list[NBusDataValue]:
-        return values
-
-    def map_data_set(self, values: list[NBusDataValue]) -> list[int]:
-        return values
-
-
 if __name__ == "__main__":
 if __name__ == "__main__":
-
-    try:
-
-        port = NBusSerialPort(NBusSerialConfig(**config))
-
-        module = NBusSlaveModule(port, 5)
-
-        module.add_device(DummySlave(1))
-        module.add_device(DummySlave(2))
-        module.add_device(DummySlave(3))
-        module.add_device(DummySlave(4))
-        module.add_device(DummySlave(5))
-        module.add_device(DummySlave(129))
-        module.add_device(DummySlave(130))
-
-        # test module get
-        print("CMD GET ECHO: ", module.cmd_get_echo(bytearray("Hello world!", "ascii")))
-        print("CMD GET PARAM SAMPLERATE: ", module.cmd_get_param(NBusParameterID.PARAM_SAMPLERATE))
-        print("CMD GET ALL PARAMS: ", module.cmd_get_all_params())
-        print("CMD GET SENSOR COUNT: ", module.cmd_get_sensor_cnt())
-        print("CMD GET SENSOR TYPE: ", module.cmd_get_sensor_type())
-        print("CMD GET INFO: ", module.cmd_get_info())
-        print("CMD GET SENSOR FORMAT: ", module.cmd_get_format())
-        print("CMD GET SENSOR DATA: ", module.cmd_get_data())
-
-
-       # print("ALL PARAMS: ", sensing_element.cmd_get_all_params())
-        #print("PARAM GAIN: ", sensing_element.cmd_get_param(NBusParameterID.PARAM_GAIN))
-       # print("SENSOR TYPE: ", sensing_element.cmd_get_sensor_type())
-       # print("SENSOR FORMAT: ", sensing_element.cmd_get_info(NBusInfoParam.INFO_FORMAT))
-        #print("DATA: ", sensing_element.cmd_get_data())
-
-        #print(module.cmd_get_format())
-       # print(sensing_element.cmd_get_data())
-        #print(sensing_element.cmd_set_data([129, 1]))
-        #print(sensing_element.cmd_get_data())
-
+    # create port
+    port = NBusSerialPort(NBusSerialConfig(**config))
+
+    # create module
+    module = NBusSlaveModule(port, 5)
+
+    # assemble module
+    module.add_sensor(NBusGenericSensor(1))
+    module.add_sensor(NBusGenericSensor(2))
+    module.add_sensor(NBusGenericSensor(3))
+    module.add_sensor(NBusGenericSensor(4))
+    module.add_sensor(NBusGenericSensor(5))
+    module.add_sensor(NBusGenericSensor(129))
+    module.add_sensor(NBusGenericSensor(130))
+
+    # get sensors
+    accelerometer = module.get_sensor(1)
+    led = module.get_sensor(129)
+
+    # test module get
+    print("<<TEST MODULE GET>>")
+    print("CMD GET ECHO: ", module.cmd_get_echo(bytearray("Hello world!", "ascii")))
+    print("CMD GET PARAM SAMPLERATE: ", module.cmd_get_param(NBusParameterID.PARAM_SAMPLERATE))
+    print("CMD GET ALL PARAMS: ", module.cmd_get_all_params())
+    print("CMD GET SENSOR COUNT: ", module.cmd_get_sensor_cnt())
+    print("CMD GET SENSOR TYPE: ", module.cmd_get_sensor_type())
+    print("CMD GET INFO: ", module.cmd_get_info())
+    print("CMD GET SENSOR FORMAT: ", module.cmd_get_format())
+    print("CMD GET SENSOR DATA: ", module.cmd_get_data())
+
+    # test module set
+    print("\n<<TEST MODULE SET>>")
+    print("CMD SET STOP: ", module.cmd_set_module_stop())
+    print("CMD SET START: ", module.cmd_set_module_start())
+
+    print("CMD SET PARAM SAMPLERATE: ", module.cmd_set_param(NBusParameterID.PARAM_SAMPLERATE, 12345))
+    print("CMD GET PARAM SAMPLERATE: ", module.cmd_get_param(NBusParameterID.PARAM_SAMPLERATE))
+
+    params = {NBusParameterID.PARAM_RANGE: 12, NBusParameterID.PARAM_RANGE0: 4234}
+    print("CMD SET MULTI PARAMS: ", module.cmd_set_multi_params(params))
+    print("CMD GET ALL PARAMS: ", module.cmd_get_all_params())
+
+    print("CMD SET CALIBRATE: ", module.cmd_set_calibrate())
+
+    data = {129: [1], 130: [10, -32]}
+    print("CMD SET DATA: ", module.cmd_set_data(data))
+    print("CMD GET SENSOR DATA: ", module.cmd_get_data())
+
+    # test sensor get
+    print("\n<<TEST SENSOR GET>>")
+    print("CMD GET PARAM SAMPLERATE: ", accelerometer.cmd_get_param(NBusParameterID.PARAM_SAMPLERATE))
+    print("CMD GET ALL PARAMS: ", accelerometer.cmd_get_all_params())
+    print("CMD GET SENSOR TYPE: ", accelerometer.cmd_get_sensor_type())
+    print("CMD GET SENSOR FORMAT: ", accelerometer.cmd_get_format())
+    print("CMD GET SENSOR DATA: ", accelerometer.cmd_get_data())
+
+    # test sensor set
+    print("\n<<TEST SENSOR SET>>")
+    print("CMD SET FIND: ", led.cmd_set_find(True))
+    print("CMD SET PARAM SAMPLERATE: ", led.cmd_set_param(NBusParameterID.PARAM_SAMPLERATE, 23456))
+    print("CMD GET PARAM SAMPLERATE: ", led.cmd_get_param(NBusParameterID.PARAM_SAMPLERATE))
+
+    params = {NBusParameterID.PARAM_RANGE: 12, NBusParameterID.PARAM_RANGE0: 4234}
+    print("CMD SET MULTI PARAMS: ", led.cmd_set_multi_params(params))
+    print("CMD GET ALL PARAMS: ", led.cmd_get_all_params())
+
+    print("CMD SET CALIBRATE: ", led.cmd_set_calibrate())
+
+    print("CMD SET DATA: ", led.cmd_set_data([1]))
+    print("CMD GET SENSOR DATA: ", led.cmd_get_data())
 
 
 
 
-    except Exception as Ex:
-        print("Error")
-        print(str(Ex))
-        print(Ex.args)

+ 71 - 34
nbus_api/nbus_common_parser.py

@@ -1,13 +1,12 @@
 import struct
 import struct
-from typing import Tuple, Any
+from typing import Tuple
 from nbus_types.nbus_data_fomat import NBusDataFormat, NBusDataValue
 from nbus_types.nbus_data_fomat import NBusDataFormat, NBusDataValue
-from nbus_types.nbus_exceptions.nbus_api_exception import NBusErrorAPI, NBusErrorAPIType
 from nbus_types.nbus_parameter_type import NBusParameterID, NBusParameterValue
 from nbus_types.nbus_parameter_type import NBusParameterID, NBusParameterValue
 
 
 
 
 class NbusCommonParser:
 class NbusCommonParser:
     """
     """
-    Class for common parsers for both device and module.
+    Static class for common parsers for both device and module.
     These methods should be called from the inside of API modules.
     These methods should be called from the inside of API modules.
     """
     """
 
 
@@ -39,59 +38,97 @@ class NbusCommonParser:
                               byte_length=byte_len, samples=samples)
                               byte_length=byte_len, samples=samples)
 
 
     @staticmethod
     @staticmethod
-    def data_from_response(nbus_device: Any, response: list[int]) -> Tuple[list[NBusDataValue], int]:
+    def parameters_from_response(resp_len: int, response: list[int]) \
+            -> list[Tuple[NBusParameterID, NBusParameterValue]]:
+        """
+        Parse multiple parameters from response.
+        :param resp_len: response length in bytes
+        :param response: response from nBus
+        :return: list of (parameter id, parameter value)
+        """
+        offset = 0  # response offset
+        params = []
+        while offset < resp_len:  # parse all params
+            new_offset = offset + 5
+
+            # get param id and type
+            param_id, *param_value = response[offset:new_offset]
+            param_type = NBusParameterID(param_id)
+
+            param_raw_value = struct.unpack("<I", bytearray(param_value))[0]  # get single raw value from bytes
+            params.append((param_type, param_raw_value))
+            offset = new_offset
+
+        return params
+
+    @staticmethod
+    def data_from_response(data_format: NBusDataFormat, response: list[int]) -> Tuple[list[NBusDataValue], int]:
         """
         """
         Parse data from response.
         Parse data from response.
-        :param nbus_device: device to parse for
+        :param data_format: format of data
         :param response: response from NBus
         :param response: response from NBus
         :return: parsed data and length of parsed data in bytes
         :return: parsed data and length of parsed data in bytes
         """
         """
-        if nbus_device.data_format is None:  # check for format and params
-            raise NBusErrorAPI(NBusErrorAPIType.FORMAT_NOT_LOADED, nbus_device)
-        if not nbus_device.data_parameters_loaded():
-            raise NBusErrorAPI(NBusErrorAPIType.PARAMS_NOT_LOADED, nbus_device)
-
         # variables for 2's complement
         # variables for 2's complement
-        max_uint = 1 << (nbus_device.data_format.byte_length << 3)
+        max_uint = 1 << (data_format.byte_length << 3)
         half_max_uint = max_uint >> 1
         half_max_uint = max_uint >> 1
 
 
         values = []
         values = []
 
 
-        for s in range(nbus_device.data_format.samples):
+        for s in range(data_format.samples):
             value = 0
             value = 0
-            for i in range(nbus_device.data_format.byte_length):
-                value |= response[(i + 1) + (nbus_device.data_format.byte_length * s)] << (i << 3)
+            for i in range(data_format.byte_length):
+                value |= response[(i + 1) + (data_format.byte_length * s)] << (i << 3)
                 # compose value little endian
                 # compose value little endian
 
 
-            if nbus_device.data_format.sign == 1 and value >= half_max_uint:  # convert 2's complement
+            if data_format.sign == 1 and value >= half_max_uint:  # convert 2's complement
                 value -= max_uint
                 value -= max_uint
 
 
-            value *= 10 ** nbus_device.data_format.value_multiplier  # scale number
+            value *= 10 ** data_format.value_multiplier  # scale number
 
 
             values.append(value)  # append number to list
             values.append(value)  # append number to list
 
 
-        return nbus_device.map_data_get(values), nbus_device.data_format.samples * nbus_device.data_format.byte_length
+        return values, data_format.samples * data_format.byte_length
 
 
     @staticmethod
     @staticmethod
-    def parameters_from_response(resp_len: int, response: list[int]) \
-            -> list[Tuple[NBusParameterID, NBusParameterValue]]:
+    def parameters_to_request(params: dict[NBusParameterID, NBusParameterValue]) -> bytearray:
         """
         """
-        Parse multiple parameters from response.
-        :param resp_len: response length in bytes
-        :param response: response from nBus
-        :return: list of (parameter id, parameter value)
+        Create request from parameters dictionary.
+        :param params: parameter dict
+        :return: parameter bytearray
         """
         """
-        offset = 0  # response offset
-        params = []
-        while offset < resp_len:  # parse all params
-            new_offset = offset + 5
+        param_bytes = bytearray()
 
 
-            # get param id and type
-            param_id, *param_value = response[offset:new_offset]
-            param_type = NBusParameterID(param_id)
+        for p_id in params.keys():
+            param_id_raw = struct.pack("B", p_id.value)
+            param_val_raw = struct.pack("<I", params[p_id])
+            param_bytes += bytearray(param_id_raw) + bytearray(param_val_raw)
 
 
-            param_raw_value = struct.unpack("<I", bytearray(param_value))[0]  # get single raw value from bytes
-            params.append((param_type, param_raw_value))
-            offset = new_offset
+        return param_bytes
 
 
-        return params
+    @staticmethod
+    def data_to_request(data_format: NBusDataFormat, data: list[NBusDataValue]) -> list[int]:
+        """
+        Parse data to request format.
+        :param data_format: format of data
+        :param data: data values
+        :return: request bytes
+        """
+        # variables for 2's complement
+        max_uint = 1 << (data_format.byte_length << 3)
+
+        request = []
+
+        for value in data:
+            # Reverse scaling
+            value = int(value / (10 ** data_format.value_multiplier))
+
+            # Handle 2's complement for signed values
+            if data_format.sign == 1 and value < 0:
+                value += max_uint
+
+            # Break the value into bytes (little-endian)
+            for i in range(data_format.byte_length):
+                request.append((value >> (i << 3)) & 0xFF)
+
+        return request

+ 358 - 0
nbus_api/nbus_module_slave.py

@@ -0,0 +1,358 @@
+import struct
+from nbus_api.nbus_sensor import NBusSensor
+from nbus_api.nbus_common_parser import NbusCommonParser
+from nbus_hal.nbus_serial.serial_port import *
+from nbus_types.nbus_address_type import NBusModuleAddress
+from nbus_types.nbus_data_fomat import NBusDataValue, NBusDataFormat
+from nbus_types.nbus_exceptions.nbus_api_exception import NBusErrorAPI, NBusErrorAPIType
+from nbus_types.nbus_parameter_type import NBusParameterID, NBusParameterValue
+from nbus_types.nbus_status_type import NBusStatusType
+from nbus_types.nbus_sensor_count_type import NBusSensorCount
+from nbus_types.nbus_info_type import NBusInfo
+from nbus_types.nbus_sensor_type import NBusSensorType
+
+
+@beartype
+class NBusSlaveModule:
+    """
+    Class representing nBus slave module.
+    """
+
+    def __init__(self, serial_port: NBusSerialPort, module_address: NBusModuleAddress):
+        """
+        Constructor.
+
+        :param serial_port: serial port
+        :param module_address: address of module
+        """
+        self.__port = serial_port
+        self.__module_addr = module_address
+        self.__params = {}
+        self.__devices = {}
+        self._map_param_get = lambda t, v: v    # dummy implementation
+        self._map_param_set = lambda t, v: v    # dummy implementation
+
+    """
+    ================================================================================================================
+                                                Module General Methods
+    ================================================================================================================
+    """
+
+    def set_module_parameter_mappers(self, map_param_get_cb: Callable[[NBusParameterID, NBusParameterValue], int],
+                                     map_param_set_cb: Callable[[NBusParameterID, int], NBusParameterValue]) -> None:
+        """
+        Set parameter mappers for module.
+
+        :param map_param_get_cb: callback for map param get
+        :param map_param_set_cb: callback for map param set
+        """
+        self._map_param_get = map_param_get_cb
+        self._map_param_set = map_param_set_cb
+
+    def add_sensor(self, sensor: NBusSensor) -> None:
+        """
+        Add sensor to container.
+
+        :param sensor: nbus sensor
+        """
+        sensor.set_parent_module_address(self.__module_addr)
+        sensor.set_device_port(self.__port)
+        self.__devices[sensor.address] = sensor
+
+    def get_sensor(self, sensor_address: NBusSensorAddress) -> NBusSensor:
+        """
+        Get module sensor.
+
+        :param sensor_address: address of sensor
+
+        :return: sensor
+        """
+        return self.__devices[sensor_address]
+
+    """
+    ================================================================================================================
+                                                Module Get Commands
+    ================================================================================================================
+    """
+    def cmd_get_echo(self, message: bytearray) -> bool:
+        """
+        Get echo from module.
+
+        :param message: message to send
+        :return: status (True = echo, False = no echo)
+        """
+        _, *response = self.__port.request_module(self.__module_addr, NBusCommand.CMD_GET_ECHO, message)
+        return response == list(message)
+
+    def cmd_get_param(self, parameter: NBusParameterID) -> NBusParameterValue:
+        """
+        Get single module parameter.
+
+        :param parameter: parameter id
+        :return: parameter value
+        """
+        # get response
+        resp_len, *response = self.__port.request_module(self.__module_addr, NBusCommand.CMD_GET_PARAM,
+                                                         bytearray([parameter.value]))
+
+        # parse parameter
+        param_id, param_val_raw = NbusCommonParser.parameters_from_response(resp_len, response)[0]
+        param_val = self._map_param_get(param_id, param_val_raw)
+
+        # store parameter value
+        self.__params[param_id] = param_val
+
+        return param_val
+
+    def cmd_get_all_params(self) -> dict[NBusParameterID, NBusParameterValue]:
+        """
+        Get all module parameters.
+
+        :return: dict of parameter id and parameter value
+        """
+
+        # get response
+        resp_len, *response = self.__port.request_module(self.__module_addr, NBusCommand.CMD_GET_PARAM, bytearray([]))
+
+        # parse parameters
+        params_raw = NbusCommonParser.parameters_from_response(resp_len, response)
+
+        for param_id, param_val_raw in params_raw:
+            param_val = self._map_param_get(param_id, param_val_raw)
+
+            # store parameters
+            self.__params[param_id] = param_val
+
+        return self.__params.copy()
+
+    def cmd_get_sensor_cnt(self) -> NBusSensorCount:
+        """
+        Get sensor count.
+
+        :return: count of read-only and read-write sensors
+        """
+        _, *response = self.__port.request_module(self.__module_addr, NBusCommand.CMD_GET_SENSOR_CNT, bytearray([]))
+        return NBusSensorCount(*response)
+
+    def cmd_get_data(self) -> dict[NBusSensorAddress, list[NBusDataValue]]:
+        """
+        Get data from all module sensors.
+
+        :return: dict of device addresses and data values
+        """
+
+        # get data
+        resp_length, *response = self.__port.request_module(self.__module_addr, NBusCommand.CMD_GET_DATA, bytearray([]))
+
+        # parse data
+        begin_idx = 0
+        data = {}
+
+        while begin_idx < resp_length:
+            device_id = response[begin_idx]
+
+            # handle errors
+            if self.__devices[device_id].data_format is None:  # check for format and params
+                raise NBusErrorAPI(NBusErrorAPIType.FORMAT_NOT_LOADED)
+            if not self.__devices[device_id].data_parameters_loaded():
+                raise NBusErrorAPI(NBusErrorAPIType.PARAMS_NOT_LOADED)
+
+            values, offset = NbusCommonParser.data_from_response(self.__devices[device_id].data_format,
+                                                                 response[begin_idx:])
+            data[device_id] = self.__devices[device_id].map_data_get(values)
+            begin_idx += offset + 1
+
+        return data
+
+    def cmd_get_info(self) -> NBusInfo:
+        """
+        Get module info.
+
+        :return: module info
+        """
+
+        response = self.__port.request_module(self.__module_addr, NBusCommand.CMD_GET_INFO, bytearray([]))
+
+        name = str(response[1:9], "ascii")
+        typ = str(response[9:12], "ascii")
+        uuid = struct.unpack("<I", bytearray(response[12:16]))[0]
+        hw = str(response[16:19], "ascii")
+        fw = str(response[19:22], "ascii")
+        mem_id = struct.unpack("<Q", bytearray(response[22:30]))[0]
+        ro_count = int(response[30])
+        rw_count = int(response[31])
+
+        return NBusInfo(module_name=name, module_type=typ, uuid=uuid, hw=hw, fw=fw, memory_id=mem_id,
+                        read_only_sensors=ro_count, read_write_sensors=rw_count)
+
+    def cmd_get_format(self) -> dict[NBusSensorAddress, NBusDataFormat]:
+        """
+        Get format of all on-board sensors.
+
+        :return: dict of sensor addresses and sensor formats
+        """
+
+        # get response
+        resp_length, *response = self.__port.request_module(self.__module_addr, NBusCommand.CMD_GET_FORMAT,
+                                                            bytearray([]))
+        begin_idx = 0
+        formats = {}
+
+        # parse format
+        while begin_idx < resp_length:
+            device_id = response[begin_idx]
+            device_format = NbusCommonParser.format_from_response(response[begin_idx:begin_idx + 4])
+
+            self.__devices[device_id].data_format = device_format
+            formats[device_id] = device_format
+            begin_idx += 4
+
+        return formats
+
+    def cmd_get_sensor_type(self) -> dict[NBusSensorAddress, NBusSensorType]:
+        """
+        Get type of all on-board sensors.
+
+        :return: dict of sensor addresses and sensor types
+        """
+        # get response
+        resp_length, *response = self.__port.request_module(self.__module_addr, NBusCommand.CMD_GET_SENSOR_TYPE,
+                                                            bytearray([]))
+        # parse response
+        types = {}
+        i = 0
+
+        while i < resp_length - 1:
+            types[NBusSensorAddress(response[i])] = NBusSensorType(response[i + 1])
+            i += 2
+
+        return types
+
+    """
+    ================================================================================================================
+                                                Module Set Commands
+    ================================================================================================================
+    """
+    def cmd_set_module_stop(self) -> NBusStatusType:
+        """
+        Stop automatic measuring.
+
+        :return: status
+        """
+
+        _, *response = self.__port.request_module(self.__module_addr, NBusCommand.CMD_SET_STOP, bytearray([]))
+        return NBusStatusType(response[0])
+
+    def cmd_set_module_start(self) -> NBusStatusType:
+        """
+        Start automatic measuring.
+
+        :return: status
+        """
+        _, *response = self.__port.request_module(self.__module_addr, NBusCommand.CMD_SET_START, bytearray([]))
+        return NBusStatusType(response[0])
+
+    def cmd_set_param(self, param: NBusParameterID, value: NBusParameterValue) -> NBusStatusType:
+        """
+        Set module parameter.
+
+        :param param: parameter ID
+        :param value: parameter value
+        :return: status
+        """
+
+        # create request packet
+        param_id_raw = struct.pack("B", param.value)
+        param_val_raw = struct.pack("<I", self._map_param_set(param, value))
+        param_bytes = bytearray(param_id_raw) + bytearray(param_val_raw)
+
+        # proceed request
+        _, *response = self.__port.request_module(self.__module_addr, NBusCommand.CMD_SET_PARAM, param_bytes)
+
+        # if response is valid, store parameter
+        if response[0] == param.value and response[1] == NBusStatusType.STATUS_SUCCESS:
+            self.__params[param] = value
+
+        return NBusStatusType(response[1])
+
+    def cmd_set_multi_params(self, params: dict[NBusParameterID, NBusParameterValue]) \
+            -> dict[NBusParameterID, NBusStatusType]:
+        """
+        Set multiple module parameters.
+
+        :param params: parameters
+        :return: dict od statuses
+        """
+
+        # scale parameters
+        for p_id in params.keys():
+            params[p_id] = self._map_param_set(p_id, params[p_id])
+
+        # create request packet
+        param_bytes = NbusCommonParser.parameters_to_request(params)
+
+        # send request
+        resp_length, *response = self.__port.request_module(self.__module_addr, NBusCommand.CMD_SET_PARAM,
+                                                            bytearray(param_bytes))
+        # parse statuses
+        statuses = {}
+
+        for i in range(0, resp_length - 1, 2):
+            p_id = NBusParameterID(response[i])
+            if response[i+1] == NBusStatusType.STATUS_SUCCESS:
+                self.__params[p_id] = params[p_id]  # if success, store param
+
+            statuses[p_id] = NBusStatusType(response[i + 1])
+
+        return statuses
+
+    def cmd_set_calibrate(self) -> NBusStatusType:
+        """
+        Send calibration command.
+
+        :return: calibration status
+        """
+
+        resp_length, *response = self.__port.request_module(self.__module_addr,
+                                                            NBusCommand.CMD_SET_CALIBRATE, bytearray([]))
+        print(response)
+        return NBusStatusType(response[0])
+
+    def cmd_set_data(self, data: dict[NBusSensorAddress, list[NBusDataValue]]) \
+            -> dict[NBusSensorAddress, NBusStatusType]:
+        """
+        Set data to read-write sensors.
+
+        :param data:
+        :return: operation statuses
+        """
+
+        # create request packet
+        request = []
+
+        # transform data
+        for addr in data.keys():
+            # handle errors
+            if self.__devices[addr].data_format is None:  # check for format and params
+                raise NBusErrorAPI(NBusErrorAPIType.FORMAT_NOT_LOADED)
+            if not self.__devices[addr].data_parameters_loaded():
+                raise NBusErrorAPI(NBusErrorAPIType.PARAMS_NOT_LOADED)
+
+            raw_data = self.__devices[addr].map_data_set(data[addr])
+            request.append(addr)
+            request.extend(NbusCommonParser.data_to_request(self.__devices[addr].data_format, raw_data))
+
+        # send request
+        resp_length, *response = self.__port.request_module(self.__module_addr, NBusCommand.CMD_SET_DATA,
+                                                            bytearray(request))
+
+        # return response statuses
+        statuses = {}
+
+        for i in range(0, resp_length - 1, 2):
+            statuses[NBusSensorAddress(response[i])] = NBusStatusType(response[i + 1])
+
+        return statuses
+
+
+

+ 359 - 0
nbus_api/nbus_sensor.py

@@ -0,0 +1,359 @@
+import struct
+from abc import abstractmethod, ABCMeta
+from nbus_hal.nbus_generic_port import NBusPort
+from nbus_types.nbus_command_type import NBusCommand
+from nbus_types.nbus_data_fomat import *
+from nbus_types.nbus_exceptions.nbus_api_exception import NBusErrorAPI, NBusErrorAPIType
+from nbus_types.nbus_parameter_type import *
+from nbus_types.nbus_address_type import NBusSensorAddress, NBusModuleAddress
+from nbus_types.nbus_sensor_type import NBusSensorType
+from nbus_api.nbus_common_parser import NbusCommonParser
+from nbus_types.nbus_status_type import NBusStatusType
+
+
+@beartype
+class NBusSensor(metaclass=ABCMeta):
+    """
+    Class representing nBus sensor type.
+    """
+
+    def __init__(self, address: NBusSensorAddress):
+        """
+        Constructor.
+
+        :param address: device address
+        """
+        self.__address = address
+        self.__module_address = None
+        self.__port = None
+        self.__data_format = None
+        self.__params = {}
+
+    """
+    ================================================================================================================
+                                                    Public Fields
+    ================================================================================================================
+    """
+
+    @property
+    def address(self):
+        """
+        Get sensor address.
+
+        :return: sensor address
+        """
+        return self.__address
+
+    @property
+    def data_format(self):
+        """
+        Get data format.
+
+        :return: data format
+        """
+        return self.__data_format
+
+    @data_format.setter
+    def data_format(self, data_format: NBusDataFormat):
+        """
+        Set data format.
+
+        :param data_format: format of data
+        """
+        self.__data_format = data_format
+
+    @property
+    def parameters(self) -> dict[NBusParameterID, NBusParameterValue]:
+        """
+        Get parameters.
+
+        :return: parameters
+        """
+        return self.__params
+
+    @parameters.setter
+    def parameters(self, values: dict[NBusParameterID, NBusParameterValue]):
+        """
+        Set parameters.
+
+        :param values: values to set
+        """
+        self.__params = values
+
+    """
+    ================================================================================================================
+                                                    Module-only Methods
+    ================================================================================================================
+    """
+
+    def set_parent_module_address(self, address: NBusModuleAddress) -> None:
+        """
+        Set address of parent module.
+
+        :param address: module address
+        """
+        self.__module_address = address
+
+    def set_device_port(self, port: NBusPort) -> None:
+        """
+        Set device communication port.
+        :param port: communicaiton port
+        """
+        self.__port = port
+
+    """
+    ================================================================================================================
+                                                    Abstract Methods
+    ================================================================================================================
+    """
+
+    @abstractmethod
+    def data_parameters_loaded(self) -> bool:
+        """
+        Verify that all necessary parameters are loaded
+        before performing data get/set conversion.
+
+        :return: true if ready for conversion, otherwise False
+        """
+        pass
+
+    @abstractmethod
+    def map_parameter_get(self, param_id: NBusParameterID, param_value: int) -> NBusParameterValue:
+        """
+        Convert a parameter from cmd_get_param() to its engineering range.
+
+        :param param_id: the ID of the parameter
+        :param param_value: the value of the parameter in binary format
+        :return: the converted parameter value in engineering units
+        """
+        pass
+
+    @abstractmethod
+    def map_parameter_set(self, param_id: NBusParameterID, param_value: NBusParameterValue) -> int:
+        """
+        Convert a parameter to its binary range for cmd_set_data().
+
+        :param param_id: the ID of the parameter
+        :param param_value: the value of the parameter in engineering units
+        :return: the converted parameter value in binary format
+        """
+        pass
+
+    @abstractmethod
+    def map_data_get(self, values: list[int]) -> list[NBusDataValue]:
+        """
+        Convert data from cmd_get_data() to its engineering range.
+
+        :param values: a list of values in binary format to be converted
+        :return: a list of converted values in engineering units
+        """
+        pass
+
+    @abstractmethod
+    def map_data_set(self, values: list[NBusDataValue]) -> list[int]:
+        """
+        Convert data to its binary range for cmd_set_data().
+
+        :param values: a list of values in engineering range to be converted
+        :return: a list of converted values in binary format
+        """
+        pass
+
+    """
+    ================================================================================================================
+                                                    Device Get Commands
+    ================================================================================================================
+    """
+
+    def cmd_get_param(self, parameter: NBusParameterID) -> NBusParameterValue:
+        """
+        Get single sensor parameter.
+
+        :param parameter: parameter id
+        :return: parameter value
+        """
+        # get response
+        resp_len, *response = self.__port.request_sensor(self.__module_address, self.__address,
+                                                         NBusCommand.CMD_GET_PARAM, bytearray([parameter.value]))
+
+        # parse parameter
+        param_id, param_val_raw = NbusCommonParser.parameters_from_response(resp_len, response)[0]
+        param_val = self.map_parameter_get(param_id, param_val_raw)
+
+        # store parameter value
+        self.__params[param_id] = param_val
+
+        return param_val
+
+    def cmd_get_all_params(self) -> dict[NBusParameterID, NBusParameterValue]:
+        """
+        Get all sensor parameters.
+
+        :return: dict of parameter id and parameter value
+        """
+
+        # get response
+        resp_len, *response = self.__port.request_sensor(self.__module_address, self.__address,
+                                                         NBusCommand.CMD_GET_PARAM, bytearray([]))
+
+        # parse parameters
+        params_raw = NbusCommonParser.parameters_from_response(resp_len, response)
+
+        for param_id, param_val_raw in params_raw:
+            param_val = self.map_parameter_get(param_id, param_val_raw)
+
+            # store parameters
+            self.__params[param_id] = param_val
+
+        return self.__params.copy()
+
+    def cmd_get_data(self) -> list[NBusDataValue]:
+        """
+       Get data from sensor.
+
+       :raises
+
+       :return: dict of device addresses and data values
+       """
+
+        if self.__data_format is None:  # check for format and params
+            raise NBusErrorAPI(NBusErrorAPIType.FORMAT_NOT_LOADED)
+        if not self.data_parameters_loaded():
+            raise NBusErrorAPI(NBusErrorAPIType.PARAMS_NOT_LOADED)
+
+        _, *resp = self.__port.request_sensor(self.__module_address, self.__address, NBusCommand.CMD_GET_DATA,
+                                              bytearray([]))
+        values, _ = NbusCommonParser.data_from_response(self.data_format, resp)
+        return self.map_data_get(values)
+
+    def cmd_get_sensor_type(self) -> NBusSensorType:
+        """
+        Get sensor type.
+
+        :return: sensor type
+        """
+        _, *response = self.__port.request_sensor(self.__module_address, self.__address,
+                                                  NBusCommand.CMD_GET_SENSOR_TYPE, bytearray([]))
+        return NBusSensorType(response[0])
+
+    def cmd_get_format(self):
+        """
+        Get sensor format.
+
+        :return: sensor format
+        """
+        _, *response = self.__port.request_sensor(self.__module_address, self.__address, NBusCommand.CMD_GET_FORMAT,
+                                                  bytearray([]))
+
+        self.data_format = NbusCommonParser.format_from_response(response)
+        return self.data_format
+
+    """
+    ================================================================================================================
+                                                  Device Set Commands
+    ================================================================================================================
+    """
+    def cmd_set_find(self, enable: bool) -> NBusStatusType:
+        """
+        Turn on/off physical indicator of device.
+
+        :param enable: to start (True) / stop (False) finding
+        :return: status
+        """
+        _, *response = self.__port.request_sensor(self.__module_address, self.__address,
+                                                  NBusCommand.CMD_SET_FIND, bytearray([enable]))
+        return NBusStatusType(response[0])
+
+    def cmd_set_param(self, param: NBusParameterID, value: NBusParameterValue) -> NBusStatusType:
+        """
+        Set sensor parameter.
+
+        :param param: parameter ID
+        :param value: parameter value
+        :return: status
+        """
+
+        # create request packet
+        param_id_raw = struct.pack("B", param.value)
+        param_val_raw = struct.pack("<I", self.map_parameter_set(param, value))
+        param_bytes = bytearray(param_id_raw) + bytearray(param_val_raw)
+
+        # proceed request
+        _, *response = self.__port.request_sensor(self.__module_address, self.__address,
+                                                  NBusCommand.CMD_SET_PARAM, param_bytes)
+
+        # if response is valid, store parameter
+        if response[0] == param.value and response[1] == NBusStatusType.STATUS_SUCCESS:
+            self.__params[param] = value
+
+        return NBusStatusType(response[1])
+
+    def cmd_set_multi_params(self, params: dict[NBusParameterID, NBusParameterValue]) \
+            -> dict[NBusParameterID, NBusStatusType]:
+        """
+        Set multiple sensor parameters.
+
+        :param params: parameters
+        :return: dict od statuses
+        """
+
+        # scale parameters
+        for p_id in params.keys():
+            params[p_id] = self.map_parameter_set(p_id, params[p_id])
+
+        # create request packet
+        param_bytes = NbusCommonParser.parameters_to_request(params)
+
+        # send request
+        resp_length, *response = self.__port.request_sensor(self.__module_address, self.__address,
+                                                            NBusCommand.CMD_SET_PARAM, bytearray(param_bytes))
+        # parse statuses
+        statuses = {}
+
+        for i in range(0, resp_length - 1, 2):
+            p_id = NBusParameterID(response[i])
+            if response[i + 1] == NBusStatusType.STATUS_SUCCESS:
+                self.__params[p_id] = params[p_id]  # if success, store param
+
+            statuses[p_id] = NBusStatusType(response[i + 1])
+
+        return statuses
+
+    def cmd_set_calibrate(self) -> NBusStatusType:
+        """
+        Send calibration command.
+
+        :return: calibration status
+        """
+
+        resp_length, *response = self.__port.request_sensor(self.__module_address, self.__address,
+                                                            NBusCommand.CMD_SET_CALIBRATE, bytearray([]))
+        return NBusStatusType(response[0])
+
+    def cmd_set_data(self, data: list[NBusDataValue]) -> NBusStatusType:
+        """
+        Set data to read-write sensor.
+
+        :param data: data to set
+        :raises: NBusErrorAPIType
+        :return: operation status
+        """
+
+        if self.__data_format is None:  # check for format and params
+            raise NBusErrorAPI(NBusErrorAPIType.FORMAT_NOT_LOADED)
+        if not self.data_parameters_loaded():
+            raise NBusErrorAPI(NBusErrorAPIType.PARAMS_NOT_LOADED)
+
+        # create request packet
+        request = []
+
+        # transform data
+        raw_data = self.map_data_set(data)
+        request.append(self.__address)
+        request.extend(NbusCommonParser.data_to_request(self.data_format, raw_data))
+
+        # send request
+        resp_length, *response = self.__port.request_sensor(self.__module_address, self.__address,
+                                                            NBusCommand.CMD_SET_DATA, bytearray(request))
+        # return response status
+        return NBusStatusType(response[1])

+ 0 - 183
nbus_api/nbus_slave_device.py

@@ -1,183 +0,0 @@
-import struct
-from abc import abstractmethod, ABCMeta
-from typing import Tuple
-from nbus_hal.nbus_generic_port import NBusPort
-from nbus_types.nbus_command_type import NBusCommand
-from nbus_types.nbus_data_fomat import *
-from nbus_types.nbus_exceptions.nbus_api_exception import NBusErrorAPI, NBusErrorAPIType
-from nbus_types.nbus_parameter_type import *
-from nbus_types.nbus_address_type import NBusDeviceAddress, NBusModuleAddress
-from nbus_types.nbus_sensor_type import NBusSensorType
-from nbus_api.nbus_common_parser import NbusCommonParser
-
-
-@beartype
-class NBusSlaveDevice(metaclass=ABCMeta):
-
-    def __init__(self, address: NBusDeviceAddress):
-        self.__address = address
-        self.__module_address = None
-        self.__port = None
-        self.__data_format = None
-        self.__parameters = {}
-
-    @property
-    def address(self):
-        return self.__address
-
-    @property
-    def data_format(self):
-        return self.__data_format
-
-    @data_format.setter
-    def data_format(self, data_format: NBusDataFormat) -> None:
-        self.__data_format = data_format
-
-    @property
-    def parameters(self):
-        return self.__parameters
-
-    @parameters.setter
-    def parameters(self, values):
-        self.__parameters = values
-
-    def set_parent_module_address(self, address: NBusModuleAddress):
-        self.__module_address = address
-
-    def set_device_port(self, port: NBusPort):
-        self.__port = port
-
-    """
-    ================================================================================================================
-                                                    Abstract Methods
-    ================================================================================================================
-    """
-
-    @abstractmethod
-    def data_parameters_loaded(self) -> bool:
-        """
-        Verify that all necessary parameters are loaded
-        before performing data get/set conversion.
-
-        :return: true if ready for conversion, otherwise False
-        """
-        pass
-
-    @abstractmethod
-    def map_parameter_get(self, param_id: NBusParameterID, param_value: int) -> NBusParameterValue:
-        """
-        Convert a parameter from cmd_get_param() to its engineering range.
-
-        :param param_id: the ID of the parameter
-        :param param_value: the value of the parameter in binary format
-        :return: the converted parameter value in engineering units
-        """
-        pass
-
-    @abstractmethod
-    def map_parameter_set(self, param_id: NBusParameterID, param_value: NBusParameterValue) -> int:
-        """
-        Convert a parameter to its binary range for cmd_set_data().
-
-        :param param_id: the ID of the parameter
-        :param param_value: the value of the parameter in engineering units
-        :return: the converted parameter value in binary format
-        """
-        pass
-
-    @abstractmethod
-    def map_data_get(self, values: list[int]) -> list[NBusDataValue]:
-        """
-        Convert data from cmd_get_data() to its engineering range.
-
-        :param values: a list of values in binary format to be converted
-        :return: a list of converted values in engineering units
-        """
-        pass
-
-    @abstractmethod
-    def map_data_set(self, values: list[NBusDataValue]) -> list[int]:
-        """
-        Convert data to its binary range for cmd_set_data().
-
-        :param values: a list of values in engineering range to be converted
-        :return: a list of converted values in binary format
-        """
-        pass
-
-    """
-    ================================================================================================================
-                                                    Device Get Commands
-    ================================================================================================================
-    """
-
-    def cmd_get_param(self, parameter: NBusParameterID) -> Tuple[NBusParameterID, NBusParameterValue]:
-        # get response
-        resp_len, *response = self.__port.request_device(self.__module_address, self.__address,
-                                                         NBusCommand.CMD_GET_PARAM, bytearray([parameter.value]))
-
-        param_id, param_val_raw = NbusCommonParser.parameters_from_response(resp_len, response)[0]
-        param_val = self.map_parameter_get(param_id, param_val_raw)
-
-        self.__parameters[param_id] = param_val
-
-        return param_id, param_val
-
-    def cmd_get_all_params(self) -> list[Tuple[NBusParameterID, NBusParameterValue]]:
-        resp_len, *response = self.__port.request_device(self.__module_address, self.__address,
-                                                         NBusCommand.CMD_GET_PARAM, bytearray([]))
-
-        params_raw = NbusCommonParser.parameters_from_response(resp_len, response)
-
-        params = []
-
-        for param_id, param_val_raw in params_raw:
-            param_val = self.map_parameter_get(param_id, param_val_raw)
-
-            params.append((param_id, param_val))
-            self.__parameters[param_id] = param_val
-
-        return params
-
-    def cmd_get_data(self):
-        _, *resp = self.__port.request_device(self.__module_address, self.__address, NBusCommand.CMD_GET_DATA, bytearray([]))
-        values, _ = NbusCommonParser.data_from_response(self, resp)
-        return values
-
-    def cmd_get_sensor_type(self):
-        _, *response = self.__port.request_device(self.__module_address, self.__address, NBusCommand.CMD_GET_SENSOR_TYPE,
-                                                  bytearray([]))
-        return NBusSensorType(response[0])
-
-    def cmd_get_format(self):
-        _, *response = self.__port.request_device(self.__module_address, self.__address, NBusCommand.CMD_GET_FORMAT,
-                                                  bytearray([]))
-
-        self.data_format = NbusCommonParser.format_from_response(response)
-        return self.data_format
-
-    """
-    ================================================================================================================
-                                                  Device Set Commands
-    ================================================================================================================
-    """
-
-    def cmd_set_param(self, param: NBusParameterID, value: NBusParameterValue) -> None:
-
-        raw_value = self.map_parameter_set(param, value)                        # get raw value
-        value_bytes = struct.pack('<I', raw_value & 0xFFFFFFFF)             # create bytes
-        self.__port.request_device(self.__module_address, self.__address,     # proceed request
-                                  NBusCommand.CMD_SET_PARAM, bytearray([param.value, *value_bytes]))
-        self.__parameters[param] = value     # store new value of parameter
-
-    def cmd_set_data(self, data: list[NBusDataValue]):
-
-        if self.__data_format is None:  # check for format and params
-            raise NBusErrorAPI(NBusErrorAPIType.FORMAT_NOT_LOADED)
-        if not self.data_parameters_loaded():
-            raise NBusErrorAPI(NBusErrorAPIType.PARAMS_NOT_LOADED)
-
-        binary_data = self.map_data_set(data)
-        _, *resp = self.__port.request_device(self.__module_address, self.__address, NBusCommand.CMD_SET_DATA, bytearray(binary_data))
-
-        return resp

+ 0 - 163
nbus_api/nbus_slave_module.py

@@ -1,163 +0,0 @@
-import struct
-from abc import abstractmethod
-from typing import Tuple, Annotated
-
-from beartype.vale import Is
-
-from nbus_api.nbus_slave_device import NBusSlaveDevice
-from nbus_api.nbus_common_parser import NbusCommonParser
-from nbus_hal.nbus_serial.serial_port import *
-from nbus_types.nbus_address_type import NBusModuleAddress
-from nbus_types.nbus_parameter_type import NBusParameterID, NBusParameterValue
-from nbus_types.nbus_status_type import NBusStatusType
-from nbus_types.nbus_sensor_count_type import NBusSensorCount
-from nbus_types.nbus_info_type import NBusInfo
-from nbus_types.nbus_sensor_type import NBusSensorType
-
-
-@beartype
-class NBusSlaveModule:
-
-    def __init__(self, serial_port: NBusSerialPort, module_address: NBusModuleAddress):
-        self.__port = serial_port
-        self.__module_addr = module_address
-        self.__params = {}
-        self.__devices = {}
-        self._map_param_get = lambda t, v: v
-        self._map_param_set = lambda t, v: v
-
-    def set_module_parameter_mappers(self, map_param_get_cb: Callable[[NBusParameterID, NBusParameterValue], int],
-                                     map_param_set_cb: Callable[[NBusParameterID, int], NBusParameterValue]):
-        self._map_param_get = map_param_get_cb
-        self._map_param_set = map_param_set_cb
-
-    def add_device(self, device: NBusSlaveDevice) -> None:
-        device.set_parent_module_address(self.__module_addr)
-        device.set_device_port(self.__port)
-        self.__devices[device.address] = device
-
-    def get_device(self, device_address: NBusDeviceAddress) -> NBusSlaveDevice:
-        return self.__devices[device_address]
-
-
-
-    """
-    ================================================================================================================
-                                                Module Get Commands
-    ================================================================================================================
-    """
-    def cmd_get_echo(self, message: bytearray) -> bool:
-        """
-        Send Echo Command.
-        :param message: message to send
-        :return: status (True = echo, False = no echo)
-        """
-        _, *response = self.__port.request_module(self.__module_addr, NBusCommand.CMD_GET_ECHO, message)
-        return response == list(message)
-
-    def cmd_get_param(self, parameter: NBusParameterID) -> Tuple[NBusParameterID, NBusParameterValue]:
-        # get response
-        resp_len, *response = self.__port.request_module(self.__module_addr, NBusCommand.CMD_GET_PARAM,
-                                                         bytearray([parameter.value]))
-
-        param_id, param_val_raw = NbusCommonParser.parameters_from_response(resp_len, response)[0]
-        param_val = self._map_param_get(param_id, param_val_raw)
-
-        self.__params[param_id] = param_val
-
-        return param_id, param_val
-
-    def cmd_get_all_params(self) -> dict[NBusParameterID, NBusParameterValue]:
-        resp_len, *response = self.__port.request_module(self.__module_addr, NBusCommand.CMD_GET_PARAM, bytearray([]))
-        params_raw = NbusCommonParser.parameters_from_response(resp_len, response)
-
-        for param_id, param_val_raw in params_raw:
-            param_val = self._map_param_get(param_id, param_val_raw)
-
-            self.__params[param_id] = param_val
-
-        return self.__params.copy()
-
-    def cmd_get_sensor_cnt(self) -> NBusSensorCount:
-        _, *response = self.__port.request_module(self.__module_addr, NBusCommand.CMD_GET_SENSOR_CNT, bytearray([]))
-        return NBusSensorCount(*response)
-
-    def cmd_get_data(self):
-        resp_length, *response = self.__port.request_module(self.__module_addr, NBusCommand.CMD_GET_DATA, bytearray([]))
-        begin_idx = 0
-        data = {}
-
-        while begin_idx < resp_length:
-            device_id = response[begin_idx]
-
-            values, offset = NbusCommonParser.data_from_response(self.__devices[device_id], response[begin_idx:])
-            data[device_id] = values
-            begin_idx += offset + 1
-
-        return data
-
-    def cmd_get_info(self):
-        response = self.__port.request_module(self.__module_addr, NBusCommand.CMD_GET_INFO, bytearray([]))
-
-        name = str(response[1:9], "ascii")
-        typ = str(response[9:12], "ascii")
-        uuid = struct.unpack("<I", bytearray(response[12:16]))[0]
-        hw = str(response[16:19], "ascii")
-        fw = str(response[19:22], "ascii")
-        mem_id = struct.unpack("<Q", bytearray(response[22:30]))[0]
-
-        return NBusInfo(module_name=name, module_type=typ, uuid=uuid, hw=hw, fw=fw, memory_id=mem_id)
-
-
-    def cmd_get_format(self):
-        resp_length, *response = self.__port.request_module(self.__module_addr, NBusCommand.CMD_GET_FORMAT,
-                                                            bytearray([]))
-        begin_idx = 0
-        formats = {}
-
-        while begin_idx < resp_length:
-            device_id = response[begin_idx]
-            device_format = NbusCommonParser.format_from_response(response[begin_idx:begin_idx + 4])
-
-            self.__devices[device_id].data_format = device_format
-            formats[device_id] = device_format
-            begin_idx += 4
-
-        return formats
-
-
-    def cmd_get_sensor_type(self):
-        resp_length, *response = self.__port.request_module(self.__module_addr, NBusCommand.CMD_GET_SENSOR_TYPE,
-                                                            bytearray([]))
-        types = {}
-        i = 0
-
-        while i < resp_length - 1:
-            types[NBusDeviceAddress(response[i])] = NBusSensorType(response[i+1])
-            i += 2
-
-        return types
-
-
-    """
-    ================================================================================================================
-                                                Module Set Commands
-    ================================================================================================================
-    """
-
-    def cmd_set_find(self, enable: bool) -> NBusStatusType:
-        """
-        Send Find Command.
-        :param enable: to start (True) / stop (False) finding
-        :return: status
-        """
-        _, *response = self.__port.request_module(self.__module_addr, NBusCommand.CMD_SET_FIND, bytearray([enable]))
-        return NBusStatusType(response[0])
-
-    def cmd_set_module_stop(self):
-        self._send_request_module(self.__module_addr, NBusCommand.CMD_SET_STOP, bytearray([]))
-
-    def cmd_set_module_start(self):
-        self.__port.request_module(self.__module_addr, NBusCommand.CMD_SET_START, bytearray([]))
-
-

+ 4 - 4
nbus_hal/nbus_generic_port.py

@@ -2,7 +2,7 @@ from abc import ABCMeta, abstractmethod
 from typing import Annotated
 from typing import Annotated
 from beartype import beartype
 from beartype import beartype
 from beartype.vale import Is
 from beartype.vale import Is
-from nbus_types.nbus_address_type import NBusModuleAddress, NBusDeviceAddress
+from nbus_types.nbus_address_type import NBusModuleAddress, NBusSensorAddress
 from nbus_types.nbus_command_type import NBusCommand
 from nbus_types.nbus_command_type import NBusCommand
 
 
 
 
@@ -63,12 +63,12 @@ class NBusPort(metaclass=ABCMeta):
         pass
         pass
 
 
     @abstractmethod
     @abstractmethod
-    def request_device(self, module_addr: NBusModuleAddress, device_address: NBusDeviceAddress, command: NBusCommand,
+    def request_sensor(self, module_addr: NBusModuleAddress, sensor_address: NBusSensorAddress, command: NBusCommand,
                        data: bytearray, long_answer: NBusDelay = 0.0) -> bytearray:
                        data: bytearray, long_answer: NBusDelay = 0.0) -> bytearray:
         """
         """
-        Make device request to nbus network.
+        Make sensor request to nbus network.
         :param module_addr: address of module
         :param module_addr: address of module
-        :param device_address: address of device
+        :param sensor_address: address of sensor
         :param command: command id
         :param command: command id
         :param data: command data to send
         :param data: command data to send
         :param long_answer: delay in s for longer answer
         :param long_answer: delay in s for longer answer

+ 4 - 4
nbus_hal/nbus_serial/serial_port.py

@@ -9,7 +9,7 @@ from nbus_types.nbus_exceptions.nbus_network_exception import *
 from nbus_types.nbus_exceptions.nbus_node_exception import *
 from nbus_types.nbus_exceptions.nbus_node_exception import *
 from nbus_hal.nbus_serial.serial_config import NBusSerialConfig
 from nbus_hal.nbus_serial.serial_config import NBusSerialConfig
 from nbus_hal.nbus_generic_port import NBusPort, NBusDelay
 from nbus_hal.nbus_generic_port import NBusPort, NBusDelay
-from nbus_types.nbus_address_type import NBusModuleAddress, NBusDeviceAddress
+from nbus_types.nbus_address_type import NBusModuleAddress, NBusSensorAddress
 from nbus_hal.crc8 import crc8
 from nbus_hal.crc8 import crc8
 
 
 
 
@@ -99,18 +99,18 @@ class NBusSerialPort(NBusPort):
         """
         """
         return self._request_response(module_addr, 0, command.value, data, long_answer)
         return self._request_response(module_addr, 0, command.value, data, long_answer)
 
 
-    def request_device(self, module_addr: NBusModuleAddress, device_address: NBusDeviceAddress,
+    def request_sensor(self, module_addr: NBusModuleAddress, sensor_address: NBusSensorAddress,
                        command: NBusCommand, data: bytearray, long_answer: NBusDelay = 0.0) -> bytearray:
                        command: NBusCommand, data: bytearray, long_answer: NBusDelay = 0.0) -> bytearray:
         """
         """
         Make device request to nbus network.
         Make device request to nbus network.
         :param module_addr: address of module
         :param module_addr: address of module
-        :param device_address: address of device
+        :param sensor_address: address of sensor
         :param command: command id
         :param command: command id
         :param data: command data to send
         :param data: command data to send
         :param long_answer: delay in s for longer answer
         :param long_answer: delay in s for longer answer
         :return: | payload length | payload |
         :return: | payload length | payload |
         """
         """
-        return self._request_response(module_addr, device_address, command.value, data, long_answer)
+        return self._request_response(module_addr, sensor_address, command.value, data, long_answer)
 
 
     """
     """
     ================================================================================================================
     ================================================================================================================

+ 24 - 0
nbus_sensor_drivers/generic_sensor_driver.py

@@ -0,0 +1,24 @@
+from nbus_api.nbus_sensor import NBusSensor
+from nbus_types.nbus_data_fomat import NBusDataValue
+from nbus_types.nbus_parameter_type import NBusParameterID, NBusParameterValue
+
+
+class NBusGenericSensor(NBusSensor):
+    """
+    Class for generic NBus sensor (no data transformation)
+    """
+
+    def data_parameters_loaded(self) -> bool:
+        return True
+
+    def map_parameter_get(self, param_id: NBusParameterID, param_value: int) -> NBusParameterValue:
+        return param_value
+
+    def map_parameter_set(self, param_id: NBusParameterID, param_value: NBusParameterValue) -> int:
+        return param_value
+
+    def map_data_get(self, values: list[int]) -> list[NBusDataValue]:
+        return values
+
+    def map_data_set(self, values: list[NBusDataValue]) -> list[int]:
+        return values

+ 2 - 2
nbus_types/nbus_address_type.py

@@ -7,6 +7,6 @@ Typedef for NBus module address.
 NBusModuleAddress = Annotated[int, Is[lambda x: 1 <= x <= 127]]
 NBusModuleAddress = Annotated[int, Is[lambda x: 1 <= x <= 127]]
 
 
 """
 """
-Typedef for NBus device address.
+Typedef for NBus sensor address.
 """
 """
-NBusDeviceAddress = Annotated[int, Is[lambda value: (1 <= value <= 31) or (129 <= value <= 159)]]
+NBusSensorAddress = Annotated[int, Is[lambda value: (1 <= value <= 31) or (129 <= value <= 159)]]

+ 4 - 0
nbus_types/nbus_info_type.py

@@ -17,6 +17,8 @@ class NBusInfo:
     :ivar hw: firmware version. MAJOR.MINOR
     :ivar hw: firmware version. MAJOR.MINOR
     :ivar fw: memory ID number
     :ivar fw: memory ID number
     :ivar memory_id: sensor count
     :ivar memory_id: sensor count
+    :ivar read_only_sensors: count of read-only sensors
+    :ivar read_write_sensors: count of read-write sensors
     """
     """
     module_name: Annotated[str, Is[lambda value: len(value) == 8]]
     module_name: Annotated[str, Is[lambda value: len(value) == 8]]
     module_type: Annotated[str, Is[lambda value: len(value) == 3]]
     module_type: Annotated[str, Is[lambda value: len(value) == 3]]
@@ -24,6 +26,8 @@ class NBusInfo:
     hw: Annotated[str, Is[lambda value: len(value) == 3]]
     hw: Annotated[str, Is[lambda value: len(value) == 3]]
     fw: Annotated[str, Is[lambda value: len(value) == 3]]
     fw: Annotated[str, Is[lambda value: len(value) == 3]]
     memory_id: Annotated[int, Is[lambda value: 0 <= value <= np.iinfo(np.uint64).max]]
     memory_id: Annotated[int, Is[lambda value: 0 <= value <= np.iinfo(np.uint64).max]]
+    read_only_sensors: Annotated[int, Is[lambda value: 0 <= value <= 31]]
+    read_write_sensors: Annotated[int, Is[lambda value: 0 <= value <= 31]]