Extension API Reference
Complete reference for the ext global object available in extension plugins.
Properties
ext.data_dir
The plugin's persistent data directory path. Use this for storing configuration files, caches, etc.
local config_path = ext.data_dir .. "/config.json"
ext.plugin
Read-only table containing metadata about the current extension plugin, as declared in manifest.json.
local p = ext.plugin
ext.log(p.id) -- Plugin ID, e.g. "extension.my_plugin"
ext.log(p.name.raw) -- Display name (raw string)
ext.log(p.version) -- Version string, e.g. "1.0.0"
ext.log(p.publisher) -- Publisher name
ext.log(p.type) -- Always "extension"
-- Optional fields (nil if not declared in manifest)
if p.description then
ext.log(p.description.raw)
end
if p.repository then
ext.log(p.repository)
end
if p.license then
ext.log(p.license)
end
if p.page_path then
ext.log(p.page_path)
end
| Field | Type | Description |
|---|---|---|
id | string | Plugin ID |
name | LocalizedText | Plugin display name |
version | string | Plugin version |
publisher | string | Plugin publisher |
permissions | string[] | Declared permissions |
type | string | Always "extension" |
description | LocalizedText? | Plugin description (nil if not set) |
repository | string? | Source repository URL (nil if not set) |
license | string? | License identifier (nil if not set) |
page_path | string? | Relative path to the extension HTML page (nil if not set) |
System Information
Available since 3.0.0-dev.2. Requires the "system:info" permission.
When the plugin declares the "system:info" permission, a read-only ext.system table is injected containing hardware and OS details.
ext.system
local sys = ext.system
-- OS
sys.os.platform -- "Windows" | "macOS" | "linux"
sys.os.version -- e.g. "Microsoft Windows 11 Pro"
sys.os.build -- e.g. "22631"
sys.os.arch -- e.g. "x86_64"
sys.os.hostname -- e.g. "MY-PC"
-- Motherboard
sys.motherboard.manufacturer -- e.g. "ASUSTeK COMPUTER INC."
sys.motherboard.model -- e.g. "ROG STRIX B550-F GAMING"
sys.motherboard.product -- same as model
sys.motherboard.serial_number -- board serial
-- BIOS
sys.bios.vendor -- e.g. "American Megatrends Inc."
sys.bios.version -- e.g. "2803"
sys.bios.date -- e.g. "12/01/2023"
-- CPU
sys.cpu.name -- e.g. "AMD Ryzen 9 5900X 12-Core Processor"
sys.cpu.manufacturer -- e.g. "AMD"
sys.cpu.cores -- physical core count
sys.cpu.threads -- logical thread count
sys.cpu.base_clock_mhz -- base clock in MHz
sys.cpu.architecture -- e.g. "x64"
-- GPU (array, 1-indexed)
for i, gpu in ipairs(sys.gpu) do
gpu.name -- e.g. "NVIDIA GeForce RTX 3080"
gpu.manufacturer -- e.g. "NVIDIA"
gpu.driver_version -- e.g. "537.58"
gpu.vram_mb -- VRAM in MB
end
-- RAM
sys.ram.total_memory_mb -- total physical memory in MB
for i, m in ipairs(sys.ram.modules) do
m.manufacturer -- module manufacturer
m.part_number -- module part number
m.capacity_mb -- module capacity in MB
m.speed_mhz -- module speed in MHz
m.form_factor -- e.g. "DIMM", "SO-DIMM"
end
Utility
ext.json_encode(value)
Available since 3.0.0-dev.3.
Encode a Lua table or value into a JSON string.
local json_str = ext.json_encode({ hello = "world", count = 5 })
ext.json_decode(json_string)
Available since 3.0.0-dev.3.
Decode a JSON string into a Lua table or value.
local data = ext.json_decode('{"hello": "world"}')
ext.log(data.hello)
ext.sleep(ms)
Sleep for the specified number of milliseconds.
ext.sleep(1000) -- Sleep 1 second
Logging
ext.trace(msg)
Log at trace level.
ext.trace("USB scan tick")
ext.debug(msg)
Log at debug level.
ext.debug("Matched VID/PID candidate")
ext.info(msg)
Log at info level.
ext.info("Extension initialized")
ext.log(msg)
Legacy alias for ext.info(msg).
ext.log("Extension initialized")
ext.warn(msg)
Log at warning level.
ext.warn("Device not responding, retrying...")
ext.error(msg)
Log at error level.
ext.error("Connection failed: " .. err)
Notifications
ext.notify(title, description [, level])
Show a toast notification to the user.
ext.notify("Device Found", "Corsair Vengeance RGB connected")
ext.notify("Warning", "Connection unstable", "warning")
ext.notify("Done", "Firmware updated successfully", "success")
level—"info"(default),"success","warning", or"error"titleanddescriptioncan be strings, manifest i18n keys, or localized text tables.
ext.notify(
{ key = "notifications.connected.title", fallback = "Connected" },
{
key = "notifications.connected.description",
fallback = "Connected to {server}",
args = { server = "OpenRGB" },
},
"success"
)
ext.notify_persistent(id, title, description)
Show a persistent notification that remains until dismissed. The notification level is always "info".
If a persistent notification with the same id already exists, its title and description will be updated in place.
title and description accept the same string, manifest key, and localized text table forms as ext.notify().
ext.notify_persistent("conn_status", "Connecting...", "Attempting to connect to server")
-- Update existing notification
ext.notify_persistent("conn_status", "Connected", "Successfully connected to server")
ext.dismiss_persistent(id)
Dismiss a persistent notification.
ext.dismiss_persistent("conn_status")
Device Management
ext.register_device(config)
Register a virtual device in Skydimo.
local port = ext.register_device({
controller_port = "bridge://device_0",
device_path = "bridge://device_0", -- optional, defaults to controller_port
nickname = "My Device", -- optional
manufacturer = "Vendor",
model = "Device Name",
serial_id = "SN123456",
description = "RGB Controller",
controller_id = "extension.my_bridge",
device_type = "light",
image_url = "https://example.com/device.png", -- optional
outputs = {
{
id = "zone0",
name = "Main Zone",
leds_count = 144,
output_type = "linear", -- "single", "linear", "matrix"
editable = false,
min_total_leds = 1,
max_total_leds = 300,
allowed_total_leds = {30, 60, 144}, -- optional: restrict to specific counts
matrix = nil, -- or {width, height, map}
default_effect = "rainbow_wave", -- optional
}
}
})
The default_effect field is available since 3.0.0-dev.4. When set, this effect is automatically applied to the output when no user configuration exists.
Returns: string — the controller port identifier for this device.
ext.remove_extension_device(port)
Remove a previously registered virtual device.
ext.remove_extension_device("bridge://device_0")
ext.set_device_nickname(port, nickname)
Set a custom display name for a device.
ext.set_device_nickname("bridge://device_0", "Living Room Strip")
ext.get_devices()
Get all devices in the system.
local devices = ext.get_devices()
for _, dev in ipairs(devices) do
ext.log("Device: " .. dev.port .. " - " .. dev.model)
end
ext.get_device_info(port)
Get detailed information about a specific device.
local info = ext.get_device_info("COM3")
if info then
ext.log("Model: " .. info.model)
end
Output Management
ext.set_output_leds_count(port, output_id, count)
Change the LED count for an output.
ext.set_output_leds_count("bridge://device_0", "zone0", 120)
ext.update_output(port, output_id, config)
Update an output's configuration.
ext.update_output("bridge://device_0", "zone0", {
leds_count = 144,
matrix = {width = 12, height = 12, map = {...}}
})
LED Locking & Direct Control
ext.lock_leds(port, output_id, indices)
Lock specific LEDs for direct control, overriding the active effect.
local locked, rejected = ext.lock_leds("COM3", "out1", {0, 1, 2, 3, 4})
ext.log("Locked: " .. locked .. ", Rejected: " .. rejected)
indices— Zero-based LED indices to lock
Returns: integer, integer — (locked_count, rejected_count). LEDs may be rejected if already locked by another extension.
ext.unlock_leds(port, output_id, indices)
Release LED locks.
ext.unlock_leds("COM3", "out1", {0, 1, 2, 3, 4})
ext.set_leds(port, output_id, colors)
Set colors on locked LEDs.
Index-based format:
ext.set_leds("COM3", "out1", {
{0, 255, 0, 0}, -- {index, r, g, b}
{1, 0, 255, 0},
{2, 0, 0, 255},
})
Flat RGB format:
ext.set_leds("COM3", "out1", {255, 0, 0, 0, 255, 0, 0, 0, 255})
-- Sets LED 0=red, LED 1=green, LED 2=blue
ext.get_led_locks([port [, output_id]])
Query current LED lock state.
local all_locks = ext.get_led_locks()
local device_locks = ext.get_led_locks("COM3")
local output_locks = ext.get_led_locks("COM3", "out1")
Effect Management
ext.get_effects()
Get all available effects (built-in + plugin effects).
local effects = ext.get_effects()
for _, effect in ipairs(effects) do
ext.log("Effect: " .. effect.id .. " - " .. effect.name.raw)
end
Each entry in the returned array has the following fields:
| Field | Type | Description |
|---|---|---|
id | string | Effect plugin ID |
name | LocalizedText | Effect display name |
description | LocalizedText? | Short description (nil if not set) |
group | LocalizedText? | Category/group name (nil if not set) |
icon | string? | Icon identifier (nil if not set) |
ext.get_effect_params(effect_id)
Get the parameter schema for an effect.
local params = ext.get_effect_params("rainbow")
ext.set_effect(port, output_id, effect_id [, params [, options]])
This is a legacy convenience wrapper. For new plugins, prefer ext.set_scope_effect(scope, ...) which supports segment_id.
Set the active effect on a device output.
ext.set_effect("COM3", "out1", "rainbow")
ext.set_effect("COM3", "out1", "rainbow", {speed = 3.0, preset = 1})
ext.set_effect("COM3", "out1", "rainbow", nil, {skip_transition = true})
The optional options table uses the same transition options as ext.set_scope_effect. If you only need options, pass nil for params.
Resource Queries
Available since 3.0.0-dev.3.
ext.get_media_session([max_edge])
Also available as ext.get_current_media().
Requires the "media:session" permission.
Get the current system media playback session snapshot, including metadata, playback status, timeline, and album artwork.
local session = ext.get_media_session(256) -- Optional: max edge size for artwork
if session then
ext.log("Playing: " .. session.title .. " by " .. session.artist)
ext.log("Status: " .. session.playback_status)
if session.artwork then
ext.log("Artwork size: " .. session.artwork.width .. "x" .. session.artwork.height)
end
end
Returns: A media session object or nil if no active session.
ext.get_displays()
Get a list of all connected displays.
local displays = ext.get_displays()
for _, d in ipairs(displays) do
ext.log("Display: " .. d.name .. " [" .. d.width .. "x" .. d.height .. "]")
end
Returns: array of display objects.
ext.get_audio_devices()
Get a list of all audio output devices.
local devices = ext.get_audio_devices()
for i, dev in ipairs(devices) do
ext.log(i .. ": " .. dev.name)
end
Returns: array of audio device objects.
System State
Available since 3.0.0-dev.3.
System state APIs allow extensions to monitor OS-level state such as running processes and the currently focused window. Each topic requires its own permission.
System state monitoring is currently only supported on Windows. On unsupported platforms, topics report supported = false and return empty data.
ext.list_system_state_topics()
List available system state topics for this extension, filtered by declared permissions.
local topics = ext.list_system_state_topics()
for _, topic in ipairs(topics) do
ext.log(topic.id .. " supported=" .. tostring(topic.supported))
end
Returns: array of topic info objects:
| Field | Type | Description |
|---|---|---|
id | string | Topic identifier ("process", "window_focus") |
permission | string | Permission required for this topic |
supported | boolean | Whether the topic is supported on the current platform |
ext.get_system_state(topic)
Get a snapshot of the current state for a given topic.
topic— Topic identifier string.
local state = ext.get_system_state("process")
local focus = ext.get_system_state("window_focus")
Returns: A snapshot table (structure depends on the topic). Raises an error if the topic is unknown or the required permission is not declared.
Topic: process
Requires the "system:process" permission.
Snapshot (ext.get_system_state("process")):
| Field | Type | Description |
|---|---|---|
supported | boolean | Whether process monitoring is supported on the current platform |
apps | array | List of running applications |
apps[].name | string | Application executable name (lowercase, trimmed) |
apps[].instance_count | integer | Number of running instances |
Change event (on_system_state_changed("process", data)):
| Field | Type | Description |
|---|---|---|
supported | boolean | Whether process monitoring is supported |
apps | array | Full list of currently running applications |
changes | array | List of applications whose instance count changed |
changes[].name | string | Application executable name |
changes[].previous_instance_count | integer | Instance count before this change |
changes[].current_instance_count | integer | Instance count after this change |
-- Snapshot
local state = ext.get_system_state("process")
for _, app in ipairs(state.apps) do
ext.log(app.name .. ": " .. app.instance_count)
end
-- Change callback
function plugin.on_system_state_changed(topic, data)
if topic == "process" then
for _, c in ipairs(data.changes) do
ext.log(c.name .. ": " .. c.previous_instance_count .. " → " .. c.current_instance_count)
end
end
end
Topic: window_focus
Requires the "system:window-focus" permission.
Snapshot (ext.get_system_state("window_focus")):
| Field | Type | Description |
|---|---|---|
supported | boolean | Whether window focus monitoring is supported on the current platform |
current | object? | Currently focused window, or nil if none |
current.app_name | string? | Application executable name (lowercase) |
current.window_title | string? | Window title text |
Change event (on_system_state_changed("window_focus", data)):
| Field | Type | Description |
|---|---|---|
supported | boolean | Whether window focus monitoring is supported |
reason | string | Reason for the change: "snapshot", "foreground_changed", or "title_changed" |
current | object? | Currently focused window, or nil |
previous | object? | Previously focused window, or nil |
-- Snapshot
local focus = ext.get_system_state("window_focus")
if focus.current then
ext.log("Focused app: " .. (focus.current.app_name or "unknown"))
ext.log("Window title: " .. (focus.current.window_title or ""))
end
-- Change callback
function plugin.on_system_state_changed(topic, data)
if topic == "window_focus" then
ext.log("Focus reason: " .. data.reason)
if data.current then
ext.log("Now: " .. (data.current.app_name or ""))
end
if data.previous then
ext.log("Was: " .. (data.previous.app_name or ""))
end
end
end
Scope API
Available since 3.0.0-dev.3.
All scope functions accept a scope table as their first argument:
-- Scope table structure
local scope = {
port = "COM3", -- required: device port
output_id = "out1", -- optional: specific output
segment_id = "seg0", -- optional: specific segment (requires output_id)
}
Scope State Queries
ext.get_scope_screen_state(scope)
Get the current screen capture state for a scope (selected screen index and region).
local state = ext.get_scope_screen_state({port = "COM3", output_id = "out1"})
-- state.screen_index, state.region ...
ext.get_scope_audio_device_state(scope)
Get the current audio device index assigned to a scope.
local index = ext.get_scope_audio_device_state({port = "COM3", output_id = "out1"})
Scope Media Management
ext.set_scope_screen_index(scope, screen_index)
Set the display index used for screen-capture effects on a scope.
screen_index— Zero-based display index, ornilto use default.
ext.set_scope_screen_index({port = "COM3", output_id = "out1"}, 0)
ext.set_scope_screen_index({port = "COM3", output_id = "out1"}, nil) -- reset
ext.set_scope_screen_region(scope, region)
Set the screen capture region for a scope.
region— AScreenRegiontable:{x, y, width, height}.
ext.set_scope_screen_region({port = "COM3", output_id = "out1"}, {
x = 0, y = 0, width = 1920, height = 1080
})
ext.set_scope_audio_device_index(scope, audio_device_index)
Set the audio device index for audio-reactive effects on a scope.
audio_device_index— Zero-based device index, ornilto use default.
ext.set_scope_audio_device_index({port = "COM3", output_id = "out1"}, 0)
Scope Mode Management
The optional transition options table for ext.set_scope_effect, ext.set_scope_power, and legacy ext.set_effect is available in versions after 3.0.2.
Transition options
Pass an optional options table when an effect or power change should apply immediately instead of using the normal effect-switch fade. The option only affects the current mutation and is not persisted.
Any of these boolean keys can be set to true:
skip_transitionskipTransitionno_transitionimmediate
local immediate = {skip_transition = true}
ext.set_scope_effect({port = "COM3", output_id = "out1"}, "rainbow", nil, immediate)
ext.set_scope_power({port = "COM3", output_id = "out1"}, false, {immediate = true})
ext.set_scope_effect(scope, effect_id [, params [, options]])
Set the active effect on a scope. Supports segment_id.
ext.set_scope_effect({port = "COM3", output_id = "out1"}, "rainbow")
ext.set_scope_effect(
{port = "COM3", output_id = "out1", segment_id = "seg0"},
"breathing",
{speed = 2.0}
)
ext.set_scope_effect({port = "COM3", output_id = "out1"}, nil) -- clear effect
ext.set_scope_effect({port = "COM3", output_id = "out1"}, "rainbow", nil, {skipTransition = true})
ext.update_scope_effect_params(scope, params)
Update only the parameters of the currently active effect on a scope, without changing the effect itself.
ext.update_scope_effect_params({port = "COM3", output_id = "out1"}, {
speed = 5.0,
color = {r = 255, g = 0, b = 0}
})
ext.reset_scope_effect_params(scope)
Reset the effect parameters of a scope to their defaults.
ext.reset_scope_effect_params({port = "COM3", output_id = "out1"})
ext.set_scope_mode_paused(scope, paused)
Pause or resume the active effect on a scope.
ext.set_scope_mode_paused({port = "COM3", output_id = "out1"}, true) -- pause
ext.set_scope_mode_paused({port = "COM3", output_id = "out1"}, false) -- resume
ext.set_scope_power(scope, is_off [, options])
Turn a scope's output on or off.
ext.set_scope_power({port = "COM3", output_id = "out1"}, true) -- turn off
ext.set_scope_power({port = "COM3", output_id = "out1"}, false) -- turn on
ext.set_scope_power({port = "COM3", output_id = "out1"}, false, {immediate = true})
ext.set_scope_brightness(scope, brightness)
Set the brightness level for a scope (0–100).
ext.set_scope_brightness({port = "COM3", output_id = "out1"}, 80)
Networking
The new structured ext.net.* APIs are available since 3.0.0-dev.3.
Requires the "network", "network:tcp", or "network:http" permission depending on the feature used.
HTTP Client (ext.net.http)
Requires "network:http" or "network".
ext.net.http.request(options)
Make a one-shot HTTP request.
local response = ext.net.http.request({
method = "GET",
url = "https://api.github.com/repos/skydimo/light",
headers = { ["User-Agent"] = "SkydimoExtension" },
timeout_ms = 10000
})
if response.ok then
local data = ext.json_decode(response.body)
ext.log("Repo: " .. data.full_name)
end
Options:
method— HTTP method (default:"GET").url— The full target URL.headers— Table of HTTP headers.body— String payload.json— Table/Value to be sent as JSON (setsContent-Type: application/jsonautomatically). Cannot be used together withbody.timeout_ms— Request timeout in milliseconds (default:30000).connect_timeout_ms— Connection timeout in milliseconds (default:10000).max_response_bytes— Max allowed response size (default: 4MB).follow_redirects— Whether to follow HTTP redirects (default:true).max_redirects— Limit the maximum number of redirects.
Returns: A HttpResponseData table containing ok (boolean), status (integer), url (string), headers (table), and body (string).
ext.net.http.stream(options)
Also available as ext.net.http.open().
Open a streamed HTTP request. Useful for Server-Sent Events (SSE) or downloading large payloads in chunks.
Events must be consumed manually using read().
local handle = ext.net.http.stream({
url = "https://example.com/events"
})
Returns: integer — Stream handle.
ext.net.http.read(handle [, timeout_ms])
Read the next event from an HTTP stream.
local event = ext.net.http.read(handle, 5000)
if event then
if event.type == "headers" then
ext.log("Response status: " .. event.status)
elseif event.type == "chunk" then
ext.log("Received chunk of size: " .. #event.data)
elseif event.type == "done" then
ext.log("Stream finished")
elseif event.type == "error" then
ext.error("Stream error: " .. event.message)
end
end
Returns: Event table (type, status, data, message), or nil if it timed out. The available properties depend on the event type ("headers", "chunk", "done", or "error").
ext.net.http.close(handle)
Close an active HTTP stream. Streams are not closed automatically until they reach "done" or "error".
ext.net.http.close(handle)
TCP Client (ext.net.tcp)
Requires "network:tcp" or "network".
ext.net.tcp.connect(options)
Open a blocking TCP connection.
local handle = ext.net.tcp.connect({
host = "192.168.1.100",
port = 8080,
connect_timeout_ms = 5000,
read_timeout_ms = nil,
write_timeout_ms = nil,
no_delay = true
})
Options:
host— IP address or hostname.port— Port number.connect_timeout_ms— connection timeout (default:5000).read_timeout_ms— default timeout for reads on this connection.write_timeout_ms— default timeout for writes on this connection.no_delay— EnablesTCP_NODELAY(default:true).
Returns: integer — Connection handle, or raises an error on failure.
ext.net.tcp.write(handle, data [, timeout_ms])
Write data to a TCP connection.
local bytes_written = ext.net.tcp.write(handle, "HELLO\n")
Returns: integer — Number of bytes successfully written.
ext.net.tcp.write_all(handle, data [, timeout_ms])
Write all data to a TCP connection. Blocks until the whole payload is sent.
ext.net.tcp.write_all(handle, "HELLO\n")
ext.net.tcp.read(handle, max_len [, timeout_ms])
Receive up to max_len bytes. If timeout_ms is 0 or omitted, it relies on the connection's default read timeout or blocks indefinitely.
local data = ext.net.tcp.read(handle, 4096)
Returns: string — received data.
ext.net.tcp.read_exact(handle, bytes [, timeout_ms])
Receive exactly bytes bytes. Blocks until all are received or an error/timeout occurs.
local data = ext.net.tcp.read_exact(handle, 4)
Returns: string — received data.
ext.net.tcp.close(handle)
Close a TCP connection.
ext.net.tcp.close(handle)
Legacy TCP API (Deprecated)
The following global ext.tcp_* interfaces are deprecated and will be removed in a future release. Please transition to ext.net.tcp.*.
ext.tcp_connect(host, port [, timeout_ms])->ext.net.tcp.connect({host=host, port=port, connect_timeout_ms=timeout_ms})ext.tcp_send(handle, data [, timeout_ms])->ext.net.tcp.write(...)ext.tcp_recv(handle, max_len [, timeout_ms])->ext.net.tcp.read(...)ext.tcp_recv_exact(handle, bytes [, timeout_ms])->ext.net.tcp.read_exact(...)ext.tcp_close(handle)->ext.net.tcp.close(...)ext.tcp_write_all(handle, data [, timeout_ms])->ext.net.tcp.write_all(...)
Legacy HTTP API (Deprecated)
The following global ext.http_* interfaces are deprecated and will be removed in a future release. Please transition to ext.net.http.*.
ext.http_request(options)->ext.net.http.request(...)ext.http_open(options)->ext.net.http.stream(...)ext.http_read(handle [, timeout_ms])->ext.net.http.read(...)ext.http_close(handle)->ext.net.http.close(...)
HID Hardware Access
Available since 3.0.0-dev.3. Requires the "hardware:hid" permission.
Direct USB HID device communication. Handles are managed automatically and cleaned up when the extension stops.
ext.hid_enumerate([vid [, pid]])
Enumerate connected HID devices, optionally filtered by Vendor ID and Product ID.
-- List all HID devices
local devices = ext.hid_enumerate()
-- Filter by VID/PID
local devices = ext.hid_enumerate(0x1532, 0x0084)
for _, dev in ipairs(devices) do
ext.log(dev.product .. " @ " .. dev.path)
end
Returns: array of device info tables:
| Field | Type | Description |
|---|---|---|
path | string | Platform-specific device path |
vid | integer | USB Vendor ID |
pid | integer | USB Product ID |
serial | string | Serial number (may be empty) |
manufacturer | string | Manufacturer string |
product | string | Product string |
interface_number | integer | USB interface number |
usage | integer | HID usage ID |
usage_page | integer | HID usage page |
ext.hid_open(vid, pid [, serial])
Open a HID device by VID/PID, optionally specifying a serial number to disambiguate.
local handle = ext.hid_open(0x1532, 0x0084)
Returns: integer — Device handle.
ext.hid_open_path(path)
Open a HID device by its platform-specific path (from hid_enumerate).
local handle = ext.hid_open_path(dev.path)
Returns: integer — Device handle.
ext.hid_write(handle, data)
Write data to a HID device.
local bytes_written = ext.hid_write(handle, "\x00\x01\x02")
data— Binary string to write.
Returns: integer — Number of bytes written.
ext.hid_read(handle, length [, timeout_ms])
Read data from a HID device.
local data = ext.hid_read(handle, 64, 1000)
length— Maximum number of bytes to read.timeout_ms— Read timeout in milliseconds (default:0for blocking).
Returns: string — Binary data read from the device.
ext.hid_send_feature_report(handle, data)
Send a HID feature report.
local bytes_written = ext.hid_send_feature_report(handle, "\x06\x00\x01")
Returns: integer — Number of bytes written.
ext.hid_get_feature_report(handle, length [, report_id])
Get a HID feature report.
local report = ext.hid_get_feature_report(handle, 64, 0x06)
length— Maximum report length.report_id— Report ID (default:0).
Returns: string — Binary report data.
ext.hid_close(handle)
Close a HID device handle.
ext.hid_close(handle)
Process Management
Requires the "process" permission.
ext.spawn_process(exe, args [, options])
Spawn an external process.
local handle = ext.spawn_process("openrgb", {"--server", "--port", "6742"}, {
hidden = true,
working_dir = ext.data_dir
})
args— Table of command-line argumentsoptions.hidden— Hide the process window (boolean)options.working_dir— Working directory path
Returns: integer — process handle.
ext.is_process_alive(handle)
Check if a process is still running.
if ext.is_process_alive(handle) then
ext.log("Process is running")
end
Returns: boolean
ext.kill_process(handle)
Terminate a process.
ext.kill_process(handle)
Page Communication
ext.page_emit(data)
Send data to the extension's embedded HTML page.
ext.page_emit({type = "devices_update", devices = ext.get_devices()})
data— Any Lua table (serialized to JSON for the page)
Lifecycle Hooks Summary
| Hook | Signature | Description |
|---|---|---|
on_start() | function() | Extension loaded |
on_scan_devices() | function() | Manual scan triggered |
on_devices_changed(devices) | function(table) | Device list changed |
on_led_locks_changed(locks) | function(table) | LED lock state changed |
on_system_media_changed(session) | function(table) | System media metadata/artwork changed (requires media:session; ≥ 3.0.0-dev.3) |
on_system_media_playback_changed(session) | function(table) | System media playback status changed (requires media:session; ≥ 3.0.0-dev.3) |
on_system_media_timeline_changed(session) | function(table) | System media timeline/progress changed (requires media:session; ≥ 3.0.0-dev.3) |
on_system_state_changed(topic, data) | function(string, table) | System state topic changed (requires topic permission; ≥ 3.0.0-dev.3) |
on_device_frame(port, outputs) | function(string, table) | Real-time LED frame data |
on_page_message(data) | function(table) | Message from HTML page |
on_stop() | function() | Extension stopping |