Pixel Streaming SKY only
LaMetric SKY devices support the LaMetric Streaming Protocol (LMSP) for pushing real-time RGB888 frames over UDP at up to 30 FPS. All three streaming services target the Light entity of a SKY device.
How it works
-
Read canvas dimensions — check the
Light entity's state attributes
(
canvas_pixelorcanvas_triangle) to find the correct canvas size for your device and chosen render mode. -
Start a stream — call
start_stream. The service returns asession_idand the device enters streaming state. -
Send frames — call
send_stream_datarepeatedly, up to 30 FPS, passing thesession_idand raw RGB888 pixel data. -
Stop the stream — call
stop_stream. The device returns to its normal app display immediately.
Light entity stream attributes
The Light entity always exposes the current stream state and canvas dimensions as extra state attributes, updated on every coordinator poll:
| Attribute | Description |
|---|---|
stream_status |
Current stream status, e.g. stopped or receiving. |
canvas_pixel |
Object with width and height for pixel render mode
(e.g. {"width": 24, "height": 8}). |
canvas_triangle |
Object with width and height for triangle render mode
(typically twice the pixel dimensions). |
Use these attributes to determine the correct rgb_data length
(width × height triplets) before sending frames.
start_stream
Starts an LMSP streaming session and configures the canvas rendering parameters. Returns a
session_id which must be passed to every subsequent send_stream_data
call.
Fields
| Field | Required | Type | Description |
|---|---|---|---|
config |
yes | object | Canvas configuration object. See the canvas config table below. |
canvas config object
| Field | Required | Values | Description |
|---|---|---|---|
canvas.fill_type |
yes |
scale
tile
|
How to fill the physical display when content is smaller than the screen:
|
canvas.render_mode |
yes |
pixel
triangle
|
Determines the addressable pixel unit:
|
canvas.post_process.type |
no |
none
effect
|
Post-processing applied on top of the streamed content. none displays
content as-is. |
canvas.post_process.params |
no | object | Effect parameters. Only used when type = effect.
See fading_pixels effect. |
fading_pixels effect
Currently the only available post-process effect. It adds a fade-in/fade-out animation on top of the raw pixel content.
| Parameter | Type | Range | Description |
|---|---|---|---|
effect_params.smooth |
boolean | — | true — pixels appear gradually; false — pixels
appear
instantly. |
effect_params.pixel_fill |
float | 0.0 – 1.0 | Fill area percentage. 1.0 = pixels fill 100 % of the
LED area. |
effect_params.fade_speed |
float | 0.0 – 1.0 | Brightness delta added per render cycle. Larger value = faster fade. |
effect_params.pixel_base |
float | 0.0 – 1.0 | Base (minimum) pixel brightness. 0.0 = fully off;
1.0 = full brightness.
|
Service response
The service returns the session_id needed for all subsequent
send_stream_data calls:
{
"session_id": "a2891aa891ab4f8e8a1a16eb319b00f3"
}
Example: basic pixel mode
service: lametric_hass_local.start_stream
target:
entity_id: light.lametric_sky_light
data:
config:
canvas:
fill_type: scale
render_mode: pixel
post_process:
type: none
Example: pixel mode with fading effect
service: lametric_hass_local.start_stream
target:
entity_id: light.lametric_sky_light
data:
config:
canvas:
fill_type: scale
render_mode: pixel
post_process:
type: effect
params:
effect_type: fading_pixels
effect_params:
smooth: true
pixel_fill: 1.0
fade_speed: 0.005
pixel_base: 0.05
send_stream_data
Sends one RGB888 frame to an active LMSP stream session. The service fetches the current
stream state itself on every call (to get the UDP port and validate the session), so you only
need to supply the session_id and the pixel data.
send_stream_data does not call an
HTTP API endpoint. It sends a raw UDP datagram directly to the device's streaming port.
Fields
| Field | Required | Type | Description |
|---|---|---|---|
session_id |
yes | string | The session_id returned by start_stream. |
rgb_data |
yes | list of [R, G, B] triplets |
One [R, G, B] triplet per pixel, ordered left-to-right
top-to-bottom. Each channel is an integer 0–255. The number of triplets
must match canvas_width × canvas_height — read these from
the Light entity's stream attributes. |
Example
service: lametric_hass_local.send_stream_data
target:
entity_id: light.lametric_sky_light
data:
session_id: "{{ session_id }}"
rgb_data: "[[255,0,0],[255,0,0],[0,255,0],[0,0,255],...]"
session_id returned by start_stream in a template variable
or input_text entity, then pass it to send_stream_data in a loop or
repeat action.
stop_stream
Stops the active streaming session. The device returns to its normal app display immediately. The service takes no additional fields beyond the entity target.
service: lametric_hass_local.stop_stream
target:
entity_id: light.lametric_sky_light
API response
{
"success": {
"data": {
"status": "stopped"
},
"path": "api/v2/device/stream/stop"
}
}
LMSP UDP packet format
This section describes the low-level wire format used by the integration when sending frames. It is provided for debugging and advanced use-cases. Full reference: LaMetric Streaming API.
Packet header (28 bytes fixed)
| Offset | Size (bytes) | Field | Value / Notes |
|---|---|---|---|
| 0 | 4 | Protocol name | ASCII lmsp = 0x6c 0x6d 0x73 0x70 |
| 4 | 2 | Version | 0x01 0x00 (version 1, little-endian) |
| 6 | 16 | Session ID | UUID bytes from start_stream response (no dashes, raw 16 bytes).
Packets with a mismatched session ID are silently discarded by the device. |
| 22 | 1 | Content encoding | 0x00 = RAW, 0x01 = PNG,
0x02 = JPEG, 0x03 = GIF.
The integration always uses 0x00 (RAW RGB888).
|
| 23 | 1 | Reserved | 0x00 |
| 24 | 1 | Canvas area count | Number of canvas areas in this packet. The integration always sends
0x01 (one area per packet).
|
| 25 | 1 | Reserved | 0x00 |
Canvas area descriptor (8 bytes per area)
| Offset | Size (bytes) | Field | Value |
|---|---|---|---|
| 26 | 2 | X offset | 0–canvas_width; usually 0x00 0x00 |
| 28 | 2 | Y offset | 0–canvas_height; usually 0x00 0x00 |
| 30 | 2 | Width | Canvas width in pixels (e.g. 0x18 0x00 for 24) |
| 32 | 2 | Height | Canvas height in pixels (e.g. 0x08 0x00 for 8) |
| 34 | 2 | Data length | width × height × 3 bytes (RGB888). For a 24×8 canvas:
576 bytes = 0x40 0x02 |
Pixel data
Immediately after the area descriptor: width × height RGB888 triplets,
ordered left-to-right, top-to-bottom. Each triplet is three bytes: R, G, B.
Total packet size
26 (header) + 10 (area descriptor) + width × height × 3 (pixel data)
For a 24×8 pixel canvas: 26 + 10 + 576 = 612 bytes
Annotated example (24×8, all red)
6c 6d 73 70 // "lmsp"
01 00 // version 1
a2 89 1a a8 91 ab 4f 8e
8a 1a 16 eb 31 9b 00 f3 // session_id (16 bytes)
00 // RAW encoding
00 // reserved
01 // 1 canvas area
00 // reserved
00 00 // x = 0
00 00 // y = 0
18 00 // width = 24
08 00 // height = 8
40 02 // data length = 576
ff 00 00 ff 00 00 ff 00 00 ... // 192 red pixels (24*8)
Full LMSP reference: LaMetric Streaming API.