Casambi WebSocket Service
Casambi WebSocket service is used for receiving event and state information from Casambi bluetooth mesh network. This kind of event information can change very often and depends on state of the device.
WebSocket Service URL: wss://door.casambi.com/v1/bridge/
Event and state information received via WebSocket connection does not contain all the same device information as what is received via the REST API requests even though in some parts they may overlap. Purpose of event data is to offer supplemental state information that complements the data received from REST API. Recommended way to use WebSocket services is to first request information about network and it devices trough REST API and then create related WebSocket connection to receive additional state data.
You can find more information about WebSocket protocol and how to use it from here: WebSocket API
Version History
- /v1
- Receive network related event and device state information
- Basic light control and dimming options for network, related devices and scenes
Changes
- 13.05.2020 - Creating WebSocket connection, opening wires and receiving event data.
- 07.12.2020 - Sending control messages via WebSocket.
- 04.03.2021 - Datalogging and API documentation added. FAQ page added.
- 15.08.2021 - Added javascript code example how to create WebSocket connection, open wire and receive event data.
- 16.11.2022 - Added max limit of 20 different wires per network (and one per same WebSocket).
Getting Started
-
Acquire API Key - Acquire API key, contact Casambi Support for more info.
-
Obtain Credentials - Create session by using REST API with your Casambi user or network credentials. More info here: API Authentication.
-
Test Requests - Test how opening WebSocket connection and receiving event data works with WebSocket web console.
API key availability is currently limited.
Creating a WebSocket Connection
To create Casambi WebSocket connection you need to pass your API key as a "protocol" to the server. With javascript (ES6) you can do this as in the following code example.
let api_key = "8aSdFG678M8nPL63FNe5fjrey42loASFWg64v29Se23GAm67576werQtyz1";
webSocket = new WebSocket("wss://door.casambi.com/v1/bridge/", api_key);
After the WebSocket has been connected an OPEN message must be sent to the server without delay!
OPEN message
When WebSocket connection has opened you must send valid OPEN message to server to initialize the connection and to keep it open. Otherwise server will automatically close the connection after few seconds. Use "onopen" event listener of WebSocket to do this. For OPEN message you will need to have valid session and network as parameters as shown in the following code example.
webSocket.onopen = function () {
let session_id = "SESSION-ID"; // Received from API create session request
let network_id = "NETWORK-ID"; // Received from API create session request
let reference = "REFERENCE-ID"; // Reference handle created by client to link messages to relevant callbacks
let wire = 1; // Connection ID, incremental value to identify messages of network/connection
let type = 1; // Client type, use value 1 (FRONTEND)
const OPEN = JSON.stringify({
"method": "open",
"id": network_id,
"session": session_id,
"ref": reference,
"wire": wire,
"type": type
});
this.send(decodeURIComponent(escape(OPEN)));
};
Expected way to use OPEN message is to create one wire per one network. Thus event messages from each network can be mapped to specific wire ID. Wire ID is expected to be integer value starting from 1. Wire ID is unique to the opened WebSocket connection and messages from specific wire can be "paused".
In addition use of reference ID is recommended. When given by client in the OPEN message it can be then used to map initial WebSocket response message from server to relevant callback on client side. Note that reference ID (if given) is added only to initial response message from server per related OPEN message.
If client tries to open wire to the same network from the same connection more than once then server will block this and return tooManyWires response with wireStatus: "Only one wire allowed per network!". Different WebSocket connections can point to the same network up to maximum of 20 active wire connections per network. If client or clients try to open more than 20 WebSocket connections to the same network then server will block this and return tooManyWires response with wireStatus: "Too many wires opened!".
On OPEN success
When OPEN message is successful server will send initial openWireSucceed response message along with possible reference ID (if given). In addition if there is active (authorized) gateway related to the network defined in the OPEN message then server will also send peerChanged event message. If gateway is active and any devices are connected then server will send also current state of connected devices as event message. After this new messages will be sent only when some event occurs within the network(s) related to given wire. For more information see receiving messages.
If there is no active (authorized) gateway added related to the network(s) of the OPENed wire then server will only send openWireSucceed message and nothing else until the gateway is active again. Also note that if server does not receive any traffic from the Opened WebSocket (and wire) then after 5 minutes of inactivity it will automatically close the WebSocket connection. See Keeping connection alive for more info.
On OPEN failure
When OPEN message fails server will send one message with information about the failure along with possible reference ID (if given). For more information see OPEN message response wire status types.
CLOSE message
In case you want to "pause" current WebSocket wire you can send CLOSE message to server. This way the WebSocket connection will still stay alive even though no messages will be sent to the closed wire anymore. Following code example shows how you can send the wire CLOSE message to server.
let wire = 1; // Use same wire ID as was used in the related OPEN message for the targeted network
if (webSocket.readyState === webSocket.OPEN) {
const CLOSE = JSON.stringify({
"method": "close",
"wire": wire
});
webSocket.send(decodeURIComponent(escape(CLOSE)));
}
To re-open "paused" WebSocket connection you need to send the OPEN message again with same wire ID. For more information see OPEN message.
Keeping connection alive
To keep the WebSocket connection alive over times of inactivity it is recommended to send PING messages to server within the Keep-Alive time span. Currently this Keep-Alive time span is 5 minutes. Thus to keep the connection alive it is recommended to send PING message to server within every 4 minutes or so.
Following code example shows how you can send PING message to server.
let wire = 1; // Use same wire ID as was used in the related OPEN message for the targeted network
if (webSocket.readyState === webSocket.OPEN) {
const PING = JSON.stringify({
"method": "ping",
"wire": wire
});
webSocket.send(decodeURIComponent(escape(PING)));
}
When server receives PING message it will respond with PONG message. Response to the PONG message looks like this.
{"response":"pong"}
This PONG message does not have any other function than to notify client that server has received PING message. Regardless of if PING messages are sent or not it is highly recommended that one implements WebSocket disconnected functionality to keep the connection open every time WebSocket disconnects for some reason.
WebSocket disconnected
In some situations it is possible that server disconnects WebSocket connection. In this case reopen connection and related wires to not lose any event data.
webSocket.onerror = function (error) {
console.log("WebSocket Error:", error);
// REOPEN the WebSocket connection and all related wires..
};
webSocket.onclose = function () {
console.log("WebSocket Closed!");
// REOPEN the WebSocket connection and all related wires..
};
To re-open disconnected WebSocket connection and wire you need to create new WebSocket connection and send the OPEN message again. For more information see Creating WebSocket connection and OPEN message.
Receiving messages
When WebSocket connection is created and valid OPEN message sent from client then server will send initial response messages to the WebSocket including current state information of all active devices in the network. After sending initial messages server will not send any new messages to WebSocket until some event occurs in the related network and/or to its devices. Use "onmessage" event listener of WebSocket to receive messages. Following code example shows how messages can be received from server.
webSocket.onmessage = function (event) {
(new Response(event.data)).text().then(function (result) {
let data = JSON.parse(result);
if ("method" in data) {
console.log(data);
if (data.method === "unitChanged") {
// Initial device state info and device state changed event
// In case data.id is not in "network.units" list (fetched via API) this event can be ignored.
} else if (data.method === "networkUpdated") {
// Network changed event, for example device added to a group within the network
} else if (data.method === "peerChanged") {
// Online peers changed, for example new API client has joined the network when gateway is connected
}
}
}, function (error) {
console.log(error);
});
};
Wire Status message
On specific situations server will respond with Wire Status message. For example initial WebSocket response message (received after OPEN message) will contain a "wireStatus" key/value pair that holds information if OPEN message was successful or not. This initial response message will include reference ID given by the client in the OPEN message (if any), this key/value pair will be simply named as "ref".
In some situations server will respond with Wire Status message when there was a problem handling the received message. For example if client sends invalid CONTROL message to server that contains invalid values then server will respond with wireStatus: invalidValueType message. This kind of response message will not include any reference ID or other identifier data and is only sent to the client that sent the related CONTROL message in the first place.
Following list includes possible wireStatus values.
openWireSucceed | Wire opened successfully. |
keyAuthenticateFailed | API key authentication failed. Given key was invalid. |
keyAuthorizeFailed | API key authorize failed. Given key has not been authorized or WebSocket functionality is not enabled for it. |
invalidSession | Either access to given network is not authorized by session or given session is invalid. |
tooManyWires | Trying to open more wires to the same network than is allowed. One wire per connection/network or maximum of 20 different wires per network are allowed. |
invalidValueType | Received values are not in correct value type, for example when expecting a number but receiving string value instead. |
invalidData | Received data is invalid and cannot be processed, for example expected list of items is in wrong data format. |
Message method types
WebSocket event messages include a "method" key/value pair that holds information about what kind of event has occurred. In addition event messages will always include related wire ID originally given by the client, this key/value pair will be simply named as "wire".
Following list includes common event types that message can have.
unitChanged | Device state has changed from the previous known state. Returned device information and control state list contain the changed information. In case when receiving information about device that is currently not part of the network.units list (fetched via API) this event can be ignored. |
peerChanged | API client/gateway has joined or left "active" network. In most cases no action required. |
networkUpdated | Network setting or composition has somehow changed. Fetching latest network information from REST API and re-sending the OPEN message to WebSocket is recommended. * |
The networkUpdated event is triggered by any persistent change in configuration of network or its scene or device. In other words if something else than state info changed and it needs to be stored to related configuration then it will require network info update.
Event message info
Event messages contain information about the state of specific device or related network. This information is supplemental to data received from REST API even though in some parts it may overlap. Let's look a bit closer what kind of details are available through device specific unitChanged event messages. See the example message below.
Each event is specific to that current state of the device and does not contain information from previous events. If one wants to keep "history" of events and related details then those should be stored per each event on client side.
{
"controls": [
{
"type": "Dimmer",
"value": 0.5
}, {
"source": "XY",
"type": "Colorsource"
}, {
"type": "Color",
"x": 0.368343917,
"y": 0.13,
"rgb": "rgb(255, 143, 255)"
}, {
"min": 2700,
"max": 6000,
"type": "CCT",
"value": 6000,
"level": 1
}
],
"method": "unitChanged",
"priority": 15,
"id": 45,
"groupId": 0,
"position": 2,
"address": "df89c844c301",
"name": "Example Luminaire",
"fixtureId": 1234,
"type": "Luminaire",
"condition": 0,
"wire": 10,
"sensors": {},
"online": true,
"activeSceneId": 0,
"dimLevel": 0.5,
"details": {
"DALI": {
"SERIAL.4456935198821319392": {
"GTIN": "8718696698181",
"ODM": "Philips",
"address": "0",
"device_type": "6:SR",
"energy_resettable": 900,
"energy_total": 1.5,
"energy_ts": 1560345734.924028,
"lamp_time": 79,
"model": "Xitanium 60W 0.08-0.35A 300V SR 230V",
"operating_time": 16685,
"output_power": 300,
"serial": "4456935198821319392",
"status": "02",
"system_starts": 45
}
},
"OEM": "Casambi",
"fixture_model": "ExampleXY"
},
"status": "ok"
}
id — Identifier of this device.
name — Name of this device.
on — Either device is ON or it is not. Naturally if device is OFF it won't be sending events to the network but in most cases server/gateway will detect these situations.
online — Either device is Online or Offline. Naturally if device is Offline it won't be sending events to the network but in most cases server/gateway will detect these situations.
condition — Numeric presentation of status of the device. If condition is 0, 128 or 160 then status is "ok" otherwise device is experiencing some failure situation.
status — Textual presentation of the status of the device. If all is good then status is "ok" and if not then status will have text description about the current failure condition. Below a list of known failure statuses.
"overheated" => activation of thermal protection
"thermal_overload" => ~ thermal derating, includes thermal shutdown state
"lamp_failure" => reported by output module
"hw_failure" => reported by output module
"driver_failure" => DALI: reported by gear
"io_error" => the I/O system has flagged excessive communication errors
"incompatible_hw" => Mismatch between expected capabilities of DALI gear
"hw_not_found" => Missing gear (not detectable, possibly not addressed yet)
"configuration_failed" => Casambi code for start-up state (it's error if it stays)
"overload" => current limit (OCP - overcurrent protection)
"short_circuit"
"open_circuit"
groupId — ID of the related group if any. If this device is not part of any group then will be set to 0.
activeSceneId — ID of the scene that is currently active related to this specific luminaire. If "activeSceneId" is not set or is set to 0 then no scene is currently active related to this device.
dimLevel — The current level of dimming (0..1) of this specific luminaire.
fixtureId — ID of the related fixture.
type — Type name of this device, usually "Luminaire".
position — Position of this device within Casambi App view. Position of grouped items refers to position within the group. Position numbers may or may not be linear.
image — Identifier of related device icon/image. By default not set.
details — Holds information about the hardware and related fixture including fixture ID. For example in case of DALI activated device here will be some DALI specific information about the device.
priority — Numeric type identifier of the active device priority. Device can have multiple priority levels based on if it is switch, sensor or time controlled through a scene or animation. Below is listed different priority values.
1 emergency
3 manual
5 date
6 weekday
8 presence sensor
11 timer/date
12 timer/weekday
15 startup animation
controls — Holds information about the state of the device depending on the type of device (Luminaire, Sensor, etc.). For example luminaires have Dimmer value between 0 .. 1, if value is 0 light is OFF and if it is 1 light is ON. Or if light is dimmed then the value will be something between 0 and 1.
In control with type "Color" there will be information about the color of the light (XY or Hue/Sat) and related rgb color string.
In addition there can be information about the light temperature (CCT) and other "control" specific data like the state of the switch or sensor event. Basically information in "controls" list presents the "state" of the device.
Sending CONTROL messages
To change the state of the luminaire you can send CONTROL messages from client to server. These CONTROL messages will control the dim level of the luminaire. When server receives CONTROL message from the client it will then forward the message to related devices via the related gateway. After the state of the target luminaire has changed then related eventUpdate messages will be sent to all connected clients listening to WebSocket of related network.
In case if sent CONTROL message values were in wrong format then server will respond with { "wireStatus":"invalidValueType" } message instead.
Target controls specification
Control methods refer to device's control fields which are provided as "controls" in description of unit state. There are several complementing ways how controls can be specified.
- General control name: "Dimmer", "Slider", "ColorTemperature" (alias "CCT"), "RBG"/"XY" (alias "Color"), "WhiteColorBalance" (alias "ColorBalance"), etc.
- Indexed typename: dimmer[0..3], slider[0..7], onoff[0..7], pushbutton[0..3].
- Named custom element: using the "name" property of custom controls from unit state "controls" details.
- "$reference" name of custom elements as specified in the fixture profile.
- Control typename (lowercase aliases of advertised controls names): dimmer, slider, onoff, pushbutton, etc.
Multiple examples what may be used in the "targetControls" specification are shown below. Note that for multiple controls of the same base type, the general name/typename affects all of them.
let targetControls = {
// General names:
"Dimmer": {"value": 0.5}, // Dimmer value can be anything from 0 to 1
"Slider": {"value": 45}, // value in the MIN..MAX range of the control
"ColorTemperature": {"value" : 5000}, // value in Kelvin
"Colorsource": {"source": "TW"}, // "RGB" (also for HueSat model), "XY" or "TW"
"RGB": {"hue": 0.5, "sat": 0.5},
"RGB": {"rgb": "rgb(0, 125, 255)"}, // "Color" can be used as more general alias for RGB/HS/XY setters
"XY": {"x": 0.375, "y": 0.425 },
"ColorBalance": {"value": 0.5}, // alias for "WhiteColorBalance"
"OnOff": {"value" : 1.0}, // On/Off
"PushButton": {"value" : 1.0}, // Pressed/Released
...
// Indexed control types:
"dimmer0": {"value": 0.5}, // the first slider
"dimmer1": {"value": 1.0}, // the second slider, etc.
...
"slider4": {"value": 0.5}, // the 5th slider
...
"onoff0": {"value": 0.0}, // the first ON/OFF toggle
...
"pushbutton0": {"value": 1.0}, // PushButton controls
...
// Named custom elements:
"height": {"value": 200.0}, // for a "$height" custom element, the name property is just "height",
"$angle": {"value": 30.0}, // and both ways can be used; the "$" prefix may be needed to disambiguate
};
Turn luminaire on/off/dim
To control the dim level of a luminaire you can send a CONTROL message to server over active WebSocket connection (and opened wire). The "targetControls" parameter of the message uses similar format as received with unitChanged event of the related device.
let wire = 1; // Use same wire ID as was used in the related OPEN message for the targeted network
let unit_id = 1; // Device ID of the related luminaire
let targetControls = {"Dimmer": {"value": 0.5}}; // Dimmer value can be anything from 0 to 1
if (webSocket.readyState === webSocket.OPEN) {
const data = JSON.stringify({
"wire": wire,
"method": "controlUnit",
"id": unit_id,
"targetControls": targetControls
});
socket.send(decodeURIComponent(escape(data)));
}
When CONTROL luminaire message was successful then server will send unitChanged event (with updated state info) to all related clients and related luminaire will be on/off/dimmed.
Turn set of luminaires on/off/dim
To control the dim level of a set of luminaires you can send a CONTROL message to server over active WebSocket connection (and opened wire). The "targetControls" parameter of the message uses similar format as received with any unitChanged event of the related device. The "ids" parameter of the message is a list of targeted device ID's (number).
let wire = 1; // Use same wire ID as was used in the related OPEN message for the targeted network
let targetControls = {"Dimmer": {"value": 0.5}}; // Dim value can be anything from 0 to 1
let units = [10, 77] // Array of target device ID's
if (webSocket.readyState === webSocket.OPEN) {
const data = JSON.stringify({
"wire": wire,
"method": "controlUnits",
"targetControls": targetControls,
"ids": units
});
socket.send(decodeURIComponent(escape(data)));
}
When CONTROL set of luminaires message was successful then server will send unitChanged events (with updated state info) of all related devices to all related clients and related luminaires will be on/off/dimmed.
Turn scene on/off/dim
To control the dim level of all luminaires of a scene in a network you can send a CONTROL message to server over active WebSocket connection (and opened wire). The "id" parameter of the message is the ID (number) of the related scene of the network related to the current wire. The "level" parameter of the message is the wanted dim level (number) for the related luminaires.
let wire = 1; // Use same wire ID as was used in the related OPEN message
let scene_id = 1; // Scene ID of the network related to the current wire
let value = 0.5; // Dim value can be anything from 0 to 1
if (webSocket.readyState === webSocket.OPEN) {
const data = JSON.stringify({
"wire": wire,
"method": "controlScene",
"id": scene_id,
"level": value
});
socket.send(decodeURIComponent(escape(data)));
}
When CONTROL luminaires of scene message was successful then server will send unitChanged events (with updated state info) of all related devices to all related clients and related luminaires will be on/off/dimmed.
Turn group of luminaires on/off/dim
To control the dim level of a group of luminaires you can send a CONTROL message to server over active WebSocket connection (and opened wire). The "id" parameter of the message is the ID (number) of the related group of the network related to the current wire. The "level" parameter of the message is the wanted dim level (number) for the related luminaires.
let wire = 1; // Use same wire ID as was used in the related OPEN message for the targeted network
let value = 0.5; // Dim value can be anything from 0 to 1
let group_id = 1; // ID of the related group
if (webSocket.readyState === webSocket.OPEN) {
const data = JSON.stringify({
"wire": wire,
"method": "controlGroup",
"id": group_id,
"level": value
});
socket.send(decodeURIComponent(escape(data)));
}
When CONTROL luminaire group message was successful then server will send unitChanged events (with updated state info) of all related devices to all related clients and related luminaires will be on/off/dimmed.
Turn network on/off/dim
To control the dim level of all luminaires of a network you can send a CONTROL message to server over active WebSocket connection (and opened wire). The "level" parameter of the message is the wanted dim level (number) for the related luminaires.
let wire = 1; // Use same wire ID as was used in the related OPEN message for the targeted network
let value = 0.5; // Dim value can be anything from 0 to 1
if (webSocket.readyState === webSocket.OPEN) {
const data = JSON.stringify({
"wire": wire,
"method": "controlNetwork",
"level": value
});
socket.send(decodeURIComponent(escape(data)));
}
When CONTROL luminaires of network message was successful then server will send unitChanged events (with updated state info) of all related devices to all related clients and related luminaires will be on/off/dimmed.
Control color temperature
To control the color temperature of specific luminaire of network you can send a CONTROL message to server over active WebSocket connection (and opened wire). The "targetControls" parameter of the message uses similar format as received with unitChanged event of the related device. The "source" of Colorsource object must be set to "TW" for color temperature functionality to work as expected. The "value" of the ColorTemperature object of the message is the wanted color temperature in Kelvins (number) for the related luminaire.
let wire = 1; // Use same wire ID as was used in the related OPEN message for the targeted network
let unit_id = 1; // Device ID of the related luminaire
let targetControls = {"ColorTemperature": {"value" : 5000}, "Colorsource": {"source": "TW"}}; // ColorTemperature value in Kelvins, anything between Kelvin range of luminaire
if (webSocket.readyState === webSocket.OPEN) {
const data = JSON.stringify({
"wire": wire,
"method": "controlUnit",
"id": unit_id,
"targetControls": targetControls
});
socket.send(decodeURIComponent(escape(data)));
}
When CONTROL luminaire of network message was successful then server will send unitChanged event (with updated state info) of related device to all related clients and color temperature of related luminaire will be updated.
Control OnOff
To control the OnOff of specific luminaire of network you can send a CONTROL message to server over active WebSocket connection (and opened wire). The "targetControls" parameter of the message uses similar format as received with unitChanged event of the related device. The "value" of the OnOff object of the message is the wanted value between 0 and 1 for the related luminaire. Value 0.0 = Off and anything above that = On.
let wire = 1; // Use same wire ID as was used in the related OPEN message for the targeted network
let unit_id = 1; // Device ID of the related luminaire
let targetControls = {"OnOff": {"value": 1.0}}; // OnOff value normalized to range [0..1]
if (webSocket.readyState === webSocket.OPEN) {
const data = JSON.stringify({
"wire": wire,
"method": "controlUnit",
"id": unit_id,
"targetControls": targetControls
});
socket.send(decodeURIComponent(escape(data)));
}
When CONTROL luminaire of network message was successful then server will send unitChanged event (with updated state info) of related device to all related clients and color of related luminaire will be updated.
Control Slider
To control the Slider value of specific luminaire of network you can send a CONTROL message to server over active WebSocket connection (and opened wire). The "targetControls" parameter of the message uses similar format as received with unitChanged event of the related device. The "value" of the Slider object of the message is the wanted percentage (decimal number) between Slider Min and Max value for the related luminaire. The Min and Max values of the Slider are available via related unitChanged event. Min and Max values are normally within range of [0..100].
let wire = 1; // Use same wire ID as was used in the related OPEN message for the targeted network
let unit_id = 1; // Device ID of the related luminaire
let targetControls = {"Slider": {"value": 75.0}}; // Slider value converted to range [Min..Max]
if (webSocket.readyState === webSocket.OPEN) {
const data = JSON.stringify({
"wire": wire,
"method": "controlUnit",
"id": unit_id,
"targetControls": targetControls
});
socket.send(decodeURIComponent(escape(data)));
}
When CONTROL luminaire of network message was successful then server will send unitChanged event (with updated state info) of related device to all related clients and color of related luminaire will be updated.
Control hue/saturation color
To control the hue/saturation color of specific luminaire of network you can send a CONTROL message to server over active WebSocket connection (and opened wire). The "targetControls" parameter of the message uses similar format as received with unitChanged event of the related device. The "hue" and "sat" values of the RGB object of the message define the wanted color in HS color map (V = 100%) for the related luminaire. The "source" of Colorsource object must be set to "RGB" for color functionality to work as expected. Note that the specific luminaire must support hue/saturation color scheme for this to work.
let wire = 1; // Use same wire ID as was used in the related OPEN message for the targeted network
let unit_id = 1; // Device ID of the related luminaire
let targetControls = {"RGB": {"hue": 0.5, "sat": 0.5}, "Colorsource": {"source": "RGB"}}; // RGB value where hue and sat are converted to range [0..1]
// Optionally you can use "rgb" value instead but use of "hue" and "sat" is recommended way because it is more accurate..
// let targetControls = {"RGB": {"rgb": "rgb(0, 125, 255)"}, "Colorsource": {"source": "RGB"}};
if (webSocket.readyState === webSocket.OPEN) {
const data = JSON.stringify({
"wire": wire,
"method": "controlUnit",
"id": unit_id,
"targetControls": targetControls
});
socket.send(decodeURIComponent(escape(data)));
}
When CONTROL luminaire of network message was successful then server will send unitChanged event (with updated state info) of related device to all related clients and color of related luminaire will be updated. Note that color conversions are not fully lossless and thus accuracy can vary a bit.
Control XY color (experimental)
To control the XY color of specific luminaire of network you can send a CONTROL message to server over active WebSocket connection (and opened wire). The "targetControls" parameter of the message uses similar format as received with unitChanged event of the related device. The "x" and "y" values of the XY object of the message define the wanted color in XY color map for the related luminaire. The "source" of Colorsource object must be set to "XY" for color functionality to work as expected. Note that the specific luminaire must support XY color scheme for this to work and that XY color conversion is experimental.
let wire = 1; // Use same wire ID as was used in the related OPEN message for the targeted network
let unit_id = 1; // Device ID of the related luminaire
let targetControls = {"XY": {"x": 0.375, "y": 0.425 }, "Colorsource": {"source": "XY"}}; // XY value where x is converted to range [0..0.750] and y to range [0..0.850]
if (webSocket.readyState === webSocket.OPEN) {
const data = JSON.stringify({
"wire": wire,
"method": "controlUnit",
"id": unit_id,
"targetControls": targetControls
});
socket.send(decodeURIComponent(escape(data)));
}
When CONTROL luminaire of network message was successful then server will send unitChanged event (with updated state info) of related device to all related clients and color of related luminaire will be updated. Note that color conversions are not fully lossless and thus accuracy can vary a bit.
Javascript example
Here is javascript (ES6) code example how client can open and use WebSocket connection to receive event data.
WebSocket code example
const api_key = "API-KEY-HERE";
const session_id = "SESSION-ID-HERE";
const network_id = "NETWORK-ID-HERE";
const wire = 1; // can be any positive number..
let socket = null;
function initWebsocketConnection(network_id, session_id) {
if (!socket) {
socket = new WebSocket("wss://door.casambi.com/v1/bridge/", api_key);
initWebsocketListeners(network_id, session_id);
} else {
initWebsocketListeners(network_id, session_id);
}
}
function initWebsocketListeners(network_id, session_id) {
socket.onopen = function () {
sendWireOpenMessage(network_id, session_id);
console.log("Websocket connection opened", network_id);
};
socket.onmessage = function (msg) {
(new Response(msg.data)).text().then(function (result) {
let data = JSON.parse(result);
if ("method" in data && "wire" in data) {
let wire_id = data.wire;
// Some change has occurred in the related network..
if (data.method === "unitChanged") {
console.log("Device state update event, see message data..", data);
} else if (data.method === "networkUpdated") {
console.log("Network updated => fetch network data via REST API..", data);
} else if (data.method === "peerChanged" && !data.online) {
console.log("Peer updated => device(s) online status in the network..", data);
}
} else if ("wireStatus" in data && data.wireStatus === "openWireSucceed") {
console.log("WebSocket wire connection opened successfully! Ref:" + data.ref, data);
sendPingMessage(network_id);
} else if ("response" in data && data.response === "pong") {
console.log("WebSocket keep-alive message (ping) response received (pong)..", data);
// Note: device, group and scene ID's are int values..
let device_id = 1; // DEVICE-ID
let devices = [1, 2]; // [DEVICE-ID-A, DEVICE-ID-B]
let group_id = 1; // GROUP-ID
let scene_id = 1; // SCENE-ID
let controls = {
"Dimmer": {
"value": 0.75
}
};
sendUnitControlMessage(device_id, controls);
controls["Dimmer"]["value"] = 0.5;
sendUnitsControlMessage(devices, controls);
let value = 0.25;
sendGroupControlMessage(group_id, value);
value = 0;
sendSceneControlMessage(scene_id, value);
value = 1;
sendNetworkControlMessage(value);
}
}, function (error) {
console.log(error);
});
};
socket.onerror = function (error) {
console.log("WebSocket Error:", error);
// On websocket error create new websocket connection to keep the connection alive..
initWebsocketConnection(network_id, session_id);
};
socket.onclose = function () {
socket = null;
console.log("Websocket closed!");
// On websocket close create new websocket connection to keep the connection alive..
initWebsocketConnection(network_id, session_id);
// Note: Websocket connection will close after 5 minutes of inactivity.
// To keep the websocket connection alive send ping message to server every 4 minutes or so..
};
}
function sendWireOpenMessage (network_id, session_id) {
let reference = "REFERENCE-STRING-HERE";
let wire_id = wire;
const data = JSON.stringify({
"method": "open",
"id": network_id,
"session": session_id,
"ref": reference,
"wire": wire_id, // transient connection ID, unique for network
"type": 1, // FRONTEND
});
socket.send(decodeURIComponent(escape(data)));
}
function sendPingMessage(network_id) {
let wire_id = wire;
const data = JSON.stringify({
"wire": wire_id,
"method": "ping"
});
socket.send(decodeURIComponent(escape(data)));
}
function sendUnitsControlMessage(devices, targetControls) {
let wire_id = wire;
const data = JSON.stringify({
"wire": wire_id,
"method": "controlUnits",
"targetControls": targetControls,
"ids": devices
});
socket.send(decodeURIComponent(escape(data)));
}
function sendUnitControlMessage(device_id, targetControls) {
let wire_id = wire;
const data = JSON.stringify({
"wire": wire_id,
"method": "controlUnit",
"id": parseInt(device_id),
"targetControls": targetControls
});
socket.send(decodeURIComponent(escape(data)));
}
function sendGroupControlMessage(group_id, value) {
let wire_id = wire;
const data = JSON.stringify({
"wire": wire_id,
"method": "controlGroup",
"id": parseInt(group_id),
"level": value
});
socket.send(decodeURIComponent(escape(data)));
}
function sendSceneControlMessage(scene_id, value) {
let wire_id = wire;
const data = JSON.stringify({
"wire": wire_id,
"method": "controlScene",
"id": parseInt(scene_id),
"level": value
});
socket.send(decodeURIComponent(escape(data)));
}
function sendNetworkControlMessage(value) {
let wire_id = wire;
const data = JSON.stringify({
"wire": wire_id,
"method": "controlNetwork",
"level": value
});
socket.send(decodeURIComponent(escape(data)));
}
initWebsocketConnection(network_id, session_id);