API
Types
- class rctclient.types.Command(value, names=None, *, module=None, qualname=None, type=None, start=1, boundary=None)
Commands that can be used with
ReceiveFrame
,make_frame()
as well asSendFrame
.- EXTENSION = 60
Extension, can't be parsed using
ReceiveFrame
.
- LONG_RESPONSE = 6
Long response (for variables > 251 bytes)
- LONG_WRITE = 3
Long write command (use for variables > 251 bytes)
- PLANT_LONG_RESPONSE = 70
Plant: Long response to a read or write to master
- PLANT_LONG_WRITE = 67
Plant: Long write
- PLANT_READ = 65
Plant: Read command
- PLANT_READ_PERIODICALLY = 72
Plant: Periodic reading
- PLANT_RESPONSE = 69
Plant: Response to a read or write to master
- PLANT_WRITE = 66
Plant: Write command
- READ = 1
Read command
- READ_PERIODICALLY = 8
Periodic reading
- RESPONSE = 5
Response to a read or write command
- WRITE = 2
Write command
- static is_long(command)
Returns whether a command is a long command.
- Return type:
bool
- static is_plant(command)
Returns whether a command is for plant communication by checking if bit 6 is set.
- Return type:
bool
- static is_response(command)
Returns whether a command is a response. :rtype:
bool
New in version 0.0.4.
- static is_write(command)
Returns whether a command is a write command. :rtype:
bool
New in version 0.0.4.
- class rctclient.types.ObjectGroup(value, names=None, *, module=None, qualname=None, type=None, start=1, boundary=None)
Grouping information for object IDs. The information is not used by the protocol and only provided to aid the user in using the software.
- ACC_CONV = 12
- ADC = 10
- BATTERY = 4
- BATTERY_PLACEHOLDER = 34
- BAT_MNG_STRUCT = 23
- BUF_V_CONTROL = 18
- CAN_BUS = 26
- CS_MAP = 31
- CS_NEG = 5
- DB = 19
- DC_CONV = 13
- DISPLAY_STRUCT = 27
- ENERGY = 1
- FAULT = 29
- FLASH_PARAM = 28
- FLASH_RTC = 16
- FRT = 35
- GRID_LT = 25
- GRID_MON = 2
- G_SYNC = 7
- HW_TEST = 6
- IO_BOARD = 15
- ISO_STRUCT = 24
- LINE_MON = 32
- LOGGER = 8
- MODBUS = 22
- NET = 11
- NSM = 14
- OTHERS = 33
- PARTITION = 36
- POWER_MNG = 17
- PRIM_SM = 30
- P_REC = 21
- RB485 = 0
- SWITCH_ON_COND = 20
- TEMPERATURE = 3
- WIFI = 9
- class rctclient.types.FrameType(value, names=None, *, module=None, qualname=None, type=None, start=1, boundary=None)
Enumeration of supported frame types.
- PLANT = 8
Plant frame with ID and address
- STANDARD = 4
Standard frame with an ID
- class rctclient.types.DataType(value, names=None, *, module=None, qualname=None, type=None, start=1, boundary=None)
Enumeration of types, used to select the correct structure when encoding for sending or decoding received data. See
decode_value()
andencode_value()
.- BOOL = 1
Boolean data (true or false)
- ENUM = 8
Enum, will be handled like a 16-bit unsigned integer
- EVENT_TABLE = 21
Non-native: Event table entries consisting of a tuple of a timestamp for the record (usually the day) and a dict mapping values to timestamps. Can not be used for encoding.
- FLOAT = 9
Floating point number
- INT16 = 5
16-bit signed integer
- INT32 = 7
32-bit signed integer
- INT8 = 3
8-bit signed integer
- STRING = 10
String (may contain 0 padding).
- TIMESERIES = 20
Non-native type: Timeseries data consisting of a tuple of a timestamp for the record (usually the day) and a dict mapping values to timestamps. Can not be used for encoding.
- UINT16 = 4
16-bit unsigned integer
- UINT32 = 6
32-bit unsigned integer
- UINT8 = 2
8-bit unsigned integer
- UNKNOWN = 0
Unknown type, default. Do not use for encoding or decoding.
- class rctclient.types.EventEntry(entry_type, timestamp, element2=None, element3=None, element4=None)
A single entry in the event table. An entry consists of a type, which controls the meaning of the other fields.
Note
Not a whole lot is known about the entries. Information (and this structure) may change in the future. The payload fields are stored as-is for now, as the information known to this date is too limited. Refer to the documentation for more information about the event table.
Furthermore, the entry type is believed to be a single byte, so unless more information is known that changes this, the type is validated to be in the range 0-255.
Each entry has a timestamp field that, depending on the type, either denotes the start time for a ranged event (such as the start of an error condition) or the precise time when the event occured (such as for a parameter change).
The element-fields contain the raw value from the device. Use
decode_value()
to decode them if the data type is known.- Parameters:
entry_type (
int
) -- The type of the entry.timestamp (
datetime
) -- Timestamp of the entry (element1).element2 (
Optional
[bytes
]) -- The second element of the entry.element3 (
Optional
[bytes
]) -- The third element of the entry.element4 (
Optional
[bytes
]) -- The fourth element of the entry.
Exceptions
- class rctclient.exceptions.RctClientException
Base exception for this Python module.
- class rctclient.exceptions.FrameError
Base exception for frame handling code.
- class rctclient.exceptions.FrameCRCMismatch(message, received_crc, calculated_crc, consumed_bytes=0)
Indicates that the CRC that was received did not match with the computed value.
- Parameters:
received_crc (
int
) -- The CRC that was received with the frame.calculated_crc (
int
) -- The CRC that was calculated based on the received data.
- class rctclient.exceptions.FrameLengthExceeded(message, consumed_bytes=0)
Indicates that more data was consumed by ReceiveFrame than it should have. This usually indicates a bug in the parser code and should be reported.
- class rctclient.exceptions.InvalidCommand(message, command, consumed_bytes=0)
Indicates that the command is not supported. This means that
Command
does not contain a field for it, or that it is the EXTENSION command that cannot be handled.- Parameters:
command (
int
) -- The command byte.
Classes
- class rctclient.registry.ObjectInfo(group, object_id, index, name, request_data_type, description=None, unit=None, sim_data=None, response_data_type=None, enum_map=None)
Information about an object that can be sent to or received from the device. It describes a single object ID and adds more information to it. Some of this information is required to interact with the device (receive and send data type), while other bits are purely to aid the user when using the structures.
It is in concept similar to SNMP OIDs or their MIB information respectively, in that it describes an object ID.
Each instance of this class describes a single object ID. When interacting with the device, the object ID is used to target the information that should be returned (read command) or changed (write command). Data received from or sent to the device needs to be decoded or encoded, and object IDs may respond with a different data type than the request for it uses (such as the logger-group). To facilitate this, a request_data_type tells the user how to encode a request to the device (for both read and write commands), while the response_data_type tells the user how to decode the response from the device (for both read and write commands). If the response_data_type is not set, the request_data_type is returned as a default fallback.
While object IDs are grouped when looking at their name (such as
rb485.version_boot
in grouprb485
), this information is not actually used by the protocol. Similarly, the index, name and description are not used by the protocol, but allow the user to quickly identify what they are dealing with.Refer to the
Registry
for information about how to handle the information.- Parameters:
group (
ObjectGroup
) -- The group the ID belongs to.object_id (
int
) -- The unique message id.index (
int
) -- Numerical index.request_data_type (
DataType
) -- Data type used for encoding the payload of aRctSendFrame
.response_data_type (
Optional
[DataType
]) -- Data type used for decoding the response payload of aRctReceiveFrame
. If omitted, the value of request_data_type is used.description (
Optional
[str
]) -- Optional description.unit (
Optional
[str
]) -- Optional unit symbol.sim_data (
Any
) -- Data used by the simulator.enum_values -- Mapping of integer ID to string value.
-
description:
Optional
[str
] Optional description in English text.
-
enum_map:
Optional
[Dict
[int
,str
]] Optional enum mapping
- enum_str(value)
For DataType.ENUM: converts the integer value to the string. If there is no mapping or the type is not DataType.ENUM, raises an exception.
- Parameters:
value (
int
) -- The value to convert.- Return type:
str
- Returns:
The string key associated with the value.
- Raises:
RctClientException -- If the type is not ENUM or no mapping is defined.
KeyError -- If the value is not in the range of the enum mapping.
-
group:
ObjectGroup
The group the ID belongs to
-
index:
int
Numerical index.
-
name:
str
Name internal to the device, may be found in the official app.
-
object_id:
int
The unique message id that identifies it.
-
unit:
Optional
[str
] Optional unit.
- class rctclient.registry.Registry(data)
Registry object maintaining all the
ObjectInfo
instances. Its main purpose is to provide functions to query for IDs by various means. As it contains the whole lot of IDs, loading it is slow. It should be kept around as a singleton.- Parameters:
data (
List
[ObjectInfo
]) -- List of the IDs it should maintain.
- get_by_id(id)
Returns a specific id.
- Parameters:
id (
int
) -- The object_id to query for.- Return type:
- Returns:
The id that was found.
- Raises:
KeyError -- If the id is not in the registry.
- get_by_name(name)
Returns the id identified by its name field.
- Parameters:
name (
str
) -- The name to query for.- Return type:
- Returns:
The id.
- Raises:
KeyError -- If no id with that name is in the registry.
- name_max_length()
Returns the length of the longest name managed by this instance, primarily for improving user interface.
- Return type:
int
- prefix_complete_name(prefix)
To aid the CLI commands when autocompleting, this function returns a list of names that start with the given prefix, or all names if the prefix is empty.
- Parameters:
prefix (
str
) -- Prefix to match.- Return type:
List
[str
]- Returns:
A list of names that start with the given prefix, or all if the prefix is an empty string.
- class rctclient.frame.ReceiveFrame(ignore_crc_mismatch=False)
Structure to receive and decode data received from the RCT device. Each instance can only consume a single frame and a new one needs to be constructed to receive the next one. Frames are decoded incrementally, by feeding data to the
consume()
function as it arrives over the network. The function returns the amount of bytes it consumed, and it automatically stops consumption the frame has been received completely.Use
complete()
to determin if the frame has been received in its entirety.When the frame has been received completely (
complete()
returns True), it extracts the CRC and compares it with its own calculated checksum. Unlessignore_crc_match
is set, aFrameCRCMismatch
is raised if the checksums do not match.If the command encoded in the frame is not supported or invalid, a
InvalidCommand
will be raised unconditionally during consumption.Both exceptions carry the amount of consumed bytes in a field as to allow users to remove the already consumed bytes from their input buffer in order to start consumption with a new ReceiveFrame instance for the next frame.
Some of the fields (such as command, id, frame_type, ...) are populated if enough data has arrived, even before the checksum has been received and compared. Until
complete()
returns True, this data may not be valid, but it may hint towards invalid frames (invalid length being the most common problem).To decode the payload, use
decode_value()
.Note
The parsing deviates from the protocol in the following ways:
arbitrary data (instead of just a single
0x00
) before a start byte is ignored.the distinction between normal and long commands is ignored. No error is reported if a frame that should be a
LONG_RESPONSE
is received withRESPONSE
, for example.
Changed in version 0.0.3:
The frame type is detected from the consumed data and the
frame_type
parameter was removed.Debug logging is now handled using the Python logging framework.
debug()
was dropped as it served no use anymore.The
decode()
method was removed as the functionality was integrated intoconsume()
.
New in version 0.0.3: The
ignore_crc_match
parameter prevents raising an exception on CRC mismatch. Use thecrc_ok
property to figure out if the CRC matched when setting the parameter toTrue
.- Parameters:
ignore_crc_mismatch (
bool
) -- If not set, no exception is raised when the CRC checksums do not match. Usecrc_ok
to figure out if they matched.
- property address: int
Returns the address if the frame is a plant frame (
FrameType.PLANT
) or 0.- Raises:
FrameNotComplete -- If the frame has not been fully received.
- complete()
Returns whether the frame has been received completely. If this returns True, do not
consume()
any more data with this instance, but instead create a new instance of this class for further consumption of data.- Return type:
bool
- consume(data)
Consumes data until the frame is complete. Returns the number of consumed bytes. Exceptions raised also carry the amount of consumed bytes.
- Parameters:
data (
Union
[bytes
,bytearray
]) -- Data to consume.- Return type:
int
- Returns:
The amount of bytes consumed from the input data.
- Raises:
FrameCRCMismatch -- If the checksum didn't match and
ignore_crc_mismatch
was not set.FrameLengthExceeded -- If the parser read past the frames advertised length.
InvalidCommand -- If the command byte is invalid or can't be decoded (such as
EXTENSION
).
- property consumed_bytes: int
Returns how many bytes the frame has consumed over its lifetime. This includes data that was consumed before the start of a frame was found, so the amount reported here may be larger than the amount of data that makes up the frame.
New in version 0.0.3.
- property crc_ok: bool
Returns whether the CRC is valid. The value is only valid after a complete frame has arrived.
New in version 0.0.3.
- property data: bytes
Returns the received data payload. This is empty if there has been no data received or the CRC did not match.
- property frame_length: int
Returns the length of the frame. This is
0
until the header containing the length field has been received. Note that this is not the length field of the protocol but rather the length of the frame in its entirety, from start byte to the end of the CRC.New in version 0.0.3.
- property frame_type: FrameType
Returns the frame type if enough data has been received to decode it, and
FrameType._NONE
otherwise.New in version 0.0.3.
- property id: int
Returns the ID. If the frame has been received but the checksum does not match up, 0 is returned.
- property ignore_crc_mismatch: bool
Returns whether CRC mismatches are ignored during decoding.
New in version 0.0.3.
- class rctclient.frame.SendFrame(command, id, payload=b'', address=0, frame_type=FrameType.STANDARD)
A container for data to be transmitted to the target device. Instances of this class keep the input values so they can be retrieved later, if that is not a requirement it's easier to use
make_frame()
which is called by this class internally to generate the byte stream. The byte stream stored by this class is generated on initialization and can be retrieved at any time using thedata
property.The frame byte stream that is generated by this class is meant to be sent to a device. The receiving side is implemented in
ReceiveFrame
.payload needs to be encoded before it can be transmitted. See
encode_value()
. It is ignored forREAD
commands.address is used for
PLANT
frames and otherwise ignored, when queried later using theaddress
property, 0 is returned for non-PLANT frames.- Parameters:
- property address: int
Returns the address for plant communication. Note that this returns 0 unless plant-communication was requested.
- property data: bytes
Returns the data after encoding, ready to be sent over the socket.
- property id: int
Returns the object ID.
- property payload: bytes
Returns the payload (input data). To get the result to send to a device, use
data
. Note that this returns an empty byte stream forREAD
commands, regardless of any input.
Functions
- rctclient.frame.make_frame(command, id, payload=b'', address=0, frame_type=FrameType.STANDARD)
Crafts the byte-stream representing the input values. The result of this function can be sent as-is to the target device.
payload is ignored for
READ
commands. and the address is ignored forSTANDARD
frames.For a variant which stores the input values as well as the output, see
SendFrame
.New in version 0.0.2.
- Parameters:
command (
Command
) -- The command to transmit.id (
int
) -- The object ID to target.payload (
bytes
) -- The payload to be transmitted. Useencode_value()
to generate valid payloads.address (
int
) -- Address for plant communication (untested, ignored for standard communication).frame_type (
FrameType
) -- The type if frame to transmit (standard or plant).
- Return type:
bytes
- Returns:
byte object ready to be sent to a device.
- rctclient.utils.decode_value(data_type, data)
Decodes a value received from the device.
Note
Values for a message id may be decoded using a different type than was used for encoding. For example, the logger history writes a unix timestamp and receives a timeseries data structure.
- Parameters:
data_type (
DataType
) -- Data type of the value to be decoded. This selects the decoding mechanism.value -- The value to be decoded.
- Return type:
Union
[bool
,bytes
,float
,int
,str
,Tuple
[datetime
,Dict
[datetime
,int
]],Tuple
[datetime
,Dict
[datetime
,EventEntry
]]]- Returns:
The decoded value, depending on the data_type.
- Raises:
struct.error -- If decoding of native types failed.
- rctclient.utils.encode_value(data_type, value)
Encodes a value suitable for transmitting as payload to the device. The actual encoding depends on the data_type.
- Parameters:
data_type (
DataType
) -- Data type of the value to be encoded. This selects the encoding mechanism.value (
Union
[bool
,bytes
,float
,int
,str
]) -- Data to be encoded according to the data_type.
- Return type:
bytes
- Returns:
The encoded value.
- Raises:
struct.error -- If the packing failed, usually when the input value can't be encoded using the selected type.
ValueError -- For string values, if the data type is not
str
orbytes
.
- rctclient.utils.CRC16(data)
Calculates the CRC16 checksum of data. Note that this automatically skips the first byte (start token) if the length is uneven.
- Return type:
int