API Reference

frame_msg - Frame Message Package defines Transmit- and Receive-related frame message classes and their associated Lua handlers for Brilliant Labs Frame (https://brilliant.xyz/)

FrameMsg

class frame_msg.frame_msg.FrameMsg[source]

Bases: object

A high-level library for interacting with Brilliant Labs Frame by passing structured messages between a Frameside app and a hostside app.

async connect(initialize: bool = True)[source]

Connect to the Frame device and optionally run the initialization sequence.

Parameters:

initialize (bool) – If True, runs the break/reset/break sequence after connecting. Defaults to True.

Returns:

True if connection and initialization were successful

Return type:

bool

Raises:

Any exceptions from the underlying FrameBle connection

async disconnect()[source]

Disconnect from the Frame device

is_connected()[source]

Check if currently connected to the Frame device.

async print_short_text(text: str = '')[source]

Convenience wrapper around frame.display.text() that can only be used prior to the main frame_app starting (e.g. immediately after connection).

async upload_stdlua_libs(lib_names: List[str] = ['data'], minified: bool = True)[source]

Send the specified standard frame-msg Lua files to Frame that are used by the frame_app, e.g. [‘data’, ‘camera’]

async upload_frame_app(local_filename: str, frame_filename: str = 'frame_app.lua')[source]

Send the main lua application from this project to Frame that will run the app (but doesn’t run the file)

async start_frame_app(frame_app_name: str = 'frame_app', await_print: bool = True)[source]

‘require’ the main lua file to run it

Note: This require() doesn’t return - frame_app.lua has a main loop, so we can’t put a ‘print(0)’ after the require() statement and wait for it to print, however if our main loop prints something (even a byte) once it has started up, then the await_print can be used to determine that the frameside app is ready rather than waiting for an app-dependent amount of time, or sending messages to Frame too early. Set await_print to False if the Frame app should be asynchronously started and without waiting for any printed confirmation that the frameside app is ready.

async stop_frame_app(reset=True)[source]

Sends a break signal to terminate the running main loop on Frame, if applicable. A custom app may prefer to send a specific TxCode to the Frameside app to instruct it to shut down cleanly, but a break signal will also be caught by the exception handler of the main loop and is enough to clean up the display, release memory etc.

If reset is True (default), then also send a reset signal that will reinitialize the Lua VM and boot into a saved main.lua, if present.

attach_print_response_handler(handler=<built-in function print>)[source]

Attach the print response handler so we can see stdout from Frame Lua print() statements

detach_print_response_handler()[source]

Detach the print response handler so we no longer see stdout from Frame Lua print() statements

async send_message(msg_code: int, payload: bytes, show_me: bool = False) None[source]

Sends a structured message from hostside to the Frameside app, identified by the specified msg_code. For example, if the frame_app is expecting a TxCaptureSettings message on msg_code 0x0d to initiate a photo capture, you might send: frame.send_message(0x0d, TxCaptureSettings(resolution=720).pack()) Wraps the frame_ble function of the same name

register_data_response_handler(subscriber, msg_codes: List[int], handler: Callable[[bytes], None])[source]

Register a handler for a subscriber that is interested in specific msg codes.

Parameters:
  • subscriber – The subscriber object.

  • msg_codes (List[int]) – List of single byte msg codes the subscriber is interested in.

  • handler – The handler function to receive the data.

unregister_data_response_handler(subscriber)[source]

Unregister a subscriber from receiving data responses.

Parameters:

subscriber – The subscriber object to unregister.

RxAudio

class frame_msg.rx_audio.RxAudio(non_final_chunk_flag: int = 5, final_chunk_flag: int = 6, streaming: bool = False)[source]

Bases: object

handle_data(data: bytes) None[source]

Process incoming audio data packets with either a non-final or a final msg code.

Parameters:

data – Bytes containing audio data with flag byte prefix

async attach(frame: FrameMsg) Queue[source]

Attach the audio handler to the Frame data response and return a queue that will receive audio data.

Returns:

asyncio.Queue that will receive bytes containing audio data. In streaming mode, receives chunks as they arrive. In single-clip mode, receives complete audio clip at once. A None value indicates end of stream/clip.

detach(frame: FrameMsg) None[source]

Detach the audio handler from the Frame data response and clean up resources

static to_wav_bytes(pcm_data: bytes, sample_rate: int = 8000, bits_per_sample: int = 8, channels: int = 1) bytes[source]

Create a WAV file from PCM data.

Parameters:
  • pcm_data – Raw PCM audio data - signed 8-bit or 16-bit samples straight from Frame (8-bit signed will be converted to unsigned 8-bit for WAV)

  • sample_rate – Audio sample rate in Hz

  • bits_per_sample – Number of bits per sample

  • channels – Number of audio channels

Returns:

Bytes containing complete WAV file

RxAutoExpResult

class frame_msg.rx_auto_exp_result.RxAutoExpResult(msg_code: int = 17)[source]

Bases: object

handle_data(data: bytes) None[source]

Process incoming data packets.

Parameters:

data – Bytes containing auto exposure result data with flag byte prefix and 16 floats

async attach(frame: FrameMsg) Queue[source]

Attach the receive handler to the Frame data response and return a queue that will receive autoexposure result data.

Returns:

asyncio.Queue that will receive autoexposure result objects

detach(frame: FrameMsg) None[source]

Detach the receive handler from the Frame data response and clean up resources

RxIMU

class frame_msg.rx_imu.SensorBuffer(max_size: int)[source]

Bases: object

Buffer class to provide smoothed moving average of samples

add(value: Tuple[int, int, int]) None[source]
property average: Tuple[int, int, int]
class frame_msg.rx_imu.IMURawData(compass: Tuple[int, int, int], accel: Tuple[int, int, int])[source]

Bases: object

compass: Tuple[int, int, int]
accel: Tuple[int, int, int]
class frame_msg.rx_imu.IMUData(compass: Tuple[int, int, int], accel: Tuple[int, int, int], raw: frame_msg.rx_imu.IMURawData | None = None)[source]

Bases: object

compass: Tuple[int, int, int]
accel: Tuple[int, int, int]
raw: IMURawData | None = None
property pitch: float
property roll: float
class frame_msg.rx_imu.RxIMU(imu_flag: int = 10, smoothing_samples: int = 1)[source]

Bases: object

handle_data(data: bytes) None[source]

Process incoming IMU data packets.

Parameters:

data – Bytes containing IMU data with flag byte prefix

async attach(frame: FrameMsg) Queue[source]

Attach the IMU handler to the Frame data response and return a queue that will receive IMU data.

Returns:

asyncio.Queue that will receive IMUData objects

detach(frame: FrameMsg) None[source]

Detach the IMU handler from the Frame data response and clean up resources

RxMeteringData

class frame_msg.rx_metering_data.RxMeteringData(msg_code: int = 18)[source]

Bases: object

handle_data(data: bytes) None[source]

Process incoming data packets.

Parameters:

data – Bytes containing metering data with flag byte prefix and 6 unsigned bytes (spot r,g,b, matrix r,g,b)

async attach(frame: FrameMsg) Queue[source]

Attach the receive handler to the Frame data response and return a queue that will receive metering data.

Returns:

asyncio.Queue that will receive metering data objects

detach(frame: FrameMsg) None[source]

Detach the receive handler from the Frame data response and clean up resources

RxPhoto

class frame_msg.rx_photo.RxPhoto(non_final_chunk_flag: int = 7, final_chunk_flag: int = 8, upright: bool = True, is_raw: bool = False, quality: str | None = None, resolution: int | None = None)[source]

Bases: object

classmethod has_jpeg_header(quality: str, resolution: int) bool[source]

Check if we have a stored JPEG header for the given quality and resolution

handle_data(data: bytes) None[source]

Process incoming chunks of image data.

Parameters:

data – Bytes containing image chunk with flag byte prefix

async attach(frame: FrameMsg) Queue[source]

Attach the photo handler to the Frame data response and return a queue that will receive complete images.

Returns:

asyncio.Queue that will receive bytes containing complete JPEG images

detach(frame: FrameMsg) None[source]

Detach the photo handler from the Frame data response and clean up resources

RxTap

class frame_msg.rx_tap.RxTap(tap_flag: int = 9, threshold: float = 0.3)[source]

Bases: object

handle_data(data: bytes) None[source]

Process an incoming Tap message

Parameters:

data – A single byte with the tap_flag prefix

async attach(frame: FrameMsg) Queue[source]

Attach the tap handler to the Frame data response and return a queue that will receive tap counts.

Returns:

asyncio.Queue that will receive integers representing tap counts

detach(frame: FrameMsg) None[source]

Detach the tap handler from the Frame data response and clean up resources

TxAutoExpSettings

class frame_msg.tx_auto_exp_settings.TxAutoExpSettings(metering_index: int = 1, exposure: float = 0.1, exposure_speed: float = 0.45, shutter_limit: int = 16383, analog_gain_limit: int = 16, white_balance_speed: float = 0.5, rgb_gain_limit: int = 287)[source]

Bases: object

Message for auto exposure and gain settings.

metering_index

Zero-based index into [‘SPOT’, ‘CENTER_WEIGHTED’, ‘AVERAGE’] i.e. 0, 1 or 2.

Type:

int

exposure

Target exposure value (0.0-1.0)

Type:

float

exposure_speed

Speed of exposure adjustments (0.0-1.0)

Type:

float

shutter_limit

Maximum shutter value (4-16383)

Type:

int

analog_gain_limit

Maximum analog gain value (1-248)

Type:

int

white_balance_speed

Speed of white balance adjustments (0.0-1.0)

Type:

float

rgb_gain_limit

Maximum gain value for red, green, blue channels (0-1023)

Type:

int

metering_index: int = 1
exposure: float = 0.1
exposure_speed: float = 0.45
shutter_limit: int = 16383
analog_gain_limit: int = 16
white_balance_speed: float = 0.5
rgb_gain_limit: int = 287
pack() bytes[source]

Pack the settings into 9 bytes.

TxCaptureSettings

class frame_msg.tx_capture_settings.TxCaptureSettings(resolution: int = 512, quality_index: int = 4, pan: int = 0, raw: bool = False)[source]

Bases: object

Message for camera capture settings.

resolution

Image resolution (256-720, must be even)

Type:

int

quality_index

Index into [VERY_LOW, LOW, MEDIUM, HIGH, VERY_HIGH]

Type:

int

pan

Image pan value (-140 to 140)

Type:

int

raw

Whether to capture in RAW format

Type:

bool

resolution: int = 512
quality_index: int = 4
pan: int = 0
raw: bool = False
pack() bytes[source]

Pack the settings into 6 bytes.

TxCode

class frame_msg.tx_code.TxCode(value: int = 0)[source]

Bases: object

A simple message containing only a message code and an optional byte value. Used for signaling the frameside app to take some action.

value: int = 0
pack() bytes[source]

Pack the message into a single byte.

TxImageSpriteBlock

class frame_msg.tx_image_sprite_block.TxImageSpriteBlock(image: TxSprite, sprite_line_height: int = 16, progressive_render: bool = True, updatable: bool = True)[source]

Bases: object

An image split into horizontal sprite strips.

image

Source sprite to split

Type:

frame_msg.tx_sprite.TxSprite

sprite_line_height

Height of each sprite strip. If the TxSprite is compressed, the strip has a packed size limit of 4kB and this value is ignored.

Type:

int

progressive_render

Whether to render lines as they arrive

Type:

bool

updatable

Whether lines can be updated after initial render

Type:

bool

image: TxSprite
progressive_render: bool
updatable: bool
sprite_line_height: int
pack() bytes[source]

Pack the image block header.

TxManualExpSettings

class frame_msg.tx_manual_exp_settings.TxManualExpSettings(manual_shutter: int = 3072, manual_analog_gain: int = 16, manual_red_gain: int = 121, manual_green_gain: int = 64, manual_blue_gain: int = 140)[source]

Bases: object

Message for manual exposure and gain settings.

manual_shutter

Shutter value (4-16383)

Type:

int

manual_analog_gain

Analog gain value (1-248)

Type:

int

manual_red_gain

Red gain value (0-1023)

Type:

int

manual_green_gain

Green gain value (0-1023)

Type:

int

manual_blue_gain

Blue gain value (0-1023)

Type:

int

manual_shutter: int = 3072
manual_analog_gain: int = 16
manual_red_gain: int = 121
manual_green_gain: int = 64
manual_blue_gain: int = 140
pack() bytes[source]

Pack the settings into 9 bytes.

TxPlainText

class frame_msg.tx_plain_text.TxPlainText(text: str, x: int = 1, y: int = 1, palette_offset: int = 1, spacing: int = 4)[source]

Bases: object

A message containing plain text with positioning and formatting information.

text

The plain text content to be transmitted

Type:

str

x

X-coordinate for text position (1-640, Lua/1-based indexing)

Type:

int

y

Y-coordinate for text position (1-400, Lua/1-based indexing)

Type:

int

palette_offset

Color palette offset (1-15, 0/’VOID’ is invalid)

Type:

int

spacing

Character spacing value

Type:

int

text: str
x: int = 1
y: int = 1
palette_offset: int = 1
spacing: int = 4
pack() bytes[source]

Packs the message into a binary format.

Returns:

Binary representation of the message in the format:

[x_msb, x_lsb, y_msb, y_lsb, palette_offset, spacing, text_bytes…]

Return type:

bytes

TxSprite

class frame_msg.tx_sprite.TxSprite(width: int, height: int, num_colors: int, palette_data: bytes, pixel_data: bytes, compress: bool = False)[source]

Bases: object

A sprite message containing image data with a custom palette.

width

Width of the sprite in pixels

Type:

int

height

Height of the sprite in pixels

Type:

int

num_colors

Number of colors in the palette (2, 4, or 16)

Type:

int

palette_data

RGB values for each color (3 bytes per color)

Type:

bytes

pixel_data

Array of palette indices for each pixel

Type:

bytes

width: int
height: int
num_colors: int
palette_data: bytes
pixel_data: bytes
compress: bool = False
static from_indexed_png_bytes(image_bytes: bytes, compress=False) TxSprite[source]

Create a TxSprite from an indexed PNG with minimal processing.

static from_image_bytes(image_bytes: bytes, max_pixels=48000, compress=False) TxSprite[source]

Create a sprite from the bytes of any image file format supported by PIL Image.open(), quantizing and scaling to ensure it fits within max_pixels (e.g. 48,000 pixels).

property bpp: int

Bits per pixel based on the number of colors.

pack() bytes[source]

Pack the sprite into its binary format.

TxTextSpriteBlock

class frame_msg.tx_text_sprite_block.TxTextSpriteBlock(width: int, font_size: int, max_display_rows: int, text: str, font_family: str | None = None)[source]

Bases: object

A block of text rendered as sprites.

width

Width constraint for text layout

Type:

int

font_size

Font size in pixels

Type:

int

max_display_rows

Maximum number of rows to display

Type:

int

text

The text to render

Type:

str

font_family

Optional font family name

Type:

str | None

width: int
font_size: int
max_display_rows: int
text: str
font_family: str | None = None
pack() bytes[source]

Pack the text block header.