In Indigo v2022.2, we’re completely redesigning the web server plugin (commonly referred to as IWS). The major components of the new web server are:
We’re introducing two new APIs:
Both of these APIs are authenticated with HTTP Digest and API Keys (either as a query string or an Authorization header which is preferable) depending on how the user configures it in the Start Local Server dialog. We’re deprecating HTTP Basic authentication. This version of the plugin will support all the necessary endpoints for Indigo Touch as outlined below.
We also intend to deprecate the REST API (though we may reverse course if users demand it).
In these APIs, we’re using JSON (JavaScript Object Notation) as the message format for communicating between the Websocket and HTTP APIs and IWS. In JavaScript, an “object” definition looks (almost) exactly like a Python dictionary (and vice versa). So we may refer to an object or dictionary (dict): for the purposes of this document, they refer to the same JSON construct. A simple example, we may call this an object or a dict:
{ "key1": "value 1", "key2": 2 }
We expect that there will be both Python and JavaScript users integrating our APIs, so we wanted to explicitly call this out. As a primarily Python organization, you may notice a bias towards “dict”. It’s also important to note that throughout this article, there are examples of JSON objects that contain comments marked by //
. These are for illustration only. The JSON specification does not support comments, and these comments will not be present in messages sent by the server and should be removed from client-side messages.
{ // These comments can not be in the actual JSON payload and should be removed. "key1": "value 1", "key2": 2 }
Python developers will notice the use of null
in the message descriptions. This corresponds to the Python None
object. Also of note are the booleans true
and false
, which are capitalized in Python but not in JSON. Here’s a handy cheat sheet:
Python | JSON Equivalent |
---|---|
True | true |
False | false |
float | Number |
int | Number |
None | null |
dict | Object |
list | Array |
tuple | Array |
Starting with Indigo 2022.2, we’re implementing an API versioning scheme. For the original URLs, we’ll implement these for Indigo Touch older than 3.0 (or maybe 2023.1 or whatever):
/servercommand
/serverrequest
/images/
/resolveimagepath
/refreshingimage
Moving forward, all APIs will be versioned under the following scheme:
/v2/
- this is the top level version number and will change as necessary/v2/ws/
- path to all websocket endpoints/v2/ws/devices-feed
- the device websocket endpoint/v2/ws/variable-feed
- the variable websocket endpoint/v2/ws/action-feed
- the action group websocket endpoint/v2/ws/page-feed
- the control websocket endpoint/v2/ws/log-feed
- the event log websocket endpoint/v2/api/
- path to the new API endpoints (REST replacement)/v2/api/command
- path to the endpoint when sending Indigo a command (device control, variable update, action execution). Use a POST with the message payloads described below, use an API key to authenticate - preferable as an Authorization header but also can be specified as api_key query arg./v2/api/devices
- path to the endpoint to get a list of devices (TBD may allow specifying some kind of smaller message rather than the full device dict)/v2/api/devices/12345
- path to the endpoint to get a specific device object (the device dict described below)/v2/api/variables
- path to the endpoint to get a list of variables/v2/api/variables/12345
- path to the endpoint to specific variable object (dict to be described below)/v2/api/actiongroups
- path to the endpoint to get a list of action groups/v2/api/actiongroups/12345
- path to the endpoint to get a specific action group (dict to be described below)/v2/api/controlpages
- path to the endpoint to get a list of control pages/v2/api/controlpages/12345
- path to the endpoint to get a specific control page (dict to be described below)/v2/controlpage/IDOFCONTROLPAGE
- the actual HTML control page rendering endpoint
One exception is /index.html
(or no path at all) - this will always launch the web UI. For this version, it’s a Single Page Application (SPA) built using Svelte, SvelteUI, and the new websocket API.
This is the API for websockets in the web server in Indigo v2022.2. Websockets are bidirectional TCP connections, which clients can read from and write to – much like you can a socket or serial connection. This initial API is meant to support the current Indigo Touch (iOS and Web) functionality that was previously provided via the old client API (delivered over IWS polls). It’s expected that any other client apps (like DomoticsPad) that want to present a control interface should be able to use this API to create full-fledged clients. It’s important to note that this version will not present functionality enough to build a full-fledged configuration client like the Indigo Mac client. Authentication will be accomplished via OAuth, API Key, or HTTP Digest auth.
There are 5 websocket feeds that work over local IP or via the reflector:
ws://localhost:8176/v2/ws/device-feed
ws://yourreflector.indigodomo.net/v2/ws/action-feed
ws://yourreflector.indigodomo.net/v2/ws/variable-feed
ws://yourreflector.indigodomo.net/v2/ws/page-feed
ws://yourreflector.indigodomo.net/v2/ws/log-feed
Each feed (except log-feed) will send the following server CRUD messages:
When a websocket connection is made, the client will receive two refresh messages: one with the entire collection of Indigo objects and the other with the entire collection of Indigo folders corresponding to the feed (device folders in the device-feed, etc). From that point on, the client will receive the add / refresh / update / delete / messages.
At any time, the client can request a refresh, and Indigo will return the entire object hierarchy again (or the specific object) in a refresh message. If an objectId
is specified in the refresh message, only the specified Indigo object will be retrieved rather than the full list.
The log-feed is different in that it will only send add messages with the appropriate log event object defined below.
For JavaScript developers, the following functions are examples of how to use the typeVal
to determine rendering colors for various aspects of the log line display:
/** * This function will return the color of the border that we draw around event * log entries based on the typeVal of the message (see the EventTypes * enumeration for details). * * @param le - the log event object * */ function getBorderColor(le) { let eType = le.typeVal; if (eType === EventTypes.Error || eType === EventTypes.Error_Client) { return 'red'; } else if (eType === EventTypes.Warning || eType === EventTypes.Warning_Client) { return 'orange'; } else if ( eType === EventTypes.Debug_Client || eType === EventTypes.Debug_Plugin || eType === EventTypes.Debug_Server) { return 'green'; } else { return theme.colors["gray500"].value; } } /** * This function will determine the color of the message or the color of the type * string in log view. * * @param le - the log event object * @param part - return the color for this part of the message (primarily the message * or the typeStr) */ function getTextColor(le, part="message") { let eType = le.typeVal; if (eType === EventTypes.Error || eType === EventTypes.Error_Client) { return 'red'; } else if (eType === EventTypes.Warning || eType === EventTypes.Warning_Client) { return 'orange'; } else if ( eType === EventTypes.Debug_Client || eType === EventTypes.Debug_Plugin || eType === EventTypes.Debug_Server) { return 'green'; } else { if (part === "message") { return theme.colors.secondary; } else { return theme.colors["gray600"].value; } } }
Messages from clients to the server are specific to the feed type and are described below.
Messages sent to the HTTP API are formatted in exactly the same way as those used with the websockets API.
For Python developers, here is a sample script that sends a device toggle request to the HTTP API:
import requests API_KEY = "API_TOKEN_HERE" COMMAND_URL = "http://127.0.0.1:8176/v2/api/command" headers = {"Authorization": f"Bearer {API_KEY}"} toggle_message_target_id = 1198679701 # THE INDIGO ID OF THE TARGET DEVICE toggle_message = { "id": "someid", # RESERVED FOR FUTURE USE "message": "indigo.device.toggle", "objectId": toggle_message_target_id, # THE INDIGO ID OF THE TARGET DEVICE "parameters": { "delay": 5, "duration": 5 } } print(f"Sending toggle message to device {toggle_message_target_id}") reply = requests.post(url=COMMAND_URL, headers=headers, json=toggle_message) print(f"Reply received: {reply.status_code}") print(f"Reply JSON: {reply.json})
First, every object type (except logs) may have folders. This is an example of a folder object. It is the same for any folder in any feed (child
or children
is the generic name for the Indigo objects contained in the folder – device, variable, etc.) Note that folder messages are added to the feed by the server; there are no folder endpoints to manage folders from a client at this time.
{ "id": 617272302, "class": "indigo.Folder", "name": "Airfoil", "remoteDisplay": true }
Folder messages work in any of the websockets (except the log-feed websocket). The following are messages that you’ll receive from the server.
{ "message": "add", "objectType": "indigo.Device.Folder", // or indigo.Variable.Folder, etc "objectDict": {} // A folder object defined above }
{ "message": "refresh", // we use refresh here because the folder object is small "objectType": "indigo.Device.Folder", // or indigo.Variable.Folder, etc "objectDict": {} // A folder object defined above }
{ "message": "delete", "objectType": "indigo.Device.Folder", // or indigo.Variable.Folder, etc "objectId": 1234567 }
{ "message": "refresh", "id": "someid", // Reserved for future use. "objectType": "indigo.Device.Folder", "objectDict": {} // A folder object defined above }
{ "message": "refresh", "id": "someid", // Reserved for future use. "objectType": "indigo.Device.Folder", // or indigo.Variable.Folder, etc "list": [] // A list of folder objects defined above }
We’re using the dict(device)
functionality added a few releases back and then converting that dict
to JSON
for all device messages sent to clients. This contains everything about the device.
ws://localhost:8176/v2/ws/device-feed wss://yourreflector.indigodomo.net/v2/ws/device-feed http://localhost:8176/v2/api/devices http://yourreflector.indigodomo.net/v2/api/devices/12345
You’ll receive full device JSON objects which will represent an Indigo device. Each device will be slightly different based on the device class and the definition (if a custom device). See the Indigo Object Model docs for device details.
{ "address": "3B.04.7A", "batteryLevel": null, "blueLevel": null, "brightness": 0, "buttonConfiguredCount": 0, "buttonGroupCount": 1, "class": "indigo.DimmerDevice", // added class key in 2022.2 "configured": true, "defaultBrightness": 100, "description": "valve", "deviceTypeId": "", "displayStateId": "brightnessLevel", "displayStateImageSel": "DimmerOff", "displayStateValRaw": 0, "displayStateValUi": "0", "enabled": true, "energyAccumBaseTime": null, "energyAccumTimeDelta": null, "energyAccumTotal": null, "energyCurLevel": null, "errorState": "", "folderId": 0, "globalProps": { "com.indigodomo.indigoserver": {} }, "greenLevel": null, "id": 1508839119, "lastChanged": "2021-09-25T08:24:22", "lastSuccessfulComm": "2021-09-25T08:24:22", "ledStates": [], "model": "LampLinc (dual-band)", "name": "Insteon Dimmer", "onBrightensToDefaultToggle": true, "onBrightensToLast": false, "onState": false, "ownerProps": {}, "pluginId": "", "pluginProps": {}, "protocol": "indigo.kProtocol.Insteon", // changed to the full enum in 2022.2 "redLevel": null, "remoteDisplay": true, "sharedProps": {}, "states": { "brightnessLevel": 0, "onOffState": false }, "subModel": "Plug-In", "subType": "Plug-In", "supportsAllLightsOnOff": true, "supportsAllOff": true, "supportsColor": false, "supportsRGB": false, "supportsRGBandWhiteSimultaneously": false, "supportsStatusRequest": true, "supportsTwoWhiteLevels": false, "supportsTwoWhiteLevelsSimultaneously": false, "supportsWhite": false, "supportsWhiteTemperature": false, "version": 67, "whiteLevel": null, "whiteLevel2": null, "whiteTemperature": null }
Here are some examples of the server messages that clients will receive on the device feed.
{ "message": "add", "objectType": "indigo.Device", "objectDict": {} // Device object as outlined above }
{ "message": "patch", // we use a patch rather than send the entire updated device "objectType": "indigo.Device", "patch": {} // A patch object - see the Object Patches below for details }
Device patch objects are created via the dictdiffer python module, by comparing the device dictionary (dict(some_device)
) for the old device with the one for the new dictionary as they are received in the device_updated()
Plugin method call.
{ "message": "delete", "objectType": "indigo.Device", "objectId": 1234567 }
{ "id": "someid", // Reserved for future use. "message": "refresh", "objectType": "indigo.Device", "objectDict": {} // Device object as outlined above }
{ "id": "someid", // Reserved for future use. "message": "refresh", "objectType": "indigo.Device", "list": [] // a list of Device objects as outlined above }
Messages sent from clients to the server. This will most often be commands to control a device, but there are a few other commands (refresh).
These messages are sent to the server to refresh a single device, the entire device list, a single device folder, or the entire device folder list.
{ "id": "someid", // Reserved for future use. "message": "refresh", // Specify the object type "objectType": "indigo.Device", // Specifying an objectId is optional. If it's included the server will send a refresh // message for the specified object. If no id is specified, the whole object list will be // returned "objectId": 123456 }
{ "id": "someid", // Reserved for future use. "message": "refresh", "objectType": "indigo.Device.Folder", // Specifying a objectId is optional. If it's included the server will send a refresh // message for the specified folder. If no folder is specified, the whole folder // list will be returned "objectId": 123456 }
These commands can be used on any Indigo device type - it can be considered the “base” class for messages
status request
{ // Note, this won't necessarily cause a device update message - if the device // didn't have any changes after the status request, there will be no updates // to the device in the server, so no update message will be received. "id": "someid", // Reserved for future use. "message": "indigo.device.statusRequest", "objectId": 123456 // the device id }
toggle
{ "id": "someid", // Reserved for future use. "message": "indigo.device.toggle", "objectId": 123456, // the device id "parameters": { "delay": 5, "duration": 10 } }
turn off
{ "id": "someid", // Reserved for future use. "message": "indigo.device.turnOff", "objectId": 123456, // the device id "parameters": { "delay": 5, "duration": 10 } }
turn on
{ "id": "someid", // Reserved for future use. "message": "indigo.device.turnOn", "objectId": 123456, // the device id "parameters": { "delay": 5, "duration": 10 } }
lock
{ "id": "someid", // Reserved for future use. "message": "indigo.device.lock", "objectId": 123456, // the device id "parameters": { "delay": 5, "duration": 10 } }
unlock
{ "id": "someid", // Reserved for future use. "message": "indigo.device.unlock", "objectId": 123456, // the device id "parameters": { "delay": 5, "duration": 10 } }
brighten
{ "id": "someid", // Reserved for future use. "message": "indigo.dimmer.brighten", "objectId": 123456, // the device id "parameters": { "by": 5, "delay": 10 } }
dim
{ "id": "someid", // Reserved for future use. "message": "indigo.dimmer.dim", "objectId": 123456, // the device id "parameters": { "by": 5, "delay": 10 } }
set brightness
{ "id": "someid", // Reserved for future use. "message": "indigo.dimmer.dim", "objectId": 123456, // the device id "parameters": { "value": 50, "delay": 10 } }
set brightness
{ "id": "someid", // Reserved for future use. "message": "indigo.dimmer.dim", "objectId": 123456, // the device id "parameters": { "value": 50, "delay": 10 } }
set binary output
{ "id": "someid", // Reserved for future use. "message": "indigo.iodevice.setBinaryOutput", "objectId": 123456, // the device id "parameters": { "index": 5, "value": true } }
set on state
{ "id": "someid", // Reserved for future use. "message": "indigo.sensor.setOnState", "objectId": 123456, // the device id "parameters": { "value": true } }
decrease speed index
{ "id": "someid", // Reserved for future use. "message": "indigo.speedcontrol.decreaseSpeedIndex", "objectId": 123456, // the device id "parameters": { "by": 2, "delay": 5 } }
increase speed index
{ "id": "someid", // Reserved for future use. "message": "indigo.speedcontrol.increaseSpeedIndex", "objectId": 123456, // the device id "parameters": { "by": 2, "delay": 5 } }
set speed index
{ "id": "someid", // Reserved for future use. "message": "indigo.speedcontrol.setSpeedIndex", "objectId": 123456, // the device id "parameters": { "value": 2, "delay": 5 } }
set speed level
{ "id": "someid", // Reserved for future use. "message": "indigo.speedcontrol.setSpeedLevel", "objectId": 123456, // the device id "parameters": { "value": 50, "delay": 5 } }
next zone
{ "id": "someid", // Reserved for future use. "message": "indigo.sprinkler.nextZone", "objectId": 123456 // the device id }
previous zone
{ "id": "someid", // Reserved for future use. "message": "indigo.sprinkler.previousZone", "objectId": 123456 // the device id }
pause schedule
{ "id": "someid", // Reserved for future use. "message": "indigo.sprinkler.pause", "objectId": 123456 // the device id }
resume schedule
{ "id": "someid", // Reserved for future use. "message": "indigo.sprinkler.resume", "objectId": 123456 // the device id }
run schedule
{ "id": "someid", // Reserved for future use. "message": "indigo.sprinkler.run", "objectId": 123456, // the device id "parameters": { "schedule": [10,15,8, 0, 0, 0, 0, 0] } }
stop schedule
{ "id": "someid", // Reserved for future use. "message": "indigo.sprinkler.stop", "objectId": 123456 // the device id }
set active zone
{ "id": "someid", // Reserved for future use. "message": "indigo.sprinkler.setActiveZone", "objectId": 123456, // the device id "parameters": { "index": 2 } }
decrease heat setpoint
{ "id": "someid", // Reserved for future use. "message": "indigo.thermostat.decreaseHeatSetpoint", "objectId": 123456, // the device id "parameters": { "value": 2 } }
increase heat setpoint
{ "id": "someid", // Reserved for future use. "message": "indigo.thermostat.increaseHeatSetpoint", "objectId": 123456, // the device id "parameters": { "value": 2 } }
**set heat setpoint
{ "id": "someid", // Reserved for future use. "message": "indigo.thermostat.setHeatSetpoint", "objectId": 123456, // the device id "parameters": { "value": 76 } }
decrease cool setpoint
{ "id": "someid", // Reserved for future use. "message": "indigo.thermostat.decreaseCoolSetpoint", "objectId": 123456, // the device id "parameters": { "delta": 2 } }
increase cool setpoint
{ "id": "someid", // Reserved for future use. "message": "indigo.thermostat.increaseCoolSetpoint", "objectId": 123456, // the device id "parameters": { "delta": 2 } }
set cool setpoint
{ "id": "someid", // Reserved for future use. "message": "indigo.thermostat.setCoolSetpoint", "objectId": 123456, // the device id "parameters": { "value": 76 } }
set hvac mode
{ "id": "someid", // Reserved for future use. "message": "indigo.thermostat.setHvacMode", "objectId": 123456, // the device id "parameters": { "value": "indigo.kHvacMode.HeatCool" } }
set fan mode
{ "id": "someid", // Reserved for future use. "message": "indigo.thermostat.setFanMode", "objectId": 123456, // the device id "parameters": { "value": "indigo.kFanMode.AlwaysOn" } }
We implemented the dict(variable)
functionality that parallels what we already had in place for devices.
ws://localhost:8176/v2/ws/variable-feed wss://yourreflector.indigodomo.net/v2/ws/variable-feed http://localhost:8176/v2/api/variables http://yourreflector.indigodomo.net/v2/api/variables/12345
You’ll receive full variable JSON objects which will represent an Indigo variable.
{ "class": "indigo.Variable", "description": "", "folderId": 0, "globalProps": { "com.indigodomo.indigoserver": {} }, "id": 345633244, "name": "house_status", "pluginProps": {}, "readOnly": false, "remoteDisplay": true, "sharedProps": {}, "value": "home" }
Here are some examples of the server messages that clients will receive on the variable feed.
{ "message": "add", "objectType": "indigo.Variable", "objectDict": {} // Variable object as outlined above }
{ "message": "patch", // we use a patch rather than send the entire updated device "objectType": "indigo.Variable", "patch": {} // A patch object - see the Object Patches below for details }
Variable patch objects are created via the dictdiffer python module](https://dictdiffer.readthedocs.io/en/latest/), by comparing the variable dictionary (dict(some_variable)
) for the old variable with the one for the new dictionary as they are received in the variable_updated()
Plugin method call.
{ "message": "delete", "objectType": "indigo.Variable", "objectId": 1234567 }
{ "id": "someid", // Reserved for future use. "message": "refresh", "objectType": "indigo.Variable", "objectDict": {} // Variable object as outlined above }
{ "id": "someid", // Reserved for future use. "message": "refresh", "objectType": "indigo.Variable", "list": [] // a list of Variable objects as outlined above }
Messages sent from clients to the server. This will most often be commands to update a variable, but there are a few other commands (refresh).
These messages are sent to the server to refresh a single varable, the entire variable list, a single variable folder, or the entire variable folder list.
{ "id": "someid", // Reserved for future use. "message": "refresh", // Specify the object type "objectType": "indigo.Variable", // Specifying an objectId is optional. If it's included the server will send a refresh // message for the specified object. If no id is specified, the whole object list will be // returned "objectId": 123456 }
{ "id": "someid", // Reserved for future use. "message": "refresh", "objectType": "indigo.Variable.Folder", // Specifying a objectId is optional. If it's included the server will send a refresh // message for the specified folder. If no folder is specified, the whole folder // list will be returned "objectId": 123456 }
This is the only command message you can send to the variable feed.
{ // Note, values passed in the parameter dictionary must be strings. You can // pass in an empty string ("") to clear the variable value. "id": "someid", // Reserved for future use. "message": "indigo.variable.updateValue", "objectId": 123456 // the variable id to update "parameters": { "value": "Some string value" } }
We implemented the dict(action_group)
functionality that parallels what we already had in place for devices.
ws://localhost:8176/v2/ws/action-feed wss://yourreflector.indigodomo.net/v2/ws/action-feed http://localhost:8176/v2/api/actiongroups http://yourreflector.indigodomo.net/api/ws/actiongroups/12345
You’ll receive full variable JSON objects which will represent an Indigo action group.
{ "class": "indigo.ActionGroup", "description": "", "folderId": 532526508, "globalProps": { "com.indigodomo.indigoserver": { "speakDelayTime": "5", "speakTextVariable": "speech_string" } }, "id": 94914463, "name": "Movie Night", "pluginProps": {}, "remoteDisplay": true, "sharedProps": { "speakDelayTime": "5", "speakTextVariable": "speech_string" } }
Here are some examples of the server messages that clients will receive on the action feed.
{ "message": "add", "objectType": "indigo.ActionGroup", "objectDict": {} // ActionGroup object as outlined above }
{ "message": "patch", // we use a patch rather than send the entire updated device "objectType": "indigo.ActionGroup", "patch": {} // A patch object - see the Object Patches below for details }
Variable patch objects are created via the dictdiffer python module, by comparing the action dictionary (dict(some_action_group)
) for the old action with the one for the new dictionary as they are received in the action_group_updated()
Plugin method call.
{ "message": "delete", "objectType": "indigo.ActionGroup", "objectId": 1234567 }
{ "id": "someid", // Reserved for future use. "message": "refresh", "objectType": "indigo.ActionGroup", "objectDict": {} // ActionGroup object as outlined above }
{ "id": "someid", // Reserved for future use. "message": "refresh", "objectType": "indigo.ActionGroup", "list": [] // a list of ActionGroup objects as outlined above }
Messages sent from clients to the server. This will most often be commands to execute an action group, but there are a few other commands (refresh).
These messages are sent to the server to refresh a single action group, the entire action group list, a single action group folder, or the entire action group folder list.
{ "id": "someid", // Reserved for future use. "message": "refresh", // Specify the object type "objectType": "indigo.ActionGroup", // Specifying an objectId is optional. If it's included the server will send a refresh // message for the specified object. If no id is specified, the whole object list will be // returned "objectId": 123456 }
{ "id": "someid", // Reserved for future use. "message": "refresh", "objectType": "indigo.ActionGroup.Folder", // Specifying a objectId is optional. If it's included the server will send a refresh // message for the specified folder. If no folder is specified, the whole folder // list will be returned "objectId": 123456 }
There is only one command message you can send to the action feed.
{ "id": "someid", // Reserved for future use. "message": "indigo.ActionGroup.execute", "objectId": 123456 // the action group id to execute }
We implemented the dict(control_page)
functionality that parallels what we already had in place for devices.
ws://localhost:8176/v2/ws/page-feed wss://yourreflector.indigodomo.net/v2/ws/page-feed http://localhost:8176/v2/api/controlpages http://yourreflector.indigodomo.net/v2/api/controlpages/12345
You’ll receive full variable JSON objects which will represent an Indigo control page.
{ "class": "indigo.ControlPage", "backgroundImage": "", "description": "", "folderId": 0, "globalProps": {}, "hideTabBar": true, "id": 963336187, "name": "Weather Images", "pluginProps": {}, "remoteDisplay": true, "sharedProps": {} }
Here are some examples of the server messages that clients will receive on the variable feed.
{ "message": "add", "objectType": "indigo.ControlPage", "objectDict": {} // ControlPage object as outlined above }
{ "message": "patch", // we use a patch rather than send the entire updated control page "objectType": "indigo.ControlPage", "patch": {} // A patch object - see the Object Patches below for details }
Page patch objects are created via the dictdiffer python module, by comparing the device dictionary (dict(some_page)
) for the old page with the one for the new dictionary as they are received in the control_page_updated()
Plugin method call.
{ "message": "delete", "objectType": "indigo.ControlPage", "objectId": 1234567 }
{ "id": "someid", // Reserved for future use. "message": "refresh", "objectType": "indigo.ControlPage", "objectDict": {} // ControlPage object as outlined above }
{ "id": "someid", // Reserved for future use. "message": "refresh", "objectType": "indigo.ControlPage", "list": [] // a list of ControlPage objects as outlined above }
Messages sent from clients to the server. This consists only of refresh requests since there are no other actions that can be taken on control pages.
These messages are sent to the server to refresh a single page, the entire page list, a single page folder, or the entire page folder list.
{ "id": "someid", // Reserved for future use. "message": "refresh", // Specify the object type "objectType": "indigo.ControlPage", // Specifying an objectId is optional. If it's included the server will send a refresh // message for the specified object. If no id is specified, the whole object list will be // returned "objectId": 123456 }
{ "id": "someid", // Reserved for future use. "message": "refresh", "objectType": "indigo.ControlPage.Folder", // Specifying a objectId is optional. If it's included the server will send a refresh // message for the specified folder. If no folder is specified, the whole folder // list will be returned "objectId": 123456 }
We convert the event Indigo dictionary into a python dictionary in the event_log_line_received
plugin method.
ws://localhost:8176/v2/ws/log-feed wss://yourreflector.indigodomo.net/v2/ws/log-feed
You’ll receive full variable JSON objects which will represent an Indigo log entry.
{ "message": "add", "objectDict": { "message": "Stopping plugin \"Web Server 2022.2.0\" (pid 1020)", "timeStamp": "2022-12-01T12:03:27.759000", "typeStr": "Application", "typeVal": 0 }, "objectType": "indigo.LogEvent" }
When you first open a websocket connection to the log feed, you’ll immediately receive the last 25 event log entries (individually) and any further event log entries as long as the connection is open. So you only need one handler for messages coming from the log feed since they will always be objects as deviced above (the message
key will always be add
). Note that folder messages are added to the feed by the server; there are no folder endpoints to manage folders from a client at this time.
Note that typeVal
will be one of the following values:
export enum EventTypes { Application = 0, Error, Error_Client, Warning, Warning_Client, Debug_Server, Debug_Client, Debug_Plugin, Custom, LastBaseEnumItem }
You can use the values above to help determine any kind of decoration you want to use when displaying or otherwise interpreting the log event.
Error messages will be returned to API clients in the event that something didn’t go as planned. The structure of messages returned will depend on what went wrong and how the message was sent. Note that folder messages are added to the feed by the server; there are no folder endpoints to manage folders from a client at this time.
A generic example message is provided in JSON format:
{ "error": "Some error description", "id": "the id sent from the client in the message, or null if there wasn't one", "validationErrors": { "field1": "some error that occurred in the message with the key field1" } }
where the value of the JSON name (or key) validationErrors
is a dictictionary with a field name and a description of the error in that field that came from the client. For instance, if you pass a float value
to the indigo.variable.updateValue
message:
{ "id": "a-random-id-for-this-message", "message": "indigo.variable.updateValue", "objectId": 123456 "parameters": { "value": 1234.56 } }
You will receive the following error response:
{ "validationErrors": { "value": "variable values must be strings" }, "error": "invalid command payload received, id: my-set-var-command", "id": "a-random-id-for-this-message" }
The error
key is the indicator that the response is some kind of error. validationErrors
is a dict that contains all the validation errors for the message, in this case the value
that was passed in was not a string (it was the float 1234.56
). The possible keys in the error message reply validationErrors
could be:
message
,objectId
,parameters
, andvalue
based on the indigo.variable.updateValue
message format (we do no validation on the id
value passed in, we just pass it through, and if your message doesn’t contain one then the value will be null
). Only the keys from your message that have errors will be returned. So in the example error above, only the value
key had a validation error (because we passed in a float) so that was the only key returned.
One other type of error that you may receive would be if you POST a string (or something else, like XML, etc.) that’s not JSON. This will result in the following message return:
{ "request_body": "this is not valid JSON", "error": "invalid JSON" }
We will just return the entire request body since it isn’t valid JSON and we don’t know what else to do with it.