Stand with Ukraine flag
Try it now Pricing
IoT Gateway
Documentation > Configuration guides > CAN Connector
Getting Started
Installation
On this page

CAN Connector Configuration

This guide will help you to get familiar with CAN connector configuration for ThingsBoard IoT Gateway.
Use general configuration to enable this connector.
We will describe connector configuration file below.

Example of CAN Connector config file.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
{
  "interface": "socketcan",
  "channel": "vcan0",
  "backend": {
    "fd": true
  },
  "reconnectPeriod": 5,
  "devices": [
    {
      "name": "Car",
      "sendDataOnlyOnChange": false,
      "enableUnknownRpc": true,
      "strictEval": false,
      "attributes": [
        {
          "key": "isDriverDoorOpened",
          "nodeId": 41,
          "command": "2:2:big:8717",
          "value": "4:1:int",
          "expression": "bool(value & 0b00000100)",
          "polling": {
            "type": "once",
            "dataInHex": "AB CD AB CD"
          }
        }
      ],
      "timeseries": [
        {
          "key": "rpm",
          "nodeId": 1918,
          "isExtendedId": true,
          "command": "2:2:big:48059",
          "value": "4:2:big:int",
          "expression": "value / 4",
          "polling": {
            "type": "always",
            "period": 5,
            "dataInHex": "aaaa bbbb aaaa bbbb"
          }
        },
        {
          "key": "milliage",
          "nodeId": 1918,
          "isExtendedId": true,
          "value": "4:2:little:int",
          "expression": "value * 10",
          "polling": {
            "type": "always",
            "period": 30,
            "dataInHex": "aa bb cc dd ee ff aa bb"
          }
        }
      ],
      "attributeUpdates": [
        {
          "attributeOnThingsBoard": "softwareVersion",
          "nodeId": 64,
          "isExtendedId": true,
          "dataLength": 4,
          "dataExpression": "value + 5",
          "dataByteorder": "little"
        }
      ],
      "serverSideRpc": [
        {
          "method": "sendSameData",
          "nodeId": 4,
          "isExtendedId": true,
          "isFd": true,
          "bitrateSwitch": true,
          "dataInHex": "aa bb cc dd ee ff    aa bb aa bb cc d ee ff"
        },
        {
          "method": "setLightLevel",
          "nodeId": 5,
          "dataLength": 2,
          "dataByteorder": "little",
          "dataBefore": "00AA"
        },
        {
          "method": "setSpeed",
          "nodeId": 16,
          "dataAfter": "0102",
          "dataExpression": "userSpeed if maxAllowedSpeed > userSpeed else maxAllowedSpeed"
        }
      ]
    }
  ]
}

Root section

The root part of the CAN connector configuration provides basic information on how to connect/reconnect to a Can bus and includes the list of device configurations.

Parameter Default value Description
name CAN Connector Name of connector.
interface socketcan Type of CAN interface.
channel vcan0 Channel name of CAN interface.
backend   Interface specific configuration.
reconnect true Determines whether to reconnect after bus error while sending/receiving CAN messages.
reconnectPeriod 30.0 The period, in seconds, between reconnect attempts. Floating point means more precise time than seconds.
reconnectCount   Number of reconnect attempts after a bus error. If not specified, it means an infinite number of attempts.
devices   List of devices.

You can find the list of supported CAN interfaces in the documentation of the Python CAN library.

Section “backend”

This section is optional and it provides configuration for specific CAN interface. Each option has a default value. To get a list of available options, see the documentation for specific interface type.

For example, the SocketCAN interface supports the following configuration options:

  • receive_own_messages
  • fd
  • can_filters
1
2
3
4
"backend": {
  "receive_own_messages": true,
  "fd": true
}

This means that transmitted messages should also be received and CAN-FD frames should be supported. By default, these options are disabled.

Section “devices”

This section provides an array of configurations for devices connected through the CAN bus.

Parameter Default value Description
name   Name of device.
type can Type of device.
sendDataOnlyOnChange false Sends data only if it has changed from the last check, if not specified data will be sent after each received CAN message.
strictEval true Restricted mode of Python eval() API.
enableUnknownRpc false Allow processing RPC commands not listed in serverSideRpc subsection.
overrideRpcConfig false Allow overriding RPC command configuration (all or some of options) by data received from server.
converters   Custom converters.
attributes   List of device attributes.
timeseries   List of time series keys.
attributeUpdates   List of shared attributes to be subscribed for.
serverSideRpc   List of RPC commands.

If enableUnknownRpc is set to true, overrideRpcConfig is forcibly set to true as well.

Note that despite attributes, timeseries, attributeUpdates and serverSideRpc being optional subsections, at least one of them must be set to utilize the device configuration.

Subsection “converters”

CAN connector is provided with built-in uplink/downlink data converters. One can specify a custom converter for either uplink, downlink, or both.

Parameter Default value Description
uplink   Python class of uplink converter.
downlink   Python class of downlink converter.

As input data the uplink converter gets CAN payload (array of bytes) and list of configurations from “attributes” and “timeseries” subsection to know which bytes to get and how they need to be interpreted.

As output data the uplink converter returns dictionary with attribute and telemetry lists. Each element of this list is key/value pair, where key is attribute name or time series key and the value is what it is.

1
2
3
4
{
  "attributes": [{"isDriverDoorOpened": "true"}],
  "telemetry": [{"rpm":100},{"milliage": 300000}]
}

As input data the downlink converter gets the value (or values in case of RPC) and configuration (from “attributeUpdates” or “serverSideRpc” subsections) that describes how to convert the value (or values) to CAN payload.

As output data the downlink converter returns CAN payload (array of bytes) for the further sending.

Subsection “attributes” or “timeseries”

This subsection provides the list of configurations, each of them describes which bytes to get from CAN payload (array of bytes) and how to convert these bytes to a Thingsboard attribute or a time series key.

Parameter Default value Description
key   Name of attribute or time series key.
nodeId   CAN node (arbitration) id.
value   Value conversion configuration.
expression   Python eval() expression to modify value in some way.
command   Command conversion configuration.
polling   Polling configuration.
isExtendedId false If True means extended CAN node (arbitration) id.
isFd false If True means using CAN FD mode.
bitrateSwitch false Only for CAN FD mode If True means a higher bitrate is used for the data transmission.
“commmand”

The option command is an additional but non-neccessary level of abstraction what lets one to interpret the one part of CAN message differently based on the another part of this CAN message.

For example, the controller of an irrigation system can inform about different parameters of the system. Communication is done via CAN bus.
The first byte of a CAN payload is command. If the value of a command is 2, it means that following bytes is temperature.
If value of command is 4, data is a humidity level.

The option command supports the following formats:

  • As JSON string:
    1
    
    command: "<start>:<length>:[byteorder]:[value]"
    
  • As JSON object:
    1
    2
    3
    4
    5
    6
    
    "command": {
      "start": <start_value>,
      "length": <length_value>,
      "byteorder": <byteorder_value>,
      "value": <value>
    }
    

where:

  • start - the position of the first byte - 0 to 7 for CAN protocol, 0 to 63 for CAN FD protocol
  • length - the number of bytes to get the value of a command
  • byteorder - the order of bytes - big or little (default big)
  • value - the integer value of a command in the decimal format

Example:

  1. Read 2 bytes starting from 0th position as the little byte order and trigger processing of the following bytes only if the command value is 12345.
    1
    
    "command": "0:2:little:12345"
    
“value”

The option value describes how many bytes to get from CAN payload and the corresponding primitive type for conversion.

The option value supports the following formats:

  • As JSON string:
    1
    
    "value": "<start>:<length>:[byteorder]:<type>:[encoding|signed]"
    
  • As JSON object:
    1
    2
    3
    4
    5
    6
    7
    8
    
    "value": {
      "start": <start_value>,
      "length": <length_value>,
      "byteorder": <byteorder_value>,
      "type": <type_value>,
      "encoding": <encoding_value>,
      "signed": <signed_value>
    }
    

where

  • start - the position of the first byte - 0-7 for CAN protocol, 0-63 for CAN FD protocol
  • length - the number of bytes to get the value
  • byteorder - the order of bytes - big or little (default big)
  • type - the Python primitive types bool, boolean, int, long, float, double or string. By types bool, int and float it is meant Thingsboard boolean, long and double types respectively. Note, float type value requires 4 bytes and double type value requires 8 bytes.
  • encoding - Only for string type Encoding of string (default ascii).
  • signed - Only for int/long types indicates whether integer is signed value or not - signed or unsigned (default unsigned)

Examples:

  • Read 1 byte starting from 2d position as the big byte order and cast to the value of the unsigned int type.
    1
    
    "value": "2:1:int" 
    
  • Read 8 bytes starting from 0th position as the big byte order and cast to the value of the double type.
    1
    
    "value": "0:7:double"
    
  • Read 4 bytes starting from 0th position as the little byte order and cast to the value of the float type.
    1
    
    "value": "0:4:little:float"
    
  • Read 2 bytes starting from 4th position as the little byte order and cast to the value the signed int type. The value is used in Python eval() expression to get the final value.
    1
    2
    
    "value": "4:2:little:int:signed",
    "expression": "value / 4"
    
“expression”

The option expression is evaluated via Python eval() API. The following variables are available in the eval() context:

  1. value - the result of applying the value configuration to the CAN payload
  2. can_data - the CAN payload (array of bytes)

Note, by default Python eval() API is working in some kind of a restricted mode by denying the explicit access to __builtins__ API. To disable the restricted mode, set the option strictEval to False.

“polling”

If a polling configuration is not specified the CAN connector receives only the data that CAN node decides to send on its own.

On-demand sending is activated after CAN node receives specific data, as specified in the polling configuration. Depending on the type of polling, the CAN connector can send that data either once or periodically.

Parameter Default value Description
type always Type always implies sending CAN message periodically, while once implies single-time sending.
period 1.0 Period of polling in seconds. Floating point means more precise time than seconds.
dataInHex   CAN message payload in the hexadecimal format.

Subsection “attributeUpdates”

This subsection provides the list of configurations to subscribe for changes of Thingsboard shared attributes.

Parameter Default value Description
attribute   Name of the shared attribute.
nodeId   CAN node (arbitration) id.
isExtendedId false If True means extended CAN node (arbitration) id.
isFd false If True means using CAN FD mode.
bitrateSwitch false Only for CAN FD mode If True means a higher bitrate is used for the data transmission.
dataLength 1 Only for integer values Number of bytes to pack integer value.
dataByteorder big Only for integer and float values Order of bytes to pack numeric value.
dataSigned false Only for int/long types indicates whether integer is signed value or not.
dataExpression   Python eval() expression to modify attribute value in some way before packing it to array of bytes.
dataEncoding ascii Only for string values Encoding of string packing.
dataBefore   Hexadecimal string of bytes that are preceded value bytes.
dataAfter   Hexadecimal string of bytes that are followed by value bytes.

The steps of processing an attribute update are the following:

  1. If dataExpression is set, the value that received from Thingsboard server is modified via Python eval() API. The variable value is available in dataExpression. This is a value of the attribute that was changed. If dataExpression is not set, the value is left as it is.
  2. The value from the step 1 is packed to the array of bytes based on its type (deduced by Python isinstance() API) and configuration provided for this attribute. Note, float type value requires 4 bytes.
  3. If dataBefore or/and dataAfter are set, they are converted to the arrays of bytes and are added to the value bytes (from the step 2) before and after respectively.
  4. Send the final byte array through a CAN bus.

Subsection “serverSideRpc”

This subsection provides the list of configurations to process RPC commands from a ThingsBoard server to a device.

Parameter Default value Description
method   Name of RPC command.
response false If true, response will be sent to ThingsBoard.
nodeId   CAN node (arbitration) id.
isExtendedId false If True means extended CAN node (arbitration) id.
isFd false If True means using CAN FD mode.
bitrateSwitch false Only for CAN FD mode If True means a higher bitrate is used for the data transmission.
dataLength 1 Only for integer values Number of bytes to pack integer value.
dataByteorder big Only for integer and float values Order of bytes to pack numeric value.
dataSigned false Only for int/long types indicates whether integer is signed value or not.
dataExpression   Python eval() expression to modify attribute value in some way before packing it to array of bytes.
dataEncoding ascii Only for string values Encoding of string packing.
dataBefore   Hexadecimal string of bytes that are preceded value bytes.
dataAfter   Hexadecimal string of bytes that are followed by value bytes.
dataInHex   Only for RPC without parameters Hexadecimal string of bytes that are sent to CAN node.

The CAN connector supports RPC commands without and with parameters (see params JSON object).

The without parameters RPC type requires only dataInHex to be set (another data* options are not used). The value of dataInHex is sent as payload of a CAN message each time when the RPC command is processed.

The with parameters RPC type is based on all data* options except dataInHex. The steps of processing are the same as for attribute updates except:

  • if dataExpression is not set, RPC params must have the JSON property named value. The value of this JSON property is packed to the array of bytes and send to CAN node as payload of a CAN message.
    1
    2
    3
    4
    5
    6
    7
    8
    9
    
    {
    "device": "Car", 
    "data": {
      "method": "setLightLevel", 
      "params": {
        "value": 70
      }
    }
    }
    
  • if dataExpression is set, no specific JSON property is required and all RPC params are available in dataExpression.


    For example, user wants to increase a car speed to 150 mph, but a car control system has its own limit that is set to 100 mph.
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    
    {
    "device": "Car", 
    "data": {
      "id": 1,
      "method": "setSpeed", 
      "params": {
        "userSpeed": 150,
        "maxAllowedSpeed": 100
      }
    }
    }
    

    The configuration of such RPC command is set up in a way that if user exceeds the limit the car speed is forcibly set to this limit:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    
    "serverSideRpc": [
    {
      "method": "setSpeed",
      "nodeId": 16,
      "dataBefore": "09",
      "dataAfter": "aabb",
      "dataExpression": "userSpeed if maxAllowedSpeed > userSpeed else maxAllowedSpeed"
    }
    ]
    

    So after processing the setSpeed RPC command, CAN payload is as follows: [ 0x09, 0x64, 0xAA, 0xBB ], where 0x64 is 100 mph because user exceeded the limit.

Next steps

Explore guides related to main ThingsBoard features: