This project provides a Python library for encoding, decoding, and manipulating data frames for Sterilor EVO protocol. It is designed for embedded systems (e.g., ESP32, MicroPython). The library simplifies communication between devices and control systems (see sterilor_ble2mqtt repository).
FrameField: Represents a single field in a frame, including metadata (type, length, scale, choices) and methods for validation, encoding, and decoding.FrameBitField: Manages bitmask fields, where each bit represents a binary state (e.g., error flags).Mapping: Maps a name to a bit position in aFrameBitField.
- Custom Formats:
HexString: Hexadecimal strings (e.g.,"1A2B").DotHexVersion: Version strings (e.g.,"01.02.3a").SerialNo: Null-terminated ASCII serial numbers.DotIntVersion: Numeric versions with dots (e.g.,"1.23").
- Signed/Unsigned Integers: Conversion between bytes and integers, with support for negative values, specific for MicroPython.
Parser: Base class to parse raw bytes (bytes) into structured dictionaries and vice versa.create(): Builds a frame from a data dictionary.parse(): Extracts data from raw bytes.set_frame_data(): Modifies an existing frame with new data.
ParserWithProblems: Subclass to handle problem lists encoded as bitmasks.
utils.py: Helper functions for byte manipulation (e.g.,reverse_bytearray,signed_int_to_bytes).constants.py: Definitions for request codes, frame types, etc.
- Supported Types: Integers (signed/unsigned), floats, booleans, strings, and bitfields.
- Scaling and Masking: Apply scaling factors (e.g.,
value * 10) or bitmasks (e.g.,value & 0xFF). - Predefined Choices: Map integer values to labels (e.g.,
1: "OK",2: "Error").
- Bitmask Encoding/Decoding: Convert boolean lists to bytes (and vice versa), with support for:
- Byte Order Reversal (
reverse=True). - Nibble Swapping (
swap_byte=True).
- Byte Order Reversal (
- Variable Length: Frames can be fixed or dynamic in length.
- Conditional Fields: Some fields are only present under specific conditions (e.g.,
extend_read).
- Tested on Olimex POE ESP32.
from parsers import Parser, FrameField
class MyFrameParser(Parser):
name = "my_frame"
code = "A1B2"
fields = [
FrameField(name="temperature", field_type=float, index=0, length=2, scale=0.1),
FrameField(name="status", field_type=int, index=2, length=1, choices={0: "OFF", 1: "ON"}),
]
# Usage
parser = MyFrameParser()
data = {"temperature": 25.5, "status": 1}
frame = parser.create(data) # -> bytes
parsed_data = parser.parse(frame) # -> {"temperature": 25.5, "status": 1}from parsers import ParserWithProblems, Mapping
class ProblemParser(ParserWithProblems):
name = "problem_frame"
code = "C3D4"
problems_data = {
0: "Overheat",
1: "Low Pressure",
2: "Communication Error",
-1: "No Problems",
}
fields = [...] # Other fields
# Usage
parser = ProblemParser()
data = {"problems": ["Overheat", "Communication Error"]}
frame = parser.create(data)
parsed_data = parser.parse(frame) # -> {"problems": ["Overheat", "Communication Error"], ...}from formats import DotHexVersion
formatter = DotHexVersion(length=3)
encoded = formatter.encode("1A.2B.3C") # -> b'\x1a\x2b\x3c'
decoded = formatter.decode(encoded) # -> "1A.2B.3C"The following Micropython libraries are necessary to run on an embedded device:
- typing
- pathlib
- copy
- inspect
You are welcome to contribute using the Issues section in the Github projet or directly with push requests.