API Reference

Logo

Introduction

This is a description of the Cambrionix Hub API that can be used to control Cambrionix PD-Sync and Universal charging units that use the Cambrionix Very Intelligent Charging Protocol.

The Cambrionix Hub 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 Hub 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 Hub API is used to communicate with a remote network attached Cambrionix unit this is done over an SSH tunnel.

The Cambrionix Hub API supports multiple simultaneous client connections to itself and supports simultaneous access to multiple Cambrionix units.

Prerequisites

Before you can use the Cambrionix Hub API, there are a few steps and checks that need to be completed.

Direct access to USB hardware

For the Hub 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 Hub 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.

JSON-RPC library

The Hub 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.

macOS Installation

For macOS an installer is provided that will set up CambrionixApiService to run as a daemon process.

The installation can also perform all necessary steps to install and configure Python for the supplied example scripts.

Windows Installation

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 for the supplied example scripts.

Linux Installation

The Linux package comes as a Debian package which you can install either via the GUI or from the command line using apt:

$ sudo apt install ~/Downloads/cambrionix-api-setup-?????????.deb

There is also an armhf version that has been tested on oDroid and Raspberry Pi.

Command Line Options for CambrionixApiService

# -–version: Return the version of CambrionixApiService and then exit:
# Example:
$ CambrionixApiService -–version

CambrionixApiService 2.21.11
Copyright 2021 Cambrionix Ltd
http://www.cambrionix.com/

Return Codes for CambrionixApiService

The following values will be returned on exit of CambrionixApiService:

  • 0 on successful exit (i.e. on doing CambrionixApiService –-version).
  • non zero unsuccessful exit.

Logging

Log messages generated by CambrionixApiService go to syslog.

Quick Start

Some example scripts in Node.JS, C#, VB.Net, and Python are included in with the installed files. For Python, we strongly recommend using the newer asyncio example rather than the older synchronous examples.

To install the Python async api package go to examples/python/asyncio and run

pip install .

Minimal Example

Here is a minimal example of using the synchronous Hub API package, the code is written in Python 3.6:

# Import the cbrxapi library.
import sys
from cbrxapi import cbrxapi

print("Querying Hub API Version...")
try:
    result = cbrxapi.cbrx_apiversion()
except Exception as e:
    print(f"Could not communicate with API : {e}")
    result = None

if result:
    print(f"Hub API Version {result[0]}.{result[1]}")


# Call cbrx_discover with "local" to find any locally attached Cambrionix units.
# This will return a list of local Cambrionix units.
print("Discovering local devices..")
result = cbrxapi.cbrx_discover("local")
if not result or len(result) == 0:
    print("No Cambrionix unit found.")
    sys.exit(0)

print(f"Discovered {len(result)} units")

for unit_id in result:
    serial_port = cbrxapi.cbrx_discover_id_to_os_reference(unit_id)

    try:
        # Open a connection to the Cambrionix unit, which will return a handle for
        # the connection.
        handle = cbrxapi.cbrx_connection_open(unit_id)
    except Exception as e:
        print(f"Could not open connection to {unit_id} : {e}")
        handle = None

    if handle:
        # Using the handle, get the "Hardware" and "nrOfPorts" properties
        hardware = cbrxapi.cbrx_connection_get(handle, "Hardware")
        n_ports = cbrxapi.cbrx_connection_get(handle, "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(f"* {hardware} on {serial_port} has {n_ports} ports")

JavaScript Example

And another example demonstrating access from a React application. Note that the socket connection address is prefixed with ws. This allows the Hub 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 {
  lastId = 0;

  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) {
        request.callback(data);
      }
      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 = {}
  }
}

HTTP GET Example

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\"]}

Error Handling

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:
    handle = cbrxapi.cbrx_connection_open(id)
except jsonrpc.RPCFault as e:
    gotException = True
    errorCode = e.error_code
    errorMessage = e.error_message
    errorData = e.error_data

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.

Environment

The Cambrionix Hub API is implemented in CambrionixApiService, which sits between the application and the Cambrionix units. It maps the properties of the Cambrionix units into Hub API commands.

In its simplest form, it accepts socket connections on localhost:43424 and subsequent JSON-RPC request packets to which it will respond. These socket connections may also be WebSockets.

Description of Hub API Calls

The descriptions of the Hub API calls contain a sample Python call and the raw jsonrpc requests / responses as you would see them on the wire.

JSON-RPC Requests

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

Version

cbrx_apiversion

Return the interface version of the local Hub 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]
}

cbrx_apidetails

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": "release",
        "capability": [
            "protobuf",
            "crash-report",
            "notification"
        ],
        "bundled": true, // Only if run via LiveViewer bundling
        "commitid": 3298696760,
        "documentation": "/Library/Cambrionix/ApiService/doc/Cambrionix API Reference.html",
        "install": "/Library/Cambrionix/ApiService",
        "logging": "/Library/Log/Cambrionix",
        "settings": "/Library/Cambrionix/ApiService",
        "notifications": [
            "usb-changed",
            "usb-device-attached",
            "usb-device-detached",
            "discover-changed",
            "dead-hub-changed",
            "firmware-progress",
            "rfid-received",
            "rfid-removed",
            "over-temperature",
            "over-voltage",
            "under-voltage",
        ],
        "semver": "3.1.15+123",
        "version": [3, 1, 15, 123]
    }
}

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 Hub API and is used to communicate to the Recorder service. The protobuf message format may be made available at a later date.

Discovery

cbrx_discover

Discover Cambrionix units.

Input:

Returns:

Example Python call:

cbrxapi.cbrx_discover("local")

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"
    }
}

cbrx_discover_id_to_os_reference

Map a unit ID for a discovered Cambrionix unit to a device name as used by the OS.

Input:

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"
    }
}

cbrx_find

Search for devices attached to local Cambrionix units.

Input:

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
cbrxapi.cbrx_find("iPhone")

# Regex can be used too
cbrxapi.cbrx_find("i(Phone|Pad)")

# 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_find(‘Super’):

{
    "jsonrpc": "2.0",
    "id": 1234,
    "result": {
        "a7cfd7345fad329819cfad3781632ac8a65c": {
            "HostDescription": "ThunderSync3-16",
            "HostDevice": "0000034CCC2AA16",
            "HostPort": 9,
            "HostSerial": "COM31",
            "Device": {
                "VID": 1234
                "PID": 5678,
                "Manufacturer": "SuperPhone Makers Inc.",
                "Description": "SuperPhone6",
                "LocationID": 07100000,
                "DevicePath": "\\\\?\\usb#vid_1234&pid_5678#08070960a76757#{a5dcbf10-6530-11d2-901f-00c04fb951ed}",
                "SerialNumber": "08070960a76757",
                "USBVersion": 3,
                  "USBPower": {
                  "State": "D0",
                  "Description": "On"
                },
                "USBSpeed": {
                  "Speed": "480Mbps",
                  "Description": "High"
                },
                "Endpoints": {
                  "Active": 4,
                  "Memory": 16384
                }
            }
        }
    }
}

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(handle, '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 cbrx_connection_get(handle, 'PortsInfo') or cbrx_get_usbtree, and we’re simply showing everything from the point of connection upwards.

cbrx_get_usbtree

This method is deprecated in favour of cbrx_get_usb('tree'). It will never be removed.

cbrx_config_set

This function allows setting various persistent configuration options. params should be an object with key value pairs. Multiple options may be set at once.

Possible configuration values are:

{
    "jsonrpc": "2.0",
    "method": "cbrx_config_set",
    "params": {
        "battery-update-enabled": true,
        "battery-update-concurrency": 2,
        "battery-update-frequency-seconds": 60
    },
    "id": 0
}

cbrx_config_get

This function allows retrieving the configuration options set with cbrx_config_set.

{
    "jsonrpc": "2.0",
    "method": "cbrx_config_get",
    "params": ["key"],
    "id": 0
}

The return value will be as it was set via cbrx_config_set.

Connection

cbrx_connection_open

Open a connection to the Cambrionix unit specified. A successful open results in a connection handle that can be used for further calls to query information about the hub. This handle should be closed with a call to cbrx_connection_close when it is no longer required. An unsuccessful open does not need a corresponding call to cbrx_connection_close.

Open handles will automatically expire after 30 seconds of inactivity. If this occurs, further queries will return an CBRXAPI_ERRORCODE_INVALIDHANDLE error.

Input:

Returns:

Example Python call:

# Connect to local device
connectionHandle = cbrxapi.cbrx_connection_open("DB0074F5")

<!--
# Connect to remote device
connectionHandle = cbrxapi.cbrx_connection_open("EtherSync1d94a0.local.", "remote", "password")

–>

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"
    }
}

cbrx_connection_close

Close a connection to a Cambrionix unit previously opened, as specified by the connection handle.

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:

result = cbrxapi.cbrx_connection_close(connectionHandle)

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"
    }
}

cbrx_connection_getdictionary

List all tags that can return information on the Cambrionix unit specified by connectionHandle.

Input parameter:

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",
        ...
    ]
}

cbrx_connection_get

From the Cambrionix unit specified by the connection handle, get the value of the tag.

Input parameters:

Returns:

Example Python call:

value = cbrxapi.cbrx_connection_get(connectionHandle, "nrOfPorts")

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"
    }
}

cbrx_hub_get

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.

cbrx_device_get

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:

deviceSerialNumber = "123123123123"
allDevices = cbrxapi.cbrx_find("iPhone")
myDevice = allDevices[deviceSerialNumber]
if myDevice:
    handle = cbrxapi.cbrx_connection_open(myDevice["HostDevice"])
    deviceStatus = cbrxapi.cbrx_connection_get(handle, "PortInfo." + myDevice["HostPort"])
    cbrxapi.cbrx_connection_close(handle)

You can use:

deviceSerialNumber = "123123123123"
deviceStatus = cbrxapi.cbrx_device_get(deviceSerialNumber, "PortInfo")

cbrx_connection_setdictionary

List all writeable value tags and command tags for the Cambrionix unit specified by connectionHandle.

Input parameter:

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",
        ...
    ]
}

cbrx_connection_set

On the Cambrionix unit specified by the connection handle, set the tag to the value specified.

Input:

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_set(connectionHandle, "Reboot", True)

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"
    }
}

cbrx_hub_set

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.

cbrx_device_set

Like cbrx_connection_set, but instead of a handle takes the devices’s serial number as the initial argument.

Also, instead of specifying (for example) Port.N.led1, you just specify led1 because the rest is already known from the context of the device.

For example, instead of:

deviceSerialNumber = "123123123123"
allDevices = cbrxapi.cbrx_find("iPhone")
myDevice = allDevices[deviceSerialNumber]
if myDevice:
    handle = cbrxapi.cbrx_connection_open(myDevice["HostDevice"])
    if handle:
        deviceStatus = cbrxapi.cbrx_connection_set(handle, "Port." + myDevice["HostPort"] ".led1", 255)
        cbrxapi.cbrx_connection_close(handle)

You can use:

deviceSerialNumber = "123123123123"
deviceStatus = cbrxapi.cbrx_device_set(deviceSerialNumber, "led1", 255)

Note that this is a convenience function and will almost certainly be slower if you need to do multiple operations on the same hub that are separated by more than a few seconds.

cbrx_notifications

The Hub API supports sending of notifications for certain events.

For example, to enable four separate 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 examples, and the "firmware-update" one shown here.

Example of usb-device-attached notification (The same information comes with the "usb-device-detached" 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": "012a37d1fa07617ad7ef0430ba49f479ab9fb6b8",
            "USBVersion": 2,
            "VID": 1452,
        },
    }
}

Or when an RFID card is scanned on a ModIT Boss.

{
    "jsonrpc": "2.0",
    "method": "rfid-received",
    "params": "1278634123461283764"
}

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. See the examples/nodejs folder (installed with the API) for ideas about handling notifications in your code

cbrx_firmware

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

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 Hub API as an available update source
# It does not affect any connected hubs

rawBytes = myReadFileFunction("SomeCambrionixFirmwareFile.enfir")
encodedBytes = base64.b64encode(zip(rawBytes))
cbrxapi.cbrx_firmware("add", "SomeCambrionixFirmwareFile.enfir", encodedBytes)

Removing Firmware

# Example of removing firmware from Hub API storage
cbrxapi.cbrx_firmware("remove", "CambrionixFirmware-un")

Listing 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"}
# ]

Starting Firmware Update

Instruct the Hub API to initiate firmware update on a specific hub. Multiple hubs may be updated simultaneously by issuing the same command per hub. The API will deal with rebooting hubs in the correct order when they are chained.

# 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 of files keyed on the type of firmware update.

handle = cbrxapi.cbrx_connection_open("1212343456567878")

# For example, update all firmware for selected device from the firmware files provided.
cbrxapi.cbrx_firmware("update", handle, {"un": "CambrionixFirmware-un", "mc": "MotorControlFirmware-mc"})

New in 3.9.0, you can also use the serial number directly instead of the handle.

# Initiate firmware update for hub by serial number
cbrxapi.cbrx_firmware("update", "1212343456567878", {"un": "CambrionixFirmware-un", "mc": "MotorControlFirmware-mc"})

Getting Firmware Update Status

# Example of getting status of firmware update
cbrxapi.cbrx_firmware("status", handle)

Could give:

{
  "Version": "1.88.0",              // Only present after initialising stage
  "PreviousVersion": "1.79",        // Only present after initialising stage
  "Type": "charger",
  "Progress": 60,                   // Percent progress
  "Stage": "updating",
  "HostDevice": "COM3",
  "HostSerial": "1212343456567878",
  "HostDescription": "SuperSync15",
  "Started": 123123123123,          // UTC time of start
  "Ended": 123123123123             // UTC time of end time (only when status is complete)
}

An option “Error” field will be set if there was an issue at a particular stage.

  • Stage values:
    • "connecting", "initialising", "erasing", "updating", "verifying", "complete", "rebooted", "skipped"

An error during "initialising" will usually mean the wrong type of firmware was used for the selected device. For example, a firmware file suffixed with -ps is specifically for a PD-Sync, whereas suffixes of -un are for PowerPad, SuperSync, ThunderSync and ModIT style hubs.

All other errors after this stage 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.

Getting Previous Firmware Update Status

Retrieve previous firmware update results since the Hub API was running for any device.

# Example of getting status of firmware update
cbrxapi.cbrx_firmware("history", handle)

# Could give:
# {
#   "un": {
#     Version: "1.79",
#     Type: "display",
#     Progress: 60,
#     Stage: "flashing"
#   }
# }

The return value is keyed by the firmware type that was updated and includes the same results as the status command.

Getting Firmware Update Status via Notification

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™ application to show firmware update progress.

cbrx_connection_closeandlock

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 receive a CBRXAPI_ERRORCODE_LOCKED error 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:

cbrxapi.cbrx_connection_closeandlock("DB0074F5")

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"
    }
}

cbrx_connection_unlock

Unlock a Cambrionix unit that was previously locked with cbrx_connection_closeandlock. 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:

cbrxapi.cbrx_connection_unlock("DB0074F5")

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"
    }
}

cbrx_connection_cli

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

cbrxapi.cbrx_connection_cli(7654, "id")

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"
    ]
}

cbrx_pair_device

Initiate pairing of an iOS device. This is not usually necessary as it will occur automatically when the Hub API attempts to query battery information.

In both examples here, "UDID" is the phone’s USB serial number.

cbrxapi.cbrx_pair_device("UDID")

Example JSONRPC request

{
    "jsonrpc": "2.0",
    "method": "cbrx_pair_device",
    "params": ["UDID"],
    "id": 1337
}

cbrx_certificate

Supply (or remove) a certificate and private key to the Hub API to allow SSL connections from outside of localhost (the machine the Hub API is running on). Without this certificate, the Hub API will only listen for connections on localhost:43424. Once a valid certificate and private key are provided, this will change to 0.0.0.0:43424. External connections (not from localhost) will only be allowed if they are SSL connections (HTTPS or Secure WebSockets).

It is up to the user to supply a certificate that is suitable for their usage. For example, if it is not signed by a certificate authority, then you will need to deal with this in the usual way, such as signing your certificate with your own certificate autority and adding that to your application or browser. With Google Chrome you can use this guide. There are similar guides for other browsers.

Only a single certificate configuration is supported.

If a password is supplied, it is obfuscated to avoid prying eyes.

To add a certificate and private key to the API:

{
    "id": 1234,
    "jsonrpc": "2.0",
    "method": "cbrx_certificate",
    "params": [
        "set",
        {
            "private-key": <private key filename>,
            "certificate": <certificate filename>,
            "password": <optional password if required by private key>
        }
    ]
}

Remove the certificate and private from the API:

{
    "id": 1234,
    "jsonrpc": "2.0",
    "method": "cbrx_certificate",
    "params": [
        "remove"
    ]
}

cbrx_get_usb

First parameter describes the information to fetch. * tree - Psynonym for cbrx_get_usbtree. * descriptors - Get all USB descriptor information from a single USB node.

cbrx_get_usb(‘tree’)

Return the entire USB tree that has been discovered.

Returns:

  • An object containing the entire USB tree.

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. Or just view as JSON from a browser request such as: cbrx_get_usb(‘tree’)

Example Python call:

# Example output from cbrx_usbtree.py example
[{'Description': 'Intel(R) USB 3.20 eXtensible Host Controller - 1.20 (Microsoft)',
  'HostController': {'EndpointMemoryUsed': 0x25000, 'EndpointPeakMemoryUsed': 0x9b000, 'EndpointPeakTotal': 0x007d, 'EndpointTotal': 0x0021, 'Type': 'XHCI'},
  'LocationID': 0x21000000,
  'PID': 0x7ae0,
  'SerialNumber': '3&11583659&0&a0',
  'USBSpeed': {'Description': 'SuperSpeed USB 20Gbps', 'Speed': '20Gbps'},
  'USBVersion': 3.2,
  'VID': 0x8086},
 {'Description': 'TS3-C10',
  'LocationID': 0x23000000,
  'Manufacturer': 'Cambrionix',
  'PID': 0x15d3,
  'SerialNumber': 'a-2aa5366c-0-2',
  'USBSpeed': {'Description': 'SuperSpeed USB 5Gbps', 'Speed': '5Gbps'},
  'USBVersion': 3.0,
  'VID': 0x8086,
  'children': [{'Description': 'Fresco Logic USB 3.0 eXtensible Host Controller - 1.0 (Microsoft)',
                'HostController': {'EndpointMemoryUsed': 0x18000, 'EndpointTotal': 12, 'Type': 'XHCI'},
                'LocationID': 0x23000000,
                'PID': 9,
                'SerialNumber': 'c&2d6c3950&0&0000000800e4',
                'USBSpeed': {'Description': 'SuperSpeed USB 5Gbps', 'Speed': '5Gbps'},
                'USBVersion': 3.0,
                'VID': 0xca3b},
               {'Description': 'Fresco Logic USB 3.0 eXtensible Host Controller - 1.0 (Microsoft)',
                'HostController': {'EndpointMemoryUsed': 0, 'EndpointTotal': 6, 'Type': 'XHCI'},
                'LocationID': 0x24000000,
                'PID': 10,
                'SerialNumber': 'c&2cc681d1&0&0008000800e4',
                'USBSpeed': {'Description': 'SuperSpeed USB 5Gbps', 'Speed': '5Gbps'},
                'USBVersion': 3.0,
                'VID': 0xca3b,
                'children': [{'Description': 'Ultra USB 3.0',
                              'Endpoints': {'Active': 3, 'Memory': 0x6000},
                              'FlashDrive': {'Available': 0x1f2378000, 'Capacity': 0x1fffff000, 'Path': 'D:\'
                              'LocationID': 0x24300000,
                              'Manufacturer': 'SanDisk',
                              'PID': 0x5595,
                              'SerialNumber': '4C530000131105120260',
                              'USBPower': {'Description': 'On', 'State': 'D0'},
                              'USBSpeed': {'Description': 'SuperSpeed USB 5Gbps', 'Speed': '5Gbps'},
                              'USBVersion': 3.0,
                              'VID': 0x0781}]},
               {'Description': 'Fresco Logic USB 3.0 eXtensible Host Controller - 1.0 (Microsoft)',
                'HostController': {'EndpointMemoryUsed': 0, 'EndpointTotal': 3, 'Type': 'XHCI'},
                'LocationID': 0x25000000,
                'PID': 11,
                'SerialNumber': 'c&1601d69&0&0010000800e4',
                'USBSpeed': {'Description': 'SuperSpeed USB 5Gbps', 'Speed': '5Gbps'},
                'USBVersion': 3.0,
                'VID': 0xca3b,
                'children': [{'Description': 'TS3-C10',
                              'Endpoints': {'Active': 3, 'Memory': 0x3000},
                              'LocationID': 0x25200000,
                              'Manufacturer': 'Cambrionix',
                              'PID': 0x6015,
                              'SerialNumber': 'a-2aa5366c-0-2',
                              'USBPower': {'Description': 'On', 'State': 'D0'},
                              'USBSpeed': {'Description': 'Full', 'Speed': '12Mbps'},
                              'USBVersion': 2.0,
                              'VID': 0x0403,
                              'VirtualSerialPort': 'COM25'}]}]}]
cbrx_get_usb(‘descriptors’)

Request entire dump of a USB device’s descriptor information. USB Descriptors define the behaviour and capabilities of a USB device and are present for all USB devices.

This can be a lot of data for some devices (especially phones and tablets), so we won’t go into the details of it here. All variable names in the returned data match the names in Chapter 9 of the USB 3.2 specification for ease of reference.

A small example is shown here, however some devices can have very many configurations and descriptors.

An additional argument may be provided to output an additional RawBytes member for each descriptor (except for string descriptors). This output can either be hex or base64 encoded by specifying "hex" or "base64".

Each descriptors raw fields (as taken from the USB 3.2 spec) are represented first, and where appropriate an additional "Derived" member will be present that shows bitfields or resolved string descriptors. For example, on the device’s main descriptor there is an iManufacturer field, which is the index of the string descriptor used for that name. This will also be present in Derived.Manufacturer.

{
    "jsonrpc": "2.0",
    "method": "cbrx_get_usb",
    "params": ["descriptors", "123456789abcdef"],
    "id": 1337
}

Output from a standard USB flash drive:

{
  "jsonrpc": "2.0",
  "id": 0,
  "result": {
    "RawBytes": "120120030000000951092b17010001020301",
    "bLength": 18,
    "bDescriptorType": 1,
    "bNumConfigurations": 1,
    "bcdUSB": 800,
    "bDeviceClass": 0,
    "bDeviceSubClass": 0,
    "bDeviceProtocol": 0,
    "bMaxPacketSize0": 9,
    "idVendor": 2385,
    "idProduct": 5931,
    "bcdDevice": 1,
    "iManufacturer": 1,
    "iProduct": 2,
    "iSerialNumber": 3,
    "Derived": {
      "DescriptorType": "Device",
      "CurrentConfiguration": 1,
      "DeviceClass": "Reserved"
    },
    "Configurations": {
      "1": [
        {
          "RawBytes": "09022c00010100ff8025",
          "bLength": 9,
          "bDescriptorType": 2,
          "wTotalLength": 44,
          "bConfigurationValue": 1,
          "bmAttributes": 128,
          "bNumDescriptors": 1,
          "iConfiguration": 0,
          "reserved1": 0,
          "reserved2": 1,
          "SelfPowered": 0,
          "Derived": {
            "DescriptorType": "Configuration",
            "MaxPower": 37,
            "RemoteWakeUp": 0,
            "BusPowered": 0
          }
        },
        {
          "RawBytes": "090400000208065000",
          "bLength": 9,
          "bDescriptorType": 4,
          "iInterface": 0,
          "bInterfaceNumber": 0,
          "bAlternateSetting": 0,
          "bNumEndpoints": 2,
          "bInterfaceClass": 8,
          "bInterfaceSubClass": 6,
          "bInterfaceProtocol": 80,
          "Derived": {
            "DescriptorType": "Interface"
          }
        },
        {
          "RawBytes": "0705ff8102000400",
          "bLength": 7,
          "bDescriptorType": 5,
          "bInterval": 0,
          "bEndpointAddress": 129,
          "bmAttributes": 2,
          "wMaxPacketSize": 1024,
          "Derived": {
            "DescriptorType": "Endpoint",
            "EndpointAddress": 1,
            "Direction": "In",
            "Type": "Bulk"
          }
        },
        {
          "RawBytes": "06300f000000",
          "bLength": 6,
          "bDescriptorType": 48,
          "wBytesPerInterval": 0,
          "bMaxBurst": 15,
          "bmAttributes": 0,
          "Derived": {
            "DescriptorType": "SuperSpeedEndpointCompanion",
            "MaxStreams": 0,
            "Mult": 0,
            "SspCompanion": 0
          }
        },
        {
          "RawBytes": "07050202000400",
          "bLength": 7,
          "bDescriptorType": 5,
          "bInterval": 0,
          "bEndpointAddress": 2,
          "bmAttributes": 2,
          "wMaxPacketSize": 1024,
          "Derived": {
            "DescriptorType": "Endpoint",
            "EndpointAddress": 2,
            "Direction": "Out",
            "Type": "Bulk"
          }
        },
        {
          "RawBytes": "06300f000000",
          "bLength": 6,
          "bDescriptorType": 48,
          "wBytesPerInterval": 0,
          "bMaxBurst": 15,
          "bmAttributes": 0,
          "Derived": {
            "DescriptorType": "SuperSpeedEndpointCompanion",
            "MaxStreams": 0,
            "Mult": 0,
            "SspCompanion": 0
          }
        }
      ]
    },
    "Strings": {
      "1": "Kingston",
      "2": "DataTraveler 70",
      "3": "1831BFBD3065F551C96001E7"
    },
    "BOS": {
      "RawBytes": "050f160002",
      "bLength": 5,
      "bDescriptorType": 15,
      "Derived": {
        "DescriptorType": "BOS"
      },
      "wTotalLength": 22,
      "bNumDescriptors": 2,
      "Capabilities": [
        {
          "RawBytes": "07100206000000",
          "bLength": 7,
          "bDescriptorType": 16,
          "bDevCapabilityType": 2,
          "bmAttributes": 6,
          "Derived": {
            "DescriptorType": "DeviceCapability",
            "CapabilityType": "USB20Extension",
            "LPMCapable": 1,
            "BESLAndAlternateHIRDSupported": 1,
            "BaselineBESLValid": 0,
            "DeepBESLValid": 0,
            "BaselineBESL": 0,
            "DeepBESL": 0
          }
        },
        {
          "RawBytes": "0a1003000e00020affff07",
          "bLength": 10,
          "bDescriptorType": 16,
          "bDevCapabilityType": 3,
          "wU2DevExitLat": 2047,
          "bmAttributes": 0,
          "wSpeedsSupported": 14,
          "bFunctionalitySupport": 2,
          "bU1DevExitLat": 10,
          "Derived": {
            "DescriptorType": "DeviceCapability",
            "CapabilityType": "SuperSpeedUSB",
            "LTMCapable": 0,
            "SpeedsSupported": [
              "Full",
              "High",
              "SuperSpeed"
            ]
          }
        }
      ]
    }
  }
}

Local or Remote

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 Hub 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 Hub API but is instead connected to a network that is accessible from the machine which is running the Hub 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 Hub API to distinguish local or remote and so other calls do not need to specify the location.

U8S and U8S-EXT

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 Hub 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 Hub API.

Docks

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.

Dynamic Hubs

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'

handleA = cbrxapi.cbrx_connection_open("AAAA")
handleB = cbrxapi.cbrx_connection_open("BBBB")
handleC = cbrxapi.cbrx_connection_open("CCCC")
handleABC = cbrxapi.cbrx_connection_open("Dynamic:AAAA:BBBB:CCCC")

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.

Dictionaries

For each Cambrionix unit, the Hub API can return two dictionaries:

The keys returned depend on the feature set(s) supported by the unit.

Feature Sets

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
ThunderSync3-C10 yes1 yes yes

1 It is to be noted that while the chargers with TypeC connections are always in sync mode unless the ports are turned off. 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.

Get Dictionary

Key Feature set
Attached 5V
Compiled base
EnabledProfiles 5V
Firmware base
FirmwareRequirements base
FiveVoltRail_flags 5V
FiveVoltRail_Limit_Max_V 5V
FiveVoltRail_Limit_Min_V 5V
FiveVoltRail_V 5V
FiveVoltRailMax_V 5V
FiveVoltRailMin_V 5V
Gates gate
Group base
Hardware base
HardwareFlags base
HardwareInformation base
Health base
HostPresent sync, PD
InputRail_flags PD
InputRail_Limit_Max_V PD
InputRail_Limit_Min_V PD
InputRail_V PD
InputRailMax_V PD
InputRailMin_V PD
Key.N 5V
ModeChangeAuto sync
nrOfPorts base
PanelID base
Port.N.Battery sync
Port.N.Current_mA base
Port.N.Description sync, PD
Port.N.Energy_Wh base
Port.N.FlashDrive sync
Port.N.Mode base
Port.N.Flags base
Port.N.LocationID sync
Port.N.Manufacturer sync, PD
Port.N.PID sync, PD
Port.N.ProfileID 5V
Port.N.Profiles 5V
Port.N.SerialNumber sync, PD
Port.N.TimeCharged_sec base
Port.N.TimeCharging_sec base
Port.N.USBStrings sync, PD
Port.N.VID sync, PD
Port.N.Voltage_10mV PD
Port.all.LocationID sync
PortInfo.N base
PortsInfo base
Profile.N.enabled 5V
pwm_percent temperature
Rebooted base
SecurityArmed 5V
SystemTitle base
Temperature_C temperature
Temperature_flags temperature
Temperature_Limit_Max_C temperature
TemperatureMax_C temperature
TotalCurrent_mA 5V
TotalPower_W 5V
TwelveVoltRail_flags 12V
TwelveVoltRail_Limit_Max_V 12v
TwelveVoltRail_Limit_Min_V 12v
TwelveVoltRail_V 12V
TwelveVoltRailMax_V 12V
TwelveVoltRailMin_V 12V
Uptime_sec base

Get Dictionary Variables

Get Attached

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

Get Compiled

Timestamp of firmware version.

Example return value:

"Jul 08 2015 10:43:20"

Get EnabledProfiles

List of global profiles currently enabled

Example return value:

"1 2 3 4"

Get Firmware

Firmware version string

Example return value:

"1.55"

Get FirmwareRequirements

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"
    }
]

Get FiveVoltRail_flags

Returns list of 5V supply rail error flags that have been detected, if any.

  • UV – under voltage occurred.
  • OV – over voltage occurred.
  • UV OV - Both under and over voltage occurred.
  • empty – voltage is acceptable.

Example return value:

""

Get FiveVoltRail_Limit_Max_V

Upper limit of the 5V rail that will trigger the error flag.

Example return value:

5.58

Get FiveVoltRail_Limit_Min_V

Lower limit of the 5V rail that will trigger the error flag

Example return value:

3.5

Get FiveVoltRail_V

Current 5V supply voltage in Volt (V)

Example return value:

5.25

Get FiveVoltRailMax_V

Highest 5V supply voltage seen in Volt (V)

Example return value:

5.25

Get FiveVoltRailMin_V

Lowest 5V supply voltage seen in Volt (V)

Example return value:

5.2

Get Gates

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"
}

Get Group

Group letter read from PCB jumpers, or “–” if no group jumper was fitted.

Example return value:

"-"

Get Hardware

Type of the Cambrionix unit such as “U8S-EXT”, “PP15”, “PS15-USB3”, “ThunderSync3-16”.

Example return value:

"ThunderSync3-16"

Get HardwareFlags

Flags indicating whether features are present

  • S = Sync feature set
  • L = 5V feature set
  • E = 12V feature set
  • T = Temperature feature set
  • P = PD feature set

Example return value:

"SLET"

Get HardwareInformation

Static information related to the hub. This is fixed information, such as dimensions, web page, or port connector types.

Example return value:

{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "ProductName": "ThunderSync3-C10",
    "ProductWebPage": "https://www.cambrionix.com/products/thundersync3-c10",
    "TemperatureRangeC": {
      "Min": 10,
      "Max": 35
    },
    "HumidityRange": {
      "Min": 5,
      "Max": 95
    },
    "DimensionsMillimetres": {
      "Width": 136,
      "Length": 193,
      "Height": 34
    },
    "HostPortType": "Thunderbolt 3",
    "HostPortBandwidth": "40Gbps",
    "HubMaxPowerOutputWatts": 150,
    "Ports": {
      "1": {
        "HardwareInformation": {
          "Type": "USB Type-C",
          "Bandwidth": "5Gbps",
          "VoltageMax": 5.2,
          "MilliampsMax": 3000
        }
      },
      // etc for each port
    }
  }
}

Get Health

All available keys that are not port specific and change dynamically, as a dictionary.

Get HostPresent

Host is connected to the Cambrionix unit

Example return value:

true

Get InputRail_flags

List of input rail error flags if any are set.

  • UV – under voltage occurred
  • OV – over voltage occurred
  • no flags – voltage is acceptable

Example return value:

"OV UV"

Get InputRail_Limit_Max_V

Upper limit of the input rail that will trigger the error flag

Example return value:

24.7

Get InputRail_Limit_Min_V

Lower limit of the input rail that will trigger the error flag.

Example return value:

9.59

Get InputRail_V

Current input rail supply in Volts (V).

Example return value:

24.03

Get InputRailMax_V

Highest input voltage seen in Volts (V).

Example return value:

24.14

Get InputRailMin_V

Lowest input voltage seen in Volts (V).

Example return value:

23.82

Get Key.N

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

Get ModeChangeAuto

Mode change from Charge to Sync is automatic.

Example return value:

true

Get nrOfPorts

Number of USB ports on the Cambrionix unit.

Example return value:

8

Get PanelID

PanelID number of front panel board, if fitted, or “Absent”/“None”.

Example return value:

"Absent"

Get Port.N.Battery

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,
}

Note that battery information may only be available after a device is paired or trusted with the host computer. If this does not occur automatically, you can use cbrx_pair_device(UDID). Where UDID is the USB serial number of the device.

Get Port.N.Current_mA

Current being delivered to the USB device connected to this USB port in milli-Amperes (mA).

Example return value:

0

Get Port.N.Description

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"

Get Port.N.Energy_Wh

Energy the USB device on this USB port has consumed in Watt-hours (calculated every second).

Example return value:

0.0

Get Port.N.FlashDrive

If detected, returns the mount point of a USB flash drive. For Windows this will be a drive letter, otherwise it will be a volume mount point.

As of Hub API version 3.10.0, the addition of the "Volumes" field will list all the volumes of the drive in addition to the first discovered volume prior to 3.10.0.

Example return values:

# Windows
{
    "Path:": "H:\\",
    "Capacity": 123123123,
    "Available": 123123,
    "Volumes": [
        {
            "Path:": "H:\\",
            "Capacity": 123123123,
            "Available": 123123,
            "Label": "Volume Label 1",
            "Index": 1,
            "FileSystem": "exFAT"
        },
        {
            "Path:": "I:\\",
            "Capacity": 123123123,
            "Available": 123123,
            "Label": "Volume Label 2",
            "Index": 2,
            "FileSystem": "NTFS"
        }
    ]
}

# macOS
{
    "Path:": "/Volumes/Volume\ Label\ 1",
    "Capacity": 123123123,
    "Available": 123123,
    "Volumes": [
        {
            "Path:": "/Volumes/Volume\ Label\ 1",
            "Capacity": 123123123,
            "Available": 123123,
            "Label": "Volume Label 1",
            "Index": 1,
            "FileSystem": "exFAT"
        },
        {
            "Path:": "/Volumes/Volume\ Label\ 2",
            "Capacity": 123123123,
            "Available": 123123,
            "Label": "Volume Label 2",
            "Index": 2,
            "FileSystem": "NTFS"
        }
    ]
}

# Linux
{
    "Path:": "/media/bob/Volume\ Label\ 1",
    "Capacity": 123123123,
    "Available": 123123,
    "Volumes": [
        {
            "Path:": "/media/bob/Volume\ Label\ 1",
            "Capacity": 123123123,
            "Available": 123123,
            "Label": "Volume Label 1",
            "Index": 1,
            "FileSystem": "exFAT"
        },
        {
            "Path:": "/media/bob/Volume\ Label\ 2",
            "Capacity": 123123123,
            "Available": 123123,
            "Label": "Volume Label 2",
            "Index": 2,
            "FileSystem": "NTFS"
        }
    ]
}

If there is no flash drive, the return value will simply be false.

This same information will also be provided in PortsInfo, PortInfo.N or cbrx_discover('all') in a "FlashDrive" field where applicable and present. If not applicable or preset, this field will be absent.

Get Port.N.LocationID

Return the location ID for a specific port. This does not require a device to be attached and so may be used to uniquely identify a USB slot.

Note that for USB3 hubs, this location ID will be different when a USB3 device is plugged in compared to a USB2 device.

Location IDs indicate the bus number that a USB host controller is on in the first byte, then the port numbers down the tree for child devices.

Example return values (shown in hex as it makes more sense that way):

# Bus 21, port 2, port 1
0x21210000

# In this case, the parent hub for the device would be 0x21200000.

Get Port.N.Mode

Current port mode, using the same characters that #set-port.n.mode will use them to change the mode.

For Standard USB hubs, the mode can be any of:

  • s - Sync mode
  • c - Charge mode
  • b - Biassed mode
  • o - Off

For Type-C hubs, the mode can be:

  • c - On
  • o - Off

Get Port.N.Flags

Port flags separated by spaces.

  • O S B I P C F are mutually exclusive
    • O = USB port Off
    • S = USB port in Sync mode (can only be returned on devices that implement the sync feature set).
    • B = USB port in Biased mode.
    • I = USB port in charge mode and Idle.
    • P = USB port in charge mode and Profiling.
    • C = USB port in charge mode and Charging.
    • F = USB port in charge mode and has Finished charging
  • A D are mutually exclusive
    • A = a USB device is Attached to this USB port
    • D = Detached, no USB device is attached
  • e = Errors are present
  • R = system has been Rebooted
  • r = Vbus is being reset during mode change

Example return value:

"R D S"

Get Port.N.Manufacturer

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

Get Port.N.PID

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

Get Port.N.ProfileID

Profile ID number, or 0 if not charging.

Example return value:

0

Get Port.N.Profiles

List of enabled profiles for this port.

Example return value:

"1 2 3 4"

Get Port.N.SerialNumber

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"

Get Port.N.TimeCharged_sec

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 charging completed.

Get Port.N.TimeCharging_sec

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

Get Port.N.USBStrings

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."
}

Get Port.N.VID

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

Get Port.N.Voltage_10mV

Voltage being supplied to the port in 10mV.

Example return value:

520

Get Port.all.LocationID

Retreives an object containing port location IDs for the entire hub.

The advantage over port info is that no device needs to be connectd to a port to know beforehand which location IDs would be valid for the slot.

This request:

{
  "id": 5,
  "jsonrpc": "2.0",
  "method": "cbrx_connection_get",
  "params": [
    handle,
    "Port.all.LocationID"
  ]
}

Could produce:

{
  "jsonrpc": "2.0",
  "id": 5,
  "result": {
    "1": {
      "USB2": 591466496,
      "USB3": 3812691968
    },
    "2": {
      "Current": 591470592,
      "USB2": 591470592,
      "USB3": 3812696064
    },
    "3": {
      "USB2": 591597568,
      "USB3": 3812823040
    },
    "4": {
      "Current": 591601664,
      "USB2": 591601664,
      "USB3": 3812827136
    }
  }
}

And for the same hub, this request:

{
  "id": 5,
  "jsonrpc": "2.0",
  "method": "cbrx_connection_get",
  "params": [
    handle,
    "Port.all.LocationID",
    "USB2"
  ]
}

Could produce:

{
  "jsonrpc": "2.0",
  "id": 5,
  "result": {
    "1": 591466496,
    "2": 591470592,
    "3": 591597568,
    "4": 591601664
  }
}

Get PortInfo.N

Get all port information for specified port.

All available keys and values for this port as a dictionary.

Get PortsInfo

Get all port information for all ports.

All available information for all ports as a dictionary of dictionaries.

Trimmed example of information returned by cbrx_connection_get('PortsInfo') if a device was connected to port 1. Most of these values can be queried individually such as Port.1.SerialNumber or Port.1.Current_mA for example.

{
  "Port.1": {
    "Port": 1,
    "Current_mA": 22,
    "Flags": "R A S",
    "LocationID": 591470592,
    "USBVersion": 2.0,
    "VID": 1452,
    "PID": 4779,
    "Manufacturer": "SuperPhone Makers Inc.",
    "Description": "SuperPad",
    "SerialNumber": "c13d62e0c8bef04ff4b48b4748b020be76725d5d",
    "DeviceType": "Apple" | "Android",  // Currently only present for "Apple" and "Android" devices
    "Battery": {
      "DataSource": "imobiledevice",
      "TrustLevel": "paired",
      "PairingSupported": true,
      "HealthPercent": 95,
      "CurrentLevel": 100,
      "CurrentTime": 1613056296,
      "StartingLevel": 100,
      "StartingTime": 1613056293,
      "CapacityNew": 1751,
      "Capacity": 1678,
      "ChargingStatus": "full"
    },
    "USBTree": {
      "LocationID": 591470592,
      "USBVersion": 2.0,
      "USBPower": {
        "State": "D0",
        "Description": "On"
      },
      "USBSpeed": {
        "Speed": "480Mbps",     // Currently any of "1.5Mbps", "12Mbps", "480Mbps", "5Gbps", "10Gbps", "20Gbps", "40Gbps"
        "Description": "High"   // Any of "Low", "Full", "High",
                                // "SuperSpeed USB 5Gbps", "SuperSpeed USB 10Gbps", "SuperSpeed USB 20Gbps",
                                // "SuperSpeed USB 40Gbps", "USB4® 10Gbps", "USB4® 20Gbps", "USB4® 40Gbps"
      },
      "Endpoints": {
        "Active": 6,
        "Maximum": 8,
        "Memory": 32768         // Amount of memory used (in bytes) for this node on the USB tree
      },
      "USBConnectionError": "string", // Only present on Windows if a device error occurs
                                // "DeviceFailedEnumeration" | "DeviceGeneralFailure" |
                                // "DeviceCausedOvercurrent" | // "DeviceNotEnoughPower" |
                                // "DeviceNotEnoughBandwidth" | "DeviceHubNestedTooDeeply" |
                                // "DeviceInLegacyHub" | "DeviceEnumerating" | "DeviceReset",
      "USBErrors": [    // Only present if any errors are detected
        // Errors can be any of the following:
        "No open pipes : USB stack has not loaded the device",
        "Invalid Device Descriptor : bLength was <N> instead of 18",
        "Invalid Device Descriptor : Low speed devices require bMaxPacketSize0 = 8 (<N> was given)",
        "Invalid Device Descriptor : Full Speed devices require bMaxPacketSize0 = 8, 16, 32, or 64 (<N> was given)",
        "Invalid Device Descriptor : High Speed devices require bMaxPacketSize0 = 64 (<N> was given)",
        "Invalid Device Descriptor : SuperSpeed devices require bMaxPacketSize0 = 9 (512) (<N> was given)",
        "Invalid Device Descriptor : SuperSpeed device reporting less than USB 3.0",
        "Invalid Device Qualifier Descriptor : bLength was <N> instead of 10",
        "Invalid Other Speed Configuration Descriptor : bLength was <N> instead of 10",
        "Invalid Configuration Descriptor : bLength was <N> instead of 9",
        "Invalid Interface Descriptor : bLength was <N> instead of 9 or 11",
        "Invalid Endpoint Descriptor : bLength was <N> instead of 7 or 8",
        "Invalid HID Descriptor : bLength was <N> instead of >= 9",
        "Invalid OTG Descriptor : bLength was <N> instead of 3",
        "Invalid InterfaceAssociation Descriptor : bLength was <N> instead of 8",
        "Invalid BOS SuperSpeedUSB Descriptor : bLength was <N> instead of 10",
        "Invalid BOS SuperSpeedPlusUSB Descriptor : bLength was <N> instead of >= 16",
        "Invalid BOS Billboard Descriptor : bLength was <N> instead of >= 48",
        "Invalid BOS ContainerID Descriptor : bLength was <N> instead of 20",
        "Invalid BOS FirmwareStatus Descriptor : bLength was <N> instead of 8",
        "Invalid BOS PDConsumerPort Descriptor : bLength was <N> instead of 24",
        "Invalid BOS Platform Descriptor : bLength was <N> instead of >= 21",
        "Invalid BOS PowerDelivery Descriptor : bLength was <N> instead of 18",
        "Invalid BOS USB20Extension Descriptor : bLength was <N> instead of 7"
      ]

    }
  },
  "Port.2": {
    "Port": 2,
    "Current_mA": 0,
    "Flags": "R D S",
    "LocationID": 591597568
  },
  "Port.3": ...
}

Get Profile.N.enabled

Is global profile n enabled?

Example return value:

false

Get pwm_percent

Fan speed.

Example return value:

100

Get Rebooted

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

Get SecurityArmed

Is security armed?

Example return value:

false

Get SystemTitle

The system identification text.

Example return value:

"cambrionix U8S-EXT 8 Port USB Charge+Sync"

Get Temperature_C

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

Get Temperature_flags

Temperature error flags:

  • OT – over temperature event has occurred.
  • empty - temperature is acceptable

Example return value:

""

Get Temperature_Limit_Max_C

Upper limit of the acceptable temperature range that will trigger the error flag.

Example return value:

65.0

Get TemperatureMax_C

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

Get TotalCurrent_mA

Total current in mA for all USB ports.

Example return value:

0

Get TotalPower_W

Total power being consumed on all USB ports in Watts (W).

Example return value:

3.4

Get TwelveVoltRail_flags

List of 12V supply rail error flags.

  • “UV” – under voltage occurred
  • “OV” – over voltage occurred
  • “OV UV” – both over and under voltage occurred
  • “” - voltage is acceptable

Example return value:

""

Get TwelveVoltRail_Limit_Max_V

Upper limit of the 12V rail that will trigger the error flag.

Example return value:

14.5

Get TwelveVoltRail_Limit_Min_V

Lower limit of the 12V rail that will trigger the error flag.

Example return value:

9.59

Get TwelveVoltRail_V

Current 12V supply voltage in Volts (V).

Example return value:

12.43

Get TwelveVoltRailMax_V

Highest 12V supply voltage seen.

Example return value:

12.52

Get TwelveVoltRailMin_V

Lowest 12V supply voltage seen in Volts (V).

Example return value:

12.31

Get Uptime_sec

Time in seconds the Cambrionix unit has been running since the last reset.

Example return value:

151304

Get USBTree

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.

Set Dictionary

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
Port.N.RebootDevice sync
ProfileEnable.n 5V
Reboot base
RebootDevices sync
RemoteControl base
RGBControl gate
SecurityArmed 5V
Temperature.OverTemperature temperature
TwelveVoltRail.OverVoltage 12V
TwelveVoltRail.UnderVoltage 12V

Set Mode

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:

  • c - charge mode
  • s - sync mode
  • b - biased mode
  • o - off

With Python, this could be

# Example - setting all ports to sync mode
cbrx_connection_set(handle, 'Mode', 's')

Or with JSON-RPC

{
    "id": 0,
    "jsonrpc": "2.0",
    "method": "cbrx_connection_set",
    "params": [
        handle,
        "Mode",
        "s"
    ]
}

Set Port.N.mode

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:

  • c - charge mode
  • s - sync mode
  • b - biased mode
  • o - off

With Python, this could be

# Example - setting port 1 to charge mode
cbrx_connection_set(handle, 'Port.1.mode', 'c')

Or with JSON-RPC

{
    "id": 0,
    "jsonrpc": "2.0",
    "method": "cbrx_connection_set",
    "params": [
        handle,
        "Port.1.Mode",
        "c"
    ]
}

Set Port.N.led1

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
cbrx_connection_set(handle, 'Port.1.led1', 170) # 170 = 0b10101010

Or with JSON-RPC

{
    "id": 0,
    "jsonrpc": "2.0",
    "method": "cbrx_connection_set",
    "params": [
        handle,
        "Port.1.led1",
        170
    ]
}

Set Port.N.led2

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
cbrx_connection_set(handle, 'Port.1.led2', 240) # 240 = 0b11110000

Or with JSON-RPC:

{
    "id": 0,
    "jsonrpc": "2.0",
    "method": "cbrx_connection_set",
    "params": [
        handle,
        "Port.1.led2",
        240
    ]
}

Set Port.N.led3

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
cbrx_connection_set(handle, 'Port.1.led3', 255) # 255 = 0b11111111

Or with JSON-RPC:

{
    "id": 0,
    "jsonrpc": "2.0",
    "method": "cbrx_connection_set",
    "params": [
        handle,
        "Port.1.led3",
        255
    ]
}

Set Port.N.leds

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
led1 = 0b10101010
led2 = 0b11001100
led3 = 0b00111100
pattern = led1 << 16 | led2 << 8 | led3         # 11,193,404
cbrx_connection_set(handle, 'Port.1.led34', pattern)

Or with JSON-RPC:

{
    "id": 0,
    "jsonrpc": "2.0",
    "method": "cbrx_connection_set",
    "params": [
        handle,
        "Port.1.leds",
        11193404
    ]
}

Set Port.N.RGB

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"
cbrx_connection_set(handle, 'Port.1.RGB', "#FFFF00")

# or at half intensity
cbrx_connection_set(handle, 'Port.1.RGB', "#FFFF0080")

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 Port.N.profiles

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
cbrx_connection_set(handle, "Port.1.profiles", "1,2,3")

Or with JSON-RPC:

{
    "id": 0,
    "jsonrpc": "2.0",
    "method": "cbrx_connection_set",
    "params": [
        handle,
        "Port.1.profiles",
        "1,2,3"
    ]
}

Set Port.N.RebootDevice

Reboot the device attached to the specified port.

Note that the device must be either an iOS or Android device. If an iOS device it must have been previously paired to the host computer. If an Android device, it must have USB debugging enabled and previously trusted the host computer.

Set Port.N.gate

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
cbrx_connection_set(handle, "Port.1.gate", "open")

Or with JSON-RPC:

{
    "id": 0,
    "jsonrpc": "2.0",
    "method": "cbrx_connection_set",
    "params": [
        handle,
        "Port.1.gate",
        "open"
    ]
}

Set ClearLCD

Clear the LCD.

# Python example
cbrx_connection_set(handle, "ClearLCD")

Set LCDText.ROW.COL

Write the string on the LCD at (row, column). Row and column are zero based.

# Python example
cbrx_connection_set(handle, "LCDText.0.0", "Hello World!")

Set RemoteControl

Enable / disable controlling of the unit controls. This will allow the LEDs or LCD to be updated or panel button pushes to be detected.

Allowed values: true | false | “auto”

# Python example
cbrx_connection_set(handle, "RemoteControl", true)

Set RGBControl

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
        }
    ]
}

Set SecurityArmed

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
cbrx_connection_set(handle, "SecurityArmed", true)

Set Beep

Beep for the number of milliseconds passed in.

Arguments: integer

# Python example - beep for 1/4 sec
cbrx_connection_set(handle, "Beep", 250)

Set ClearRebootFlag

Clear the reboot flag.

Arguments: true

# Python example
cbrx_connection_set(handle, "ClearRebootFlag", true)

Set ClearErrorFlags

Clear all error flags

Arguments: true

# Python example
cbrx_connection_set(handle, "ClearErrorFlags", true)

Set Reboot

Reboot the hub now. The Hub API will attempt to re-establish connection automatically, but you should not expected to receive updated results for several seconds.

Arguments: true

# Python example
cbrx_connection_set(handle, "Reboot", true)

Set RebootDevices

Reboot all of the devices attached to the hub.

Note that the devices must be either an iOS or Android devices. If iOS devices they must have been previously paired to the host computer. If Android devices, they must have USB debugging enabled and previously trusted the host computer.

Set FiveVoltRail.OverVoltage

Force the behaviour of a 5V over voltage condition.

Arguments: true

# Python example
cbrx_connection_set(handle, "FiveVoltRail.OverVoltage", true)

Set FiveVoltRail.UnderVoltage

Force the behaviour of a 5V under voltage condition.

Arguments: true

# Python example
cbrx_connection_set(handle, "FiveVoltRail.UnderVoltage", true)

Set TwelveVoltRail.OverVoltage

Force the behaviour of a 12V over voltage condition.

This is the same as TwelveVoltRail is the same as InputRail.

Arguments: true

# Python example
cbrx_connection_set(handle, "TwelveVoltRail.OverVoltage", true)

Set TwelveVoltRail.UnderVoltage

Force the behaviour of a 12V under voltage condition.

This is the same as TwelveVoltRail is the same as InputRail.

Arguments: true

# Python example
cbrx_connection_set(handle, "TwelveVoltRail.UnderVoltage", true)

Set InputRail.OverVoltage

Force the behaviour of an input rail over voltage condition.

Arguments: true

# Python example
cbrx_connection_set(handle, "InputRail.OverVoltage", true)

Set InputRail.UnderVoltage

Force the behaviour of an input rail under voltage condition.

Arguments: true

# Python example
cbrx_connection_set(handle, "InputRail.UnderVoltage", true)

Set Temperature.OverTemperature

Force the behaviour of an over temperature condition.

Arguments: true

# Python example
cbrx_connection_set(handle, "Temperature.OverTemperature", true)

Set ProfileEnable.n

Enable or disable the global profile n

Arguments: boolean

# Python example, enabling profile 1
cbrx_connection_set(handle, "ProfileEnable.1", true)

Socket connections

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 Hub API and keeping this socket open until you wish to stop using the Hub API. Keeping the socket open for the lifetime of your communication with the Hub API will reduce the load on the system and lead to shorter communication cycles with the Hub 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 Hub API will only accept connections from the local machine, unless a certificate has been provided. External connections must thereafter be secure types, such as https or wss.

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"]}

Timeouts

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

Controlling the LEDs

The Hub 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 Hub API this automatic control must be disabled and this is done by setting the “RemoteControl” key to be ‘True’.

result = cbrxapi.cbrx_connection_set(handle, "RemoteControl", True)

If you wish to return control of the LEDs to the automatic control then you simply set “RemoteControl” to be ‘False’.

result = cbrxapi.cbrx_connection_set(handle, "RemoteControl", False)

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.

Battery Information

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.

Android

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
# Start the adb service with
adb start-server

Limitations

The Hub API provides a means of controlling most of the features of Cambrionix Universal devices, however there are some limitations.

The Hub API does not currently support:

The LiveViewer Recorder Service

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.

Cambrionix Hub API JSON-RPC Error codes

Code Value Description
CBRXAPI_ERRORCODE_IDNOTFOUND -10001 The unit ID passed in does not represent a Cambrionix unit or it has been disconnected since discovery was last run.
CBRXAPI_ERRORCODE_KEYNOTFOUND -10003 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 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 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, or has expired due to 30 seconds of inactivity.
CBRXAPI_ERRORCODE_TIMEOUT -10006 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 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 Hub 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.
CBRXAPI_ERRORCODE_CONNECTION_ERROR -10014 Could not open the serial port connection to the hub.
CBRXAPI_ERRORCODE_INVALID_DYNAMIC_NAME -10015 Invalid Dynamic hub name.
CBRXAPI_ERRORCODE_LOCKED -10016 Hub is locked via cbrx_connection_closeandlock.

Revision history

Version Changes

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