Casambi - Developer site Beta

Overview

This documentation covers Casambi REST API and WebSocket service (beta version). In addition related javascript code examples and web console services are provided. Please note that to use REST API or Casambi WebSocket one must have valid developer API key.

Casambi WebSocket and API web consoles support Chrome browser. Functionality with other browsers is expected but not guaranteed.

To acquire API key contact Casambi Support <support@casambi.com>. Note that this version of API and WebSocket services are still under development. Feedback and feature requests are welcome.

Terminology

Casambi mesh network
A network of Casambi devices that are connected via bluetooth connection. Each device can work independently and be connected to the Casambi cloud service via gateway application.
Casambi cloud service
Cloud service that enables information flow and data control of connected Casambi devices over secure internet connection.
Gateway
Casambi app that works as a gateway for Casambi devices and networks to connect to Cloud service. Gateway forwards bluetooth messages to Cloud service via secure internet connection. Gateway is required to receive real-time event data from a network.
Casambi app
Mobile app used to connect and control different Casambi devices. App connects to close by devices via bluetooth connection. Is used to create named virtual presentations and networks of these different devices. App can be used as a gateway to connect close by devices to Casambi cloud service.
Unit
Physical Casambi device that is part of the mesh network. For example LED light, light switch or sensor device.
Fixture
Casambi device hardware configuration information. Fixture defines in which way device will be used/work.
Network
Network is a term used in Casambi app and in Casambi systems. Network is a named virtual presentation of defined set of physical Casambi devices. Network can be created with Casambi app.
Scene
Virtual control/animation setting for some network or devices. Can control how the devices are animated/turned on/turned off in specified scenario based on timing, sensor information and other factors.
Group
Virtual group of Casambi light devices that is connected to a network and can be controlled via Casambi app.
Luminaire
Casambi light device. Can be connected to a network and can be controlled via Casambi app.
API web console
Web page that can be used for testing API requests and responses. Use requires valid API key. Web console can be found from here: web console.
API key
The API key is a unique identifier that is used to authenticate requests associated with the API. Developer can request API key from Casambi Support <support@casambi.com>.
User session
When user logs in to Casambi API with Casambi (site) user credentials a user session is created with related session ID. This session is not same as the network session and has access to all networks, sites and related data of that user. User session and site user session mean the same thing and have access to all related sites (if any).
Network session
When user logs in to Casambi API with network (admin) credentials a network session is created with related session ID. This session is not same as the (site) user session and has access only to all networks and related data of used network credentials. This session has only access to networks created with the related credentials.
WebSocket wire
After WebSocket connection to server has been created server is waiting for a OPEN message from the client. In this OPEN message client defines the wire ID to be used in addition to some other details related to network and the connection. If OPEN message is successful wire identified by given ID will be created to the server and related event messages will be sent to it. Wire is unique to the Websocket connection. One websocket connection can have multiple wires at the same time.
Control
Casambi device can have one or many "controls" that relate to state and functionality of the device. Basically one "control" is presentation of specific functionality/state of the device. Information about device state, in other words "control" values can be received via WebSocket event messages.

Datalogging and API

REST API and Websocket service offer various Casambi Datalogging related information. In following document you can find more information about these Datalogging features related to Casambi Public API.

Datalogging and API

Casambi REST API

Casambi Restful API is used for accessing persistent Casambi bluetooth mesh network information from Casambi cloud services. This kind of information does not change very often and in most cases is tied to configuration of related network, luminaires and devices. Casambi API is located at: https://door.casambi.com.

To gain access to Casambi WebSocket (and its events) use of information like session id and network id received from REST API are required. Note that event information reveiced from the WebSocket is supplementing the information received from the REST API and in some parts may overlap.

Note that GET request parameter values (URL?param=VALUE) must be URL encoded.

Version history

  • /v1 - Create network/Casambi user session and request network related information.

Changes
  • 13.05.2020 - Datapoints request updated to use string based data type filter values, int based sensor type values are deprecated
  • 07.12.2020 - Datapoints support timezone offset parameter to define the "timezone" for time range parameters and response time values
  • 07.12.2020 - Added support for ISO 8601 formatted time range parameters.
  • 16.12.2020 - Renamed mac property to address as it is more describing.
  • 04.03.2021 - Added CURL request examples for REST API requests. Datalogging and API documentation added. FAQ page added.
  • 15.08.2021 - Added XmlHttp based javascript code examples. Navigation split to sections: Overview, Rest Api and WebSocket.

Get started

  1. Acquire API key, contact Casambi Support <support@casambi.com> for more info.
  2. Acquire user (site) or network credentials with at least one network and connected devices (Casambi app).
  3. Test how authentication and requests work with REST API web console.

Summary - API endpoints

API authentication

Use your Casambi user (site account) or network (admin) credentials to authenticate and to create a session.
With Casambi (site) user session you will have access to all network, site and device data related to that site user account.
With network session you will have access only to network and device data related to that network admin credentials.

Casambi user and network sessions are both created with POST request where credentials are given in the payload of the request body. In addition API key must be set to custom request header property named X-Casambi-Key.

NOTE: In general API session ID will be valid for a long time. When session ID expires then new one needs to be created.

Example: X-Casambi-Key: 8aSdFG678M8nPL63FNe5fjrey42loASFWg64v29Se23GAm67576werQtyz1

API Key use limits

  • Size of request data per minute
  • Size of response data per minute
  • Amount of requests per minute
  • Amount of concurrent requests
If any of these limits are exceeded then request will fail with HTTP status code 429.

Authentication endpoints

Using created session

Successful create session API request will return JSON data object that includes different network related information and session ID. Note that network session has different session ID for each network included in the result set.

This session ID is required to be used as custom header property X-Casambi-Session along with the API key to access any related information from REST API.

Example: X-Casambi-Key: 8aSdFG78678M8nPL63FSNe5fjrey45762loASFWg64v29Se23GWAm67576werQtyz1
X-Casambi-Session: hJK65SenmlL2354y.P822D76HufewNSloo780PvU-78DwdmnMA8exzIo9.mmNWD23whEqbPOsl11hjjWo03___

Endpoint definitions

Response information

All request response data are in JSON object or array format except for image requests which will return image blob data in png format instead. If request was not successful will return HTTP status error code.

Successful request response data examples are listed with relevant endpoint definitions.

With valid API key you can test requests (and responses) with API web console.

Position info

The view position of device, photos and scenes (used in Casambi App) are given as numeric value, where smaller position number should be shown first in the order and so forth. Note that there might be gaps between the position values. Also items like sensors and similar that are not shown within the Casambi App network luminaires view may have same position number as some group or device that is shown in the luminaires view.

Exception to this ordering is that if device (item of units list) is part of a group (groupId > 0) it will have it's position value always set to 0 as the actual position within the related group will be found in the group information. See groups list of network data to find the actual position info of the group and its devices. Positioning of devices and groups used in Casambi App is only given as a reference and use of this info is fully optional.

Response status codes

Status Code Description
200 request OK.
400 Bad request, given parameters invalid.
401 Unauthorized. Invalid API key or credentials given.
403 Api not enabled by Casambi administrator or trying to create session after failed attempt too soon.
404 Requested data not found.
405 Method not allowed.
410 Invalid session.
416 Retrieval interval is too long.
429 Quota limits exceeded.
500 Server error.

Javascript examples (Axios)

Here are javascript (ES6) code examples how client can authenticate and then use API endpoints to receive information.

Example code uses axios for API requests. More information: https://github.com/axios/axios.

+

Creating (site) user session


const api_key = "API-KEY-HERE";
const login = {
	"email": "EMAIL-ADDRESS-HERE",
	"password": "PASSWORD-HERE",
};

axios.post("https://door.casambi.com/v1/users/session/", { ...login }, {
	headers: { "X-Casambi-Key": api_key }
}).then(response => {
	console.log(response.data);

	const session_data = response.data;
	const session_id = session_data.sessionId;

	for (let network in session_data) {
		const network_id = network.id;
		const network_name = network.name;
	}

	for (let site in session_data) {
		const networks = site.networks;
	}

	// Use session_id for further API requests..

}).catch(error => {
	console.log(error);

	if (error.response && error.response.status === 401) {
		if ("statusText" in error.response
			&& error.response.statusText === "Api authorization failed.") {
			// Given API key is invalid!
		} else {
			// User not found!
		}
	} else if (error.response) {
		// See error.response && status
	}
});
Click to expand..
+

Creating network (admin) session


const api_key = "API-KEY-HERE";
const login = {
	"email": "EMAIL-ADDRESS-HERE",
	"password": "PASSWORD-HERE",
};

axios.post("https://door.casambi.com/v1/networks/session/", { ...login }, {
	headers: { "X-Casambi-Key": api_key }
}).then(response => {
	console.log(response.data);

	const network_session_data = response.data;
	for (let network_id id network_session_data) {
		const session_id = network_session_data[network_id].sessionId;
		const network_name = network_session_data[network_id].name;

		// Use session_id for further API requests..
	}

}).catch(error => {
	console.log(error);

	if (error.response && error.response.status === 401) {
		if ("statusText" in error.response
			&& error.response.statusText === "Api authorization failed.") {
			// Given API key is invalid!
		} else {
			// Network user not found!
		}
	} else if (error.response) {
		// See error.response && status
	}
});
Click to expand..
+

Fetch network information


const api_key = "API-KEY-HERE";
const session_id = "SESSION-ID-HERE";
const network_id = "NETWORK-ID-HERE";

axios.get("https://door.casambi.com/v1/networks/" + network_id, {
	headers: { "X-Casambi-Session": session_id, "X-Casambi-Key": api_key }
}).then(response => {
	console.log(response.data);

	const network = response.data;
	const network_id = network.id;
	const network_name = network.name;
	const devices = network.units;
	const groups = network.groups;
	const scenes = network.scenes;

	// network info including information about groups, devices, scenes (if any)..

}).catch(error => {
	console.log(error);
});
Click to expand..
+

Fetch unit state


const api_key = "API-KEY-HERE";
const session_id = "SESSION-ID-HERE";
const network_id = "NETWORK-ID-HERE";
const device_id = "DEVICE-ID-HERE";

axios.get("https://door.casambi.com/v1/networks/" + network_id + "/units/" + device_id + "/state", {
	headers: { "X-Casambi-Session": session_id, "X-Casambi-Key": api_key }
}).then(response => {
	console.log(response.data);

	const device = response.data;
	const device_id = device.id;
	const device_status = device.status;
	const device_dim_level = device.dimLevel;
	const device_controls = device.controls;

	// device info including information about status, fixture, controls (dim, color temperature, color etc. if any)..

}).catch(error => {
	console.log(error);
});
Click to expand..
+

Fetch network state


const api_key = "API-KEY-HERE";
const session_id = "SESSION-ID-HERE";
const network_id = "NETWORK-ID-HERE";

axios.get("https://door.casambi.com/v1/networks/" + network_id + "/state", {
	headers: { "X-Casambi-Session": session_id, "X-Casambi-Key": api_key }
}).then(response => {
	console.log(response.data);

	const network = response.data;
	const network_id = network.id;
	const network_name = network.name;
	const devices = network.units;
	const groups = network.groups;
	const scenes = network.scenes;
	const dim_level = network.dimLevel;
	const active_scene_ids = network.activeScenes;

	for (let device in devices) {
		const device_id = device.id;
		const device_status = device.status;
		const device_dim_level = device.dimLevel;
		const device_controls = device.controls;

		// device info including information about status, fixture, controls (dim, color temperature, color etc. if any)..
	}

	// network info including information about groups, device states, scenes (if any)..

}).catch(error => {
	console.log(error);
});
Click to expand..
+

Fetch datapoints


const api_key = "API-KEY-HERE";
const session_id = "SESSION-ID-HERE";
const network_id = "NETWORK-ID-HERE";

// Note that filter options are mandatory for datapoints requests. In addition optional units value can be used as well.
// Time range and datatype (or keys) value must be given. Note that datapoint data is stored only for 60 days.
// Time range parameters and response time values are by default in UTC but can be adjusted with (URL encoded) tzOffset parameter.

const filter_options = {
	"dataType": "control",
	"keys": ["dimmer", "lux"],
	"units": [15, 22],
	"from": 201907221013,
	"to": 201907290431,
	"tzOffset": +02:30
};
const query_params = Object.keys(filter_options).map(key => key + '=' + encodeURIComponent(filter_options[key])).join('&');

axios.get("https://door.casambi.com/v1/networks/" + network_id + "/datapoints?" + query_params, {
	headers: { "X-Casambi-Session": session_id, "X-Casambi-Key": api_key }
}).then(response => {
	console.log(response.data);

	const datapoints = response.data;

	// datapoints array including sensor and luminaire data if any..
	// NOTE: The response "time" values are by default in UTC but can be adjusted with (URL encoded) tzOffset parameter

}).catch(error => {
	console.log(error);
});
Click to expand..
+

Fetch image


const api_key = "API-KEY-HERE";
const session_id = "SESSION-ID-HERE";
const network_id = "NETWORK-ID-HERE";
const image_id = "IMAGE-ID-HERE";

axios.get("https://door.casambi.com/v1/networks/" + network_id + "/images/" + image_id, {
	headers: { "X-Casambi-Session": session_id, "X-Casambi-Key": api_key}, "responseType": "arraybuffer"
}).then(response => {
	console.log(response.data);

	const bytes = new Uint8Array(response.data);
	const binary = bytes.reduce((data, byte) => data + String.fromCharCode(byte), '');
	const image_src = "data:image/png;base64," + btoa(binary);

	// use image_src to show the image with img html element..

}).catch(error => {
	console.log(error);
});
Click to expand..

Javascript examples (XmlHttp)

Here are javascript (ES6) examples how client can authenticate and then use API endpoints to receive information.

Example code uses XmlHttp for API requests. More information: https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest.

+

Creating (site) user session


const api_key = "API-KEY-HERE";
const login = {
	"email": "EMAIL-ADDRESS-HERE",
	"password": "PASSWORD-HERE",
};

const xmlhttp = new XMLHttpRequest();
xmlhttp.open("POST", "https://door.casambi.com/v1/users/session", "true");
xmlhttp.setRequestHeader("X-Casambi-Key", api_key);
xmlhttp.setRequestHeader("Content-Type", "application/JSON");
xmlhttp.onload = function () {
	console.log(JSON.parse(this.responseText), this.status, this.statusText);

	const user_session_data = JSON.parse(this.responseText);
	const session_id = user_session_data.sessionId;

	for (let network in user_session_data) {
		const network_id = network.id;
		const network_name = network.name;
	}

	for (let site in user_session_data) {
		const networks = site.networks;
	}
};
xmlhttp.send(JSON.stringify(login));

Click to expand..
+

Creating network (admin) session


const api_key = "API-KEY-HERE";
const login = {
	"email": "EMAIL-ADDRESS-HERE",
	"password": "PASSWORD-HERE",
};

const xmlhttp = new XMLHttpRequest();
xmlhttp.open("POST", "https://door.casambi.com/v1/networks/session", "true");
xmlhttp.setRequestHeader("X-Casambi-Key", api_key);
xmlhttp.setRequestHeader("Content-Type", "application/JSON");
xmlhttp.onload = function () {
	console.log(JSON.parse(this.responseText), this.status, this.statusText);

	const network_session_data = JSON.parse(this.responseText);
	for (let network_id id network_session_data) {
		const session_id = network_session_data[network_id].sessionId;
		const network_name = network_session_data[network_id].name;

		// Use session_id for further API requests..
	}
};
xmlhttp.send(JSON.stringify(login));

Click to expand..
+

Fetch network information


const api_key = "API-KEY-HERE";
const session_id = "SESSION-ID-HERE";
const network_id = "NETWORK-ID-HERE";

const xmlhttp = new XMLHttpRequest();
xmlhttp.open("GET", "https://door.casambi.com/v1/networks/" + network_id);
xmlhttp.setRequestHeader("X-Casambi-Session", session_id);
xmlhttp.setRequestHeader("X-Casambi-Key", api_key);
xmlhttp.onload = function () {
	console.log(JSON.parse(this.responseText), this.status, this.statusText);

	const network = JSON.parse(this.responseText);
	const network_id = network.id;
	const network_name = network.name;
	const devices = network.units;
	const groups = network.groups;
	const scenes = network.scenes;

	// network info including information about groups, devices, scenes (if any)..
};
xmlhttp.send();

Click to expand..
+

Fetch unit state


const api_key = "API-KEY-HERE";
const session_id = "SESSION-ID-HERE";
const network_id = "NETWORK-ID-HERE";
const device_id = "DEVICE-ID-HERE";

const xmlhttp = new XMLHttpRequest();
xmlhttp.open("GET", "https://door.casambi.com/v1/networks/" + network_id + "/units/" + device_id + "/state");
xmlhttp.setRequestHeader("X-Casambi-Session", session_id);
xmlhttp.setRequestHeader("X-Casambi-Key", api_key);
xmlhttp.onload = function () {
	console.log(JSON.parse(this.responseText), this.status, this.statusText);

	const device = JSON.parse(this.responseText);
	const device_id = device.id;
	const device_status = device.status;
	const device_dim_level = device.dimLevel;
	const device_controls = device.controls;

	// device info including information about status, fixture, controls (dim, color temperature, color etc. if any)..

};
xmlhttp.send();

Click to expand..
+

Fetch network state


const api_key = "API-KEY-HERE";
const session_id = "SESSION-ID-HERE";
const network_id = "NETWORK-ID-HERE";

const xmlhttp = new XMLHttpRequest();
xmlhttp.open("GET", "https://door.casambi.com/v1/networks/" + network_id + "/state");
xmlhttp.setRequestHeader("X-Casambi-Session", session_id);
xmlhttp.setRequestHeader("X-Casambi-Key", api_key);
xmlhttp.onload = function () {
	console.log(JSON.parse(this.responseText), this.status, this.statusText);

	const network = JSON.parse(this.responseText);
	const network_id = network.id;
	const network_name = network.name;
	const devices = network.units;
	const groups = network.groups;
	const scenes = network.scenes;
	const dim_level = network.dimLevel;
	const active_scene_ids = network.activeScenes;

	for (let device in devices) {
		const device_id = device.id;
		const device_status = device.status;
		const device_dim_level = device.dimLevel;
		const device_controls = device.controls;

		// device info including information about status, fixture, controls (dim, color temperature, color etc. if any)..
	}

	// network info including information about groups, device states, scenes (if any)..
};
xmlhttp.send();

Click to expand..
+

Fetch datapoints


const api_key = "API-KEY-HERE";
const session_id = "SESSION-ID-HERE";
const network_id = "NETWORK-ID-HERE";

// Note that filter options are mandatory for datapoints requests. In addition optional units value can be used as well.
// Time range and datatype (or keys) value must be given. Note that datapoint data is stored only for 60 days.
// Time range parameters and response time values are by default in UTC but can be adjusted with (URL encoded) tzOffset parameter.

const filter_options = {
	"dataType": "control",
	"keys": ["dimmer", "lux"],
	"units": [15, 22],
	"from": 201907221013,
	"to": 201907290431,
	"tzOffset": +02:30
};
const query_params = Object.keys(filter_options).map(key => key + '=' + encodeURIComponent(filter_options[key])).join('&');

xmlhttp = new XMLHttpRequest();
xmlhttp.open("GET", "https://door.casambi.com/v1/networks/" + network_id + "/datapoints?" + query_params);
xmlhttp.setRequestHeader("X-Casambi-Session", session_id);
xmlhttp.setRequestHeader("X-Casambi-Key", api_key);
xmlhttp.onload = function () {
	console.log(JSON.parse(this.responseText), this.status, this.statusText);

	const datapoints = response.data;

	// datapoints array including sensor and luminaire data if any..
	// NOTE: The response "time" values are by default in UTC but can be adjusted with (URL encoded) tzOffset parameter

};
xmlhttp.send();

Click to expand..
+

Fetch image


const api_key = "API-KEY-HERE";
const session_id = "SESSION-ID-HERE";
const network_id = "NETWORK-ID-HERE";
const image_id = "IMAGE-ID-HERE";

const xmlhttp = new XMLHttpRequest();
xmlhttp.open("GET", "https://door.casambi.com/v1/networks/" + network_id + "/images/" + image_id);
xmlhttp.setRequestHeader("X-Casambi-Session", session_id);
xmlhttp.setRequestHeader("X-Casambi-Key", api_key);
xmlhttp.responseType = "arraybuffer";
xmlhttp.onload = function () {
	console.log(this.response, this.status, this.statusText);

	const bytes = new Uint8Array(this.response);
	const binary = bytes.reduce((data, byte) => data + String.fromCharCode(byte), '');
	const image_src = "data:image/png;base64," + btoa(binary);

	// use image_src to show the image with img html element..

}
xmlhttp.send();

Click to expand..

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. Casambi WebSocket service is located at: wss://door.casambi.com/v1/bridge/.

NOTE: 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.

Get started

  1. Acquire WebSocket enabled API key, contact Casambi Support <support@casambi.com> for more info.
  2. Create session by using REST API with your Casambi user or network credentials. More info here: API Authentication.
  3. Test how opening WebSocket connection and receiving event data works with WebSocket web console.

Creating 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);
	

Note that 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)));
};
	

Recommended 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.

On OPEN success

When OPEN message is successful server will send initial openWireSucceed response message along with possible referecen 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 referecen ID (if given). For more information see WebSocket message method 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 it's 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") {
				// Devices online changed event, for example new device has joined the network

			}

		}
	}, 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 succesful 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
API key authentication failed. Either given key was invalid or WebSocket functionality is not enabled for it.
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.
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
Some device 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. *

* NOTE: 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 trough device specific unitChanged event messages. See the example message below.

NOTE: 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

Key/value pair "id" is identifier of this device.

name

Key/value pair "name" is name of this device.

on

Key/value pair "on" is self explanatory. Either device is ON or it is not. Naturally if device is OFF it wont be sending events to the network but in most cases server/gateway will detect these situations.

online

Key/value pair "online" is self explanatory. Either device is Online or Offline. Naturally if device is Offline it wont be sending events to the network but in most cases server/gateway will detect these situations.

condition

Key/value pair "condition" is 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

Key/value pair "status" is 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

Key/value pair "groupId" is ID of the related group if any. If this device is not part of any group then will be set to 0.

activeSceneId

Key/value pair "activeSceneId" is 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

Key/value pair "dimLevel" is the current level of dimming (0..1) of this specific luminaire.

fixtureId

Key/value pair "fixtureId" is ID of the related fixture.

type

Key/value pair "type" is type name of this device, usually "Luminaire".

position

Key/value pair "position" is position of this device within Casambi App view. Position of groupped items refers to position within the group. Position numbers may or may not be linear.

image

Key/value pair "image" is identifier of related device icon/image. By default not set.

details

Key/value pair "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

Key/value pair "priority" is a numeric type identifier of the active device priority. Device can have multiple priority levels based on if it is switch, sensor or time controlled trough 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

Key/value pair "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 message 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.

Turn luminaire on/off/dim

To control the dim level of a luminaire you can send an 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 succesful 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 an 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 succesful 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 an 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 succesful 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 an 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 = 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 succesful 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 an network you can send an 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 succesful 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 an 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 succesful 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 an 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 succesful 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 an 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 off 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 succesful 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 an 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 succesful 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 loseless and thus accuracy can vary a bit.

Control XY color (experimental)

To control the XY color of specific luminaire of network you can send an 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 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 succesful 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 loseless 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 = WIRE-ID-HERE; // 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 = DEVICE-ID;
				let devices = [DEVICE-ID-A, DEVICE-ID-B];
				let group_id = GROUP-ID;
				let scene_id = 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 webscoket 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);

Click to expand..