====== Integration APIs ====== In Indigo v2022.2, we’ve completely redesigned the Indigo Web Server plugin (commonly referred to as IWS). The first major change is the new Indigo Touch for Web UI. We know you'll love this new UI (particularly given the old UI which was super dated): {{:indigo_2022.2_documentation:itw_screenshot.png?500|}} This article, however, is about the two new APIs in IWS that developers can use to integrate Indigo with external services: * [[#WebSocket API]] – (which the new Indigo Touch Web UI uses, and * [[#HTTP API]] – shares as much of the messaging construction with the WebSocket interface as is practical. Both of these APIs are authenticated with HTTP Digest and API Keys (either as a query string or preferably an Authorization header) depending on how the user configures it in the Start Local Server dialog. **NOTE**: * We’re **deprecating HTTP Basic authentication** due to its insecure nature. * The old [[https://wiki.indigodomo.com/doku.php?id=indigo_s_restful_urls|REST API]] has been deprecated in favor of the new [[#HTTP API]]. ==== Versioning ==== A quick note on versioning: moving forward, all APIs will be versioned under the following scheme: * ''%%/v2/%%'' - this is the top level version number and will change as necessary ==== Python vs JavaScript ==== In these APIs, we’re using [[https://www.json.org/|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. For example, we may call this an object or a dict: { "key1": "value 1", "key2": 2 } We expect 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”. 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 | |str |String | If you are new to JSON, you may want to use the [[https://jsonlint.com|JSON Validator website]] to validate that the JSON message you are sending is valid JSON. ===== WebSocket API ===== The Indigo WebSocket API is a persistent connection, meaning that your app/integration will open the connection and keep it open until your app/integration quits. If you are looking for a transactional API, try our [[#HTTP API]]. WebSockets are bidirectional TCP connections, which clients can read from and write to – much like you can a socket or serial connection. This initial version of this API is meant to support functionality like that provided by the Indigo Touch and Domotics Pat clients and does not provide all the necessary bits to support a full configuration clients like the Mac Client. In other words, there are things that the Indigo client can do that are not supported in the WebSockets API at this time. There are 5 WebSocket feeds that that are available in this release: * ''%%/v2/api/ws/device-feed%%'' - WebSocket to do all communication about devices * ''%%/v2/api/ws/variable-feed%%'' - WebSocket to do all communication about variables * ''%%/v2/api/ws/action-feed%%'' - WebSocket to do all communication about action groups * ''%%/v2/api/ws/page-feed%%'' - WebSocket to do all communication about control pages * ''%%/v2/api/ws/log-feed%%'' - WebSocket to do all communication about logs Each feed (except log feed) sends the following server messages: * **add** (when a new Indigo object is added) * **patch** (when an Indigo object changes - you would apply the patch to an existing object) * **delete** (when the Indigo object is deleted) * **refresh** (when you request a fresh copy of a device or the entire list of devices) === WebSocket Lifecycle === The flow of how you will interact with any of the WebSockets above will generally be: - Setup: * Open the websocket connection, and * Send a refresh message to obtain all of the existing instances of that Indigo type in your database. - Routine operation (asynchronously processing for the lifetime of your app/integration): * Read incoming messages from the server (add/patch/delete/refresh) and handle those as appropriate, and * Write messages to the server to instruct the server to do something (commands like statusRequest, turnOn, or refresh). - Close the connection when your app/integration quits. The **log-feed** is different in that it will only send **add** messages with the appropriate log event object defined below. ==== Authentication ==== WebSocket API requests must be authenticated using an **API Key**. You can manage API Keys in the [[https://www.indigodomo.com/account/authorizations|Authorizations section of your Indigo Account]]. Using keys instead of your Indigo Server username/password has several advantages: you can, at any time, revoke an API key, and it will immediately cause anything using it to fail. This will not affect anything else using a your username/password or another API key, so your server protections against intrusions are much more granular. Also, if someone does manage to get your API Key, they can control devices, but they cannot modify your database (add/delete devices, etc) - that is reserved for Indigo clients using the username/password. The best way to use an API Key is to include it in an **Authorization** header on your HTTP request. If you are using a system which does not allow you to set headers for your HTTP request, you can include the API Key as a query argument with the URL: ''%%wss://YOUR-REFLECTOR-NAME.indigodomo.net/v2/api/ws/device-feed?api-key=YOUR-API-KEY%%'' Note the protocol: ''**wss**''. WebSockets actually begin their life as HTTP/HTTPS connections, which the WebSocket client then requests the server to upgrade to a WebSocket. In this respect, you can think of WSS as HTTPS (protected) and WS as HTTP (unprotected). When using WSS, such as when you are using your Indigo Reflector, then your API Key (in both instances) is protected by the TLS security used by the HTTPS protocol. You may use the API locally (or thorough your own router port forwarding), but those connections will be WS and **will not be secure**. It is highly recommended that you always use your Indigo Reflector because it provides a very simple and **secure** solution for accessing your system. IMPORTANT! Be sure not to share your API keys with anyone not authorized to use them — especially in posts to the Indigo user forums. ==== Examples ==== The WebSocket and HTTP APIs are designed to be familiar to those that have been using the legacy RESTful API. However, anyone with knowledge of Python, JavaScript or similar languages should be able to pick up the structure of the new APIs very quickly. To help those making the transition as well as those learning to use API calls for the first time, we've laid out several examples to show how API calls are made, as well as all the current API hooks available. Here's a simple Python script to open the device-feed and print out any messages it receives (you'll need to ''**pip3 install websockets**'' before running it). === Python Receiver Example === This example opens a websocket connection and prints all messages received to the console. It runs until you stop it. import asyncio import websockets import json API_KEY = 'YOUR-API-KEY' async def receiver(): try: headers = {"Authorization": f"Bearer {API_KEY}"} async with websockets.connect("ws://localhost:8176/v2/api/ws/device-feed", extra_headers=headers) as websocket: while True: message = await websocket.recv() print(json.dumps(json.loads(message), indent=2)) except Exception as exc: print(f"Exception:\n{exc}") asyncio.run(receiver()) === Python Receiver/Sender Example === This example opens a websocket connection and shows how messages can be received and sent from the same websocket connection. It runs until the loop counters run out. import asyncio import json from websockets import connect API_KEY = 'YOUR_API_KEY' # YOUR API KEY HERE DEVICE_ID = 12345678 # YOUR DEVICE ID HERE HEADERS = {"Authorization": f"Bearer {API_KEY}"} URI = "ws://127.0.0.1:8176/v2/api/ws/device-feed" # wss:// if using the reflector async def receiver(ws): try: print("Starting receiver task") # Ask for a refresh of device with ID 12345678 refresh_message = { "id": "initial-device-refresh", "message": "refresh", "objectType": "indigo.Device", "objectId": DEVICE_ID } await ws.send(json.dumps(refresh_message)) counter = 0 device = {} while counter < 20: # just keep looping waiting for a message to come log_string = "ignoring message" message_json = await ws.recv() message = json.loads(message_json) message_type = message['message'] if message_type == "refresh": # This is the response to the refresh message we sent above. It gets us a full copy of the device. device = message["objectDict"] log_string = f"receiver: device refresh message: '{device.get('name', 'unknown')}'" elif message_type == "patch": # There's been a change, so confirm it's the device we want then log the change if message["objectId"] == device["id"]: log_string = f"'receiver: device patch message: {device.get('name', 'unknown')}' update: \n{message_json}" print(f"receiver: loop count: {counter}") print(f"receiver: {log_string}") counter += 1 except Exception as exc: print(f"Exception:\n{exc}") async def sender(ws, count): try: print("Starting sender task") message = { "id": "initial-device-refresh", "message": "refresh", "objectType": "indigo.Device", "objectId": DEVICE_ID } for count in range(10): print(f"sender: loop count: {count}") msg = json.dumps(message) print(f"sender: sending message: {msg}") await ws.send(json.dumps(msg)) await asyncio.sleep(5) except Exception as exc: print(f"Exception:\n{exc}") async def main(): try: async with connect(URI, extra_headers=HEADERS) as websocket: await asyncio.gather(receiver(websocket), sender(websocket, 10)) except Exception as exc: print(f"Exception:\n{exc}") asyncio.run(main()) === JavaScript Example === Here's a simple nodejs JavaScript to open the device-feed and print out any messages it receives (you'll need to ''**npm install websocket**'' before running it). const APIKEY = "YOUR-API-KEY"; const W3CWebSocket = require("websocket").w3cwebsocket; console.log("Creating websocket"); const client = new W3CWebSocket( `ws://localhost:8176/v2/api/ws/device-feed?api-key=${APIKEY}` ); client.onmessage = function (message) { console.log(message.data); }; client.onerror = function (err) { console.log(`Error: ${JSON.stringify(err)}`); }; ==== Device Feed ==== This is the WebSocket you'll use for all device-related communication. You will receive the following messages from the Indigo server during the lifetime of the WebSocket. Here are the URLs you will use to connect to this feed. ''%%ws://localhost:8176/v2/api/ws/device-feed%%'' ''%%wss://YOUR-REFLECTOR-NAME.indigodomo.net/v2/api/ws/device-feed%%'' === Device messages from the server === The following are examples of all the device messages that you will receive from the server. == add device message == { "message": "add", "objectType": "indigo.Device", objectDict": { "class": "indigo.DimmerDevice", "address": "3B.04.7A", "batteryLevel": null, "blueLevel": null, "brightness": 100, "buttonConfiguredCount": 0, "buttonGroupCount": 1, "configured": true, "defaultBrightness": 100, "description": "- sample device -", "deviceTypeId": "", "displayStateId": "brightnessLevel", "displayStateImageSel": "indigo.kStateImageSel.DimmerOn", "displayStateValRaw": 100, "displayStateValUi": "100", "enabled": true, "energyAccumBaseTime": null, "energyAccumTimeDelta": null, "energyAccumTotal": null, "energyCurLevel": null, "errorState": "", "folderId": 1552926800, "globalProps": { "com.indigodomo.indigoserver": {}, "emptyDict": {} }, "greenLevel": null, "id": 1508839119, "lastChanged": "2023-02-16T15:43:53", "lastSuccessfulComm": "2023-02-16T15:43:53", "ledStates": [], "model": "LampLinc (dual-band)", "name": "Insteon Dimmer", "onBrightensToDefaultToggle": true, "onBrightensToLast": false, "onState": true, "ownerProps": {}, "pluginId": "", "pluginProps": {}, "protocol": "indigo.kProtocol.Insteon", "redLevel": null, "remoteDisplay": false, "sharedProps": {}, "states": { "brightnessLevel": 100, "onOffState": true }, "subModel": "Plug-In", "subType": "Plug-In", "supportsAllLightsOnOff": true, "supportsAllOff": true, "supportsColor": false, "supportsOnState": true, "supportsRGB": false, "supportsRGBandWhiteSimultaneously": false, "supportsStatusRequest": true, "supportsTwoWhiteLevels": false, "supportsTwoWhiteLevelsSimultaneously": false, "supportsWhite": false, "supportsWhiteTemperature": false, "version": 67, "whiteLevel": null, "whiteLevel2": null, "whiteTemperature": null } } When a new device is added to the Indigo Server after you've opened the connection, you will receive this message. It contains a [[#device_objects|device object]] that you will want to add to your device list (since you'll want to patch it as it changes over time - see the next section). You'll also receive this message when a device's remote display property is changed from False to True. == update device message == { "message": "patch", "objectType": "indigo.Device", "objectId": 1508839119, "patch": [ [ "change", "brightness", [100, 0] ], [ "change", "displayStateImageSel", ["indigo.kStateImageSel.DimmerOn", "indigo.kStateImageSel.DimmerOff"] ], [ "change", "displayStateValRaw", [100, 0] ], [ "change", "displayStateValUi", ["100", "0"] ], [ "change", "lastChanged", ["2023-02-17T16:29:56", "2023-02-17T16:30:54"] ], [ "change", "lastSuccessfulComm", ["2023-02-17T16:29:56", "2023-02-17T16:30:54"] ], [ "change", "onState", [true, false] ], [ "change", "states.brightnessLevel", [100, 0] ], [ "change", "states.onOffState", [true, false] ] ] } Patch objects are created via the [[https://dictdiffer.readthedocs.io/en/latest/|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. We've implemented a JavaScript library, [[https://github.com/IndigoDomotics/dictdiffer-js|dictdiffer-js]], to patch JavaScript objects given the patch object created by the dictdiffer Python library. You can use it in your projects if you like. == device refresh messages == When you send a command that asks to refresh the entire list of devices, you'll receive the following message from the server: { "id": "optional-user-generated-refresh-device-list-message", // Reserved for future use. "message": "refresh", "objectType": "indigo.Device", "list": [] } And if you requested just a single device refresh, you will receive the following message from the server: { "id": "optional-user-generated-refresh-device-message", "message": "refresh", "objectType": "indigo.Device", "objectDict": {} } Note that the first message includes a list of objectDict elements, and the second includes a single objectDict element. == delete device message == { "message": "delete", "objectType": "indigo.Device", "objectId": 123456789 } This is the simplest of the messages, as it just contains the Indigo ID of the device to delete from your collection. You'll receive this message when a device is deleted from the Indigo server and when a device's remote display property is set from True to False. === Device messages to the server === You have a variety of messages you can send to the server. == device refresh requests == To refresh either the full device list or a single device from the server, send the following message. { "id": "optional-user-generated-refresh-device-message", "message": "refresh", // Specify the object type "objectType": "indigo.Device", "objectId": 123456789 } If you want the entire device list, simply omit the ''**objectId**'' key and the server will return the full list. The server will respond with the appropriate [[#device_refresh_messages|device refresh message]] shown above. == device command messages == To command devices to do something, you will be using the [[#Device Command Messages]] described below. For instance, to toggle a lamp device, you would send the following message: { "id": "optional-user-generated-id", "message": "indigo.device.toggle", "objectId": 123456789, } You will receive a "patch" message as a result of this command. ==== Variable Feed ==== This is the WebSocket you'll use for all variable-related communication. You will receive the following messages from the Indigo server during the lifetime of the WebSocket. Here are the URLs you will use to connect to this feed. ''%%ws://localhost:8176/v2/api/ws/variable-feed%%'' ''%%wss://YOUR-REFLECTOR-NAME.indigodomo.net/v2/api/ws/variable-feed%%'' === Variable messages from the server === The following is an example of the variable message that you will receive from the server. == Example variable object (dictionary in Python) == { "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. == add variable message == { "message": "add", "objectType": "indigo.Variable", "objectDict": {} // Variable object as outlined above } When a new variable is added to the Indigo Server after you've opened the connection, you will receive this message. It contains a [[#variable_objects|variable object]] that you will want to add to your variable list (since you'll want to patch it as it changes over time - see the next section). You'll also receive this message when a variable's remote display property is changed from False to True. == update variable message == { "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 [[https://dictdiffer.readthedocs.io/en/latest/|dictdiffer python module]] 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. == delete variable message == { "message": "delete", "objectType": "indigo.Variable", "objectId": 123456789 } This is the simplest of the messages, as it just contains the Indigo ID of the variable to delete from your collection. You'll receive this message when a variable is deleted from the Indigo server and when a variable's remote display property is set from True to False. === Variable messages to the server === There are a few messages you can send to the server. == variable refresh messages == { "id": "optional-user-generated-id", // Reserved for future use. "message": "refresh", "objectType": "indigo.Variable", "objectDict": {} // Variable object as outlined above } == Example refresh all variables message == { "id": "optional-user-generated-id", // Reserved for future use. "message": "refresh", "objectType": "indigo.Variable", "list": [] // a list of Variable objects as outlined above } === variable command messages === The ''updateValue'' command is currently the only command message you can send to the variable feed. It closely mirrors the Python-based [[indigo_2022.2_documentation:object_model_reference|IOM command for updating variables]]. This was completely intentional to make learning one API a stepping stone to another. The HTTP API messages and the Websocket API messages are identical, and are very clearly a JSON-rendered version of the associated IOM command. == updateValue == { // Note, values passed in the parameter dictionary must be strings. You can // pass in an empty string ("") to clear the variable value. "id": "optional-user-generated-id", // Reserved for future use. "message": "indigo.variable.updateValue", "objectId": 123456789, // the variable id to update "parameters": { "value": "Some string value" } } ==== Action Group Feed ==== This is the WebSocket you'll use for all action group-related communication. You will receive the following messages from the Indigo server during the lifetime of the WebSocket. Here are the URLs you will use to connect to this feed. ''%%ws://localhost:8176/v2/api/ws/action-feed%%'' ''%%wss://YOUR-REFLECTOR-NAME.indigodomo.net/v2/api/ws/action-feed%%'' === Action Group messages from the server === The following are examples of all the action group messages that you will receive from the server. == Example action group object (dictionary in Python) == { "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. == add action group message == { "message": "add", "objectType": "indigo.ActionGroup", "objectDict": {} // ActionGroup object as outlined above } When a new action group is added to the Indigo Server after you've opened the connection, you will receive this message. It contains an [[#action_group_objects|action group object]] object that you will want to add to your action group list (since you'll want to patch it as it changes over time - see the next section). You'll also receive this message when an action group's remote display property is changed from False to True. == update action group message == The update action group message is received when an action group has been updated on the Indigo server. It doesn't allow users to update action groups via the WebSocket API. { "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 } Action group patch objects are created via the [[https://dictdiffer.readthedocs.io/en/latest/|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. == delete action group message == { "message": "delete", "objectType": "indigo.ActionGroup", "objectId": 123456789 } This is the simplest of the messages, as it just contains the Indigo ID of the action group to delete from your collection. You'll receive this message when an action group is deleted from the Indigo server and when a action group's remote display property is set from True to False. === Action Group messages to the server === The following are examples of the action group messages that you can send to the server. == action group refresh messages == { "id": "optional-user-generated-id", // Reserved for future use. "message": "refresh", "objectType": "indigo.ActionGroup", "objectDict": {} // ActionGroup object as outlined above } == Example refresh all action groups message == { "id": "optional-user-generated-id", // Reserved for future use. "message": "refresh", "objectType": "indigo.ActionGroup", "list": [] // a list of ActionGroup objects as outlined above } === action group command messages === The ''execute'' command is currently the only command message you can send to the action group feed. It closely mirrors the Python-based [[indigo_2022.2_documentation:object_model_reference|IOM command for executing action groups]]. This was completely intentional to make learning one API a stepping stone to another. The HTTP API messages and the Websocket API messages are identical, and are very clearly a JSON-rendered version of the associated IOM command. == Execute == { "id": "optional-user-generated-id", // Reserved for future use. "message": "indigo.actionGroup.execute", "objectId": 123456789 // the action group id to execute } ==== Control Page Feed ==== This is the WebSocket you'll use for all control page-related communication. You will receive the following messages from the Indigo server during the lifetime of the WebSocket. The control page feed has no command messages you can send to the server; rather, it's purpose is to use incoming messages to manage a list of the available control pages which (presumably) the user would select to open that page. Here are the URLs you will use to connect to this feed. ''%%ws://localhost:8176/v2/api/ws/page-feed%%'' ''%%wss://YOUR-REFLECTOR-NAME.indigodomo.net/v2/api/ws/page-feed%%'' === Control Page messages from the server === The following are examples of the control page messages that you will receive from the server. == Example variable object (dictionary in Python) == { "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. == add control page message == { "message": "add", "objectType": "indigo.ControlPage", "objectDict": {} // ControlPage object as outlined above } When a new control page is added to the Indigo Server after you've opened the connection, you will receive this message. It contains a control page that you will want to add to your control page list (since you'll want to patch it as it changes over time - see the next section). You'll also receive this message when a control page's remote display property is changed from False to True. == update control page message == The update control page message is received when a control page has been updated on the Indigo server. It doesn't allow users to update control pages via the WebSocket API. { "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 [[https://dictdiffer.readthedocs.io/en/latest/|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. == delete control page message == { "message": "delete", "objectType": "indigo.ControlPage", "objectId": 123456789 } This is the simplest of the messages, as it just contains the Indigo ID of the control page to delete from your collection. You'll receive this message when a control page is deleted from the Indigo server and when a control page's remote display property is set from True to False. ==== Indigo Object Folders ==== Each object type above may have folders. Since those folders are specific to the type, you will use the same feed (i.e. device-feed, etc.) to get all of the available folders for that type. This is an example of a folder object. It is the same for any folder in any feed - children is the generic name for the indigo objects contained in the folder (device, variable, etc). { "id": 617272302, "class": "indigo.Folder", "name": "My Device Folder", "remoteDisplay": true } === refresh folder server message === To get the full folder list from the server, send the following message. { "message": "refresh", "id": "optional-user-generated-id", // This is just a pass through from the refresh request "objectType": "indigo.Device.Folder", } You will then receive the following message with all of the folders for that Indigo object type. { "message": "refresh", "id": "optional-user-generated-id", // This is just a pass through from the refresh request "objectType": "indigo.Device.Folder", // or indigo.Variable.Folder, etc "list": [] // A list of folder objects defined above } As of this release, this is the only way to get the current state of folders (there are not add/update/delete messages). If you think you need to refresh your folder list, then send the refresh message. Since folders are generally static, there really isn't much need to continually get the folder list. ==== Log Feed ==== Use this feed to catch all log messages as they happen in the Indigo Server. When you first open the log-feed WebSocket, you will receive the last 25 log messages from the server **//in chronological order//**. After that, the messages come through the socket as they are generated (chronological order). See the [[#Log Messages]] section below for a description of a log message object. Here are the URLs you will use to connect to this feed: ws://localhost:8176/v2/api/ws/log-feed wss://YOUR-REFLECTOR-NAME.indigodomo.net/v2/api/ws/log-feed You won't be able to send the server any messages on the log-feed, and the only message you get will be an add message for every new log entry: { "message": "add", "objectType": "indigo.LogEvent", "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" } } ===== HTTP API ===== This API is meant for use with standard HTTP as the communication mechanism. HTTP **GET** requests to get Indigo object instances in JSON format, and **POST** requests to send commands to the Indigo Server. ==== HTTP API Endpoints ==== The following is a summary of endpoints (URLs that you will need to use the API) that are available in this release (detail on each is further down): * ''%%/v2/api/indigo.devices%%'' - endpoint to get a list of devices * ''%%/v2/api/indigo.devices/123456789%%'' - endpoint to get a specific device instance (See [[api#device_objects|Device Objects]] below) * ''%%/v2/api/indigo.variables%%'' - endpoint to get a list of variables * ''%%/v2/api/indigo.variables/123456789%%'' - endpoint to specific variable object (See [[api#variable_objects|Variable Objects]] below) * ''%%/v2/api/indigo.actionGroups%%'' - endpoint to get a list of action groups * ''%%/v2/api/indigo.actionGroups/123456789%%'' - endpoint to get a specific action group (See [[api#action_group_objects|Action Group Objects]] below) * ''%%/v2/api/command%%'' - endpoint to send Indigo a command (device control, variable update, action execution). You’ll receive full JSON objects which represent either a list of all instances of the object type requested (for example, a list of all action groups) or an individual Indigo object instance (a single device, variable, etc.) Each individual object will be different based on the object type, class and its definition (a custom device, for example). See the [[https://www.indigodomo.com/docs/object_model_reference | Indigo Object Model]] docs for details about each object type. ==== Authentication ==== HTTP API requests must be authenticated using an **API Key**. You can manage API Keys in the [[https://www.indigodomo.com/account/authorizations|Authorizations section of your Indigo Account]]. Using keys instead of your Indigo Server username/password has several advantages: you can, at any time, revoke an API key, and it will immediately cause anything using it to fail. This will not affect anything else using your username/password or another API key, so your server protections against intrusions are much more granular. Also, if someone does manage to get your API Key, they can control devices, but they cannot modify your database (add/delete devices, etc) - that is reserved for Indigo clients using the username/password. The best way to use an API Key is to include it in an **Authorization** header on your HTTP request. All the examples below show this approach. If you are using a system which does not allow you to set headers for your HTTP request, you can include the API Key as a query argument with the URL: ''%%https://YOUR-REFLECTOR-NAME.indigodomo.net/v2/api/indigo.devices/123456789?api-key=YOUR-API-KEY%%'' When using HTTPS, such as when you are using your Indigo Reflector, then your API Key (in both instances) is protected by the TLS security used by the HTTPS protocol. You may use the API locally (or thorough your own router port forwarding), but those connections will be HTTP and **will not be secure**. It is highly recommended that you always use your Indigo Reflector because it provides a very simple and **secure** solution for accessing your system. IMPORTANT! Be sure not to share your API keys with anyone not authorized to use them — especially in posts to the user forums. ==== Getting Device Objects ==== The HTTP API includes a couple of methods for getting device instances as JSON objects. === Getting All Device Objects === [[api#device_objects|Device Objects]] are JSON representations of an Indigo device instance. This JSON object will contain all information about the object, which you can use in your solutions. By using the endpoint without specifying a specific device id, you can get the complete list of all devices in your Indigo database: ''%%/v2/api/indigo.devices%%'' Here are some examples in different languages/technologies that illustrate how to get all devices. == Pure Python 3 (no additional libraries) == * Replace ''//YOUR-API-KEY//'' with a valid key from your Indigo account. * Replace ''//YOUR-REFLECTOR-NAME//'' with the reflector name for your Indigo server. # This is a pure python example - no additional libraries needed from urllib.request import Request, urlopen import json REFLECTORNAME = "YOUR-REFLECTOR-NAME" APIKEY = "YOUR-API-KEY" req = Request(f"https://{REFLECTORNAME}.indigodomo.net/v2/api/indigo.devices") req.add_header('Authorization', f"Bearer {APIKEY}") with urlopen(req) as request: device_list = json.load(request) print(device_list) == JavaScript run from nodejs (no additional libraries) == * Replace ''//YOUR-API-KEY//'' with a valid key from your Indigo account. * Replace ''//YOUR-REFLECTOR-NAME//'' with the reflector name for your Indigo server. // Things that are specific to your environment const REFLECTORNAME = "YOUR-REFLECTOR-NAME" const APIKEY = "YOUR-API-KEY" // Get the http module, and tell it that you're using HTTPS const http = require("https") // These are options that you'll pass to the get call const options = { hostname: `${REFLECTORNAME}.indigodomo.net`, path: `/v2/api/indigo.devices`, headers: { Authorization: `Bearer ${APIKEY}` } } // Get the device JSON from Indigo, parse it into an object, and log it to the console http.get(options, (response) => { let result = "" response.on("data", chunk => { result += chunk; }) response.on("end", () => { const deviceList = JSON.parse(result); console.log(deviceList); }) }) == Using curl from the command line == * Replace ''//YOUR-API-KEY//'' with a valid key from your Indigo account. * Replace ''//YOUR-REFLECTOR-NAME//'' with the reflector name for your Indigo server. curl -H "Authorization: Bearer YOUR-API-KEY" https://YOUR-REFLECTOR-NAME.indigodomo.net/v2/api/indigo.devices === Getting a Single Device Object === Here are a few examples in different languages that illustrate how to get device objects. == Pure Python 3 (no additional libraries) == * Replace ''//YOUR-API-KEY//'' with a valid key from your Indigo account. * Replace ''//YOUR-REFLECTOR-NAME//'' with the reflector name for your Indigo server. * Replace ''//123456789//'' with a valid Indigo device ID. # This is a pure python example - no additional libraries needed from urllib.request import Request, urlopen import json REFLECTORNAME = "YOUR-REFLECTOR-NAME" APIKEY = "YOUR-API-KEY" DEVICEID = 123456789 req = Request(f"https://{REFLECTORNAME}.indigodomo.net/v2/api/indigo.devices/{DEVICEID}") req.add_header('Authorization', f"Bearer {APIKEY}") with urlopen(req) as request: device_instance = json.load(request) print(device_instance) == JavaScript run from nodejs (no additional libraries) == * Replace ''//YOUR-API-KEY//'' with a valid key from your Indigo account. * Replace ''//YOUR-REFLECTOR-NAME//'' with the reflector name for your Indigo server. * Replace ''//123456789//'' with a valid Indigo device ID. // Things that are specific to your environment const REFLECTORNAME = "YOUR-REFLECTOR-NAME" const APIKEY = "YOUR-API-KEY" const DEVICEID = 123456789 // Get the http module, and tell it that you're using HTTPS const http = require("https") // These are options that you'll pass to the get call const options = { hostname: `${REFLECTORNAME}.indigodomo.net`, path: `/v2/api/indigo.devices/${DEVICEID}`, headers: { Authorization: `Bearer ${APIKEY}` } } // Get the device JSON from Indigo, parse it into an object, and log it to the console http.get(options, (response) => { let result = "" response.on("data", chunk => { result += chunk; }) response.on("end", () => { const deviceInstance = JSON.parse(result); console.log(deviceInstance); }) }) == Using curl from the command line == * Replace ''//YOUR-API-KEY//'' with a valid key from your Indigo account. * Replace ''//YOUR-REFLECTOR-NAME//'' with the reflector name for your Indigo server. curl -H "Authorization: Bearer YOUR-API-KEY" https://YOUR-REFLECTOR-NAME.indigodomo.net/v2/api/indigo.devices/123456789 === Controlling an Indigo Device === You can control Indigo devices by sending commands through the API that instruct Indigo how to control the device. Indigo devices come in a variety of types, and each type has its own command set. See the [[#device_command_messages|Device Command Messages]] below for a description of all messages. For now, here are some simple examples to toggle devices: == Pure Python 3 (no additional libraries) == * Replace ''//YOUR-API-KEY//'' with a valid key from your Indigo account. * Replace ''//YOUR-REFLECTOR-NAME//'' with the reflector name for your Indigo server. * Replace ''//123456789//'' with a valid Indigo device ID. # This is a pure python example - no additional libraries needed from urllib.request import Request, urlopen import json REFLECTORNAME = "YOUR-REFLECTOR-NAME" APIKEY = "YOUR-API-KEY" DEVICEID = 123456789 # The message to send to the Indigo Server message = json.dumps({ "id": "optional-user-generated-id", "message": "indigo.device.toggle", "objectId": DEVICEID }).encode("utf8") req = Request(f"https://{REFLECTORNAME}.indigodomo.net/v2/api/command", data=message) req.add_header('Authorization', f"Bearer {APIKEY}") with urlopen(req) as request: reply = json.load(request) print(reply) == JavaScript toggle from nodejs (no additional libraries) == * Replace ''//YOUR-API-KEY//'' with a valid key from your Indigo account. * Replace ''//YOUR-REFLECTOR-NAME//'' with the reflector name for your Indigo server. * Replace ''//123456789//'' with a valid Indigo device ID. // Things that are specific to your environment const REFLECTORNAME = "YOUR-REFLECTOR-NAME" const APIKEY = "YOUR-API-KEY" const DEVICEID = 123456789 // Get the http module, and tell it that you're using HTTPS const http = require("https") // The message to send to the Indigo Server const message = JSON.stringify({ "id": "optional-user-generated-id", "message": "indigo.device.toggle", "objectId": DEVICEID }) // These are options that you'll pass to the get call const options = { hostname: `${REFLECTORNAME}.indigodomo.net`, path: "/v2/api/command", method: "POST", headers: { Authorization: `Bearer ${APIKEY}`, "Content-Length": message.length } } // Get the device JSON from Indigo, parse it into an object, and log it to the console const req = http.request(options, (response) => { let result = "" response.on("data", chunk => { result += chunk; }) response.on("end", () => { const deviceInstance = JSON.parse(result); console.log(deviceInstance); }) }) req.write(message) req.end() == Using curl from the command line == * Replace ''//YOUR-API-KEY//'' with a valid key from your Indigo account. * Replace ''//YOUR-REFLECTOR-NAME//'' with the reflector name for your Indigo server. * Replace ''//123456789//'' with a valid Indigo device ID. curl -X POST -H "Authorization: Bearer YOUR-API-KEY" -d '{"message": "indigo.device.toggle", "objectId": 123456789}' https://YOUR-REFLECTOR-NAME.indigodomo.net/v2/api/command Using these examples, you can now construct any command listed below for any device type. === Controlling an Indigo Device with Parameters === As noted above, Indigo devices come in a variety of types, and each type has its own command set. As a part of this command set, some devices require specific parameters in order for Indigo to be able to execute them (some devices accept optional parameters, and others do not require any parameters at all). See the [[#device_command_messages|Device Command Messages]] below for a description of all messages. The following examples use the ''indigo.dimmer.setBrightness'' command and demonstrate how to include parameters. == Pure Python 3 (no additional libraries) == * Replace ''//YOUR-API-KEY//'' with a valid key from your Indigo account. * Replace ''//YOUR-REFLECTOR-NAME//'' with the reflector name for your Indigo server. * Replace ''//123456789//'' with a valid Indigo device ID. # This is a pure python example - no additional libraries needed from urllib.request import Request, urlopen import json REFLECTORNAME = "YOUR-REFLECTOR-NAME" APIKEY = "YOUR-API-KEY" DEVICEID = 123456789 # The message to send to the Indigo Server message = json.dumps({ "id": "optional-user-generated-id", "message": "indigo.dimmer.setBrightness", "objectId": DEVICEID, "parameters": { "value": 50, "delay": 10 } }).encode("utf8") req = Request(f"https://{REFLECTORNAME}.indigodomo.net/v2/api/command", data=message) req.add_header('Authorization', f"Bearer {APIKEY}") with urlopen(req) as request: reply = json.load(request) print(reply) == JavaScript run from nodejs (no additional libraries) == * Replace ''//YOUR-API-KEY//'' with a valid key from your Indigo account. * Replace ''//YOUR-REFLECTOR-NAME//'' with the reflector name for your Indigo server. * Replace ''//123456789//'' with a valid Indigo device ID. // Things that are specific to your environment const REFLECTORNAME = "YOUR-REFLECTOR-NAME" const APIKEY = "YOUR-API-KEY" const DEVICEID = 123456789 // Get the http module, and tell it that you're using HTTPS const http = require("https") // The message to send to the Indigo Server const message = JSON.stringify({ "id": "optional-user-generated-id", "message": "indigo.dimmer.setBrightness", "objectId": DEVICEID, "parameters": { "value": 50, "delay": 10 } }) // These are options that you'll pass to the get call const options = { hostname: `${REFLECTORNAME}.indigodomo.net`, path: "/v2/api/command", method: "POST", headers: { Authorization: `Bearer ${APIKEY}`, "Content-Length": message.length } } // Get the device JSON from Indigo, parse it into an object, and log it to the console const req = http.request(options, (response) => { let result = "" response.on("data", chunk => { result += chunk; }) response.on("end", () => { const deviceInstance = JSON.parse(result); console.log(deviceInstance); }) }) req.write(message) req.end() == Using curl from the command line == * Replace ''//YOUR-API-KEY//'' with a valid key from your Indigo account. * Replace ''//YOUR-REFLECTOR-NAME//'' with the reflector name for your Indigo server. * Replace ''//123456789//'' with a valid Indigo device ID. curl -X POST -H "Authorization: Bearer YOUR-API-KEY" -d '{"message": "indigo.dimmer.setBrightness", "objectId": 123456789, "parameters": {"value": 50, "delay": 10}}' https://YOUR-REFLECTOR-NAME.indigodomo.net/v2/api/command Using these examples, you can now construct any command listed below for any device type. ==== Getting Variable Objects ==== === Getting All Variable Objects === [[api#variable_objects|Variable Objects]] are JSON representations of an Indigo variable instance. This JSON object will contain all information about the object, which you can use in your solutions. By using the endpoint without specifying a specific variable id, you can get the complete list of all variables in your Indigo database: ''%%/v2/api/indigo.variables%%'' Here are some examples in different languages/technologies that illustrate how to get all variables. == Pure Python 3 (no additional libraries) == * Replace ''//YOUR-API-KEY//'' with a valid key from your Indigo account. * Replace ''//YOUR-REFLECTOR-NAME//'' with the reflector name for your Indigo server. # This is a pure python example - no additional libraries needed from urllib.request import Request, urlopen import json REFLECTORNAME = "YOUR-REFLECTOR-NAME" APIKEY = "YOUR-API-KEY" req = Request(f"https://{REFLECTORNAME}.indigodomo.net/v2/api/indigo.variables") req.add_header('Authorization', f"Bearer {APIKEY}") with urlopen(req) as request: variable_list = json.load(request) print(variable_list) == JavaScript run from nodejs (no additional libraries) == * Replace ''//YOUR-API-KEY//'' with a valid key from your Indigo account. * Replace ''//YOUR-REFLECTOR-NAME//'' with the reflector name for your Indigo server. // Things that are specific to your environment const REFLECTORNAME = "YOUR-REFLECTOR-NAME" const APIKEY = "YOUR-API-KEY" // Get the http module, and tell it that you're using HTTPS const http = require("https") // These are options that you'll pass to the get call const options = { hostname: `${REFLECTORNAME}.indigodomo.net`, path: `/v2/api/indigo.variables`, headers: { Authorization: `Bearer ${APIKEY}` } } // Get the variable JSON from Indigo, parse it into an object, and log it to the console http.get(options, (response) => { let result = "" response.on("data", chunk => { result += chunk; }) response.on("end", () => { const VariableList = JSON.parse(result); console.log(VariableList); }) }) == Using curl from the command line == * Replace ''//YOUR-API-KEY//'' with a valid key from your Indigo account. * Replace ''//YOUR-REFLECTOR-NAME//'' with the reflector name for your Indigo server. curl -H "Authorization: Bearer YOUR-API-KEY" https://YOUR-REFLECTOR-NAME.indigodomo.net/v2/api/indigo.variables === Getting a Single Variable Object === Here are a few examples in different languages that illustrate how to get variable objects. == Pure Python 3 (no additional libraries) == * Replace ''//YOUR-API-KEY//'' with a valid key from your Indigo account. * Replace ''//YOUR-REFLECTOR-NAME//'' with the reflector name for your Indigo server. * Replace ''//123456789//'' with a valid Indigo variable ID. # This is a pure python example - no additional libraries needed from urllib.request import Request, urlopen import json REFLECTORNAME = "YOUR-REFLECTOR-NAME" APIKEY = "YOUR-API-KEY" VARID = 123456789 # Indigo variable object id req = Request(f"https://{REFLECTORNAME}.indigodomo.net/v2/api/indigo.variables/{VARID}") req.add_header('Authorization', f"Bearer {APIKEY}") with urlopen(req) as request: var_instance = json.load(request) print(var_instance) == JavaScript run from nodejs (no additional libraries) == * Replace ''//YOUR-API-KEY//'' with a valid key from your Indigo account. * Replace ''//YOUR-REFLECTOR-NAME//'' with the reflector name for your Indigo server. * Replace ''//123456789//'' with a valid Indigo variable ID. // Things that are specific to your environment const REFLECTORNAME = "YOUR-REFLECTOR-NAME" const APIKEY = "YOUR-API-KEY" const VARID = 123456789 // Get the http module, and tell it that you're using HTTPS const http = require("https") // These are options that you'll pass to the get call const options = { hostname: `${REFLECTORNAME}.indigodomo.net`, path: `/v2/api/indigo.variables/${VARID}`, headers: { Authorization: `Bearer ${APIKEY}` } } // Get the variable object JSON from Indigo, parse it into an object, and log it to the console http.get(options, (response) => { let result = "" response.on("data", chunk => { result += chunk; }) response.on("end", () => { const varInstance = JSON.parse(result); console.log(varInstance); }) }) == Using curl from the command line == * Replace ''//YOUR-API-KEY//'' with a valid key from your Indigo account. * Replace ''//YOUR-REFLECTOR-NAME//'' with the reflector name for your Indigo server. * Replace ''//123456789//'' with a valid Indigo variable ID. curl -H "Authorization: Bearer YOUR-API-KEY" https://YOUR-REFLECTOR-NAME.indigodomo.net/v2/api/indigo.variables/123456789 === Updating a Variable's Value === You can interact with Indigo variables by sending commands through the API that instruct Indigo what to do. There is only one type of Indigo variable, and the variable type has its own command set. See the [[#variable_command_messages|Variable Command Messages]] below for a description of all messages. For now, here is an example of how to set the value of a variable: == Pure Python 3 (no additional libraries) == * Replace ''//YOUR-API-KEY//'' with a valid key from your Indigo account. * Replace ''//YOUR-REFLECTOR-NAME//'' with the reflector name for your Indigo server. * Replace ''//123456789//'' with a valid Indigo variable ID. # This is a pure python example - no additional libraries needed from urllib.request import Request, urlopen import json REFLECTORNAME = "YOUR-REFLECTOR-NAME" APIKEY = "YOUR-API-KEY" VARIABLEID = 123456789 # The message to send to the Indigo Server message = json.dumps({ "id": "optional-user-generated-id", "message": "indigo.variable.updateValue", "objectId": VARIABLEID, "parameters": { "value": "Some string value" } }).encode("utf8") req = Request(f"https://{REFLECTORNAME}.indigodomo.net/v2/api/command", data=message) req.add_header('Authorization', f"Bearer {APIKEY}") with urlopen(req) as request: reply = json.load(request) print(reply) == JavaScript run from nodejs (no additional libraries) == * Replace ''//YOUR-API-KEY//'' with a valid key from your Indigo account. * Replace ''//YOUR-REFLECTOR-NAME//'' with the reflector name for your Indigo server. * Replace ''//123456789//'' with a valid Indigo variable ID. // Things that are specific to your environment const REFLECTORNAME = "YOUR-REFLECTOR-NAME" const APIKEY = "YOUR-API-KEY" const VARIABLEID = 123456789 // Get the http module, and tell it that you're using HTTPS const http = require("https") // The message to send to the Indigo Server const message = JSON.stringify({ "id": "optional-user-generated-id", "message": "indigo.variable.updateValue", "objectId": VARIABLEID, "parameters": { "value": "Some string value" } }) // These are options that you'll pass to the get call const options = { hostname: `${REFLECTORNAME}.indigodomo.net`, path: "/v2/api/command", method: "POST", headers: { Authorization: `Bearer ${APIKEY}`, "Content-Length": message.length } } // Get the variable JSON from Indigo, parse it into an object, and log it to the console const req = http.request(options, (response) => { let result = "" response.on("data", chunk => { result += chunk; }) response.on("end", () => { const VariableInstance = JSON.parse(result); console.log(VariableInstance); }) }) req.write(message) req.end() == Using curl from the command line == * Replace ''//YOUR-API-KEY//'' with a valid key from your Indigo account. * Replace ''//YOUR-REFLECTOR-NAME//'' with the reflector name for your Indigo server. * Replace ''//123456789//'' with a valid Indigo variable ID. curl -X POST -H "Authorization: Bearer YOUR-API-KEY" -d '{"message": "indigo.variable.updateValue", "objectId": 123456789, "parameters": {"value": "Some string value"}}' https://YOUR-REFLECTOR-NAME.indigodomo.net/v2/api/command Using these examples, you can now construct any command listed below for any variable type. ==== Getting Action Group Objects ==== === Getting All Action Group Objects === [[api#action_group_objects|Action Group Objects]] are JSON representations of an Indigo action group instance. This JSON object will contain all information about the object, which you can use in your solutions. By using the endpoint without specifying a specific action group id, you can get the complete list of all action groups in your Indigo database: ''%%/v2/api/indigo.actionGroups%%'' Here are some examples in different languages/technologies that illustrate how to get all action groups. == Pure Python 3 (no additional libraries) == * Replace ''//YOUR-API-KEY//'' with a valid key from your Indigo account. * Replace ''//YOUR-REFLECTOR-NAME//'' with the reflector name for your Indigo server. # This is a pure python example - no additional libraries needed from urllib.request import Request, urlopen import json REFLECTORNAME = "YOUR-REFLECTOR-NAME" APIKEY = "YOUR-API-KEY" req = Request(f"https://{REFLECTORNAME}.indigodomo.net/v2/api/indigo.actionGroups") req.add_header('Authorization', f"Bearer {APIKEY}") with urlopen(req) as request: action_group_list = json.load(request) print(action_group_list) == JavaScript run from nodejs (no additional libraries) == * Replace ''//YOUR-API-KEY//'' with a valid key from your Indigo account. * Replace ''//YOUR-REFLECTOR-NAME//'' with the reflector name for your Indigo server. // Things that are specific to your environment const REFLECTORNAME = "YOUR-REFLECTOR-NAME" const APIKEY = "YOUR-API-KEY" // Get the http module, and tell it that you're using HTTPS const http = require("https") // These are options that you'll pass to the get call const options = { hostname: `${REFLECTORNAME}.indigodomo.net`, path: `/v2/api/indigo.actionGroups`, headers: { Authorization: `Bearer ${APIKEY}` } } // Get the action group JSON from Indigo, parse it into an object, and log it to the console http.get(options, (response) => { let result = "" response.on("data", chunk => { result += chunk; }) response.on("end", () => { const actionGroupList = JSON.parse(result); console.log(actionGroupList); }) }) == Using curl from the command line == * Replace ''//YOUR-API-KEY//'' with a valid key from your Indigo account. * Replace ''//YOUR-REFLECTOR-NAME//'' with the reflector name for your Indigo server. curl -H "Authorization: Bearer YOUR-API-KEY" https://YOUR-REFLECTOR-NAME.indigodomo.net/v2/api/indigo.actionGroups === Executing an Action Group === You can control Indigo action groups by sending commands through the API that instruct Indigo how to execute the action group. There is only one type of Indigo action group, and the action group type has its own command set. See the [[#actiongroup_command_messages|Action Group Command Messages]] below for a description of all messages. For now, here is a simple example of how to execute an action group: == Pure Python 3 (no additional libraries) == * Replace ''//YOUR-API-KEY//'' with a valid key from your Indigo account. * Replace ''//YOUR-REFLECTOR-NAME//'' with the reflector name for your Indigo server. * Replace ''//123456789//'' with a valid Indigo action group ID. # This is a pure python example - no additional libraries needed from urllib.request import Request, urlopen import json REFLECTORNAME = "YOUR-REFLECTOR-NAME" APIKEY = "YOUR-API-KEY" ACTIONGROUPID = 123456789 # The message to send to the Indigo Server message = json.dumps({ "id": "optional-user-generated-id", "message": "indigo.actionGroup.execute", "objectId": ACTIONGROUPID }).encode("utf8") req = Request(f"https://{REFLECTORNAME}.indigodomo.net/v2/api/command", data=message) req.add_header('Authorization', f"Bearer {APIKEY}") with urlopen(req) as request: reply = json.load(request) print(reply) == JavaScript run from nodejs (no additional libraries) == * Replace ''//YOUR-API-KEY//'' with a valid key from your Indigo account. * Replace ''//YOUR-REFLECTOR-NAME//'' with the reflector name for your Indigo server. * Replace ''//123456789//'' with a valid Indigo action group ID. // Things that are specific to your environment const REFLECTORNAME = "YOUR-REFLECTOR-NAME" const APIKEY = "YOUR-API-KEY" const ACTIONGROUPID = 123456789 // Get the http module, and tell it that you're using HTTPS const http = require("https") // The message to send to the Indigo Server const message = JSON.stringify({ "id": "optional-user-generated-id", "message": "indigo.actionGroup.execute", "objectId": ACTIONGROUPID }) // These are options that you'll pass to the get call const options = { hostname: `${REFLECTORNAME}.indigodomo.net`, path: "/v2/api/command", method: "POST", headers: { Authorization: `Bearer ${APIKEY}`, "Content-Length": message.length } } // Get the action group JSON from Indigo, parse it into an object, and log it to the console const req = http.request(options, (response) => { let result = "" response.on("data", chunk => { result += chunk; }) response.on("end", () => { const actionGroupInstance = JSON.parse(result); console.log(actionGroupInstance); }) }) req.write(message) req.end() == Using curl from the command line == * Replace ''//YOUR-API-KEY//'' with a valid key from your Indigo account. * Replace ''//YOUR-REFLECTOR-NAME//'' with the reflector name for your Indigo server. * Replace ''//123456789//'' with a valid Indigo action group ID. curl -X POST -H "Authorization: Bearer YOUR-API-KEY" -d '{"message": "indigo.actionGroup.execute", "objectId": 123456789}' https://YOUR-REFLECTOR-NAME.indigodomo.net/v2/api/command Using these examples, you can now construct any command listed below for any action group type. ===== API Messages ===== As mentioned earlier, both the WebSocket and HTTP APIs use JSON as the message format. We have exposed JSON versions of main Indigo objects: devices, variables, action groups, and control pages. We are also exposing command messages, which parallel the IOM command namespaces (where appropriate) for each of these object types (i.e. [[device_class#commands_indigodevice|indigo.device]], [[variable_class#commands_indigovariable|indigo.variable]], etc), which will allow you to command devices, set variable values, execute action groups, etc. There are also two other message types: event log messages, which represent each message that flow into the Event Log window, and error messages, which is a standardized way to communicate error conditions with each API. In this section, we will give examples of each message type and describe their use. If you are new to JSON, you might want to use the [[https://jsonlint.com|JSON Validator website]] to validate that your JSON messages are valid JSON. ==== Device Messaging ==== This section describes the messages that you'll use when implementing either the WebSocket or HTTP APIs. They fall into two categories: device objects and device commands. === Device Objects === You’ll receive full device JSON objects which represent an Indigo device instance. Each device will be slightly different based on the device class and the definition (if a custom device). See the [[object_model_reference|Indigo Object Model]] docs for device details. == Example device object == This is an example of an Indigo device as a JSON object. Of course, to accommodate the wide variety of supported device types, each one will be somewhat different. This one represents an Insteon Dimmer. { "class": "indigo.DimmerDevice", "address": "3B.04.7A", "batteryLevel": null, "blueLevel": null, "brightness": 0, "buttonConfiguredCount": 0, "buttonGroupCount": 1, "configured": true, "defaultBrightness": 100, "description": "- sample device -", "deviceTypeId": "", "displayStateId": "brightnessLevel", "displayStateImageSel": "indigo.kStateImageSel.DimmerOff", "displayStateValRaw": 0, "displayStateValUi": "0", "enabled": true, "energyAccumBaseTime": null, "energyAccumTimeDelta": null, "energyAccumTotal": null, "energyCurLevel": null, "errorState": "", "folderId": 1552926800, "folder": { "class": "indigo.Folder", "id": 1552926800, "name": "Insteon", "remoteDisplay": true }, "globalProps": {}, "greenLevel": null, "id": 1508839119, "lastChanged": "2023-02-01T11:39:58", "lastSuccessfulComm": "2023-02-01T11:39:58", "ledStates": [], "model": "LampLinc (dual-band)", "name": "Insteon Dimmer", "onBrightensToDefaultToggle": true, "onBrightensToLast": false, "onState": false, "ownerProps": {}, "pluginId": "", "pluginProps": {}, "protocol": "indigo.kProtocol.Insteon", "redLevel": null, "remoteDisplay": false, "sharedProps": {}, "states": { "brightnessLevel": 0, "onOffState": false }, "subModel": "Plug-In", "subType": "Plug-In", "supportsAllLightsOnOff": true, "supportsAllOff": true, "supportsColor": false, "supportsOnState": true, "supportsRGB": false, "supportsRGBandWhiteSimultaneously": false, "supportsStatusRequest": true, "supportsTwoWhiteLevels": false, "supportsTwoWhiteLevelsSimultaneously": false, "supportsWhite": false, "supportsWhiteTemperature": false, "version": 67, "whiteLevel": null, "whiteLevel2": null, "whiteTemperature": null } Message that contain device objects generate those objects by first converting the device to a python dictionary and then converting the python dictionary to JSON. See the [[device_class#generating_a_dictionary_for_a_device |Generating a Dictionary for a device]] section of the IOM Reference for details. HTTP The ''**folder**'' element is only available in the HTTP API. Folders are handled differently in the WebSocket API. === Device Command Messages === One thing you will notice as you are looking through these examples, is that they closely mirror the Python-based [[object_model_reference|IOM commands for controlling devices]]. This was intentional to make learning one API a stepping stone to another. The HTTP API messages and the WebSocket API messages are identical, and are very clearly a JSON-rendered version of the associated IOM command. The ''id'' key is optional, but may contain a user generated ID that will be logged and returned to help match up with message requests. === indigo.device === [[device_class#commands_indigodevice|indigo.device]] command messages can be used for several Indigo device types - [[device_class#relaydevice|indigo.RelayDevice]], [[device_class#dimmerdevice|indigo.DimmerDevice]], [[device_class#speedcontroldevice|indigo.SpeedControl]] (fans), and some [[device_class#sensordevice|indigo.SensorDevice]] instances. **status request** ''[[device_class#status_request|indigo.device.statusRequest(123456789)]]'' { "id": "optional-user-generated-id", "message": "indigo.device.statusRequest", "objectId": 123456789 } **Note:** This message will work on any Indigo device type, though the device that it targets may not respond to status request messages in which case it will do nothing. WebSocket 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 sent out the websocket. **toggle** ''[[device_class#toggle|indigo.device.toggle(123456789, delay=5, duration=10)]]'' { "id": "optional-user-generated-id", "message": "indigo.device.toggle", "objectId": 123456789, "parameters": { "delay": 5, "duration": 10 } } ''objectId'' is the id of the device. The ''parameters'' dictionary is optional. **turn off** ''[[device_class#turn_off|indigo.device.turnOff(123456789, delay=5, duration=10)]]'' { "id": "optional-user-generated-id", "message": "indigo.device.turnOff", "objectId": 123456789, "parameters": { "delay": 5, "duration": 10 } } ''objectId'' is the id of the device. The ''parameters'' dictionary is optional. **turn on** ''[[device_class#turn_on|indigo.device.turnOn(123456789, delay=5, duration=10)]]'' { "id": "optional-user-generated-id", "message": "indigo.device.turnOn", "objectId": 123456789, "parameters": { "delay": 5, "duration": 10 } } ''objectId'' is the id of the device. The ''parameters'' dictionary is optional. **lock** ''[[device_class#lock|indigo.device.lock(123456789, delay=5, duration=10)]]'' { "id": "optional-user-generated-id", "message": "indigo.device.lock", "objectId": 123456789, "parameters": { "delay": 5, "duration": 10 } } ''objectId'' is the id of the device. The ''parameters'' dictionary is optional. **unlock** ''[[device_class#unlock|indigo.device.unlock(123456789, delay=5, duration=10)]]'' { "id": "optional-user-generated-id", "message": "indigo.device.unlock", "objectId": 123456789, "parameters": { "delay": 5, "duration": 10 } } ''objectId'' is the id of the device. The ''parameters'' dictionary is optional. **enable/disable** ''[[device_class#enable_disable|indigo.device.enable(123456789, value=True)]]'' { "id": "optional-user-generated-id", "message": "indigo.device.enable", "objectId": 123456789, "parameters": { "value": True, } } ''objectId'' is the id of the device. The ''value'' parameter is optional (''True'' to enable, ''False'' to disable). === indigo.dimmer === [[device_class#commands_indigodevice|indigo.dimmer]] command messages can be used for [[device_class#dimmerdevice|indigo.DimmerDevice]] instances. **brighten** ''[[device_class#brighten|indigo.dimmer.brighten(123456789, delay=5, duration=10)]]'' { "id": "optional-user-generated-id", "message": "indigo.dimmer.brighten", "objectId": 123456789, "parameters": { "by": 5, "delay": 10 } } ''objectId'' is the id of the device. The ''parameters'' dictionary is optional. **dim** ''[[device_class#dim|indigo.dimmer.dim(123456789, delay=5, duration=10)]]'' { "id": "optional-user-generated-id", "message": "indigo.dimmer.dim", "objectId": 123456789, "parameters": { "by": 5, "delay": 10 } } ''objectId'' is the id of the device. The ''parameters'' dictionary is optional. **set brightness** ''[[device_class#set_brightness|indigo.dimmer.setBrightness(123456789, value=50, delay=5)]]'' { "id": "optional-user-generated-id", "message": "indigo.dimmer.setBrightness", "objectId": 123456789, "parameters": { "value": 50, "delay": 10 } } ''objectId'' is the id of the device. The ''value'' parameter is required and the ''delay'' parameter is optional. === indigo.iodevice === [[device_class#commands_indigodevice| indigo.iodevice]] command messages can be used for [[device_class#dimmerdevice|indigo.MultiIODevice]] instances. **set binary output** ''[[device_class#set_binary_output|indigo.iodevice.setBinaryOutput(123456789, index=2, value=True)]]'' { "id": "optional-user-generated-id", "message": "indigo.iodevice.setBinaryOutput", "objectId": 123456789, "parameters": { "index": 5, "value": true } } ''objectId'' is the id of the device. The ''index'' and ''value'' parameters are required. === indigo.sensor === [[device_class#commands_indigosensor| indigo.sensor]] command messages can be used for [[device_class#sensorDevice|indigo.sensorDevice]] instances. **set on state** ''[[device_class#set_on_state1| indigo.sensor.setOnState(123456789, index=2, value=True)]]'' { "id": "optional-user-generated-id", "message": "indigo.sensor.setOnState", "objectId": 123456789, "parameters": { "value": true } } ''objectId'' is the id of the device. The ''value'' parameter is required. === indigo.speedcontrol === [[device_class#commands_indigospeedcontrol| indigo.speedcontrol]] command messages can be used for [[device_class#speedcontroldevice|indigo.speedcontrol]] instances. **decrease speed index** ''[[device_class#decrease_speed_index| indigo.speedcontrol.decreaseSpeedIndex(123456789, index=2, value=True)]]'' { "id": "optional-user-generated-id", "message": "indigo.speedcontrol.decreaseSpeedIndex", "objectId": 123456789, "parameters": { "by": 2, "delay": 5 } } ''objectId'' is the id of the device. The ''by'' and ''delay'' parameters are optional. **increase speed index** ''[[device_class#increase_speed_index| indigo.speedcontrol.increaseSpeedIndex(123456789, index=2, value=True)]]'' { "id": "optional-user-generated-id", "message": "indigo.speedcontrol.increaseSpeedIndex", "objectId": 123456789, "parameters": { "by": 2, "delay": 5 } } ''objectId'' is the id of the device. The ''by'' and ''delay'' parameters are optional. **set speed index** ''[[device_class#set_speed_index| indigo.speedcontrol.setSpeedIndex(123456789, index=2, value=True)]]'' { "id": "optional-user-generated-id", "message": "indigo.speedcontrol.setSpeedIndex", "objectId": 123456789, "parameters": { "value": 2, "delay": 5 } } ''objectId'' is the id of the device. The ''value'' parameter is required and the ''delay'' parameter is optional. **set speed level** ''[[device_class#set_speed_level| indigo.speedcontrol.setSpeedLevel(123456789, index=2, value=True)]]'' { "id": "optional-user-generated-id", "message": "indigo.speedcontrol.setSpeedLevel", "objectId": 123456789, "parameters": { "value": 50, "delay": 5 } } ''objectId'' is the id of the device. The ''value'' parameter is required and the ''delay'' parameter is optional. === indigo.sprinkler === [[device_class#commands_indigosprinkler| indigo.sprinkler]] command messages can be used for [[device_class#sprinklerdevice|indigo.sprinkler]] instances. **next zone** ''[[device_class#next_zone| indigo.sprinkler.nextZone(123456789, index=2, value=True)]]'' { "id": "optional-user-generated-id", "message": "indigo.sprinkler.nextZone", "objectId": 123456789 } ''objectId'' is the id of the device. The ''next zone'' command does not have any additional parameters. **pause schedule** ''[[device_class#pause_schedule| indigo.sprinkler.pause(123456789, index=2, value=True)]]'' { "id": "optional-user-generated-id", "message": "indigo.sprinkler.pause", "objectId": 123456789 } ''objectId'' is the id of the device. The ''next zone'' command does not have any additional parameters. **previous zone** ''[[device_class#previous_zone| indigo.sprinkler.previousZone(123456789, index=2, value=True)]]'' { "id": "optional-user-generated-id", "message": "indigo.sprinkler.previousZone", "objectId": 123456789 } ''objectId'' is the id of the device. The ''previous zone'' command does not have any additional parameters. **resume schedule** ''[[device_class#resume_schedule| indigo.sprinkler.resume(123456789, index=2, value=True)]]'' { "id": "optional-user-generated-id", "message": "indigo.sprinkler.resume", "objectId": 123456789 } ''objectId'' is the id of the device. The ''resume schedule'' command does not have any additional parameters. **run schedule** ''[[device_class#run_schedule| indigo.sprinkler.run(123456789, index=2, value=True)]]'' { "id": "optional-user-generated-id", "message": "indigo.sprinkler.run", "objectId": 123456789, "parameters": { "schedule": [10,15,8, 0, 0, 0, 0, 0] } } ''objectId'' is the id of the device. The ''schedule'' parameter is required. **stop schedule** ''[[device_class#stop_schedule| indigo.sprinkler.stop(123456789, index=2, value=True)]]'' { "id": "optional-user-generated-id", "message": "indigo.sprinkler.stop", "objectId": 123456789 } ''objectId'' is the id of the device. The ''resume schedule'' command does not have any additional parameters. **set active zone** ''[[device_class#set_active_zone| indigo.sprinkler.setActiveZone(123456789, index=2, value=True)]]'' { "id": "optional-user-generated-id", "message": "indigo.sprinkler.setActiveZone", "objectId": 123456789, "parameters": { "index": 2 } } ''objectId'' is the id of the device. The ''index'' parameter is required. === indigo.thermostat === [[device_class#commands_indigothermostat| indigo.thermostatdevice]] command messages can be used for [[device_class#thermostatdevice|indigo.thermostat]] instances. **decrease cool setpoint** ''[[device_class#decrease_cool_setpoint| indigo.thermostat.decreaseCoolSetpoint(123456789, index=2, value=True)]]'' { "id": "optional-user-generated-id", "message": "indigo.thermostat.decreaseCoolSetpoint", "objectId": 123456789, "parameters": { "delta": 2 } } ''objectId'' is the id of the device. The ''value'' parameter is optional. **decrease heat setpoint** ''[[device_class#decrease_heat_setpoint| indigo.thermostat.decreaseHeatSetpoint(123456789, index=2, value=True)]]'' { "id": "optional-user-generated-id", "message": "indigo.thermostat.decreaseHeatSetpoint", "objectId": 123456789, "parameters": { "delta": 2 } } ''objectId'' is the id of the device. The ''value'' parameter is optional. **increase cool setpoint** ''[[device_class#increase_cool_setpoint| indigo.thermostat.increaseCoolSetpoint(123456789, index=2, value=True)]]'' { "id": "optional-user-generated-id", "message": "indigo.thermostat.increaseCoolSetpoint", "objectId": 123456789, "parameters": { "delta": 2 } } ''objectId'' is the id of the device. The ''value'' parameter is optional. **increase heat setpoint** ''[[device_class#increase_heat_setpoint| indigo.thermostat.increaseHeatSetpoint(123456789, index=2, value=True)]]'' { "id": "optional-user-generated-id", "message": "indigo.thermostat.increaseHeatSetpoint", "objectId": 123456789, "parameters": { "delta": 2 } } ''objectId'' is the id of the device. The ''value'' parameter is optional. **set cool setpoint** ''[[device_class#set_cool_setpoint| indigo.thermostat.setCoolSetpoint(123456789, index=2, value=True)]]'' { "id": "optional-user-generated-id", "message": "indigo.thermostat.setCoolSetpoint", "objectId": 123456789, "parameters": { "value": 76 } } ''objectId'' is the id of the device. The ''value'' parameters is required. **set fan mode** ''[[device_class#set_fan_mode| indigo.thermostat.setFanMode(123456789, index=2, value=True)]]'' { "id": "optional-user-generated-id", "message": "indigo.thermostat.setFanMode", "objectId": 123456789, "parameters": { "value": "indigo.kFanMode.AlwaysOn" } } ''objectId'' is the id of the device. The ''value'' parameter is required. **set heat setpoint** ''[[device_class#set_heat_setpoint| indigo.thermostat.setHeatSetpoint(123456789, index=2, value=True)]]'' { "id": "optional-user-generated-id", "message": "indigo.thermostat.setHeatSetpoint", "objectId": 123456789, "parameters": { "value": 76 } } ''objectId'' is the id of the device. The ''value'' parameter is required. **set hvac mode** ''[[device_class#set_hvac_mode| indigo.thermostat.setHvacMode(123456789, index=2, value=True)]]'' { "id": "optional-user-generated-id", "message": "indigo.thermostat.setHvacMode", "objectId": 123456789, "parameters": { "value": "indigo.kHvacMode.HeatCool" } } ''objectId'' is the id of the device. The ''value'' parameter is required. ==== Variable Messaging ==== This section describes the messages that you'll use when implementing either the WebSocket or HTTP APIs when dealing with Indigo devices. They fall into two categories: device objects and device command messages. === Variable Objects === You’ll receive full variable JSON objects which represent an Indigo variable instance. See the [[object_model_reference|Indigo Object Model]] docs for device details. == Example variable object == { "class": "indigo.Variable", "description": "", "folderId": 0, "folder": {}, "globalProps": { "com.indigodomo.indigoserver": {} }, "id": 345633244, "name": "house_status", "pluginProps": {}, "readOnly": false, "remoteDisplay": true, "sharedProps": {}, "value": "home" } Messages that contain variable objects generate those objects by first converting the variable to a python dictionary and then converting the python dictionary to JSON. See the [[variable_class#generating_a_dictionary_for_a_variable |Generating a Dictionary for a variable]] section of the IOM Reference for details. HTTP The ''**folder**'' element is only available in the HTTP API. Folders are handled differently in the WebSocket API. === Variable Command Messages === The only action that can currently be performed on a variable is to update the value. The ''id'' key is optional, but may contain a user generated ID that will be logged and returned to help match up with message requests. **updateValue** ''[[variable_class#update_value|indigo.variable.updateValue(123456789, value="Some string value")]]'' { "id": "optional-user-generated-id", "message": "indigo.variable.updateValue", "objectId": 123456789, "parameters": { "value": "Some string value" } } ''objectId'' is the id of the variable. The ''value'' parameter is required and must be a string. Pass an empty string ("") to clear the variable value. ==== Action Group Messaging ==== === Action Group Objects === You’ll receive full variable JSON objects which represent an Indigo action group instance. See the [[object_model_reference|Indigo Object Model]] docs for action group details. == Example action group object == { "class": "indigo.ActionGroup", "description": "", "folderId": 532526508, "folder": { "class": "indigo.Folder", "id": 532526508, "name": "Mood Scenes", "remoteDisplay": true }, "globalProps": { "com.indigodomo.indigoserver": { "speakDelayTime": "5", "speakTextVariable": "speech_string" } }, "id": 94914463, "name": "Movie Night", "pluginProps": {}, "remoteDisplay": true, "sharedProps": { "speakDelayTime": "5", "speakTextVariable": "speech_string" } } HTTP The ''**folder**'' element is only available in the HTTP API. Folders are handled differently in the WebSocket API. === Action Group Command Messages === There is only a single action group command, and that's to execute it. The ''id'' key is optional, but may contain a user generated ID that will be logged and returned to help match up with message requests. ** execute ** ''[[action_group_class#execute|indigo.actionGroup.execute(123456789)]]'' { "id": "optional-user-generated-id", "message": "indigo.actionGroup.execute", "objectId": 123456789 } ''objectId'' is the id of the action group. ==== Log Messages ==== We convert the event Indigo dictionary into a python dictionary in the ''%%event_log_line_received%%'' plugin method. === Example Log Message === { "message": "Stopping plugin \"Web Server 2022.2.0\" (pid 1020)", "timeStamp": "2022-12-01T12:03:27.759000", "typeStr": "Application", "typeVal": 0 "objectType": "indigo.LogEvent" } Note that ''%%typeVal%%'' will be one of the following values: EVENT_TYPES = { Application = 0, Error = 1, Error_Client = 2, Warning = 3, Warning_Client = 4, Debug_Server = 5, Debug_Client = 6, Debug_Plugin = 7, Custom = 8, } 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 Messaging ===== 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: == Generic Error Message == { "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 dictionary 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: == Example API Call == { "id": "a-random-id-for-this-message", "message": "indigo.variable.updateValue", "objectId": 123456789, "parameters": { "value": 1234.56 } } You will receive the following error response: == Resulting Error Message == { "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 which 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%%'', and - ''%%value%%'' based on the ''%%indigo.variable.updateValue%%'' message format (we do **no validation** on the ''%%id%%'' value passed in, we 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. ''id'' is the ID you (may have) passed in when you sent the command message. === Invalid JSON === 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: == Example Invalid JSON Message == { "request_body": "this is not valid JSON", "error": "invalid JSON" } We will return the entire request body since it isn’t valid JSON, and we don’t know what else to do with it.