iqrfpy.irequest
Request message class abstraction.
1"""Request message class abstraction.""" 2 3from abc import ABC, abstractmethod 4from typing import List, Optional, Union 5from uuid import uuid4 6import iqrfpy.utils.dpa as dpa_constants 7from iqrfpy.enums.commands import Command 8from iqrfpy.enums.message_types import MessageType 9from iqrfpy.enums.peripherals import Peripheral 10from iqrfpy.exceptions import RequestNadrInvalidError, RequestPnumInvalidError, RequestPcmdInvalidError, \ 11 RequestHwpidInvalidError, RequestParameterInvalidValueError 12 13__all__ = ['IRequest'] 14 15 16class IRequest(ABC): 17 """This abstract class serves as an interface for embedded peripherals and standards request messages. 18 19 The class provides getters and setters for shared request properties in the form of the @property decorator. 20 Shared properties such as device address, peripheral, peripheral command and hwpid are validated here. 21 The class also provides generic DPA and JSON serialization methods for derived classes to amend. 22 While the abstract class cannot be instantiated, it's methods can be called from a derived class using super. 23 24 Network address (nadr) specifies target device: 0 (coordinator), 1-239 (node), 252 (local device), 25 254 (temporary address) and 255 (broadcast), other values are reserved. Values in range 0-255. 26 27 Peripheral number (pnum) specifies peripheral to use: 0-31 are served for embedded peripherals and 28 64-127 are reserved for IQRF standard peripherals. Peripheral number can be passed as a member of one 29 of the peripheral enum class members (see iqrfpy.enums.peripherals) or plain integer. Values in range 0-255. 30 31 Peripheral command (pcmd) specifies a command to execute, each peripheral implements different commands. 32 See DPA framework document for specific command numbers. Peripheral command can be passed as a member of one 33 of the peripheral command enum class members (see iqrfpy.enums.commands) or plain integer. 34 Peripheral number and peripheral command are pre-defined for each command message this library implements, 35 however they will be required for user-defined messages. Values in range 0-255, but note that only values 36 0-127 are used for request commands, as response command value is equal to request command value plus 128 (0x80). 37 38 Hardware profile ID (hwpid) specifies a unique device (by its functionality), this argument can be used to filter 39 which devices execute a commend specified by request message. Only devices with matching hwpid will execute 40 a command, unless the value 65535 (0xFFFF) is used, which ignores hwpid checking. Values in range 0-65535. 41 42 Packet data (pdata) can be required or optional data sent with the request message, depending on the command. 43 On a general level, packet data is treated as list of unsigned 1B integers. This means that when defining a user 44 command and a request message, request data should be serialized into a list of previously mentioned 45 format and stored in the pdata member. 46 47 For more detailed information, see the IQRF DPA Framework documentation. 48 49 Message type (m_type) is an optional argument, however, it is required when using JSON API as message type 50 is equivalent to a combination of peripheral number and peripheral command (see iqrfpy.enums.message_types). 51 For example, `OSMessages.READ` (iqrfEmbedOs_Read) is equivalent to `EmbedPeripherals.OS` (2) and 52 `OSRequestCommands.READ` (0). 53 54 Request parameters (params) is an optional dictionary argument, that is used when constructing a JSON API request. 55 When creating a user message, use the params member to propagate your request parameters into the final 56 JSON request object. 57 58 DPA response time (dpa_rsp_time) is an optional argument specifying DPA request timeout, not time between reception 59 of a request and delivery of response. Note that handling of this argument is the responsibility of a transport 60 and system facilitating communication between the library and devices of the IQRF network. 61 62 Device processing time (dev_process_time) is an optional argument used to specify time allotted to the device 63 executing a task beyond simple data processing. For example, a device may need to measure some quantity 64 for certain amount of time for the measured value to be valid. Note that handling of this argument 65 is the responsibility of a transport and system facilitating communication between the library and devices 66 of the IQRF network. 67 68 Message ID (msgid) is an optional argument used only by the JSON API at this time. It is used to pair 69 JSON API requests and responses as the message type argument only allows to pair requests of the same type, 70 but not pairing a specific request and response, given the asynchronous nature of the JSON API. 71 """ 72 73 __slots__ = '_nadr', '_pnum', '_pcmd', '_mtype', '_hwpid', '_pdata', '_msgid', '_params', '_dpa_rsp_time', \ 74 '_dev_process_time' 75 76 def __init__(self, nadr: int, pnum: Union[Peripheral, int], pcmd: Union[Command, int], 77 hwpid: int = dpa_constants.HWPID_MAX, pdata: Optional[List[int]] = None, 78 m_type: Optional[MessageType] = None, msgid: Optional[str] = None, 79 params: Optional[dict] = None, dpa_rsp_time: Optional[float] = None, 80 dev_process_time: Optional[float] = None): 81 """IRequest constructor. 82 83 Args: 84 nadr (int): Network address. 85 pnum (Union[Peripheral, int]): Peripheral number. 86 pcmd (Union[Command, int]): Peripheral command. 87 hwpid (int, optional): Hardware profile ID. Defaults to 65535 (Ignore HWPID check). 88 pdata (List[int], optional): DPA request data. Defaults to None. 89 m_type (MessageType, optional): JSON API message type. Defaults to None. 90 msgid (str, optional): JSON API message ID. Defaults to None. If the parameter is not specified, a random 91 UUIDv4 string is generated and used. 92 params (dict, optional): JSON API request data. Defaults to None. 93 dpa_rsp_time (float, optional): DPA request timeout in seconds. Defaults to None. 94 dev_process_time (float, optional): Device processing time. Defaults to None. 95 """ 96 self._nadr = nadr 97 self._pnum = pnum 98 self._pcmd = pcmd 99 self._hwpid = hwpid 100 self._pdata = pdata 101 self._mtype = m_type 102 self._msgid = msgid if msgid is not None else str(uuid4()) 103 self._params = params if params is not None else {} 104 self._dpa_rsp_time = dpa_rsp_time 105 self._dev_process_time = dev_process_time 106 self._validate_base(nadr, pnum, pcmd, hwpid, dpa_rsp_time, dev_process_time) 107 108 def _validate_base(self, nadr: int, pnum: Union[Peripheral, int], pcmd: Union[Command, int], hwpid: int, 109 dpa_rsp_time: Optional[float], dev_process_time: Optional[float]) -> None: 110 """Shared members validation method. 111 112 Validates shared request members to ensure the data can fit into the DPA packet and JSON request 113 object and do not violate rules for expected format of these properties. 114 115 Args: 116 nadr (int): Network address. 117 pnum (Union[Peripheral, int]): Peripheral number. 118 pcmd (Union[Command, int]): Peripheral command. 119 hwpid (int, optional): Hardware profile ID. Defaults to 65535 (Ignore HWPID check). 120 dpa_rsp_time (float, optional): DPA request timeout in seconds. Defaults to None. 121 dev_process_time (float, optional): Device processing time. Defaults to None. 122 """ 123 self._validate_nadr(nadr) 124 self._validate_pnum(pnum) 125 self._validate_pcmd(pcmd) 126 self._validate_hwpid(hwpid) 127 self._validate_dpa_rsp_time(dpa_rsp_time) 128 self._validate_dev_process_time(dev_process_time) 129 130 @staticmethod 131 def _validate_nadr(nadr: int): 132 """Validates network address parameter. 133 134 Args: 135 nadr (int): Network address value. 136 137 Raises: 138 RequestNadrInvalidError: If nadr is less than 0 or greater than 255. 139 """ 140 if not dpa_constants.BYTE_MIN <= nadr <= dpa_constants.BYTE_MAX: 141 raise RequestNadrInvalidError('NADR should be between 0 and 255.') 142 143 @property 144 def nadr(self) -> int: 145 """:obj:`int`: Network address. 146 147 Getter and setter. 148 """ 149 return self._nadr 150 151 @nadr.setter 152 def nadr(self, value: int): 153 self._validate_nadr(value) 154 self._nadr = value 155 156 @staticmethod 157 def _validate_pnum(pnum: Union[Peripheral, int]): 158 """Validates peripheral number parameter. 159 160 Args: 161 pnum (Union[Peripheral, int]): Peripheral number value. 162 163 Raises: 164 RequestPnumInvalidError: If pnum is less than 0 or greater than 255. 165 """ 166 if not dpa_constants.BYTE_MIN <= pnum <= dpa_constants.BYTE_MAX: 167 raise RequestPnumInvalidError('PNUM should be between 0 and 255.') 168 169 @property 170 def pnum(self) -> Union[Peripheral, int]: 171 """:obj:`iqrfpy.enums.peripherals.Peripheral` of :obj:`int`: Peripheral number. 172 173 Getter and setter. 174 """ 175 return self._pnum 176 177 @pnum.setter 178 def pnum(self, value: Union[Peripheral, int]): 179 self._validate_pnum(pnum=value) 180 self._pnum = value 181 182 @staticmethod 183 def _validate_pcmd(pcmd: Union[Command, int]): 184 """Validates peripheral command parameter. 185 186 Args: 187 pcmd (Union[Command, int]): Peripheral command value. 188 189 Raises: 190 RequestPcmdInvalidError: If pcmd is less than 0 or greater than 255. 191 """ 192 if not dpa_constants.BYTE_MIN <= pcmd <= dpa_constants.BYTE_MAX: 193 raise RequestPcmdInvalidError('PCMD should be between 0 and 255.') 194 195 @property 196 def pcmd(self) -> Union[Command, int]: 197 """:obj:`iqrfpy.enums.commands.Command` or :obj:`int`: Peripheral command. 198 199 Getter and setter. 200 """ 201 return self._pcmd 202 203 @pcmd.setter 204 def pcmd(self, value: Union[Command, int]): 205 self._validate_pcmd(pcmd=value) 206 self._pcmd = value 207 208 @staticmethod 209 def _validate_hwpid(hwpid: int): 210 """Validates Hardware profile ID parameter. 211 212 Args: 213 hwpid (int): Hardware profile ID value. 214 215 Raises: 216 RequestHwpidInvalidError: If hwpid is less than 0 or greater than 65535. 217 """ 218 if not dpa_constants.HWPID_MIN <= hwpid <= dpa_constants.HWPID_MAX: 219 raise RequestHwpidInvalidError('HWPID should be between 0 and 65535.') 220 221 @property 222 def hwpid(self) -> int: 223 """:obj:`int`: Hardware profile ID. 224 225 Getter and setter. 226 """ 227 return self._hwpid 228 229 @staticmethod 230 def _validate_dpa_rsp_time(dpa_rsp_time: Optional[float] = None): 231 """Validates dpa timeout parameter. 232 233 Args: 234 dpa_rsp_time (float, optional): DPA timeout value in seconds. Defaults to None. 235 236 Raises: 237 RequestParameterInvalidValueError: If dpa_rsp_time is not None and is less than 0. 238 """ 239 if dpa_rsp_time is None: 240 return 241 if dpa_rsp_time < 0: 242 raise RequestParameterInvalidValueError('DPA response time should a positive integer.') 243 244 @property 245 def dpa_rsp_time(self) -> Optional[float]: 246 """:obj:`float` or :obj:`None`: DPA timeout. 247 248 Getter and setter. 249 """ 250 return self._dpa_rsp_time 251 252 @dpa_rsp_time.setter 253 def dpa_rsp_time(self, value: Optional[float] = None): 254 self._validate_dpa_rsp_time(value) 255 self._dpa_rsp_time = value 256 257 @staticmethod 258 def _validate_dev_process_time(dev_process_time: Optional[float] = None): 259 """Validates device processing time parameter. 260 261 Args: 262 dev_process_time (float, optional): Device processing time value. Defaults to None. 263 264 Raises: 265 RequestParameterInvalidValueError: If dev_process_time is not None and is less than 0. 266 """ 267 if dev_process_time is None: 268 return 269 if dev_process_time < 0: 270 raise RequestParameterInvalidValueError('Device processing time should be a positive integer.') 271 272 @property 273 def dev_process_time(self) -> Optional[float]: 274 """:obj:`float` or :obj:`None`: Device processing time. 275 276 Getter and setter. 277 """ 278 return self._dev_process_time 279 280 @dev_process_time.setter 281 def dev_process_time(self, value: Optional[float] = None): 282 self._validate_dev_process_time(value) 283 self._dev_process_time = value 284 285 @property 286 def msgid(self) -> str: 287 """:obj:`str`: Message ID. 288 289 Getter and setter. 290 """ 291 return self._msgid 292 293 @msgid.setter 294 def msgid(self, value: str): 295 self._msgid = value 296 297 @property 298 def mtype(self) -> MessageType: 299 """:obj:`MessageType` Message type. 300 301 Getter only. 302 """ 303 return self._mtype 304 305 @abstractmethod 306 def to_dpa(self, mutable: bool = False) -> Union[bytes, bytearray]: 307 """DPA request serialization method. 308 309 Serializes a request to DPA request packet format. Each request contains the DPA request header. 310 If pdata is specified, it is appended to the DPA request header. The request can be serialized 311 into both mutable and immutable (default) byte formats. 312 313 Args: 314 mutable (bool, optional): Serialize into mutable byte representation of DPA request packet. 315 Defaults to False. 316 317 Returns: 318 :obj:`bytes`: Immutable byte representation of DPA request packet.\n 319 :obj:`bytearray`: Mutable byte representation of DPA request packet (if argument mutable is True). 320 """ 321 raise NotImplementedError('Abstract method not implemented.') 322 323 @abstractmethod 324 def to_json(self) -> dict: 325 """JSON API request serialization method. 326 327 Serializes a request to JSON API request object. Each request contains message type and data. 328 Data carries message ID for pairing requests with responses, and `req` object that contains network address, 329 hwpid and optional request parameters (equivalent to DPA packet data) if `params` is not None. 330 If DPA timeout is specified, the value is multiplied by 1000 as JSON API accepts timeout in milliseconds. 331 332 Returns: 333 :obj:`dict`: JSON API request object. 334 """ 335 raise NotImplementedError('Abstract method not implemented')
17class IRequest(ABC): 18 """This abstract class serves as an interface for embedded peripherals and standards request messages. 19 20 The class provides getters and setters for shared request properties in the form of the @property decorator. 21 Shared properties such as device address, peripheral, peripheral command and hwpid are validated here. 22 The class also provides generic DPA and JSON serialization methods for derived classes to amend. 23 While the abstract class cannot be instantiated, it's methods can be called from a derived class using super. 24 25 Network address (nadr) specifies target device: 0 (coordinator), 1-239 (node), 252 (local device), 26 254 (temporary address) and 255 (broadcast), other values are reserved. Values in range 0-255. 27 28 Peripheral number (pnum) specifies peripheral to use: 0-31 are served for embedded peripherals and 29 64-127 are reserved for IQRF standard peripherals. Peripheral number can be passed as a member of one 30 of the peripheral enum class members (see iqrfpy.enums.peripherals) or plain integer. Values in range 0-255. 31 32 Peripheral command (pcmd) specifies a command to execute, each peripheral implements different commands. 33 See DPA framework document for specific command numbers. Peripheral command can be passed as a member of one 34 of the peripheral command enum class members (see iqrfpy.enums.commands) or plain integer. 35 Peripheral number and peripheral command are pre-defined for each command message this library implements, 36 however they will be required for user-defined messages. Values in range 0-255, but note that only values 37 0-127 are used for request commands, as response command value is equal to request command value plus 128 (0x80). 38 39 Hardware profile ID (hwpid) specifies a unique device (by its functionality), this argument can be used to filter 40 which devices execute a commend specified by request message. Only devices with matching hwpid will execute 41 a command, unless the value 65535 (0xFFFF) is used, which ignores hwpid checking. Values in range 0-65535. 42 43 Packet data (pdata) can be required or optional data sent with the request message, depending on the command. 44 On a general level, packet data is treated as list of unsigned 1B integers. This means that when defining a user 45 command and a request message, request data should be serialized into a list of previously mentioned 46 format and stored in the pdata member. 47 48 For more detailed information, see the IQRF DPA Framework documentation. 49 50 Message type (m_type) is an optional argument, however, it is required when using JSON API as message type 51 is equivalent to a combination of peripheral number and peripheral command (see iqrfpy.enums.message_types). 52 For example, `OSMessages.READ` (iqrfEmbedOs_Read) is equivalent to `EmbedPeripherals.OS` (2) and 53 `OSRequestCommands.READ` (0). 54 55 Request parameters (params) is an optional dictionary argument, that is used when constructing a JSON API request. 56 When creating a user message, use the params member to propagate your request parameters into the final 57 JSON request object. 58 59 DPA response time (dpa_rsp_time) is an optional argument specifying DPA request timeout, not time between reception 60 of a request and delivery of response. Note that handling of this argument is the responsibility of a transport 61 and system facilitating communication between the library and devices of the IQRF network. 62 63 Device processing time (dev_process_time) is an optional argument used to specify time allotted to the device 64 executing a task beyond simple data processing. For example, a device may need to measure some quantity 65 for certain amount of time for the measured value to be valid. Note that handling of this argument 66 is the responsibility of a transport and system facilitating communication between the library and devices 67 of the IQRF network. 68 69 Message ID (msgid) is an optional argument used only by the JSON API at this time. It is used to pair 70 JSON API requests and responses as the message type argument only allows to pair requests of the same type, 71 but not pairing a specific request and response, given the asynchronous nature of the JSON API. 72 """ 73 74 __slots__ = '_nadr', '_pnum', '_pcmd', '_mtype', '_hwpid', '_pdata', '_msgid', '_params', '_dpa_rsp_time', \ 75 '_dev_process_time' 76 77 def __init__(self, nadr: int, pnum: Union[Peripheral, int], pcmd: Union[Command, int], 78 hwpid: int = dpa_constants.HWPID_MAX, pdata: Optional[List[int]] = None, 79 m_type: Optional[MessageType] = None, msgid: Optional[str] = None, 80 params: Optional[dict] = None, dpa_rsp_time: Optional[float] = None, 81 dev_process_time: Optional[float] = None): 82 """IRequest constructor. 83 84 Args: 85 nadr (int): Network address. 86 pnum (Union[Peripheral, int]): Peripheral number. 87 pcmd (Union[Command, int]): Peripheral command. 88 hwpid (int, optional): Hardware profile ID. Defaults to 65535 (Ignore HWPID check). 89 pdata (List[int], optional): DPA request data. Defaults to None. 90 m_type (MessageType, optional): JSON API message type. Defaults to None. 91 msgid (str, optional): JSON API message ID. Defaults to None. If the parameter is not specified, a random 92 UUIDv4 string is generated and used. 93 params (dict, optional): JSON API request data. Defaults to None. 94 dpa_rsp_time (float, optional): DPA request timeout in seconds. Defaults to None. 95 dev_process_time (float, optional): Device processing time. Defaults to None. 96 """ 97 self._nadr = nadr 98 self._pnum = pnum 99 self._pcmd = pcmd 100 self._hwpid = hwpid 101 self._pdata = pdata 102 self._mtype = m_type 103 self._msgid = msgid if msgid is not None else str(uuid4()) 104 self._params = params if params is not None else {} 105 self._dpa_rsp_time = dpa_rsp_time 106 self._dev_process_time = dev_process_time 107 self._validate_base(nadr, pnum, pcmd, hwpid, dpa_rsp_time, dev_process_time) 108 109 def _validate_base(self, nadr: int, pnum: Union[Peripheral, int], pcmd: Union[Command, int], hwpid: int, 110 dpa_rsp_time: Optional[float], dev_process_time: Optional[float]) -> None: 111 """Shared members validation method. 112 113 Validates shared request members to ensure the data can fit into the DPA packet and JSON request 114 object and do not violate rules for expected format of these properties. 115 116 Args: 117 nadr (int): Network address. 118 pnum (Union[Peripheral, int]): Peripheral number. 119 pcmd (Union[Command, int]): Peripheral command. 120 hwpid (int, optional): Hardware profile ID. Defaults to 65535 (Ignore HWPID check). 121 dpa_rsp_time (float, optional): DPA request timeout in seconds. Defaults to None. 122 dev_process_time (float, optional): Device processing time. Defaults to None. 123 """ 124 self._validate_nadr(nadr) 125 self._validate_pnum(pnum) 126 self._validate_pcmd(pcmd) 127 self._validate_hwpid(hwpid) 128 self._validate_dpa_rsp_time(dpa_rsp_time) 129 self._validate_dev_process_time(dev_process_time) 130 131 @staticmethod 132 def _validate_nadr(nadr: int): 133 """Validates network address parameter. 134 135 Args: 136 nadr (int): Network address value. 137 138 Raises: 139 RequestNadrInvalidError: If nadr is less than 0 or greater than 255. 140 """ 141 if not dpa_constants.BYTE_MIN <= nadr <= dpa_constants.BYTE_MAX: 142 raise RequestNadrInvalidError('NADR should be between 0 and 255.') 143 144 @property 145 def nadr(self) -> int: 146 """:obj:`int`: Network address. 147 148 Getter and setter. 149 """ 150 return self._nadr 151 152 @nadr.setter 153 def nadr(self, value: int): 154 self._validate_nadr(value) 155 self._nadr = value 156 157 @staticmethod 158 def _validate_pnum(pnum: Union[Peripheral, int]): 159 """Validates peripheral number parameter. 160 161 Args: 162 pnum (Union[Peripheral, int]): Peripheral number value. 163 164 Raises: 165 RequestPnumInvalidError: If pnum is less than 0 or greater than 255. 166 """ 167 if not dpa_constants.BYTE_MIN <= pnum <= dpa_constants.BYTE_MAX: 168 raise RequestPnumInvalidError('PNUM should be between 0 and 255.') 169 170 @property 171 def pnum(self) -> Union[Peripheral, int]: 172 """:obj:`iqrfpy.enums.peripherals.Peripheral` of :obj:`int`: Peripheral number. 173 174 Getter and setter. 175 """ 176 return self._pnum 177 178 @pnum.setter 179 def pnum(self, value: Union[Peripheral, int]): 180 self._validate_pnum(pnum=value) 181 self._pnum = value 182 183 @staticmethod 184 def _validate_pcmd(pcmd: Union[Command, int]): 185 """Validates peripheral command parameter. 186 187 Args: 188 pcmd (Union[Command, int]): Peripheral command value. 189 190 Raises: 191 RequestPcmdInvalidError: If pcmd is less than 0 or greater than 255. 192 """ 193 if not dpa_constants.BYTE_MIN <= pcmd <= dpa_constants.BYTE_MAX: 194 raise RequestPcmdInvalidError('PCMD should be between 0 and 255.') 195 196 @property 197 def pcmd(self) -> Union[Command, int]: 198 """:obj:`iqrfpy.enums.commands.Command` or :obj:`int`: Peripheral command. 199 200 Getter and setter. 201 """ 202 return self._pcmd 203 204 @pcmd.setter 205 def pcmd(self, value: Union[Command, int]): 206 self._validate_pcmd(pcmd=value) 207 self._pcmd = value 208 209 @staticmethod 210 def _validate_hwpid(hwpid: int): 211 """Validates Hardware profile ID parameter. 212 213 Args: 214 hwpid (int): Hardware profile ID value. 215 216 Raises: 217 RequestHwpidInvalidError: If hwpid is less than 0 or greater than 65535. 218 """ 219 if not dpa_constants.HWPID_MIN <= hwpid <= dpa_constants.HWPID_MAX: 220 raise RequestHwpidInvalidError('HWPID should be between 0 and 65535.') 221 222 @property 223 def hwpid(self) -> int: 224 """:obj:`int`: Hardware profile ID. 225 226 Getter and setter. 227 """ 228 return self._hwpid 229 230 @staticmethod 231 def _validate_dpa_rsp_time(dpa_rsp_time: Optional[float] = None): 232 """Validates dpa timeout parameter. 233 234 Args: 235 dpa_rsp_time (float, optional): DPA timeout value in seconds. Defaults to None. 236 237 Raises: 238 RequestParameterInvalidValueError: If dpa_rsp_time is not None and is less than 0. 239 """ 240 if dpa_rsp_time is None: 241 return 242 if dpa_rsp_time < 0: 243 raise RequestParameterInvalidValueError('DPA response time should a positive integer.') 244 245 @property 246 def dpa_rsp_time(self) -> Optional[float]: 247 """:obj:`float` or :obj:`None`: DPA timeout. 248 249 Getter and setter. 250 """ 251 return self._dpa_rsp_time 252 253 @dpa_rsp_time.setter 254 def dpa_rsp_time(self, value: Optional[float] = None): 255 self._validate_dpa_rsp_time(value) 256 self._dpa_rsp_time = value 257 258 @staticmethod 259 def _validate_dev_process_time(dev_process_time: Optional[float] = None): 260 """Validates device processing time parameter. 261 262 Args: 263 dev_process_time (float, optional): Device processing time value. Defaults to None. 264 265 Raises: 266 RequestParameterInvalidValueError: If dev_process_time is not None and is less than 0. 267 """ 268 if dev_process_time is None: 269 return 270 if dev_process_time < 0: 271 raise RequestParameterInvalidValueError('Device processing time should be a positive integer.') 272 273 @property 274 def dev_process_time(self) -> Optional[float]: 275 """:obj:`float` or :obj:`None`: Device processing time. 276 277 Getter and setter. 278 """ 279 return self._dev_process_time 280 281 @dev_process_time.setter 282 def dev_process_time(self, value: Optional[float] = None): 283 self._validate_dev_process_time(value) 284 self._dev_process_time = value 285 286 @property 287 def msgid(self) -> str: 288 """:obj:`str`: Message ID. 289 290 Getter and setter. 291 """ 292 return self._msgid 293 294 @msgid.setter 295 def msgid(self, value: str): 296 self._msgid = value 297 298 @property 299 def mtype(self) -> MessageType: 300 """:obj:`MessageType` Message type. 301 302 Getter only. 303 """ 304 return self._mtype 305 306 @abstractmethod 307 def to_dpa(self, mutable: bool = False) -> Union[bytes, bytearray]: 308 """DPA request serialization method. 309 310 Serializes a request to DPA request packet format. Each request contains the DPA request header. 311 If pdata is specified, it is appended to the DPA request header. The request can be serialized 312 into both mutable and immutable (default) byte formats. 313 314 Args: 315 mutable (bool, optional): Serialize into mutable byte representation of DPA request packet. 316 Defaults to False. 317 318 Returns: 319 :obj:`bytes`: Immutable byte representation of DPA request packet.\n 320 :obj:`bytearray`: Mutable byte representation of DPA request packet (if argument mutable is True). 321 """ 322 raise NotImplementedError('Abstract method not implemented.') 323 324 @abstractmethod 325 def to_json(self) -> dict: 326 """JSON API request serialization method. 327 328 Serializes a request to JSON API request object. Each request contains message type and data. 329 Data carries message ID for pairing requests with responses, and `req` object that contains network address, 330 hwpid and optional request parameters (equivalent to DPA packet data) if `params` is not None. 331 If DPA timeout is specified, the value is multiplied by 1000 as JSON API accepts timeout in milliseconds. 332 333 Returns: 334 :obj:`dict`: JSON API request object. 335 """ 336 raise NotImplementedError('Abstract method not implemented')
This abstract class serves as an interface for embedded peripherals and standards request messages.
The class provides getters and setters for shared request properties in the form of the @property decorator. Shared properties such as device address, peripheral, peripheral command and hwpid are validated here. The class also provides generic DPA and JSON serialization methods for derived classes to amend. While the abstract class cannot be instantiated, it's methods can be called from a derived class using super.
Network address (nadr) specifies target device: 0 (coordinator), 1-239 (node), 252 (local device), 254 (temporary address) and 255 (broadcast), other values are reserved. Values in range 0-255.
Peripheral number (pnum) specifies peripheral to use: 0-31 are served for embedded peripherals and 64-127 are reserved for IQRF standard peripherals. Peripheral number can be passed as a member of one of the peripheral enum class members (see iqrfpy.enums.peripherals) or plain integer. Values in range 0-255.
Peripheral command (pcmd) specifies a command to execute, each peripheral implements different commands. See DPA framework document for specific command numbers. Peripheral command can be passed as a member of one of the peripheral command enum class members (see iqrfpy.enums.commands) or plain integer. Peripheral number and peripheral command are pre-defined for each command message this library implements, however they will be required for user-defined messages. Values in range 0-255, but note that only values 0-127 are used for request commands, as response command value is equal to request command value plus 128 (0x80).
Hardware profile ID (hwpid) specifies a unique device (by its functionality), this argument can be used to filter which devices execute a commend specified by request message. Only devices with matching hwpid will execute a command, unless the value 65535 (0xFFFF) is used, which ignores hwpid checking. Values in range 0-65535.
Packet data (pdata) can be required or optional data sent with the request message, depending on the command. On a general level, packet data is treated as list of unsigned 1B integers. This means that when defining a user command and a request message, request data should be serialized into a list of previously mentioned format and stored in the pdata member.
For more detailed information, see the IQRF DPA Framework documentation.
Message type (m_type) is an optional argument, however, it is required when using JSON API as message type
is equivalent to a combination of peripheral number and peripheral command (see iqrfpy.enums.message_types).
For example, OSMessages.READ
(iqrfEmbedOs_Read) is equivalent to EmbedPeripherals.OS
(2) and
OSRequestCommands.READ
(0).
Request parameters (params) is an optional dictionary argument, that is used when constructing a JSON API request. When creating a user message, use the params member to propagate your request parameters into the final JSON request object.
DPA response time (dpa_rsp_time) is an optional argument specifying DPA request timeout, not time between reception of a request and delivery of response. Note that handling of this argument is the responsibility of a transport and system facilitating communication between the library and devices of the IQRF network.
Device processing time (dev_process_time) is an optional argument used to specify time allotted to the device executing a task beyond simple data processing. For example, a device may need to measure some quantity for certain amount of time for the measured value to be valid. Note that handling of this argument is the responsibility of a transport and system facilitating communication between the library and devices of the IQRF network.
Message ID (msgid) is an optional argument used only by the JSON API at this time. It is used to pair JSON API requests and responses as the message type argument only allows to pair requests of the same type, but not pairing a specific request and response, given the asynchronous nature of the JSON API.
77 def __init__(self, nadr: int, pnum: Union[Peripheral, int], pcmd: Union[Command, int], 78 hwpid: int = dpa_constants.HWPID_MAX, pdata: Optional[List[int]] = None, 79 m_type: Optional[MessageType] = None, msgid: Optional[str] = None, 80 params: Optional[dict] = None, dpa_rsp_time: Optional[float] = None, 81 dev_process_time: Optional[float] = None): 82 """IRequest constructor. 83 84 Args: 85 nadr (int): Network address. 86 pnum (Union[Peripheral, int]): Peripheral number. 87 pcmd (Union[Command, int]): Peripheral command. 88 hwpid (int, optional): Hardware profile ID. Defaults to 65535 (Ignore HWPID check). 89 pdata (List[int], optional): DPA request data. Defaults to None. 90 m_type (MessageType, optional): JSON API message type. Defaults to None. 91 msgid (str, optional): JSON API message ID. Defaults to None. If the parameter is not specified, a random 92 UUIDv4 string is generated and used. 93 params (dict, optional): JSON API request data. Defaults to None. 94 dpa_rsp_time (float, optional): DPA request timeout in seconds. Defaults to None. 95 dev_process_time (float, optional): Device processing time. Defaults to None. 96 """ 97 self._nadr = nadr 98 self._pnum = pnum 99 self._pcmd = pcmd 100 self._hwpid = hwpid 101 self._pdata = pdata 102 self._mtype = m_type 103 self._msgid = msgid if msgid is not None else str(uuid4()) 104 self._params = params if params is not None else {} 105 self._dpa_rsp_time = dpa_rsp_time 106 self._dev_process_time = dev_process_time 107 self._validate_base(nadr, pnum, pcmd, hwpid, dpa_rsp_time, dev_process_time)
IRequest constructor.
Arguments:
- nadr (int): Network address.
- pnum (Union[Peripheral, int]): Peripheral number.
- pcmd (Union[Command, int]): Peripheral command.
- hwpid (int, optional): Hardware profile ID. Defaults to 65535 (Ignore HWPID check).
- pdata (List[int], optional): DPA request data. Defaults to None.
- m_type (MessageType, optional): JSON API message type. Defaults to None.
- msgid (str, optional): JSON API message ID. Defaults to None. If the parameter is not specified, a random UUIDv4 string is generated and used.
- params (dict, optional): JSON API request data. Defaults to None.
- dpa_rsp_time (float, optional): DPA request timeout in seconds. Defaults to None.
- dev_process_time (float, optional): Device processing time. Defaults to None.
iqrfpy.enums.peripherals.Peripheral
of int
: Peripheral number.
Getter and setter.
iqrfpy.enums.commands.Command
or int
: Peripheral command.
Getter and setter.
306 @abstractmethod 307 def to_dpa(self, mutable: bool = False) -> Union[bytes, bytearray]: 308 """DPA request serialization method. 309 310 Serializes a request to DPA request packet format. Each request contains the DPA request header. 311 If pdata is specified, it is appended to the DPA request header. The request can be serialized 312 into both mutable and immutable (default) byte formats. 313 314 Args: 315 mutable (bool, optional): Serialize into mutable byte representation of DPA request packet. 316 Defaults to False. 317 318 Returns: 319 :obj:`bytes`: Immutable byte representation of DPA request packet.\n 320 :obj:`bytearray`: Mutable byte representation of DPA request packet (if argument mutable is True). 321 """ 322 raise NotImplementedError('Abstract method not implemented.')
DPA request serialization method.
Serializes a request to DPA request packet format. Each request contains the DPA request header. If pdata is specified, it is appended to the DPA request header. The request can be serialized into both mutable and immutable (default) byte formats.
Arguments:
- mutable (bool, optional): Serialize into mutable byte representation of DPA request packet. Defaults to False.
Returns:
bytes
: Immutable byte representation of DPA request packet.
bytearray
: Mutable byte representation of DPA request packet (if argument mutable is True).
324 @abstractmethod 325 def to_json(self) -> dict: 326 """JSON API request serialization method. 327 328 Serializes a request to JSON API request object. Each request contains message type and data. 329 Data carries message ID for pairing requests with responses, and `req` object that contains network address, 330 hwpid and optional request parameters (equivalent to DPA packet data) if `params` is not None. 331 If DPA timeout is specified, the value is multiplied by 1000 as JSON API accepts timeout in milliseconds. 332 333 Returns: 334 :obj:`dict`: JSON API request object. 335 """ 336 raise NotImplementedError('Abstract method not implemented')
JSON API request serialization method.
Serializes a request to JSON API request object. Each request contains message type and data.
Data carries message ID for pairing requests with responses, and req
object that contains network address,
hwpid and optional request parameters (equivalent to DPA packet data) if params
is not None.
If DPA timeout is specified, the value is multiplied by 1000 as JSON API accepts timeout in milliseconds.
Returns:
dict
: JSON API request object.