The purpose of this document is to outline a standardised API for integrating different cell testing devices into the kCharge Control software. This specification will focus on integrating a cell testing device with the kCharge Control backend server and will not include any part of the front end or front end API.
Protocol Version: 1 [DRAFT]
The kCharge Control protocol is web socket based. Websockets were specifically chosen over socket.io due to the easier implementation on embedded microcontroller platforms. The protocol is a defined set of JSON messages to send data to the kCharge Control backend server, and to send control messages to testing devices.
- Each websocket message must contain exactly one kCharge Control packet.
- The kCharge Control server should ignore any packets that don't meet the specification.
- The kCharge Control server may attempt to log or display an error message if it receives a packet that doesn't meet the specification.
- The kCharge Control server should treat malformed JSON as a packet that doesn't meet the specification but may process the packet if the JSON can be parsed and the resulting object meets the specification.
- Any breaking changes or updates to the specification must result in an increase to the protocol version.
- A kCharge Protocol parser should check the version number and refuse to parse a packet if it does not match the expected value(s).
- The protocol is designed to be mostly stateless and there is no requirement for acknowledgements etc.
- A device can be fully automated and the kCharge backend server / UI is simply monitoring a device, the device can be fully controlled by the kCharge backend server / UI, or a mixture of both.
A kCharge Control packet is defined as a single JSON object that follows the format below. Each packet's example object must be put in the payload
key to form a valid kCharge Control packet. The deviceId
must be unique and must be included in all packets to and from a device.
{
"version": 1,
"command": "commandName",
"deviceId": "1",
"payload": {}
}
The kCharge Control protocol defines an auto discovery mechanism to help testing devices discover a kCharge Control server on the local network. A testing device should implement auto discovery, but if it chooses not to, this section may be ignored. This is separate from the auto discovery method implemented by the kCharge app that uses mDNS (ie Bonjour/Zeroconf) for discovery and socket.io for communication.
The auto discovery mechanism works as follows:
- There must be no more than one kCharge Control backend server on a network. The behaviour of multiple backend servers on a network is undefined.
- Every 3-10 seconds the kCharge Control server must send out a
hello
packet to the broadcast address on port54321
. - Once a testing device receives a
hello
packet, it should attempt to open a websocket connection to the IP address and port included in thehello
packet. - A testing device must send a
helloServer
packet before any other packets after opening a websocket connection. - A kCharge backend server may choose to close the websocket connection, or, wait for a valid
helloServer
packet before attempting to parse any more packets from that device.
Each command definition below is a valid kCharge Control command. Any commands not listed below must be ignored. The title of each command definition should be used in the command
key and the object listed under each title should be used in the payload
key of the kCharge Control Packet. Each command should only be sent to the devices listed under each command (ie only to server or only to a device).
A device
is a battery cell charger/discharger etc. that is connecting to a kCharge Control backend.
--
Sent to: device
{
"serverHost": "192.168.0.42:12345",
"time": 1608127015,
"serverName": "name_of_server"
}
websocketHost
is the full host and port that should be connected to via a websocket.apiHost
is the full host and port that other devices (ie frontend/app) can use to connect via the HTTP API.time
is the current time in seconds since the unix epoch and may be used by a device.serverName
is the name of the backend server and may be used by a device.
--
Sent to: server
{
"id": "unique_identifier_of_device",
"deviceName": "name_of_device" | null,
"deviceManufacturer": "manufacturer_of_device" | null,
"deviceModel": "model_or_type_of_device" | null,
"capabilities": {
"channels": 8,
"charge": false,
"discharge": true,
"configurableChargeCurrent": false,
"configurableDischargeCurrent": false,
"configurableChargeVoltage": false,
"configurableDischargeVoltage": true
}
}
id
must be unique. If a backend server receives a duplicate device ID, it must ignore the second device.deviceName
can be an optional string ornull
. This value may be overidden by a user in the UI.deviceManufacturer
anddeviceModel
are both optional and can be a string ornull
. Used for display purposes.channels
specify the number of channels that can be controlled and are expected when reporting status.charge
anddischarge
specify if the device supports charging or discharging but the rate is not configurable.configurableChargeCurrent
andconfigurableDischargeCurrent
specify if the device supports charging or discharging at a configurable current.configurableChargeVoltage
andconfigurableDischargeVoltage
specify if the device supports charging or discharging with a configurable voltage cutoff.- The
deviceId
is not needed in other packets because the server keeps track of each socket connection separately.
--
Sent to: server
{
"channels": [
{
"id": channel_id,
"state": "empty" | "idle" | "complete" | "charging" | "discharging" | "overVoltage" | "underVoltage" | "overTemperature" | "error",
"stage": "arbitrary_string",
"current": 1900,
"voltage": 4200,
"temperature": 25,
"capacity": 1300
}
]
}
channels
must contain an array of channel objects for all device channels. Channels should be sorted numerically (ie 1, 2, 3) based on theid
when viewing in the UI.id
must be unique per device and must be a number.state
must contain one of the options defined above.empty
means no cell detected andidle
means a cell is detected but nothing is currently happening.stage
may be specified or set to null. A device can specify what stage of the state it's at (e.g. it could be "resting" to allow voltage to settle before performing an IR measurement, etc.)current
is the current measured on the channel in mA.voltage
is the voltage measured on the channel in mV.temperature
is the temperature measured on the channel in degrees Celsius. It must be a number ornull
.capacity
is the current capacity (so far) of the cell in the channel in mAh. It may remain at the last measured capacity, or return to 0 after a discharge is finished. This behaviour is up to the device's firmware. It must be a positive integer, or 0.- A device may send a
deviceStatus
message as often as reasonable (for example each time a channel status or measurement changes) but should be about every 1-5 seconds.
For devices that have a status LED on each channel (or another similar status interface) the following colours and animations should be used for the following states:
- Empty (ready for cell insertion) - solid blue
- Idle (cell inserted, but no current action) - solid orange
- Action in progress (dis/charge, ir measurement, etc) - flashing orange (~ 1hz)
- Action complete (cell inserted, and action has completed) - solid green
- This should revert to the empty colour/state once the cell is removed.
Note that for all "error" conditions - the device will not proceed until it is rectified.
- Error (under/over voltage) - fast flashing red (~ 2hz)
- Error (any other error) - flashing red (~ 1hz)
--
Sent to: server
{
"channel": channel_id,
"startVoltage": 4200,
"endVoltage": 3000,
"startTemperature": 25,
"endTemperature": 35,
"capacity": 2500,
"dcResistance": 60 | null,
"acResistance": 20 | null,
"data": [
{
"time": 1608127015,
"voltage": 3500,
"current": 1900,
"capacity": 300,
"temperature": 24
}
]
}
- Memory constrained devices may not be able to store a lot of data. A typical device should report data in 1-10 second sections but longer times are acceptable.
channel
channel that completed a charge session.startVoltage
voltage of the cell when charging commenced in mV.endVoltage
voltage of the cell when charging completed in mV.startTemperature
temperature of the cell when charging started in degrees Celsius.endTemperature
temperature of the cell when charging completed in degrees Celsius.capacity
capacity of the cell when charging completed in mAh.dcResistance
andacResistance
is the internal resistance of the cell in milli Ohms. Set tonull
if not available.- Data objects:
time
seconds of time that have elapsed since the charge started.voltage
voltage of the cell at this time in mV.current
current of the cell at this time in mA.capacity
total capacity of the cell at this time in mAh.temperature
temperature of the cell at this time in degrees Celsius.
--
Sent to: server
{
"channel": channel_id,
"startVoltage": 4200,
"endVoltage": 3000,
"startTemperature": 25,
"endTemperature": 35,
"dcResistance": 60 | null,
"acResistance": 20 | null,
"capacity": 2500,
"data": [
{
"time": 1608127015,
"voltage": 3500,
"current": 1900,
"capacity": 300,
"temperature": 24
}
]
}
- Memory constrained devices may not be able to store a lot of data. A typical device should report data in 1-10 second sections but longer times are acceptable.
channel
channel that completed a discharge session.startVoltage
voltage of the cell when discharging commenced in mV.endVoltage
voltage of the cell when discharging completed in mV.endTemperature
temperature of the cell when discharging completed in degrees Celsius.startTemperature
temperature of the cell when charging started in degrees Celsius.dcResistance
andacResistance
is the internal resistance of the cell in milli Ohms. Set tonull
if not available.capacity
capacity of the cell when discharging completed in mAh.- Data objects (mainly used for generating graphs, may be an empty array):
time
seconds of time that have elapsed since the discharge started.voltage
voltage of the cell at this time in mV.current
current of the cell at this time in mA.capacity
total capacity of the cell at this time in mAh.temperature
temperature of the cell at this time in degrees Celsius.
--
Sent to: server
{
"channel": channel_id,
"dcResistance": 60 | null,
"acResistance": 20 | null,
}
channel
channel that completed a discharge session.dcResistance
andacResistance
is the internal resistance of the cell in milli Ohms. Set tonull
if not available.- A device may not implement this.
--
Sent to: device
{
"channel": id_of_channel,
"action": "charge" | "discharge" | "dcResistance" | "acResistance",
"rate": 1900 | null,
"cutoffVoltage": 4200 | null
}
- Requests that a specified action is started on the specified channel. The device should ignore it and respond with a
reportMessage
packet if it is not implemented on the device. rate
the rate of charge/discharge in mA. This value will benull
if the device reported it's not implemented.cutoffVoltage
the voltage (in mV) at which the device should stop charging/discharging. This value will be set tonull
if the device reported it's not implemented.- A device may ignore this command if it doesn't want to implement it.
--
Sent to: device
{
"channel": id_of_channel
}
- Requests that an action is stopped on the specified channel. The device should ignore it and respond with a
reportMessage
packet if there isn't an active action. - A device may ignore this command if it doesn't want to implement it.
--
Sent to: device
{
"channel": id_of_channel
}
- Performs a locate channel request. A typical implementation may be flashing the channel's status LED or similar.
- A device may ignore this command if it doesn't have a reasonable way of implementing it.
--
Sent to: device
{
"channel": id_of_channel
}
- Reports that the device has started locating a channel. A typical implementation may be flashing the channel's status LED or similar.
- This could be used for many reasons such as calibrating a per channel sensor, etc. and is purely for display reasons on the UI. This can be used in combination with a
reportMessage
packet to guide a user through a process.
--
Sent to: device
{
"type": "error" | "warning" | "info",
"message": "descriptive_error_or_warning_or_info_message"
}
- A kCharge backend server may log any reported message but it should display it on the UI immediately upon receiving it.
- The UI should show red for an error, yellow for a warning and the primary colour for an info message.
- The message length should be less than 50 characters. However, messages up to 250 characters may be sent. This restriction is mainly for display purposes.
--
Sent to: device
{
"type": "powerCycle" | "factoryReset"
}
- Upon receipt of this packet, the device should perform either a power cycle or a full factory reset (ie resetting a configured name, sensor calibration data, etc.)
- A device may choose to not implement this.
--
Sent to: device
{
"configuration": {}
}
- Upon receipt of this packet, the device should replace it's internal configuration data with the new object.
- A device may choose to reboot and/or cancel any active actions.
- A device may choose to not implement this.