diff --git a/bli-guides/_developers-guides/driverDevelopmentGuide.md b/bli-guides/_developers-guides/driverDevelopmentGuide.md index d49f0d1..82b431c 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,69 @@ 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). + +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) + 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 +``` + +#### 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. + + ## onResourceDelete @@ -4212,6 +4298,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 +4386,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)