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 as SendFrame.

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() and encode_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 group rb485), 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 a RctSendFrame.

  • response_data_type (Optional[DataType]) -- Data type used for decoding the response payload of a RctReceiveFrame. 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.

request_data_type: DataType

Data type for encoding the request

response_data_type: DataType

Data type for decoding the response

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:

ObjectInfo

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:

ObjectInfo

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.

type_by_id(id)

Returns the request data type of an ID.

Parameters:

id (int) -- The object_id to query for.

Return type:

DataType

Returns:

The request data type.

Raises:

KeyError -- If the id is not in the registry.

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. Unless ignore_crc_match is set, a FrameCRCMismatch 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 with RESPONSE, 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 into consume().

New in version 0.0.3: The ignore_crc_match parameter prevents raising an exception on CRC mismatch. Use the crc_ok property to figure out if the CRC matched when setting the parameter to True.

Parameters:

ignore_crc_mismatch (bool) -- If not set, no exception is raised when the CRC checksums do not match. Use crc_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.

property command: Command

Returns the command.

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 the data 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 for READ commands.

address is used for PLANT frames and otherwise ignored, when queried later using the address property, 0 is returned for non-PLANT frames.

Parameters:
  • command (Command) -- The command to transmit.

  • id (int) -- The message id.

  • payload (bytes) -- Optional payload (ignored for read commands).

  • address (int) -- Address for plant communication (untested, ignored for non-PLANT frame types).

  • frame_type (FrameType) -- Type of frame (standard or plant).

property address: int

Returns the address for plant communication. Note that this returns 0 unless plant-communication was requested.

property command: Command

Returns the command.

property data: bytes

Returns the data after encoding, ready to be sent over the socket.

property frame_type: FrameType

Returns the type of communication frame.

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 for READ 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 for STANDARD 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. Use encode_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 or bytes.

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