This is a description of the Cambrionix API that can be used to control Cambrionix PD-Sync and Universal charging units that use the Cambrionix Very Intelligent Charging Protocol.
The Cambrionix API resides in a locally installed daemon called CambrionixApiService
. This provides a programming language independent JSON-RPC interface to control Cambrionix units connected to the local machine. The Cambrionix API can also connect with Cambrionix units that are connected to the network e.g. EtherSync.
A simple Python wrapper is provided with a public domain JSON-RPC library that will allow scripts to be written without needing to be overly familiar with JSON. Alternatively you may use the programming language of your choice to connect directly to the daemon over a standard TCP/IP socket and send and receive JSON formatted data.
When the API is used to communicate with a remote network attached Cambrionix unit this is done over an SSH tunnel.
The Cambrionix API supports multiple simultaneous client connections to itself and supports simultaneous access to multiple Cambrionix units.
Before you can use the Cambrionix API, there are a few steps and checks that need to be completed.
For the API to be able to retrieve USB information from connected devices, it must have direct access to the hardware. This means that in general running in a Virtual Machine (VM) such as Parallels or VirtualBox is not supported as the virtualisation prevents the API from being able to determine which USB device is connected to which physical port. Also, it is not unusual that such a virtual environment will not have access to serial devices which is necessary to chat with the hub to query information.
On Windows, you will need to make sure you have the latest Thunderbolt Bus Drivers.
Once the Thunderbolt device has been accepted to connect, you may need to turn it off and on again for Windows to physically make the connection.
In order for the API to be able to return USB device information such as the VID, PID, Manufacturer, Description or Serial Number, there must be a USB connection from the host machine to the connected device. This is only present on sync capable chargers. Charge only chargers have a USB connection to the charger itself but not to connected devices. The Cambrionix API is still functional with charge only chargers but will be unable to return the USB device information.
Cambrionix Universal Chargers, when used with this API, need to have firmware version 1.52 or later installed and we recommend that the latest version available on our website is installed.
The Cambrionix API daemon (CambrionixApiService
) needs to be able to communicate with the local Cambrionix unit. Each Cambrionix unit contains an FTDI USB to UART converter or that will make them appear to the local operating system as a serial port. The operating system will need to have the appropriate VCP (Virtual COM Port) driver installed. For Linux the default support in the kernel is sufficient.
Do not install the D2XX drivers on Linux or macOS as this conflicts with the required VCP drivers. On Windows only, the D2XX support can coexist with the VCP support. These drivers are automatically installed on newer versions of Windows 10.
The API uses JSON-RPC over TCP. Any programming language that has support for JSON-RPC can be used, libraries are widely available for other language.
The API is implemented in a daemon process called CambrionixApiService
. This needs to be running and contactable to be able to manage the Cambrionix units. The transport used is TCP with a default TCP port of 43424
.
If needed, the listening port can be changed:
CambrionixApiService
with the option --port XXXX
where XXXX is an alternate port number between 1-65535.For macOS an installer is provided that will set up CambrionixApiService
to run as a daemon process. The service is configured to load on demand when it’s configured listening port is attached to by launchd
.
The installation can also perform all necessary steps to configure any installed versions of Python 2 and/or 3 and direct you to various example scripts.
For Windows a self extracting installer is provided that will set up CambrionixApiService
to run as a Windows service.
The installation can also perform all necessary steps to install and configure Python 2 and/or 3 and direct you to various example scripts.
The FTDI drivers are required to access Cambrionix chargers that are connected to the host machine. These drivers are included in the installer and can be installed by ticking the tick box. The option will not appear if the necessary drivers are already present, such as the case of newer versions of Windows which include them automatically. However installation of these drivers does not complete until a Cambrionix charger is attached to the host machine. If you install the API and the FTDI drivers before the first time you connect a Cambrionix charger then the API will not start and you will need to reboot the host machine after connecting a Cambrionix charger that triggers the completion of the FTDI driver installation, in order to ensure that the API service is correctly started.
The Linux package comes with a script that can install the service binary and perform any required setup for you, such as configuring python to use the API from any folder.
The binary will be installed to /usr/local/bin
and the examples and documentation to /usr/local/share/cambrionix/api
.
# Untar the image in a temporary folder.
$ mkdir temp
$ cd temp
$ tar xvzf ~/Downloads/cambrionix-api-setup-N.N.N.tar.gz
# Review the script first if you wish, then:
$ sudo setup
# -–version: Return the version of CambrionixApiService and then exit:
# Example:
$ CambrionixApiService -–version
CambrionixApiService 2.2 (c49e1e38)
Copyright (c) 2019 Cambrionix Ltd
http://www.cambrionix.com/
# -–port XXXXX: Run cbrxd with an alternate TCP listening port.
# Specifying the command line option overrides both the default value
# of 43424 or any value previously stored in CambrionixApiService.cfg.
# Example:
$ CambrionixApiService –-port 54321
Note that the –port option is persistent so it only needs to be given once. Thereafter, this setting is remembered.
The following values will be returned on exit of CambrionixApiService
:
CambrionixApiService –-version
).CambrionixApiService
being passed an invalid port number or failed to open the listening port).Log messages generated by CambrionixApiService go to syslog.
Some example scripts in Node.JS and Python are included in with the installed files.
%ProgramFiles%\Cambrionix\Cambrionix API 2.0
/usr/local/share/cambrionix/apiservice
./Library/Cambrionix/ApiService
.Here is a minimal example of using the API, the code is written in Python 2.7.8:
# Import the cbrxapi library.
import sys
from cbrxapi import cbrxapi
# Call cbrx_discover with "local" to find any locally attached Cambrionix units.
# This will return a list of local Cambrionix units.
# This example always uses the first Cambrionix unit returned.
= cbrxapi.cbrx_discover("local")
result if result == False:
print("No Cambrionix unit found.")
0)
sys.exit(
= result[0]
unitId
try:
# Open a connection to the Cambrionix unit, which will return a handle for
# the connection.
= cbrxapi.cbrx_connection_open(unitId)
handle
# Using the handle, get the "Hardware" and "nrOfPorts" properties
= cbrxapi.cbrx_connection_get(handle, "Hardware")
hardware = cbrxapi.cbrx_connection_get(handle, "nrOfPorts")
nrOfPorts
# Done using the Cambrionix unit, close the handle.
cbrxapi.cbrx_connection_close(handle)
# Finally, print out the information retrieved from the Cambrionix unit.
print("The Cambrionix unit %s is a %s with %d ports." % (unitId, hardware, nrOfPorts))
except Exception as e:
print("Could not connect to device : " + str(e))
And another example demonstrating access from a React application. Note that the socket connection address is prefixed with ws
. This allows the API to upgrade the connection to a Web-socket and be natively used by web technologies such as this. The same methods can be used from Node.js and other similar platforms.
import React from 'react';
import Websocket from 'react-websocket';
class MyApiInterface extends React.Component {
= 0;
lastId
render() {
return (
<Websocket ref={r => this.websocket = r} reconnect
url="ws://localhost:43424" protocol="jsonrpc"
onMessage={this.onDataReceived.bind(this)}
onOpen={this.onApiConnection.bind(this)}
onClose={this.onApiDisconnection.bind(this)} />
;
)
}
= {};
requests
onDataReceived(json) {
const data = JSON.parse(json);
const id = data.id;
if (id) {
const request = this.requests[id];
if (request && request.callback) {
.callback(data);
request
}delete this.requests[id];
}else
{//Could get a notification here if you enable them on active connection
//Notifications have no id and can arrive at any time
}
}
makeRequest(method, params, callback) {
var packet = {
jsonrpc: "2.0",
id: ++this.lastId,
method: method,
params: params,
;
}
this.requests[packet.id] = {packet: packet, callback: callback};
this.websocket.sendMessage(JSON.stringify(packet));
}
onApiConnection() {
console.log("Connected");
this.makeRequest("cbrx_discover", ["local"], console.log);
}
onApiDisconnection() {
console.log("Disconnected");
this.requests = {}
} }
Connections can be made directly to an http prefixed URI, in which case the json is extracted from either the address itself, or the body content of the GET request. Try this example in your browser now: {“method”:“cbrx_discover”,“params”:[“all”],“jsonrpc”:“2.0”,“id”:1}.
Or from the command line, using curl, you can do:
curl -get 'http://localhost:43424/?{"id":0,"jsonrpc":"2.0","method":"cbrx_discover","params":["all"]}'
Note that the Python code above doesn’t check for errors so the Python script will simply stop on an error. This should be made more robust by catching any exceptions and dealing with them appropriately.
A JSON-RPC error will return an error member containing the following members:
The Python JSON-RPC used causes an exception for an error response with the following mapping:
In step 3 you could catch an error response with:
try:
= cbrxapi.cbrx_connection_open(id)
handle except jsonrpc.RPCFault as e:
= True
gotException = e.error_code
errorCode = e.error_message
errorMessage = e.error_data errorData
Depending on the errorCode
returned different actions can be taken, i.e. the user could be prompted to check whether the device is plugged in before retrying or asked to verify that cbrxd is installed.
The Cambrionix API is implemented in CambrionixApiService, which sits between the application and the Cambrionix units. It maps the properties of the Cambrionix units into API commands.
Examples
# To disable a USB port you can do
"Port.2.mode", "o") cbrx_connection_set(connectionHandle,
# To reset a Cambrionix unit you can do
"Reboot", True) cbrx_connection_set(connectionHandle,
# To get the number of USB ports of a Cambrionix unit you
# can do a `get nrOfPorts` request
"nrOfPorts") cbrx_connection_get(connectionHandle,
The descriptions of the API calls contain a sample Python call and the raw jsonrpc requests / responses as you would see them on the wire.
The JSON-RPC implementation should hide these details.
The Python request cbrxapi.cbrx_connection_get(7654, "nrOfPorts")
translates into a JSONRPC request containing the method name:
"cbrx_connection_get"
and a JSON representation of the parameters (params
), which is often a JSON array of values, unless otherwise specified:
[ 7654, "nrOfPorts" ]
Two further key-value pairs need to be passed to complete the JSON-request; One indicating the version of jsonrpc being used, in this case 2.0 and an id identifying this request:
The id is mandatory but only relevant if multiple requests can be outstanding simultaneously over the same connection. It helps to match responses to (asynchronous) requests. The response for a request will be given the matching id by CambrionixApiService. The API Service runs on many threads and there is no guarantee, nor requirement by the specification, that the replies will arrive in any particular order. If strict ordering is required, you can batch multiple request packets in an array which will be ordered the same as it arrived.
Grouping this all together will give the complete JSON-RPC request:
{
"jsonrpc": "2.0",
"method": "cbrx_connection_get",
"params": [
7654,
"nrOfPorts"
],
"id": 0
}
There are 3 groups of calls in the API:
Return the interface version of the local API running.
Input:
or
Returns:
Example Python call:
cbrxapi.cbrx_apiversion()
Example JSONRPC request:
{
"jsonrpc": "2.0",
"method": "cbrx_apiversion",
"id": 0
}
Example successful response:
{
"jsonrpc": "2.0",
"id": 0,
"result": [2, 0]
}
Returns an enhanced version of the details of the API. This information can also be gained by passing an optional true parameter to cbrx_apiversion.
Input:
Returns:
Example Python call:
cbrxapi.cbrx_apidetails()
Example JSONRPC request:
{
"jsonrpc": "2.0",
"method": "cbrx_apidetails",
"id": 0
}
Example successful response:
{
"jsonrpc": "2.0",
"id": 0,
"result": {
"branch": "master",
"capability": ["protobuf", "crash-report", "notification"],
"commitid": 3298696760,
"documentation": "/Library/Cambrionix/ApiService/doc/Cambrionix API Reference.html"
"install": "/Library/Cambrionix/ApiService"
"version": [2, 2]
}
}
This information is made available so that future versions of LiveViewer and API can detect the available features without intimate knowledge of version numbers.
The notification
capability indicates that the cbrx_notifications method is supported.
The crash-report
capability is internal and should not be used.
The protobuf
capability is currently internal to the API and is used to communicate to the Recorder service. The protobuf message format may be made available at a later date.
Discover Cambrionix units.
Input:
Returns:
Example Python call:
"local") cbrxapi.cbrx_discover(
Example JSONRPC request:
{
"jsonrpc": "2.0",
"method": "cbrx_discover",
"params": ["local"],
"id": 0
}
Example successful response:
{
"jsonrpc": "2.0",
"id": 0,
"result": ["DB0074F5"]
}
Example unsuccessful response:
{
"jsonrpc": "2.0",
"id": 0,
"error": {
"code": -32602,
"message": "Invalid params"
}
}
Map a unit ID for a discovered Cambrionix unit to a device name as used by the OS.
Input:
cbrx_discover
.Returns:
Note: This only makes sense for locally attached Cambrionix units.
Example Python call:
cbrxapi.cbrx_discover_id_to_os_reference(unitId)
Example JSONRPC request:
{
"jsonrpc": "2.0",
"method": "cbrx_discover_id_to_os_reference",
"params": ["DB0074F5"],
"id": 0
}
Example successful response:
{
"jsonrpc": "2.0",
"id": 0,
"result": ["/dev/ttyUSB0"]
}
Example unsuccessful response:
{
"jsonrpc": "2.0",
"id": 0,
"error": {
"code": -32602,
"message": "Invalid params"
}
}
Search for devices attached to local Cambrionix units.
Input:
"<manufacturer-name>\x1D<product-name>\x1D<serial-number>"
. So for a iPhone, it would be something like "Apple\x1DiPhone\x1Dfa3c8762e87f068ce16e8c6fa"
. \x1D
was chosen because it is the ASCII standard character for a field delimiter and so should be sufficient to avoid false matches crossing string boundaries. The regex is performed as a search, rather than a match, so you do not need to do things like ".*iPhone.*"
to match substrings; "iPhone"
is sufficient. You can of course be as strict as you like. Additionally, if the phone’s identity or internal serial number have been detected, then these will also be matched.The regex syntax used is Modified ECMAScript.
Returns:
The returned data is keyed on the serial number of any devices matching the search criteria. The value of each node holds details of the location and the exact device details.
Also note that the entire USB tree is searched for the specified items, and if found anywhere beneath a Cambrionix hub, then the connection details will be returned. This would be especially useful for devices that are plugged into an intermediate hub device rather than being directly connected to the Cambrionix hub, such as a phone with battery extended and extra USB slots.
This new call (as of API 2.1) can save a lot of programmatic work because you no longer need to open each Cambrionix unit individually and check for attached devices. Although, you would of course still need to do that to monitor current draw.
Example Python call:
# Python call to search for all iPhones
"iPhone")
cbrxapi.cbrx_find(
# Regex can be used too
"i(Phone|Pad)")
cbrxapi.cbrx_find(
# Find everything connected to any Cambrionix device
".")
cbrxapi.cbrx_find(
# JSON-RPC call
{"jsonrpc": "2.0",
"method": "cbrx_find",
"params": ["i(Phone|Pad)"],
"id": 1234
}
Example successful response of cbrx:
{
"jsonrpc": "2.0",
"id": 1234,
"result": {
"a7cfd7345fad329819cfad3781632ac8a65c": {
"HostDescription": "ThunderSync3-16",
"HostDevice": "0000034CCC2AA16",
"HostPort": 9,
"HostSerial": "COM31",
"Device": {
"Description": "SuperPhone6",
"LocationID": 07100000,
"Manufacturer": "SuperPhone Makers Inc",
"PID": 5678,
"SerialNumber": "a7cfd7345fad329819cfad3781632ac8a65c",
"USBVersion": 3.0,
"VID": 1234
}
},
"1bc4ac6d5a78c5af5e7c1056cfeafe5389c7": {
"HostDescription": "PS15-USB3",
"HostDevice": "00000036C0C4888E",
"HostPort": 2,
"HostSerial": "COM8",
"result": {
"Description": "SuperPad4",
"LocationID": 022112000,
"Manufacturer": "SuperPhone Makers Inc",
"PID": 4567,
"SerialNumber": "1bc4ac6d5a78c5af5e7c1056cfeafe5389c7",
"USBVersion": 3.0,
"VID": 1234
}
}
}
}
From these results, you could check the status of, for example, the iPad by running cbrx_connection_open('0000034CCC2AA16')
and then check the status of HostPort by querying cbrx_connection_get('PortInfo.9')
. But if you’re only interested in the presence of devices, then you may find that you do not need this extra information.
For any search results that do not have their own device serial number, there will be an additional entry of NoSerial
that is an array of such results.
For the curious, it may look like unneeded repetition with the serial numbers, but this is merely because the data here comes from the same place as the data produced by PortInfo
or cbrx_get_usbtree
, and we’re simply showing everything from the point of connection upwards.
Return the entire USB tree that has been discovered.
Input:
Returns:
The returned data can be quite large if you have a lot of connected devices, but can be easily printed using the cbrx_usbtree.py example.
Example Python call:
from cbrxapi import cbrxapi
from pprint import PrettyPrinter
# Python call to get entire USB Tree
= cbrxapi.cbrx_get_usbtree()
tree
= PrettyPrinter(width=160)
pp
pp.pprint(usbTree)
# Example output from cbrx_usbtree.py example
'Description': 'USB 3.0 Root Hub',
{'LocationID': 0x22000000,
'PID': 0x2142,
'USBVersion': 3.0,
'VID': 0x1b21,
'children': [{'Description': 'PP15S',
'LocationID': 0x22300000,
'Manufacturer': 'cambrionix',
'PID': 0x2514,
'USBVersion': 2.0,
'VID': 0x0424,
'children': [{'Description': 'PP15S',
'LocationID': 0x22310000,
'Manufacturer': 'cambrionix',
'PID': 0x2514,
'USBVersion': 2.0,
'VID': 0x0424},
'Description': 'PP15S',
{'LocationID': 0x22320000,
'Manufacturer': 'cambrionix',
'PID': 0x2514,
'USBVersion': 2.0,
'VID': 0x0424},
'Description': 'PP15S',
{'LocationID': 0x22330000,
'Manufacturer': 'cambrionix',
'PID': 0x2514,
'USBVersion': 2.0,
'VID': 0x0424,
'children': [{'Description': 'Ultra USB 3.0',
'LocationID': 0x22333000,
'Manufacturer': 'SanDisk',
'PID': 0x5595,
'SerialNumber': '4C530000081105121053',
'USBVersion': 2.1,
'VID': 0x0781}]},
'Description': 'PP15S',
{'LocationID': 0x22340000,
'Manufacturer': 'cambrionix',
'PID': 0x2514,
'USBVersion': 2.0,
'VID': 0x0424,
'children': [{'Description': 'FT230X Basic UART',
'LocationID': 0x22341000,
'Manufacturer': 'FTDI',
'PID': 0x6015,
'SerialNumber': 'DM02C1BR',
'USBVersion': 2.0,
'VID': 0x0403}]}]}]}]
This function allows setting various persistent configuration options.
Possible configuration values are:
{
"jsonrpc": "2.0",
"method": "cbrx_config_set",
"params": {
"key1": "value1",
"key2": "value2"
},
"id": 0
}
The function has been removed due to concerns about security. Please supply the password as an additional argument to cbrx_connection_open when opening a remote device.
This change only affects users already connecting to remote devices, such as the EtherSync.
Add a remote device that cannot be reached by auto-discovery.
Input:
Returns:
Example Python call:
= cbrxapi.cbrx_connection_remote_add_device("remoteHostName") result
Example JSONRPC request:
{
"jsonrpc": "2.0",
"method": "cbrx_connection_remote_add_device",
"params": ["remoteHostName"],
"id": 0
}
Example successful response:
{
"jsonrpc": "2.0",
"id": 0,
"result": true,
}
Example unsuccessful response:
{
"jsonrpc": "2.0",
"id": 0,
"error": {
"code": -32602,
"message": "Invalid params"
}
}
Clear the list of remote devices, currently open devices will be retained.
Input:
Returns:
Example Python call:
= cbrxapi.cbrx_connection_remote_clear_devices() result
Example JSONRPC request:
{
"jsonrpc": "2.0",
"method": "cbrx_connection_remote_clear_devices",
"id": 0
}
Example successful response:
{
"jsonrpc": "2.0",
"id": 0,
"result": true
}
Example unsuccessful response:
{
"jsonrpc": "2.0",
"id": 0,
"error": {
"code": -32602,
"message": "Invalid params"
}
}
Open a connection to the Cambrionix unit specified. A successful open results in a connection handle that can be used for further calls, which needs to be closed with a call to cbrx_connection_close
. An unsuccessful open does not need a corresponding call to cbrx_connection_close
.
Input:
cbrx_discover
.Returns:
Example Python call:
# Connect to local device
= cbrxapi.cbrx_connection_open("DB0074F5")
connectionHandle
# Connect to remote device
= cbrxapi.cbrx_connection_open("EtherSync1d94a0.local.", "remote", "password") connectionHandle
Example JSONRPC request:
{
"jsonrpc": "2.0",
"method": "cbrx_connection_open",
"params": ["DB0074F5"],
"id": 0
}
Example successful response:
{
"jsonrpc": "2.0",
"id": 0,
"result": 7654
}
Example unsuccessful response:
{
"jsonrpc": "2.0",
"id": 0,
"error": {
"code": -10001,
"message": "ID not found"
}
}
Close a connection to a Cambrionix unit previously opened, as specified by the connection handle.
Input parameter:
cbrx_connection_open
.Returns:
Note: It is important to receive the response before closing the socket to ensure the operation has time to be actioned.
Example Python call:
= cbrxapi.cbrx_connection_close(connectionHandle) result
Example JSONRPC request:
{
"jsonrpc": "2.0",
"method": "cbrx_connection_close",
"params": [7654],
"id": 123
}
Example successful response:
{
"jsonrpc": "2.0",
"id": 123,
"result": true
}
Example unsuccessful response:
{
"jsonrpc": "2.0",
"id": 123,
"error": {
"code": -10005,
"message": "Invalid handle"
}
}
Return the API version from a remote connection that has previously been opened.
Input parameter:
cbrx_connection_open
.Returns:
Example Python call:
cbrxapi.cbrx_connection_remote_apiversion(connectionHandle)
Example JSONRPC request:
{
"jsonrpc": "2.0",
"method": "cbrx_connection_remote_apiversion",
"params": [7654],
"id": 0
}
Example successful response:
{
"jsonrpc": "2.0",
"id": 0,
"result": [1, 5]
}
Deprecated - Use cbrx_connection_get with PortsInfo
or PortInfo.N
instead.
Retrieve the detailed state output from all ports on the Cambrionix unit specified by connectionHandle. This is useful for debugging issues where a port reports an error.
Input:
cbrx_connection_open
.Returns:
Example Python call:
cbrxapi.cbrx_connection_getdetail(connectionHandle)
Example JSONRPC request:
{
"jsonrpc": "2.0",
"method": "cbrx_connection_getdetail",
"params": [7654],
"id": 0
}
Example successful response:
{
"jsonrpc": "2.0",
"id": 0,
"result": "Port: 1
vstate
port_mode: 2
charge_state: 0
can_sync: 0
attached: 0
...
profile_list_len: 0
profile: None+
adet_blanking_timer: 0"
}
List all tags that can return information on the Cambrionix unit specified by connectionHandle.
Input parameter:
cbrx_connection_open
.Returns:
Example Python call:
cbrxapi.cbrx_connection_getdictionary(connectionHandle)
Example JSONRPC request:
{
"jsonrpc": "2.0",
"method": "cbrx_connection_getdictionary",
"params": [7654],
"id": 0
}
Example successful response:
{
"jsonrpc": "2.0",
"id": 0,
"result": [
"SystemTitle",
"Hardware",
"Firmware",
...
]
}
From the Cambrionix unit specified by the connection handle, get the value of the tag.
Input parameters:
connectionHandle
as returned by a previous call to cbrx_connection_open
.propertyName
tag as returned by a call to cbrx_connection_getdictionary
.Returns:
Example Python call:
= cbrxapi.cbrx_connection_get(connectionHandle, "nrOfPorts") value
Example JSONRPC request:
{
"jsonrpc": "2.0",
"method": "cbrx_connection_get",
"params": [
7654,
"nrOfPorts"
],
"id": 0
}
Example successful response:
{
"jsonrpc": "2.0",
"id": 0,
"result": 8
}
Example unsuccessful response:
{
"jsonrpc": "2.0",
"id": 0,
"error": {
"code": -10003,
"message": "Key not found"
}
}
Like cbrx_connection_get, but instead of a handle takes the hub’s serial number as the initial argument.
Note that this is a convenience function and will almost certainly be slower if you need to do multiple operations on the same hub.
Like cbrx_connection_get, but instead of a handle takes a USB device’s serial number as the initial argument. Only get values that are relevant to ports are accepted.
Note that this is a convenience function and will almost certainly be slower if you need to do multiple operations on the same device.
For example, instead of:
= "123123123123"
deviceSerialNumber = cbrxapi.cbrx_find("iPhone")
allDevices = allDevices[deviceSerialNumber]
myDevice if myDevice:
= cbrxapi.cbrx_connection_open(myDevice["HostDevice"])
handle = cbrxapi.cbrx_connection_get(handle, "PortInfo." + myDevice["HostPort"])
deviceStatus cbrxapi.cbrx_connection_close(handle)
You can use:
= "123123123123"
deviceSerialNumber = cbrxapi.cbrx_device_get(deviceSerialNumber, "PortInfo") deviceStatus
List all writeable value tags and command tags for the Cambrionix unit specified by connectionHandle
.
Input parameter:
cbrx_connection_open
.Returns:
Example Python call:
cbrxapi.cbrx_connection_setdictionary(connectionHandle)
Example JSONRPC request:
{
"jsonrpc": "2.0",
"method": "cbrx_connection_setdictionary",
"params": [7654],
"id": 0
}
Example successful response:
{
"jsonrpc": "2.0",
"id": 0,
"result": [
"Port.1.mode",
"Port.2.mode",
...
"ClearRebootFlag ",
"Reboot",
...
]
}
On the Cambrionix unit specified by the connection handle, set the tag to the value specified.
Input:
connectionHandle
as returned by a previous call to cbrx_connection_open
.cbrx_connection_setdictionary
.Returns:
Note: It is important to receive the response before closing the socket to ensure the operation has time to be actioned.
Example Python call:
"Reboot", True) cbrxapi.cbrx_connection_set(connectionHandle,
Example JSONRPC request:
{
"jsonrpc": "2.0",
"method": "cbrx_connection_set",
"params": [
7654,
"TwelveVoltRail.OverVoltage",
true
],
"id": 0
}
Example successful response:
{
"jsonrpc": "2.0",
"id": 0,
"result": true
}
Example unsuccessful response:
{
"jsonrpc": "2.0",
"id": 0,
"error": {
"code": -10004,
"message": "Error setting value"
}
}
Like cbrx_connection_set, but instead of a handle takes the hub’s serial number as the initial argument.
Note that this is a convenience function and will almost certainly be slower if you need to do multiple operations on the same hub.
The new API also supports sending of notifications for certain events.
discover-changed
- The API detected a change in the available hubs. You should re-run cbrx_discover at this point.usb-changed
- The API detected a change in the USB Tree.usb-device-attached
- More detailed that usb-changed, this will tell you of specific devices that have arrived.usb-device-detached
- … or detached.firmware-progress
- Request updates on firmware update progress.rfid-received
- Receive notification when a connected RFID ready on a ModIT Boss is read.all
- Request all notifications.{
"jsonrpc": "2.0",
"id": 0,
"method": "cbrx_notifications",
"params": [
"discover-changed",
"usb-device-attached",
"usb-device-detached",
"rfid-received"
]
}
Notification packets are the same as other JSON-RPC packets, except that they do not have an "id"
field. Most of these notifications do not supply anything in the "params"
field, except for the following example, and the "firmware-update one"
shown here.
Example of “usb-device-attached” notification:
{
"jsonrpc": "2.0",
"method": "usb-device-attached",
"params": {
"HostDevice": "1212343456567878",
"HostSerial": "/dev/tty.usbmodem1421502",
"HostPort": 7,
"HostDescription": "PS15-USB3"
"USB2": {
"Description": "iPhone",
"LocationID": 573710336,
"Manufacturer": "Apple Inc.",
"PID": 4776,
"SerialNumber": "567d53a0a3398941f8ea3e64d5f1af6053e21244",
"USBVersion": 2,
"VID": 1452,
},
}
}
In this example we show that the device was connected as USB2 only. A USB3 device would have a similar entry. It is presented this way because it is entirely possible to connect (for example) a USB3 device that has its own hub, and USB2 devices. These would be individually shown because they can’t reliably be mixed; you can have hardware entities with the same VID/PID/Serial in sibling trees.
Note: Notifications are only sent to active socket connections that have requested them. Closing a socket and opening another one will mean you need to re-request notifications.
The same information comes with the "usb-device-detached"
notification.
The firmware functions can control all aspects of updating the firmware on Cambrionix hubs.
There are several sub-commands here that allow you to add or remove firmware files from the API’s local storage, list the currently available firmware files, update firmware from provided files and check the status of existing firmware updates.
Adding firmware files is done by providing a Base64 encoded zip of the file. Encoding is necessary because the JSON packet cannot deal with binary data because it would terminate at any nul characters.
# Example of adding new firmware
# This merely provides it to the API as an available update source
# It does not affect any connected hubs
= myReadFileFunction("CambrionixFirmware-un")
rawBytes = base64.b64encode(rawBytes)
encodedBytes "add", "CambrionixFirmware-un", encodedBytes]) cbrxapi.cbrx_firmware([
# Example of removing firmware from API storage
"remove", "CambrionixFirmware-un"]) cbrxapi.cbrx_firmware([
# Example of listing available firmware files
list = cbrxapi.cbrx_firmware(["list"])
print(list)
# Would give something like:
# {
# {filename: "CambrionixFirmware-un", version: "1.79"},
# {filename: "AnotherFirmwareFile-un", version: "1.78"}
# }
# Example of starting firmware update (in this case the charger firmware)
# Other types of firmware can be available for different products,
# such as "display" for hubs with more complex LED arrangements.
# Firmware updates can either be specified with a single file,
# or an object files keyed on the type of firmware update.
= cbrxapi.cbrx_connection_open(["1212343456567878"])
handle
# Update only the charger firmware from a file with charger and display within.
"update", handle, "CambrionixFirmware-un", "charger"])
cbrxapi.cbrx_firmware([# Or, update all firmware for selected device from the firmware files provided.
"update", handle, ["CambrionixFirmware-un", "MotorControlFirmware-mc"]]) cbrxapi.cbrx_firmware([
# Example of getting status of firmware update
"status", handle])
cbrxapi.cbrx_firmware([
# Could give:
# {
# Status: "flashing",
# Version: "1.79",
# Type: "display",
# Progress: 60,
# Stage: "flashing"
# }
"init"
, "erasing"
, "flashing"
, "checking"
, "complete"
"error-crypt-init"
, "error-erasing"
, "error-flashing"
, "error-checking"
"erasing"
, "erased"
, "flashing"
, "flashed"
"init-failed"
, "erase-failed"
, "flash-failed"
, "reboot-failed"
A Status error of "error-crypt-init"
will usually mean the wrong type of firmware was used for the selected device.
All other Status errors would likely mean that the hub’s firmware is now in an invalid state and would need to be re-done.
Note that this is not possible with the python implementation that we provide because it creates a new socket per message and immediately closes it. This will change in the future when we provide more object oriented native language layers to talk to the API.
In addition to the status request option, you can also listen for notifications on the same socket that initiated the firmware update. These notifications would be JSON-RPC packets without an "id"
field. And would have a “params” field with the details of the progress. These notifications will only be sent if they are enabled using the cbrx_notifications([“firmware-progress”]) method.
Example notification packet:
{
"jsonrpc": "2.0",
"method": "firmware-progress",
"params": {
"Progress": 60,
"Stage": "flashing",
"Type": "charger",
"HostDevice": "1212343456567878",
"HostSerial": "/dev/tty.usbmodem1421502",
"HostDescription": "PS15-USB3"
}
}
This method is used in the new LiveViewer™ 2 application to show updated progress.
Deprecated - This was required for the old API so that it did not interfere with the separate firmware updater application.
Forcibly close all connections to a Cambrionix unit and lock it against further use until released by cbrx_connection_unlock
. Other processes that were using these connections will get errors returned if trying to access this Cambrionix unit. Locking a Cambrionix unit that was not previously opened does no harm and will succeed.
Input parameter:
Returns:
Note: It is important to receive the response before closing the socket to ensure the operation has time to be actioned.
Example Python call:
"DB0074F5") cbrxapi.cbrx_connection_closeandlock(
Example JSONRPC request:
{
"jsonrpc": "2.0",
"method": "cbrx_connection_closeandlock",
"params": ["DB0074F5"],
"id": 0
}
Example successful response:
{
"jsonrpc": "2.0",
"id": 0,
"result": true
}
Example unsuccessful response:
{
"jsonrpc": "2.0",
"id": 0,
"error": {
"code": -10001,
"message": "ID not found"
}
}
Deprecated - This was required for the old API so that it did not interfere with the separate firmware updater application.
Unlock a Cambrionix unit that was previously locked. Unlocking a Cambrionix unit that was not previously locked does no harm and will succeed.
Input parameter:
Returns:
Note: It is important to receive the response before closing the socket to ensure the operation has time to be actioned.
Example Python call:
"DB0074F5") cbrxapi.cbrx_connection_unlock(
Example JSONRPC request
{
"jsonrpc": "2.0",
"method": "cbrx_connection_unlock",
"params": ["DB0074F5"],
"id": 0
}
Example successful response:
{
"jsonrpc": "2.0",
"id": 0,
"result": true
}
Example unsuccessful response:
{
"jsonrpc": "2.0",
"id": 0,
"error": {
"code": -10001,
"message": "ID not found"
}
}
Perform command line interface operation on the connected hub and return the complete result. This allows you to run commands directly on the hub’s command line without stopping the API service, connecting to the serial port and so on.
The return is an array of strings containing all the lines of output returned from the command.
7654, "id") cbrxapi.cbrx_connection_cli(
Example JSONRPC request
{
"jsonrpc": "2.0",
"method": "cbrx_connection_cli",
"params": [7654, "id"],
"id": 1337
}
Example successful response:
{
"jsonrpc": "2.0",
"id": 1337,
"result": [
"mfr:cambrionix,mode:main,hw:PP15S,hwid:0x13,fw:1.83,bl:0.12,sn:000000,group:-,fc:un"
]
}
Local and remote Cambrionix units need to be treated slightly differently due to the way they are accessed.
A local
Cambrionix unit is one that is connected with a USB cable to the machine which is running the API. If you do not specify the location to cbrx_discover
or cbrx_connection_open
then the API will assume that you are using a local Cambrionix unit.
A remote
Cambrionix unit is not connected to the machine which is running the API but is instead connected to a network that is accessible from the machine which is running the API. Currently the only Cambrionix unit which connects over a network is the EtherSync.
In order to connect to a remote Cambrionix unit you must discover it first by passing "remote"
as the location parameter to cbrx_discover
. You can then call the cbrx_connection_open
specifying the device ID of the remote unit as well as "remote"
for the location with an additional parameter of the password for the unit (this is printed on the bottom of the EtherSync device). Once the connection is open the handle is sufficient for the API to distinguish local or remote and so other calls do not need to specify the location. There is also an additional call cbrx_connection_remote_apiversion
which will return the API version of the remote charger.
The U8S and U8S-EXT chargers have a small difference from other Cambrionix Universal Chargers in that their control or update port has an external connection. All other Cambrionix Universal Chargers have a single host connection that combines the functions of the upstream connection to the host with the control or update port.
In order for the U8S or U8S-EXT to work correctly with the API there must be a USB cable that connects the control or update port to an expansion port on the same board. This is in addition to the USB cable that connects the host port to the machine running the API.
When there are two Cambrionix chargers that have been built into a product, with the second charger connected to an expansion port of the first charger, this is known as a Dock
. For some operations it may be convenient to treat these two chargers as a single unit, that combines the ports of both chargers.
If the application wishes to access the dock as a single unit it should firstly call cbrx_discover
with the parameter docks
to obtain the list of docks available. The application should then call cbrx_connection_open
with the ID in question and also specifying "docks"
.
The dock unit will return the combined total for tags such as nrOfPorts
and TotalCurrent_mA
. The range of ports is expanded to cover the combined total number of ports for the two chargers. For the charger with its host port directly connected to the computer, its ports will be referenced first followed by those of the charger connected to first charger’s expansion port. e.g. if a U16S has its host port connected to the host computer and an expansion port connects to a U8S, port 11 will be port 11 on the U16S and port 23 will be port 7 on the U8S.
It is also necessary to install jumpers on the parent and child boards. These jumpers are used to set the Group ID
. The parent board must have a Group ID
of 8
i.e. a jumper installed on the pair of pins marked 8
. The child board must have a Group ID
of 8 + 1
i.e. two jumpers, one jumper on the pair of pins marked 8
and one jumper on the pair of pins marked 1
. No other jumpers should be installed on the Group ID
block of pins.
Some tags such as Hardware
or Firmware
do not combine in a meaningful way and so these tags will return the value for the parent charger. If it is desired to get the values of these tags from the downstream charger then it is possible to open and retrieve them from that charger in the usual manner. Opening a charger does not interfere with access to the dock except as to when settings are changed.
Calls to cbrx_connection_set
for a dock will result in the relevant tag being set on both the chargers except for the port specific tags which will be directed to the appropriate charger only.
Entirely at your discretion, you can open a pseudo hub that is a combination of various other hubs. This behaves in the same way that Docks hubs do, as detailed above.
To open a dynamic hub, simple combine the serial numbers of all the hubs you wish to open into a special "Dynamic:"
prefixed name as shown in this example.
# Given three Cambrionix hubs with serial numbers of 'AAAA', 'BBBB' and 'CCCC'
= cbrxapi.cbrx_connection_open("AAAA")
handleA = cbrxapi.cbrx_connection_open("BBBB")
handleB = cbrxapi.cbrx_connection_open("CCCC")
handleC = cbrxapi.cbrx_connection_open("Dynamic:AAAA:BBBB:CCCC")
handleABC
print(cbrxapi.cbrx_connection_get(handleA, "nrOfPorts")) # 15
print(cbrxapi.cbrx_connection_get(handleB, "nrOfPorts")) # 8
print(cbrxapi.cbrx_connection_get(handleC, "nrOfPorts")) # 8
print(cbrxapi.cbrx_connection_get(handleABC, "nrOfPorts")) # 31
This dynamic hub is treated as a single entity with it’s ports being numbered from 1 to N, where N is the total number of ports across all hubs included.
For each Cambrionix unit, the API can return two dictionaries:
Get dictionary
, containing keys for the tags that can be read.Set dictionary
, containing keys for the tags that can be written to or can perform an action.The keys returned depend on the feature set(s) supported by the unit.
The following feature sets are available:
Feature set | Description |
---|---|
base | Base level functionality supported by all Cambrionix units |
sync | Syncing capability |
5V | The unit has a fixed 5V power supply |
12V | The unit has a 12v power supply |
temperature | The unit has a temperature sensor |
PD | The unit implements the USB Power Delivery Specification |
gate | The unit has a motor control board to control locking gates to protect phones from removal. |
All Cambrionix units support the base
feature set.
The range of possible values for a tag in the base
feature set can be extended if an additional feature set is also available. For example, Port.n.flags
can only return a flag S
(port is in Sync mode) on a device that also implements the sync
feature set.
The Hardware
key returns a value for the type of Cambrionix unit.
These are the extra feature sets CambrionixApiService
supports for the various types of Cambrionix unit:
Cambrionix unit type returned by “Hardware” | sync | 5V | 12V | Temperature | PD | gate |
---|---|---|---|---|---|---|
PP8C | yes | yes | yes | |||
PP8S | yes | yes | yes | yes | ||
PP15C | yes | yes | yes | |||
PP15S | yes | yes | yes | yes | ||
PS15 | yes | yes | yes | yes | ||
Series8 | yes | |||||
U8C-EXT | yes | yes | yes | |||
U8C | yes | |||||
U8RA | yes | yes | ||||
U8S-EXT | yes | yes | yes | yes | ||
U8S | yes | yes | ||||
U10C | yes | |||||
U10S | yes | yes | ||||
U12S | yes | yes | ||||
U16S-NL | yes | yes | ||||
PD-Sync 4 | yes1 | yes | yes | |||
ThunderSync | yes | yes | yes | |||
ThunderSync3-16 | yes | yes | yes | |||
ModIT Pro2 | yes | yes | yes | yes |
1 It is to be noted that while the PD-Sync 4 does not implement the “sync” feature set as such, nevertheless it does have sync capabilities and these are always available. This means that there is no need to switch between charge mode and sync mode.
2 The ModIT Pro will identify itself as a ThunderSync3-16, but it has additional hardware for gate control.
A bit-field with one bit set for each port with a device attached, port 1 in bit 0, port 2 in bit 1 and so on.
Example return value:
7
Timestamp of firmware version.
Example return value:
"Jul 08 2015 10:43:20"
List of global profiles currently enabled
Example return value:
"1 2 3 4"
Firmware version string
Example return value:
"1.55"
Get the types of Firmware applicable to this hub, returned as an array containing information for all types of firmware that the hub accepts. For each entry, the FormFactor field indicates the firmware type for that part, which can be one of “un”, “ps”, “pd” for mainboard firmware, “db” for LED firmware or “mc” for Motor Control Board.
Returns an array of information about each type of firmware currently installed, with details of the firmware types required to update them.
Example return value:
[
{
"Bootloader": "0.13",
"Firmware": "1.83",
"FormFactor": "un",
"Group": "-",
"Hardware": "PP15",
"Manufacturer": "cambrionix",
"PanelID": 0,
"SerialNumber": "DN004ANJ"
}
]
Returns list of 5V supply rail error flags that have been detected, if any.
Example return value:
""
Upper limit of the 5V rail that will trigger the error flag.
Example return value:
5.58
Lower limit of the 5V rail that will trigger the error flag
Example return value:
3.5
Current 5V supply voltage in Volt (V)
Example return value:
5.25
Highest 5V supply voltage seen in Volt (V)
Example return value:
5.25
Lowest 5V supply voltage seen in Volt (V)
Example return value:
5.2
Returns an object describing the states of all gates on the expansion board if present. Currently, this is only available on the ModIT range.
Example return value:
{
"1": "open",
"2": "closed",
"3": "closing",
"4": "opening"
}
Group letter read from PCB jumpers, or “–” if no group jumper was fitted.
Example return value:
"-"
Type of the Cambrionix unit such as “U8S-EXT”, “PP15”, “PS15-USB3”, “ThunderSync3-16”.
Example return value:
"ThunderSync3-16"
Flags indicating whether features are present
Example return value:
"SLET"
All available keys that are not port specific and change dynamically, as a dictionary.
Host is connected to the Cambrionix unit
Example return value:
true
List of input rail error flags if any are set.
Example return value:
"OV UV"
Upper limit of the input rail that will trigger the error flag
Example return value:
24.7
Lower limit of the input rail that will trigger the error flag.
Example return value:
9.59
Current input rail supply in Volts (V).
Example return value:
24.03
Highest input voltage seen in Volts (V).
Example return value:
24.14
Lowest input voltage seen in Volts (V).
Example return value:
23.82
0 if button n
has not been pressed since the last time this entry was read. 1 if button n has been pressed since the last time this entry was read. Double-clicks cannot be detected.
Example return value:
0
Mode change from Charge to Sync is automatic.
Example return value:
true
Number of USB ports on the Cambrionix unit.
Example return value:
8
PanelID number of front panel board, if fitted, or “Absent”/“None”.
Example return value:
"Absent"
If possible, retrieve the current battery level of the connected device. See notes about battery information collection. Depending on the device type (Android, iOS etc.) and the host OS, different data may be returned.
Example return value:
{
"CurrentLevel": 78,
"CurrentTime": 15234254346,
"StartLevel": 23,
"StartTime": 15124151512,
}
Current being delivered to the USB device connected to this USB port in milli-Amperes (mA).
Example return value:
0
Description as reported by the USB device attached to this USB port if it could be detected. Empty string is returned if it could not be detected.
Example return value:
"SuperPhone6"
Energy the USB device on this USB port has consumed in Watt-hours (calculated every second).
Example return value:
0.0
Port flags separated by spaces.
Example return value:
"R D S"
Manufacturer as reported by the USB device attached to this USB port, if it could be detected. Empty string is returned if it could not be detected.
Example return value:
"SuperPhone Makers Inc"
Product ID of the USB device attached to this USB port, if it could be detected. 0 (zero) is returned if it could not be detected.
Example return value:
0
Profile ID number, or 0 if not charging.
Example return value:
0
List of enabled profiles for this port.
Example return value:
"1 2 3 4"
Serial number as reported by the USB device attached to this USB port, if it could be detected. Empty string is returned if it could not be detected.
Example return value:
"1127dfa9037s1a8cb1"
Time in seconds since this USB port detected the device has completed charging. -1 will be returned if this port has not detected completed charging.
Example return value:
-1
Or a number of seconds since charing completed.
Time in seconds since this USB port started charging an attached device. 0 will be returned if the USB port has not started charging an attached device.
Example return value:
0
A dictionary containing the values for “Manufacturer”, “Description” and “SerialNumber” for this USB port.
Example return value:
{"SerialNumber": "23213dfe12e2412",
"Description": "SuperPhone6",
"Manufacturer": "SuperPhone Makers Inc"
}
Vendor ID of the USB device attached to this USB port, if it could be detected. 0 (zero) is returned if it could not be detected.
Example return value:
0
Voltage being supplied to the port in 10mV.
Example return value:
520
Get all port information for specified port.
All available keys and values for this port as a dictionary.
Get all port information for all ports.
All available information for all ports as a dictionary of dictionaries.
Is global profile n enabled?
Example return value:
false
Fan speed.
Example return value:
100
A flag indicating if the system has been rebooted since power up. true – system has been rebooted or false – no reboot has occurred.
Example return value:
true
Is security armed?
Example return value:
false
The system identification text.
Example return value:
"cambrionix U8S-EXT 8 Port USB Charge+Sync"
Present PCB temperature in degrees Celsius. Measured temperatures ≤ 0 °C will return 0. Measured temperatures ≥100 °C will return 100.
Example return value:
37.7
Temperature error flags:
Example return value:
""
Upper limit of the acceptable temperature range that will trigger the error flag.
Example return value:
65.0
Highest PCB temperature in degrees Celsius. Measured temperatures ≤ 0 °C will return 0. Measured temperatures ≥ 100 °C will return 100.
Example return value:
39.9
Total current in mA for all USB ports.
Example return value:
0
Total power being consumed on all USB ports in Watts (W).
Example return value:
3.4
List of 12V supply rail error flags.
Example return value:
""
Upper limit of the 12V rail that will trigger the error flag.
Example return value:
14.5
Lower limit of the 12V rail that will trigger the error flag.
Example return value:
9.59
Current 12V supply voltage in Volts (V).
Example return value:
12.43
Highest 12V supply voltage seen.
Example return value:
12.52
Lowest 12V supply voltage seen in Volts (V).
Example return value:
12.31
Time in seconds the Cambrionix unit has been running since the last reset.
Example return value:
151304
Get USB Tree information. If a port is specified (sync only), then it will be the USB2 and USB3 (if applicable) trees associated to the specific port, otherwise it will be the entire tree.
Json object of USB tree.
Key | Feature set |
---|---|
Beep | 5V |
ClearErrorFlags | base |
ClearLCD | 5V |
ClearRebootFlag | base |
FiveVoltRail.OverVoltage | 5V |
FiveVoltRail.UnderVoltage | 5V |
InputRail.OverVoltage | PD |
InputRail.UnderVoltage | PD |
LCDText.ROW.COL | 5V |
Mode | base |
Port.N.gate | gate |
Port.N.led1 | base |
Port.N.led2 | base |
Port.N.led3 | base |
Port.N.leds | base |
Port.N.Mode | base |
Port.N.profiles | sync |
Port.N.RGB | gate |
ProfileEnable.n | 5V |
Reboot | base |
RemoteControl | base |
RGBControl | gate |
SecurityArmed | 5V |
Temperature.OverTemperature | temperature |
TwelveVoltRail.OverVoltage | 12V |
TwelveVoltRail.UnderVoltage | 12V |
Set same mode to all USB Ports.
Sync mode can only be set on device that implement the sync
feature set. Biased mode can only be set on devices that implement the 5V
feature set.
mode:
With Python, this could be
# Example - setting all ports to sync mode
'Mode', 's') cbrx_connection_set(handle,
Or with JSON-RPC
{
"id": 0,
"jsonrpc": "2.0",
"method": "cbrx_connection_set",
"params": [
handle,
"Mode",
"s"
]
}
Set mode of a single USB port.
Sync mode can only be set on device that implement the sync
feature set. Biased mode can only be set on devices that implement the 5V
feature set.
mode:
With Python, this could be
# Example - setting port 1 to charge mode
'Port.1.mode', 'c') cbrx_connection_set(handle,
Or with JSON-RPC
{
"id": 0,
"jsonrpc": "2.0",
"method": "cbrx_connection_set",
"params": [
handle,
"Port.1.Mode",
"c"
]
}
Set the status of the first LED
0-255 with the LEDs flashing according to the bit pattern represented by the value.
With Python, this could be
# Example - setting port 1 LED 1 to flash rapidly
'Port.1.led1', 170) # 170 = 0b10101010 cbrx_connection_set(handle,
Or with JSON-RPC
{
"id": 0,
"jsonrpc": "2.0",
"method": "cbrx_connection_set",
"params": [
handle,
"Port.1.led1",
170
]
}
Set the status of the second LED
0-255 with the LEDs flashing according to the bit pattern represented by the value.
With Python, this could be
# Example - setting port 1 LED 2 to flash slowly
'Port.1.led2', 240) # 240 = 0b11110000 cbrx_connection_set(handle,
Or with JSON-RPC:
{
"id": 0,
"jsonrpc": "2.0",
"method": "cbrx_connection_set",
"params": [
handle,
"Port.1.led2",
240
]
}
Set the status of the third LED
0-255 with the LEDs flashing according to the bit pattern represented by the value.
# Example - setting port 1 LED 3 to stay on
'Port.1.led3', 255) # 255 = 0b11111111 cbrx_connection_set(handle,
Or with JSON-RPC:
{
"id": 0,
"jsonrpc": "2.0",
"method": "cbrx_connection_set",
"params": [
handle,
"Port.1.led3",
255
]
}
Set the status of all three LEDs
A 24 bit numeric value consisting of the individual LED settings as 8 bit values shifted and OR’ed together. i.e. led1 | (led2 << 8) | (led3 << 16), so with led1 and led2 as zero, and led3 being 0b10101010 (decimal 170), the result should be 11,141,120 decimal.
On a ThunderSync3, 255 is Green, 65,280 is red, 16,711,680 is Yellow. On a ModIT, Blue is used instead of Yellow, but you can of course mix colours into any RGB mix.
# Python example - setting port 1 LEDs to all flash at different rates
= 0b10101010
led1 = 0b11001100
led2 = 0b00111100
led3 = led1 << 16 | led2 << 8 | led3 # 11,193,404
pattern 'Port.1.led34', pattern) cbrx_connection_set(handle,
Or with JSON-RPC:
{
"id": 0,
"jsonrpc": "2.0",
"method": "cbrx_connection_set",
"params": [
handle,
"Port.1.leds",
11193404
]
}
Set RGBA colour of ModIT LEDs.
Colour argument can either be an integer (where you must supply full RGBA), or a string.
For a string, you can specify it as RGB, RGBA, RRGGBB or RRGGBBAA. Much like you can with an HTML colour. For example, use “FF0000” or “F00” for red, “FFFFFF” for white and so on. Optionally supply the alpha (intensity) digits, so “FFFFFF80” for half bright white.
Preceding ‘#’ is optional and will be ignored.
# Python example - setting port 1 ModIT LEDs to yellow
# This colour is the same as specifying "#FF0", "FF0" or "FFFF00FF"
'Port.1.RGB', "#FFFF00")
cbrx_connection_set(handle,
# or at half intensity
'Port.1.RGB', "#FFFF0080") cbrx_connection_set(handle,
Or with JSON-RPC, same colour but in short method:
{
"id": 0,
"jsonrpc": "2.0",
"method": "cbrx_connection_set",
"params": [
handle,
"Port.1.RGB",
"ff08"
]
}
Set the list of enabled profiles.
A comma separated list of profiles to enable e.g. 1,2,3
# Python example setting port available 1 profiles to 1, 2 and 3
"Port.1.profiles", "1,2,3") cbrx_connection_set(handle,
Or with JSON-RPC:
{
"id": 0,
"jsonrpc": "2.0",
"method": "cbrx_connection_set",
"params": [
handle,
"Port.1.profiles",
"1,2,3"
]
}
Open or close specified gate.
‘open’, ‘close’ or ‘stop’ are valid options.
Returns true if successful.
The return is immediate if the command succeeds, but you should monitor the state of the required gate via cbrx_connection_get(handle, “Gates”) to ensure it completes.
# Python example to open gate of port 1
"Port.1.gate", "open") cbrx_connection_set(handle,
Or with JSON-RPC:
{
"id": 0,
"jsonrpc": "2.0",
"method": "cbrx_connection_set",
"params": [
handle,
"Port.1.gate",
"open"
]
}
Clear the LCD.
# Python example
"ClearLCD") cbrx_connection_set(handle,
Write the string on the LCD at (row, column). Row and column are zero based.
# Python example
"LCDText.0.0", "Hello World!") cbrx_connection_set(handle,
Enable / disable controlling of the unit controls. This will allow the LEDs or LCD to be updated or panel button pushes to be detected. | true / false / “auto”
# Python example
"LCDText.0.0", "Hello World!") cbrx_connection_set(handle,
Enable / disable ModIT RGB LED control for ports. This does not require RemoteControl to be enabled.
Arguments:
boolean to enable or disable for all ports
or for a specific port, an object with options:
enable: boolean, port: number
or a range of ports, an object with options:
enable: boolean, start: number, end: number,
JSON example setting ports 1 to 8 to enabled:
{
"id": 0,
"jsonrpc": "2.0",
"method": "cbrx_connection_set",
"params": [
handle,
"RGBControl",
{
"start": 1,
"end": 8,
"enable": true
}
]
}
Enable / disable security feature. If the security is enabled, removal of a device from a port will sound an alarm and flash lights.
# Python example
"SecurityArmed", true) cbrx_connection_set(handle,
Beep for the number of milliseconds passed in.
Arguments: integer
# Python example - beep for 1/4 sec
"Beep", 250) cbrx_connection_set(handle,
Clear the reboot flag.
Arguments: true
# Python example
"ClearRebootFlag", true) cbrx_connection_set(handle,
Clear all error flags
Arguments: true
# Python example
"ClearErrorFlags", true) cbrx_connection_set(handle,
Reboot the hub now. The API will attempt to re-establish connection automatically, but you should not expected to receive updated results for several seconds.
Arguments: true
# Python example
"Reboot", true) cbrx_connection_set(handle,
Force the behaviour of a 5V over voltage condition.
Arguments: true
# Python example
"FiveVoltRail.OverVoltage", true) cbrx_connection_set(handle,
Force the behaviour of a 5V under voltage condition.
Arguments: true
# Python example
"FiveVoltRail.UnderVoltage", true) cbrx_connection_set(handle,
Force the behaviour of a 12V over voltage condition.
This is the same as TwelveVoltRail is the same as InputRail.
Arguments: true
# Python example
"TwelveVoltRail.OverVoltage", true) cbrx_connection_set(handle,
Force the behaviour of a 12V under voltage condition.
This is the same as TwelveVoltRail is the same as InputRail.
Arguments: true
# Python example
"TwelveVoltRail.UnderVoltage", true) cbrx_connection_set(handle,
Force the behaviour of an input rail over voltage condition.
Arguments: true
# Python example
"InputRail.OverVoltage", true) cbrx_connection_set(handle,
Force the behaviour of an input rail under voltage condition.
Arguments: true
# Python example
"InputRail.UnderVoltage", true) cbrx_connection_set(handle,
Force the behaviour of an over temperature condition.
Arguments: true
# Python example
"Temperature.OverTemperature", true) cbrx_connection_set(handle,
Enable or disable the global profile n
Arguments: boolean
# Python example, enabling profile 1
"ProfileEnable.1", true) cbrx_connection_set(handle,
When using the Python wrapper that provides the cbrxapi module, each time a call is made to the API, a socket is created. This socket is then used to send the command and receive the response before being closed.
If you are writing your own program, in whichever language you choose, you may wish to consider creating a single socket at the start of your communication with the API and keeping this socket open until you wish to stop using the API. Keeping the socket open for the lifetime of your communication with the API will reduce the load on the system and lead to shorter communication cycles with the API.
If you do choose to manage your own socket connections to the API, either as a long lived singleton, or else created on a per use basis, it is important that you do not close the socket before receiving the response from the final command. Closing the socket without waiting to receive the response may lead to the requested operation not being completed, this is especially important on set and close operations.
The API will only accept connections from the local machine.
Socket connections can be simple binary data, http GET requests or Web-sockets (such as from Node.js).
For example, pasting the following into the address bar of your browser should allow you to see quick results:
http://localhost:43424/?{"jsonrpc":"2.0","id":1,"method":"cbrx_discover","params":["all"]}
If there is no activity on an open handle for more than 120s, the handle will be deleted. Subsequent calls attempting to use a deleted handle will fail with CBRXAPI_ERRORCODE_INVALIDHANDLE
. Software using the API must be able to cope with this situation and respond accordingly. Software may simply call cbrx_connection_open
again in order to obtain a fresh handle.
The API allows control of the LEDs that are present on some chargers or can be attached to other chargers. By default these LEDs are controlled automatically by the charger firmware to indicate the state that a port is in. In order for the LEDs to be controlled by the API this automatic control must be disabled and this is done by setting the “RemoteControl” key to be ‘True’.
= cbrxapi.cbrx_connection_set(handle, "RemoteControl", True) result
If you wish to return control of the LEDs to the automatic control then you simply set “RemoteControl” to be ‘False’.
= cbrxapi.cbrx_connection_set(handle, "RemoteControl", False) result
Control of an LED is achieved by providing an 8 bit value which is interpreted in binary as a pattern that is continuously cycled through. So by setting the value 11110000b, the LED will flash slowly. The LED will be lit where there is a ‘1’ and unlit where there is a ‘0’. Alternatively setting the value 10101010b will make the LED flash fast. The pattern need not be symmetrical so 10010000b will produce two short flashes close together with a longer pause before the cycle repeats.
Any value set for an LED while RemoteControl is False will be overwritten and so have no effect.
A special argument of "auto"
in place of True
allows the hub to override the user set LED pattern when a device attached to that port is removed.
In some cases, battery information can be retrieved for connected devices. For Android devices we can use adb
(from the Android developer kit), and for iOS devices we use an in-built build of libimobile. Additionally on Windows, if an iTunes installation is detected, it can also be used. It should be noted that this support could change with new versions of iTunes.
ADB can be used to query the battery level on any Android devices providing a few conditions are met.
See this page for details on enabling debug mode on Android devices. The only options that are required are to enable developer mode and USB debugging.
# Install Android platform tools on Linux
sudo apt install android-platform-tools
# Install Android platform tools on macOS
brew cask install android-platform-tools
# Install Android platform tools on Windows
# Goto https://developer.android.com/studio/releases/platform-tools
# Download SDK Platform-Tools for Windows
# Extract and add the folder to your path, or use
# cbrx_config_set("adb_path", <pathname>) to add to API settings.
Alternatively from setting the path, we can tell the API where to find these programs.
{
"jsonrpc": "2.0",
"id": 0,
"method": "cbrx_config_set",
"params": {
"adb_path": "/usr/local/bin"
}
}
The API provides a means of controlling most of the features of Cambrionix Universal devices, however there are some limitations.
The API does not currently support:
The related Recorder service which is an optional installation component can record events such as device health, charging history and connection events. These can subsequently be viewed in LiveViewer2. This is intended as a showcase of functionality that could be implemented. There is not currently any documentation for querying data because it is not yet finalised.
Code | Value | Description |
---|---|---|
CBRXAPI_ERRORCODE_IDNOTFOUND | -10001 | ID not found. The unit ID passed in does not represent a Cambrionix unit or it has been disconnected since discovery was last run. Note that there is an internal timeout that will close unused handles after a minute. |
CBRXAPI_ERRORCODE_NOHANDLINGTHREAD | -10002 | Unable to start handling thread. This error is not applicable past 2.1. |
CBRXAPI_ERRORCODE_KEYNOTFOUND | -10003 | Key not found. A key that is passed in cannot be found. It may be misspelled or not exist in the dictionary for this unit. |
CBRXAPI_ERRORCODE_ERRORSETTINGVALUE | -10004 | Could not set value. The (key, value) pair was not acceptable. This could mean the tag does not exist or is misspelled, the value is of the wrong type or the value passed is invalid or out of range. |
CBRXAPI_ERRORCODE_INVALIDHANDLE | -10005 | Invalid handle. The handle passed in to a function is not valid or no longer valid. This could happen either by passing in an incorrect value or if the handle has already been closed (i.e. by cbrx_closeandlock being called), or the unit has been disconnected from the computer. |
CBRXAPI_ERRORCODE_TIMEOUT | -10006 | Timeout on communication. An operation towards a Cambrionix unit took too long to complete. It may have been disconnected or just slow to respond. It is worth retrying the operation. |
CBRXAPI_ERRORCODE_DROPPED | -10007 | Socket connection to remote has been dropped. The socket connection to a remote Cambrionix unit has been dropped. To continue communication, a socket must be re-established by calling cbrx_connection_open again. |
CBRXAPI_ERRORCODE_METHOD_REMOVED | -10008 | The method has been removed. |
CBRXAPI_ERRORCODE_AGAIN | -10009 | System not ready. Try again. This is likely caused by a very prompt call to an API function and the system has not progressed through startup enough to service it. |
CBRXAPI_ERRORCODE_FIRMWARE_UPDATE | -10010 | Error performing firmware update. |
CBRXAPI_ERRORCODE_FIRMWARE_FILE | -10011 | Firmware file error. This would usually be due to file format errors. |
CBRXAPI_ERRORCODE_DEVICE_NOT_FOUND | -10012 | Device not found. |
CBRXAPI_ERRORCODE_HUB_NOT_FOUND | -10013 | Hub not found. |
Most recent revision first.
Version | Changes |
---|---|
2.19.1 | Fix cbrx_discover(“all”) returning no devices when there’s no recent cbrx_connection to that hub. |
2.19.0 | Support for LiveViewer notifications indicating when hub’s are not connectable because their serial port is already open by another application. |
2.18.3 | [Linux] Fix service issues. |
2.18.2 | Fixed an issue introduced in 2.16.5 where discovery hash would not be stored, causing multiple discoveries of hubs and notifications therein. Correct issue with logging locations and empty log files introduced in 2.18.0. |
2.18.1 | Fixed an issue where cbrx_connection_get for ports could return empty results when devices are present. |
2.18.0 | Support running in bundled mode from within LiveViewer. This allows you to run LiveViewer without installing the API. If you need scripting support when LiveViewer is not running, then you should install the whole API, which you can now do from the LiveViewer settings. |
2.17.1 | Fix issues with standard USB hubs and devices not being visible to the API on Apple M1. |
2.17.0 | Support for Native Apple Silicon. All API binaries are now Universal x86_64 and arm64. |
2.16.7 | Fix issue on Apple M1 where Thunderbolt hubs would not show information about connected devices. Fix issue detecting a SuperSync15 device on macOS when the LocationID of the hub starts with a 0. |
2.16.6 | Fix issue of starting ADB twice simultaniously which lead to Android battery reading issues. |
2.16.5 | Fix crash in firmware updater. Fix issues with detecting SuperSync on macOS and Windows when it has no firmware. Fix 10 second connection delay when a hub has no firmware. |
2.16.4 | Fix crash in timers that could cause the API to stop detecting new devices. |
2.16.3 | On Windows, ensure all installations of Python are configured during installation to cure problems where a different version of Python in the path was not configured and fails to run test script. |
2.16.2 | Fix issues with base64 library on very old processors. |
2.16.1 | Fix extended battery information for iPhone8 and later. Disable battery update when there are no connections to API. Always returns error information on battery data collection, even with paired iPhones which may still refuse certain information if locked. |
2.16.0 | Add logging configuration support. |
2.15.5 | Fix issue with API not responding on macOS after a reboot. |
2.15.4 | Fix Linux and macOS issue with serial communications to hub that could cause it to stop updating correctly. |
2.15.3 | Fix some Port.N.* dictionary items lingering long after a device is removed. |
2.15.2 | Fix parsing issue on PDSync with older firmware. |
2.15.1 | Fix Linux issue with detecing removed USB devices after the first device was removed. Fix Linux ARM WebSocket handling which corrupted the return data. |
2.15.0 | Fix issues with EnabledProfiles, Port.N.Profiles and Profile.N.enabled. Change version numbering from N.N.BUILD to standard semver.org method of N.N.N+BUILD or N.N.N-beta+BUILD and so on. |
2.14 | Fix RFID reader functionality broken in 2.13. |
2.13 | Fix issues with Thunderbolt showing wrong port mappings when unplugged and reconnected. Fix issues with some cbrx_connection_set combinations not working after a hub is unplugged and reconnected. Fix issue with EtherSync discovery stalling in calls to Bonjour API causing further discoveries to also stall. Fix issues with Android battery information collection stalling because adb hangs. |
2.12 | Add Battery Health for iOS devices. This should provide the same result as the Battery Health page in iOS introduced with 12.3. Add IMEI and WiFi Mac Address to device’s details in port results. |
2.11 | Add Linux ARMv7 support - Tested on oDroid XU4 with Ubuntu 18.04 LTS. |
2.10 | Fix issue where hubs could disappear from the API after a reboot. Fix issue where Linux could misread the USB location of a hub. |
2.9 | Add Watchdog to internal task manager to ensure jobs are always serviced in good time. |
2.8 | Fix issue during startup where USB tree scan would end up waiting for a lock for discovered iOS devices that were currently being provisioned. |
2.7 | Fix issue where an exception in IOContext thread would cause the thread to exit and cause the API to stop responding. |
2.6 | Fix libimobile timeouts causing all task manager threads to be busy and not service further jobs. Responsiveness of the initial opening of a hub greatly improved so that far less work is required internally before further commands can be issued. Battery information now included in cbrx_discover(“all”) data. |
2.5 | libimobile has been built into the API now for a more reliable method of collecting battery information for iOS devices. |
2.4 | Add cbrx_hub_get, cbrx_hub_set, cbrx_device_get, cbrx_device_set. Added “rfid-received” as a new notification type. |
2.3 | Add Node.JS example script. Fix NVRAM settings_set error. Fix generated HTML documentation styling. Add cbrx_connection_cli method. |
2.2 | Many stability and performance improvements. Add cbrx_notifications. Add cbrx_firmware. Add support for LiveViewer 2 which includes Websocket and HTTP GET capabilities. Add CambrionixRecorderService as optional installation service to record history of hubs and devices.Add battery monitoring support. Add http request support. Add Websocket support. Add built-in firmware updater. Add dynamic hubs. |
2.1 | Fix various typos and change instructions for the new C++ API installation. Add support for Thunderbolt devices under Windows. Add API functions cbrx_find and cbrx_get_usbtree .Document removal of cbrx_connection_set_password and the addition of its replacement argument to cbrx_connection_open .Change documentation versioning to align with API version ( api_major .api_minor ). |
Older changes listed here are specific to the historical versions of the API prior to the 2.1 re-write.
Version | Changes |
---|---|
0.20 | Re-brand. |
0.18 | Add “PortInfo.n”, “PortsInfo” and “Health” keys to speed up returning information from API, bump API version to 1.7. |
0.17 | Add “HardwareFlags” key to the Get dictionary to help check on feature sets available. |
0.16 | Add keys to dictionaries to manipulate enabled profiles and bump API version to 1.6. |
0.15 | Add description of new cbrx_connection_getdetail command. |
0.14 | Add in support for PD-Sync 4 with PD feature set. |
0.13 | Correct python example for reboot. Add in need to install python-setuptools |
0.12 | Add options and description for Docks . |
0.11 | Add section on controlling LEDs. |
0.10 | Add commands to allow specifying remote devices explicitly and to clear the list of remote devices. |
0.9 | Add section on use of sockets. Add section on handle timeouts. Add support for EtherSync. Fixed incorrect value for default listening port. Improved response times. Added USB event driven updates |
0.8 | Add reference to minimum supported firmware level. Fixed current api version returned. Add leds, USBStrings and Attached commands. |
0.7 | Remove listed requirement for libgtk from Linux install section. Add install instructions for OS X. Fix typo mistake Reset -> Reboot in one place.Add mode command to control all ports at once. Fix typo in Minimal Example Python code. Remove erroneous params in cbrx_apiversion JSON example. |
0.6 | API now allows multiple requests in a single TCP connection. |
0.5pre11 | New keys added to Get Dictionary:Key.1 , Key.2 , Key.3 , SecurityArmed .New keys added to Set Dictionary: SecurityArmed . |
0.5pre10 | New keys added to Set Dictionary:RemoteControl , Beep , ClearLCD , LCDText.row.column , Port.n.led1 , Port.n.led2 , Port.n.led3 . |
0.5pre9 | Linux now supports Port.n.PID and Port.n.VID .Windows installer available. cbrx_connection_id_to_os_reference call added.Unit id is now based on the serial number of the Cambrionix unit. New keys added to Get Dictionary for properties of an attached USB device: Port.n.SerialNumber , Port.n.Manufacturer , Port.n.Description . |
0.5pre8 | Initial public revision |