From 663f0527512aaa76491f76bcdc2866c93088803e Mon Sep 17 00:00:00 2001 From: Hector Date: Tue, 31 Mar 2026 10:15:01 -0300 Subject: [PATCH 1/2] Add documentation for queries implementation --- .../driverDevelopmentGuide.md | 125 ++++++++++++++++++ 1 file changed, 125 insertions(+) diff --git a/bli-guides/_developers-guides/driverDevelopmentGuide.md b/bli-guides/_developers-guides/driverDevelopmentGuide.md index d49f0d1..068f1a0 100644 --- a/bli-guides/_developers-guides/driverDevelopmentGuide.md +++ b/bli-guides/_developers-guides/driverDevelopmentGuide.md @@ -632,6 +632,29 @@ A typical example of resource with state is a dimmer with feedback as shown in t ``` + + +#### queries + +Queries define requests that BLI can make to the driver to retrieve dynamic data from the third party system for the corresponding resource. +Unlike commands (which trigger actions) or states (which are continuously synchronized), queries are executed on demand — typically when the user clicks **Synchronize** in the admin UI. + +For each resource type, an optional table of queries may be provided in which keys are the query names (e.g. `LIST_INPUTS`) and values are tables with the following data: + +- **`context_help`**: Context help describing what the query returns. + +Example of queries for a RENDERER resource type: + +```lua + queries = { + LIST_INPUTS = { context_help = "Lists the available input sources." }, + LIST_APPLICATIONS = { context_help = "Lists the installed applications." } + } +``` + +The driver must implement a corresponding [query](#query) function to handle these queries and return the appropriate data. See the [RENDERER type](#RENDERER-type) section for the expected response formats. + + ## driver\_label @@ -1140,6 +1163,44 @@ Where `commandNumbers` is defined as: ["_MULTI TAP"] = 6, ["_HOLD RELEASE"] = 32, SET= 1 } ``` + + +## query + +This function is called whenever BLI needs to retrieve dynamic data from the third party system for a resource. +Queries are triggered when the user clicks **Synchronize** in the admin UI for a resource that has queries defined in its specification. + +The function prototype must be: + +```lua + function query(queryName, resource, queryArgs) +``` + +Where: + +- **`queryName`** is the name of the query being executed, e.g. `"LIST_INPUTS"`. +- **`resource`** is the [resource](#resource-Lua-instance) for which the query is being executed. +- **`queryArgs`** is a table containing any arguments for the query (usually empty). + +The function must return a table with the query result data. + +```lua + function query(queryName, resource, queryArgs) + if queryName == "LIST_INPUTS" then + return { + inputs = { + { address = "HDMI1", name = "HDMI 1", type = "internal", capabilities = {} }, + { address = "HDMI2", name = "HDMI 2", type = "internal", capabilities = {} }, + { address = "TV", name = "TV Tuner", type = "internal", capabilities = {"CHANNEL"} } + } + } + end + end +``` + +See the [RENDERER type](#RENDERER-type) section for the expected response formats for standard queries like `LIST_INPUTS`, `LIST_APPLICATIONS`, etc. + + ## onResourceDelete @@ -4212,6 +4273,66 @@ All commands take no arguments. (M) = mandatory if the CUSTOM_COMMAND capability is included. +### Query response formats + +When the driver implements the [query](#query) function for a RENDERER or MATRIX resource, the returned data must follow these structures: + +#### LIST\_INPUTS + +Returns the available input sources for the resource. Each input entry has the following fields: + +- **`address`** (string, required): The input identifier, used as the value for `SELECT_INPUT` commands. +- **`name`** (string, optional): Display name for the input. Defaults to the address if not provided. +- **`type`** (string, required): `"internal"` — the input is handled by the resource itself. This is currently the only supported value. +- **`capabilities`** (list of strings, optional): Capabilities available when this input is selected. Valid values correspond to capability names: `"POWER"`, `"INPUT"`, `"VOLUME"`, `"NAVIGATION"`, `"PLAYER"`, `"APPLICATION"`, `"CHANNEL"`, `"CUSTOM_COMMAND"`, `"CONTENT"`, `"PLAYQUEUE"`, `"MULTIROOM"`, `"KEYBOARD"`. + +```json +{ + "inputs": [ + { "address": "HDMI1", "name": "HDMI 1", "type": "internal", "capabilities": [] }, + { "address": "HDMI2", "name": "HDMI 2", "type": "internal", "capabilities": [] }, + { "address": "TV", "name": "TV Tuner", "type": "internal", "capabilities": ["CHANNEL"] }, + { "address": "NET", "name": "Network", "type": "internal", "capabilities": ["NAVIGATION", "CONTENT"] } + ] +} +``` + +#### LIST\_APPLICATIONS + +Returns the available applications. + +```json +{ + "applications": [ + { "name": "Netflix", "icon": "https://..." }, + { "name": "YouTube", "icon": "https://..." } + ] +} +``` + +#### LIST\_CHANNELS + +Returns the available channels. + +```json +{ + "channels": [ + { "name": "BBC One", "icon": "https://..." }, + { "name": "Channel 2", "icon": "https://..." } + ] +} +``` + +#### LIST\_CUSTOM\_COMMANDS + +Returns the available custom commands. + +```json +{ + "customCommands": ["PictureMode", "SoundMode", "AspectRatio"] +} +``` + ### Example specification ```lua @@ -4240,6 +4361,10 @@ All commands take no arguments. PLAY= {}, PAUSE= {}, STOP= {}, NEXT= {}, PREV= {} }, + queries= { + LIST_INPUTS = { context_help = "Lists the available input sources." }, + LIST_APPLICATIONS = { context_help = "Lists the installed applications." } + }, states= { enumArgument("ONLINE", {0, 1}, 0), -- global capability stringArgument("INPUT", ""), -- INPUT capability (mandatory) From 39ccf04adc94cce6de92ac580e137603ccbde1f8 Mon Sep 17 00:00:00 2001 From: Hector Date: Tue, 31 Mar 2026 11:50:36 -0300 Subject: [PATCH 2/2] Add asynchronous query description --- .../driverDevelopmentGuide.md | 27 ++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/bli-guides/_developers-guides/driverDevelopmentGuide.md b/bli-guides/_developers-guides/driverDevelopmentGuide.md index 068f1a0..82b431c 100644 --- a/bli-guides/_developers-guides/driverDevelopmentGuide.md +++ b/bli-guides/_developers-guides/driverDevelopmentGuide.md @@ -1182,7 +1182,9 @@ Where: - **`resource`** is the [resource](#resource-Lua-instance) for which the query is being executed. - **`queryArgs`** is a table containing any arguments for the query (usually empty). -The function must return a table with the query result data. +Like `executeCommand`, this function should return as soon as possible. If the data is already cached or can be computed immediately, return a table with the result directly. + +#### Synchronous query ```lua function query(queryName, resource, queryArgs) @@ -1198,6 +1200,29 @@ The function must return a table with the query result data. end ``` +#### Asynchronous query + +If the driver needs to communicate with the device to gather the data and cannot return immediately, an optional fourth parameter `cont_fn` (continuation function) is provided. In this case the `query` function must **not** return a value — instead, it calls `cont_fn` when the data is ready. + +```lua + function query(queryName, resource, queryArgs, cont_fn) + if queryName == "LIST_INPUTS" then + copas.addthread(function() + local inputs = fetchInputsFromDevice(resource.address) + if inputs then + cont_fn(true, { inputs = inputs }) + else + cont_fn(false) + end + end) + end + end +``` + +The continuation function `cont_fn` takes two arguments: +- **`ok`** (boolean): `true` if the query succeeded, `false` otherwise. +- **`values`** (table, optional): the query result data (only when `ok` is `true`). + See the [RENDERER type](#RENDERER-type) section for the expected response formats for standard queries like `LIST_INPUTS`, `LIST_APPLICATIONS`, etc.