Stop the war

Support Ukraine

Try it now Pricing
Professional Edition
Community Edition Professional Edition Cloud Edge PE Edge IoT Gateway License Server Trendz Analytics Mobile Application PE Mobile Application
How to connect NVIDIA Jetson Xavier NX Developer Kit to ThingsBoard?
Getting Started Documentation Devices Library Guides Installation Architecture API FAQ

On this page

How to connect NVIDIA Jetson Xavier NX Developer Kit to ThingsBoard?

Introduction

NVIDIA Jetson Xavier NX Developer Kit The NVIDIA Jetson Xavier NX Developer Kit is a powerful, compact AI computer that delivers up to 21 TOPS of accelerated computing in a small form factor.
It’s designed for autonomous machines, industrial robots, and embedded systems that require high-performance AI at the edge.

In this guide, we will learn how to create device on Thingsboard, install required libraries and tools.
After this we will modify our code and upload it to the device, and check the results of our coding and check data on ThingsBoard using imported dashboard. Our device will synchronize with ThingsBoard using client and shared attributes requests functionality.
Of course, we will control our device using provided functionality like shared attributes or RPC requests.

Prerequisites

To continue with this guide we will need the following:

Create device on ThingsBoard

For simplicity, we will provide the device manually using the UI.

  • Login to your ThingsBoard instance and navigate to the "Entities". Then click the "Devices" page.
  • Click on the "+" icon in the top right corner of the table and then select "Add new device".
  • Input device name. For example, "My Device". No other changes required at this time. Click "Add" to add the device.
  • Your device has been added.

Install required libraries and tools

You should have installed thingsboard-python-client-sdk which can be installed using the following command. Still, we recommend installing packages outside the global environment:

1
pip3 install tb-mqtt-client

Also, you should have tools that allow editing code, for example, you can use Nano editor that is going out of the box or install any other code editor you are familiar with.

Connect device to ThingsBoard

To connect the device you need to get the device credentials first. ThingsBoard supports various device credentials. We recommend using default auto-generated credentials, which is an access token for this guide.

  • Click on the device row in the table to open device details.
  • Click "Copy access token". The token will be copied to your clipboard. Please save it in a safe place.

Now you are ready to publish telemetry data on behalf of your device. We will use, as mentioned before, the “thingsboard-python-client-sdk” library. Let’s setup our project:

  1. Create project folder:

    1
    
    mkdir thingsboard_example && cd thingsboard_example
    
  2. Install packages:

    1
    
    pip install tb-mqtt-client
    
  3. Create the main script:

    1
    
    nano main.py
    
  4. Copy and paste the following code:

    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
    90
    91
    92
    93
    94
    95
    96
    97
    
    import logging.handlers
    import time
    import os
       
    from tb_gateway_mqtt import TBDeviceMqttClient
       
    ACCESS_TOKEN = "TEST_TOKEN"
    THINGSBOARD_SERVER = 'demo.thingsboard.io'
    THINGSBOARD_PORT = 1883
    
    logging.basicConfig(level=logging.DEBUG)
       
    client = None
       
    # default blinking period
    period = 1.0
       
       
    # callback function that will call when we will change value of our Shared Attribute
    def attribute_callback(result, _):
         print(result)
         # make sure that you paste YOUR shared attribute name
         period = result.get('blinkingPeriod', 1.0)
    
    # callback function that will call when we will send RPC
    def rpc_callback(id, request_body):
        # request body contains method and other parameters
        print(request_body)
        method = request_body.get('method')
        if method == 'getTelemetry':
            attributes, telemetry = get_data()
            client.send_attributes(attributes)
            client.send_telemetry(telemetry)
        else:
            print('Unknown method: ' + method)
       
       
    def get_data():
        cpu_usage = round(float(os.popen('''grep 'cpu ' /proc/stat | awk '{usage=($2+$4)*100/($2+$4+$5)} END {print usage }' ''').readline().replace('\n', '').replace(',', '.')), 2)
        ip_address = os.popen('''hostname -I''').readline().replace('\n', '').replace(',', '.')[:-1]
        mac_address = os.popen('''cat /sys/class/net/*/address''').readline().replace('\n', '').replace(',', '.')
        processes_count = os.popen('''ps -Al | grep -c bash''').readline().replace('\n', '').replace(',', '.')[:-1]
        swap_memory_usage = os.popen("free -m | grep Swap | awk '{print ($3/$2)*100}'").readline().replace('\n', '').replace(',', '.')[:-1]
        ram_usage = float(os.popen("free -m | grep Mem | awk '{print ($3/$2) * 100}'").readline().replace('\n', '').replace(',', '.')[:-1])
        st = os.statvfs('/')
        used = (st.f_blocks - st.f_bfree) * st.f_frsize
        boot_time = os.popen('uptime -p').read()[:-1]
        avg_load = (cpu_usage + ram_usage) / 2
       
        attributes = {
            'ip_address': ip_address,
            'macaddress': mac_address
        }
        telemetry = {
            'cpu_usage': cpu_usage,
            'processes_count': processes_count,
            'disk_usage': used,
            'RAM_usage': ram_usage,
            'swap_memory_usage': swap_memory_usage,
            'boot_time': boot_time,
            'avg_load': avg_load
        }
        print(attributes, telemetry)
        return attributes, telemetry
       
    # request attribute callback
    def sync_state(result, exception=None):
         global period
         if exception is not None:
             print("Exception: " + str(exception))
         else:
             period = result.get('shared', {'blinkingPeriod': 1.0})['blinkingPeriod']
    
    def main():
         global client
         client = TBDeviceMqttClient(THINGSBOARD_SERVER, THINGSBOARD_PORT, ACCESS_TOKEN)
         client.connect()
         client.request_attributes(shared_keys=['blinkingPeriod'], callback=sync_state)
            
         # now attribute_callback will process shared attribute request from server
         sub_id_1 = client.subscribe_to_attribute("blinkingPeriod", attribute_callback)
         sub_id_2 = client.subscribe_to_all_attributes(attribute_callback)
    
         # now rpc_callback will process rpc requests from server
         client.set_server_side_rpc_request_handler(rpc_callback)
    
         while not client.stopped:
             attributes, telemetry = get_data()
             client.send_attributes(attributes)
             client.send_telemetry(telemetry)
             time.sleep(60)
       
    if __name__=='__main__':
        if ACCESS_TOKEN != "TEST_TOKEN":
            main()
        else:
            print("Please change the ACCESS_TOKEN variable to match your device access token and run script again.")
    

    In the code above change values for the following variables - THINGSBOARD_SERVER, ACCESS_TOKEN to your credentials.

    Necessary variables for connection:

    Variable name Default value Description
    ACCESS_TOKEN TEST_TOKEN Your device access token
    THINGSBOARD_SERVER demo.thingsboard.io Your ThingsBoard host or ip address.
    THINGSBOARD_PORT 1883 ThingsBoard server MQTT port. Can be default for this guide.
  5. Click Ctrl+X and Ctrl+O keys to save the file.
  6. And finally, let’s start our script:

    1
    
    python3 main.py
    

If you did everything right, you should see the following console output:

1
2
3
4
5
> INFO:tb_device_mqtt:connection SUCCESS
> 
> 
> {'ip_address': '192.168.1.198', 'macaddress': '3c:06:30:44:e0:24'} {'cpu_usage': 6.6, 'processes_count': 8, 'disk_usage': 70.0, 'RAM_usage': 73.9, 'swap_memory_usage': 69.4, 'battery': 29, 'boot_time': 1675154176.0}
> 

Let’s review and make an explanation for our code. In this step, we are interested in the get_data function. Data packing and returning in the get_data function, so you can easily add new telemetry or attributes to the dictionary if you want to monitor more values:

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
...
def get_data():
       cpu_usage = round(float(os.popen('''grep 'cpu ' /proc/stat | awk '{usage=($2+$4)*100/($2+$4+$5)} END {print usage }' ''').readline().replace('\n', '').replace(',', '.')), 2)
       ip_address = os.popen('''hostname -I''').readline().replace('\n', '').replace(',', '.')[:-1]
       mac_address = os.popen('''cat /sys/class/net/*/address''').readline().replace('\n', '').replace(',', '.')
       processes_count = os.popen('''ps -Al | grep -c bash''').readline().replace('\n', '').replace(',', '.')[:-1]
       swap_memory_usage = os.popen("free -m | grep Swap | awk '{print ($3/$2)*100}'").readline().replace('\n', '').replace(',', '.')[:-1]
       ram_usage = float(os.popen("free -m | grep Mem | awk '{print ($3/$2) * 100}'").readline().replace('\n', '').replace(',', '.')[:-1])
       st = os.statvfs('/')
       used = (st.f_blocks - st.f_bfree) * st.f_frsize
       boot_time = os.popen('uptime -p').read()[:-1]
       avg_load = (cpu_usage + ram_usage) / 2
   
       attributes = {
           'ip_address': ip_address,
           'macaddress': mac_address
       }
       telemetry = {
           'cpu_usage': cpu_usage,
           'processes_count': processes_count,
           'disk_usage': used,
           'RAM_usage': ram_usage,
           'swap_memory_usage': swap_memory_usage,
           'boot_time': boot_time,
           'avg_load': avg_load
       }
       print(attributes, telemetry)
       return attributes, telemetry
...

Send data part, as you can see below, we send our attributes and telemetry data every 60 seconds (feel free to change it if you want more frequent data updating):

1
2
3
4
5
6
7
...		
    while not client.stopped:
        attributes, telemetry = get_data()
        client.send_attributes(attributes)
        client.send_telemetry(telemetry)
        time.sleep(60)
...

Synchronize device state using client and shared attribute requests


Don’t forget to create shared attribute blinkingPeriod on your device.

In order to get the state of the device from ThingsBoard during booting we have functionality to do this in the code. Responsible parts of the example code:

Attribute callback:

1
2
3
4
5
6
def sync_state(result, exception=None):
    global period
    if exception is not None:
        print("Exception: " + str(exception))
    else:
        period = result.get('shared', {'blinkingPeriod': 1.0})['blinkingPeriod']

Attribute request:

1
2
3
4
5
def main():
    client = TBDeviceMqttClient("thingsboard.cloud", 1883, "ACCESS_TOKEN")
    client.connect()
    client.request_attributes(shared_keys=['blinkingPeriod'], callback=sync_state)
    ...

In order to give ability to our callbacks to receive the data we have to send a request to ThingsBoard. This functionality allows us to keep the actual state after rebooting.

Check data on ThingsBoard

Once you have successfully published the attributes and telemetry data, you should immediately see them in the Device Telemetry Tab:

  • Click on the device row in the table to open device details.
  • Navigate to the telemetry tab.

Also, let’s display single board computer attributes and telemetry on a dashboard. For this, you can create your own dashboard with your custom widgets or use a ready-made dashboard and simply import it.

Import dashboard

You are able to import a dashboard in JSON format. To import a dashboard, you should go to the Dashboard group and click on the “+” button in the upper right corner of the page and choose “Import dashboard”. The dashboard import window should pop up, and you will be prompted to upload the JSON file and click “Import”.

Below you can find the dashboard JSON file:

Check and control device data dashboard

After importing we should choose entity alias for our device.
To do this - we need to press the pen icon and select entity aliases, select alias “My device” and open it for editing by pressing the pen icon.
Then choose a device with name My device from dropdown list and save entity alias, now you should be able to see the data from the device.

If you did everything right, you have to see the following dashboard:

Create new dashboard

We will create a dashboard and add the most popular widgets. See the instructions below.

  • Open the Dashboards page. Click on the "+" icon in the top right corner. Select "Create new dashboard".
  • Input dashboard name. For example, "My New Dashboard". Click "Add" to add the dashboard.
  • Now your dashboard should be listed first since the table sorts dashboards using the time of the creation by default. Click on the "Open dashboard" icon.

Add Entity Alias

Alias is a reference to a single entity or group of entities that are used in the widgets. An alias may be static or dynamic. For simplicity, we will use the “Single entity” alias that references the one and only entity (“OrangePI” in our case). It is possible to configure an alias that references multiple devices. For example, devices of a certain type or related to a certain asset. You may learn more about different aliases here.

  • Enter edit mode. Click on the pencil button in the bottom right corner.
  • Click the "Entity Aliases" icon in the top right part of the screen. You will see an empty list of Entity aliases.
  • Click "Add alias".
  • Input alias name, for example, "OrangePI". Select the "Single entity" Filter type. Select "Device" as Type and type "My New" to enable autocomplete. Choose your device from the auto-complete and click on it.
  • Click "Add" and then "Save".
  • Finally, click "Apply changes" in the dashboard editor to save the changes. Then you should enter edit mode again.

To add the new widget we need to select it from the widget library. Widgets are grouped into widget bundles. Each widget has a data source. This is how the widget “knows” what data to display. To see the latest value of our “cpu_usage” data that we sent during step 2, we should configure the data source.

  • Enter edit mode. Click on the “Add new widget” button.
  • Select the “Charts” widget bundle. Click on the header of the Entities widget. The “Add Widget” window will appear.
  • Click “Add” to add the data source. A widget may have multiple data sources, but we will use only one in this case.
  • Select the “OrangePI” entity alias. Then click on the input field on the right. The auto-complete with available data points will appear. Select the “cpu_usage” data point and click “Add”.
  • Resize the widget to make it a little bigger. Just drag the bottom right corner of the widget. You can also play with the advanced settings if you would like to edit the widget.

Control device using shared attributes


Don’t forget to create shared attribute blinkingPeriod on your device.

Also, we can change the period of the blinking using shared attribute update functionality.

This type of attribute is available only for Devices. It is similar to the Server-side attributes but has one important difference. The device firmware/application may request the value of the shared attribute(s) or subscribe to the updates of the attribute(s). The most common use case of shared attributes is to store device settings.

In order to run the code of this part of the guide, we recommend using Python 3.9 or above.

If you haven’t installed Python, please, follow next steps:

1
2
sudo apt update
sudo apt install software-properties-common
1
sudo add-apt-repository ppa:deadsnakes/ppa
1
sudo apt install python3.9
1
sudo apt-get install -y python3 git python3-pip

Also, we will need Adafruit-Blinka library. Please, use the following command to install it:

1
pip3 install Adafruit-Blinka

For now, we are ready to write our code. In this part, we use new packages for blinking our LED in the blink function. Also, we use the attibute_callback function, which will be called when we change the value of our shared attribute. And finally, we bind our callback to subscriber in the main function.

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
import digitalio
import board

...

# default blinking period
period = 1.0

# callback function that will call when we will change value of our Shared Attribute
def attribute_callback(client, result):
    print(client, result)
    # make sure that you paste YOUR shared attribute name
    period = result.get('blinkingPeriod', 1.0)

def main():
    ...
    # make sure that you paste YOUR shared attribute name
    sub_id_1 = client.subscribe_to_attribute("blinkingPeriod", attribute_callback)
    sub_id_2 = client.subscribe_to_all_attributes(attribute_callback)
    led = digitalio.DigitalInOut(board.PD14)
    led.direction = digitalio.Direction.OUTPUT
    ...
    led.value = True
    time.sleep(period)
    led.value = False
    time.sleep(period)

Also, if you are using the imported dashboard, you can change the blinking period using the following widget, which you can see in the bottom right corner of the dashboard:

Control device using RPC

ThingsBoard allows you to send Remote Procedure Calls (RPC) from server-side applications to devices and vice versa. Basically, this feature will enable you to send commands to/from devices and receive the results of command execution.

In this guide, we will configure the RPC command to get OrangePI telemetry data immediately. If you are using the imported dashboard, you don’t need to configure anything as in your dashboard you can see the following widget:

For now, we are ready to write our code. Firstly we need to create an rpc_callback function which will call when we will get RPC from the server. And as in the example with shared attributes, we need to bind our rpc callback function with the subscriber in the main function.

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
client = None

...

# callback function that will call when we will send RPC
def rpc_callback(id, request_body):
    # request body contains method and other parameters
    print(request_body)
    method = request_body.get('method')
    if method == 'getTelemetry':
        attributes, telemetry = get_data()
        client.send_attributes(attributes)
        client.send_telemetry(telemetry)
    else:
        print('Unknown method: ' + method)

...

def main():
    ...

    # now rpc_request_response will process rpc requests from server
    client.set_server_side_rpc_request_handler(rpc_callback)

    ...

Finally, let’s try to push our button and force getting OrangePI data:

Also, if you did everything right, you should see the following console output:

{'method': 'getTelemetry', 'params': {}}

Conclusion

With the knowledge outlined in this guide, you can easily connect your NVIDIA Jetson Xavier NX Developer Kit and send data to ThingsBoard.

Explore the platform documentation to learn more about key concepts and features. For example, configure alarm rules or dashboards.