Pricing Try it now
Professional Edition
API > Software development kits > MicroPython Client SDK
Getting Started Documentation Guides Installation Architecture
FAQ
On this page

MicroPython Client SDK

Overview

The MicroPython Client SDK is a software development kit for client-side integration of your MicroPython projects. It allows you to connect your MicroPython devices to SENTIENT using MQTT protocol and send telemetry data, attributes, and receive RPC calls. The SDK provides a simple and easy-to-use API for connecting to SENTIENT and sending data, making it easier for developers to integrate their MicroPython devices with the platform.

MicroPython Client SDK supports the following features:

  • Connecting to SENTIENT using MQTT protocol.
  • Sending attributes to SENTIENT.
  • Sending telemetry data to SENTIENT.
  • Receiving RPC calls from SENTIENT.
  • Request client and shared attributes from SENTIENT.
  • Subscribing to attribute updates from SENTIENT.
  • Device claiming.
  • Device provisioning.

Installation

To install the MicroPython Client SDK, you can use the mip package manager. Run the following command in the REPL or in your code:

1
2
3
import mip

mip.install('github:sentient/sentient-micropython-client-sdk')

It is recommended to use the following code snippet to make sure that the SDK is installed and imported correctly, and also to not install the SDK every time you run your code:

1
2
3
4
5
6
7
8
try:
    from sentient_sdk.tb_device_mqtt import TBDeviceMqttClient

    print("sentient-micropython-client-sdk package already installed.")
except ImportError:
    print("Installing sentient-micropython-client-sdk package...")
    mip.install('github:sentient/sentient-micropython-client-sdk')
    from sentient_sdk.tb_device_mqtt import TBDeviceMqttClient

Methods

Introduction

The MicroPython Client SDK has a TBDeviceMqttClient class that provides methods for connecting to SENTIENT and sending data.

This class is designed to be simple to use and easy to understand for developers who are new to MicroPython or SENTIENT.

connect

Connects to SENTIENT using MQTT protocol. This method should be called before sending any data to SENTIENT. Credentials for connecting to SENTIENT should be provided when creating an instance of the TBDeviceMqttClient class. When you call the connect method, self.connected property of the client will be set to True.

Method Syntax

client.connect(timeout=10)

Arguments

Arguments Default value Description
timeout 10 (Optional) Time to establish a connection to SENTIENT.

Example usage

1
2
3
4
5
6
7
8
# Default connecting
client.connect()

# Connecting with custom timeout
client.connect(timeout=20)

# Connecting with waiting for connection result
result = client.connect(timeout=20)

disconnect

Disconnects from SENTIENT. This method can be called after connecting to SENTIENT. It is recommended to call this method when you no longer need to send data to SENTIENT or when you want to free up resources. After calling this method, you will need to call the connect method again to send data to SENTIENT. When you call the disconnect method, self.connected property of the client will be set to False.

Method Syntax

client.disconnect()

Example usage

1
2
3
4
5
client.connect()

# some tasks with SENTIENT

client.disconnect()

send_attributes

Sends attributes to SENTIENT. This method can be called after connecting to SENTIENT. Method supports sending attributes in key-value pairs.

Method Syntax

client.send_attributes(data)

Arguments

Arguments Description
data (Required) Data that will be sent as attributes to SENTIENT.

Example usage

1
2
attributes = {"sensorModel": "DHT-22", "attribute_2": "value"}
client.send_attributes(attributes)

send_telemetry

Sends telemetry data to SENTIENT. This method can be called after connecting to SENTIENT. Method supports sending telemetry data in different formats, key-value pairs, and lists. Also, it supports sending telemetry data grouped by timestamp, which is useful for sending historical data to SENTIENT.

Method Syntax

client.send_telemetry(data)

Arguments

Arguments Description
data (Required) Data that will be sent as a telemetry to SENTIENT.

Example usage

1
2
3
4
5
6
7
8
9
# Sending telemetry data in dictionary format
telemetry = {"temperature": 25.5, "humidity": 60}
client.send_telemetry(telemetry)

# Sending telemetry data grouped by timestamps
from time import time
telemetry = [{"ts": 1451649600000, "values": {"temperature": 42.2, "humidity": 71}},
             {"ts": 1451649601000, "values": {"temperature": 42.3, "humidity": 72}}]
client.send_telemetry(telemetry)

request_attributes

Requests client and shared attributes from SENTIENT. This method can be called after connecting to SENTIENT. Method supports requesting both client and shared attributes. You can specify which attributes you want to request by providing a list of attribute keys. If requested attributes are received from SENTIENT, the provided callback function will be called with the result. If requested attributes are not found on SENTIENT, the callback function will be called with empty result.

Method Syntax

client.request_attributes(client_keys=None, shared_keys=None, callback=None)

Arguments

Arguments Description
client_keys (Optional) List of client attribute keys to request from SENTIENT.
shared_keys (Optional) List of shared attribute keys to request from SENTIENT.
callback (Optional) Callback function that will be called when the requested attributes are received from SENTIENT. The callback function should accept two arguments: result and exception, which will contain the requested attributes.

Example usage

1
2
3
4
5
6
7
8
9
def on_attributes_change(result, exception=None):
    # This is a callback function that will be called when client receive the response from the server
    if exception is not None:
        print("Exception: " + str(exception))
    else:
        print(result)


client.request_attributes(client_keys=["atr1", "atr2"], callback=on_attributes_change)

claim_device

Use this method to trigger the device claiming process. By passing a unique secret key, the device is automatically linked to the user’s account. This simplifies the onboarding experience, as users can activate their hardware without needing platform-level permissions.

More information about device claiming can be found in the Device claiming section of the documentation.

Method Syntax

client.claim_device(secret_key, duration_ms=None)

Arguments

Arguments Description
secret_key (Required) Secret key that will be used to claim the device on SENTIENT.
duration_ms (Optional) Duration in milliseconds for which the claim code will be valid. If not provided, the claim code will be valid indefinitely until it is used to claim a device.

Example usage

1
2
3
4
5
# Claiming a device with a claim code that will be valid indefinitely until it is used to claim a device
client.claim_device("my_claim_code")

# Claiming a device with a claim code that will be valid for 60 seconds
client.claim_device("my_claim_code", duration_ms=60000)

subscribe_to_attribute

Subscribes to attribute updates from SENTIENT. You can specify which shared attribute you want to subscribe to by providing an attribute key. If subscribed attribute value is updated, the provided callback function will be called with the corresponding attribute value.

Method will return a subscription ID that can be used to unsubscribe from attribute updates using the unsubscribe_from_attribute method.

Method Syntax

client.subscribe_to_attribute(key, callback)

Arguments

Arguments Description
key (Required) Shared attribute key to subscribe to for updates from SENTIENT.
callback (Required) A user-defined function triggered whenever a subscribed attribute is updated on SENTIENT. The callback must accept two parameters: result (the updated data dictionary) and *args (additional metadata).

Example usage

1
2
3
4
5
def callback(result, *args):
    print("Received data: %r", result)


sub_id = client.subscribe_to_attribute("frequency", callback)

subscribe_to_all_attributes

Subscribes to all shared attribute updates from SENTIENT. Whenever any shared attribute is modified on the server, the SDK triggers the designated callback function, passing the updated data as the result.

Method will return a subscription ID that can be used to unsubscribe from attribute updates using the unsubscribe_from_attribute method.

Method Syntax

client.subscribe_to_all_attributes(callback)

Arguments

Arguments Description
callback (Required) Triggers when any shared attribute change is pushed from the server. The callback receives a result object containing the modified key-value pairs and *args for extended context.

Example usage

1
2
3
4
5
def callback(result, *args):
    print("Received data: %r", result)


sub_id = client.subscribe_to_all_attributes(callback)

unsubscribe_from_attribute

Terminates an existing subscription for shared attribute updates. This method requires the subscription_id returned by the original call to subscribe_to_attribute or subscribe_to_all_attributes. Once unsubscribed, the associated callback will no longer trigger upon server-side changes.

Method Syntax

client.unsubscribe_from_attribute(subscription_id)

Arguments

Arguments Description
subscription_id (Required) Subscription ID returned when subscribing to attribute updates using the subscribe_to_attribute or subscribe_to_all_attributes methods.

Example usage

1
2
3
4
5
6
7
# Subscribing to attribute updates
def callback(result, *args):
    print("Received data: %r", result)

sub_id = client.subscribe_to_attribute("frequency", callback)
# Unsubscribing from attribute updates
client.unsubscribe_from_attribute(sub_id)

set_server_side_rpc_request_handler

Configures a handler for Remote Procedure Call requests initiated from SENTIENT. This method should be invoked after establishing a connection. When a request is received, the SDK executes the designated handler, passing the following arguments:

  • request_id - a unique identifier for the specific RPC request, required for sending a response.
  • request_body - a dictionary containing the command details, typically including the method name and params.

Method Syntax

client.set_server_side_rpc_request_handler(handler)

Arguments

Arguments Description
handler Defines the logic to execute when SENTIENT initiates a remote command. The function receives two parameters: request_id, representing the transaction ID, and request_body, containing the specific request payload.

Example usage

1
2
3
4
def handler(request_id, request_body):
    print("Received RPC request with ID: %s and body: %r", request_id, request_body)

client.set_server_side_rpc_request_handler(handler)

send_rpc_reply

Responds to an incoming RPC request from SENTIENT. Use this method inside your RPC handler to return data to the server. It requires the request_id from the initial request and a response object containing the result. Failing to call this method may result in request timeout errors on the SENTIENT dashboard.

Method Syntax

client.send_rpc_reply(request_id, response)

Arguments

Arguments Description
request_id (Required) ID of the received RPC request that will be used to send a reply to.
response (Required) Data that will be sent as a reply to the received RPC.

Example usage

1
2
3
4
5
def handler(request_id, request_body):
    print("Received RPC request with ID: %s and body: %r", request_id, request_body)
    client.send_rpc_reply(request_id, {"status": "success"})
   
client.set_server_side_rpc_request_handler(handler)

get_provision_request

Static method that forms a request for device provisioning by input arguments. The returned provision request should be sent to SENTIENT using the provision method.

Method Syntax

TBDeviceMqttClient.get_provision_request(provision_key, provision_secret)

Arguments

Arguments Description
provision_key (Required) Provisioning device key, you should take it from configured device profile.
provision_secret (Required) Provisioning device secret, you should take it from configured device profile.
device_name (Optional) Device name in SENTIENT.
access_token (Optional) Access token for device in SENTIENT.
client_id (Optional) Client id for device in SENTIENT.
username (Optional) Username for device in SENTIENT.
password (Optional) Password for device in SENTIENT.
hash (Optional) Public key X509 hash for device in SENTIENT.
gateway (Optional) Flag that indicates whether the provision request is for a gateway device. If not provided, the provision request will be for a regular device.

Example usage

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# Forming provision request with required arguments
provision_request = TBDeviceMqttClient.get_provision_request("my_provision_key", "my_provision_secret")

# Forming provision request with specified device name
provision_request = TBDeviceMqttClient.get_provision_request("my_provision_key", "my_provision_secret", device_name="My Device")

# Forming provision request with specified access token
provision_request = TBDeviceMqttClient.get_provision_request("my_provision_key", "my_provision_secret", access_token="my_access_token")

# Forming provision request with specified client ID, username, and password
provision_request = TBDeviceMqttClient.get_provision_request("my_provision_key", "my_provision_secret", client_id="my_client_id", username="my_username", password="my_password")

# Forming provision request for a gateway device
provision_request = TBDeviceMqttClient.get_provision_request("my_provision_key", "my_provision_secret", gateway=True)

provision

Sends a request to SENTIENT for device provisioning. The argument of the method should be the provision request that is formed using the get_provision_request static method. If the request is successful, the device will be provisioned on SENTIENT and associated with the account that owns the provision key and provision secret. If the request is not successful, an exception will be raised.

Method Syntax

client.provision(host, port, provision_request)

Arguments

Arguments Description
host (Required) Host of the SENTIENT server.
port (Required) Port of the SENTIENT server.
provision_request (Required) Request that will be sent to SENTIENT for device provisioning. The provision request should be formed using the get_provision_request static method.

Example usage

1
2
3
4
# Forming provision request
provision_request = TBDeviceMqttClient.get_provision_request("my_provision_key", "my_provision_secret")
# Sending provision request to SENTIENT for device provisioning
provisioned_credentials = client.provision("sentient.cloud", 1883, provision_request)

Concepts

Introduction

In this section, we will go over the core concepts of the MicroPython Client SDK, such as connecting to SENTIENT, sending and receiving data. Understanding these concepts will help you to use the MicroPython Client SDK effectively in your projects.

Let’s review the main concepts of the MicroPython Client SDK using the following code example:

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
import time
import network
from sentient_sdk.tb_device_mqtt import TBDeviceMqttClient

# Enabling WLAN interface
wlan = network.WLAN(network.STA_IF)
wlan.active(True)

# Establishing connection to the Wi-Fi
if not wlan.isconnected():
    print("Connecting to network...")
    wlan.connect("WIFI_SSID", "WIFI_PASSWORD")
    while not wlan.isconnected():
        pass

print("Connected! Network config:", wlan.ifconfig())


# This callback will be called when an RPC request is received from SENTIENT.
def on_server_side_rpc_request(request_id, request_body):
    # request_id: numeric id from the MQTT topic
    # request_body: decoded JSON dict, typically {"method": "...", "params": ...}
    print("[RPC] id:", request_id, "body:", request_body)

    client.send_rpc_reply(request_id, "ok")


# Initialising client to communicate with SENTIENT
client = TBDeviceMqttClient("SENTIENT_HOST", port=1883, access_token="ACCESS_TOKEN")
# Register the server-side RPC callback before the main loop
client.set_server_side_rpc_request_handler(on_server_side_rpc_request)
# Connect to SENTIENT
client.connect()


def safe_check_msg():
    """
    Non-blocking MQTT poll.
    """
    try:
        # non-blocking check
        client.check_for_msg()
        return True
    except OSError as e:
        print("[MQTT] check_msg OSError:", e)
    except Exception as e:
        print("[MQTT] check_msg error:", e)
    return False


# Main loop (non-blocking)
while True:
    # Non-blocking: poll for incoming MQTT packets, then continue doing other work
    safe_check_msg()
    client.send_telemetry({"CPU": 12.0})
    time.sleep_ms(50)

Connecting to SENTIENT

To connect to SENTIENT using the MicroPython Client SDK, instantiate the TBDeviceMqttClient class by providing your server credentials: host, port, and access token. Once the client is initialized, invoke the connect() method to establish the MQTT session. After a successful connection, the device is ready to transmit telemetry or subscribe to updates. We recommend the following minimal code snippet to use:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import network
from sentient_sdk.tb_device_mqtt import TBDeviceMqttClient

wlan = network.WLAN(network.STA_IF)
wlan.active(True)

# Establishing connection to the Wi-Fi
if not wlan.isconnected():
    print('Connecting to network...')
    wlan.connect("YOUR_SSID", "YOUR_PASSWORD")
    while not wlan.isconnected():
        pass

print('Connected! Network config:', wlan.ifconfig())

client = TBDeviceMqttClient(host="sentient.cloud", port=1883, access_token="YOUR_ACCESS_TOKEN")
client.connect()

while True:
    # some tasks with SENTIENT

Before communicating with the SENTIENT, the device must bridge the gap between the hardware and the network:

  • The network module initializes the Wi-Fi instance. We use STA_IF (Station Interface) to connect the device to an existing access point.
  • The TBDeviceMqttClient is the primary class. It requires SENTIENT host and a unique Access Token generated in the SENTIENT device page.

Handling Server-Side RPC

Remote Procedure Calls allow SENTIENT to send commands to your device (e.g., “Turn on the LED” or “Reset”). To handle these commands, you need to set a handler function using the set_server_side_rpc_request_handler method. This handler will be called whenever a server-side RPC request is received from SENTIENT. The handler function should accept two arguments: request_id and request_body, which will contain the ID of the received RPC request and the data of the received RPC request, respectively.

1
2
3
4
5
6
7
8
9
# This callback will be called when an RPC request is received from SENTIENT.
def on_server_side_rpc_request(request_id, request_body):
    # request_id: numeric id from the MQTT topic
    # request_body: decoded JSON dict, typically {"method": "...", "params": ...}
    print("[RPC] id:", request_id, "body:", request_body)

    client.send_rpc_reply(request_id, "ok")

client.set_server_side_rpc_request_handler(on_server_side_rpc_request)

In the SDK, we don’t “wait” for a command, instead we provide a callback function (on_server_side_rpc_request):

  • Tells the client which function to run when a RPC arrives using set_server_side_rpc_request_handler().
  • When a RPC arrives, the SDK automatically passes the request_id (used for the reply) and the request_body to your function.
  • The send_rpc_reply() informs the server that the RPC was received and processed successfully.

The Non-Blocking Loop

The most critical part of the SDK implementation is the main loop. In MicroPython, if you use time.sleep_ms(), the device is effectively “blind” to incoming messages during that pause.

client.check_for_msg() method is the “heartbeat” of your communication:

  • It checks the MQTT buffer for incoming messages.
  • By wrapping it in a safe_check_msg() function, we ensure that if a network interruption occurs (an OSError), the program doesn’t crash, but simply logs the error and tries again in the next cycle.

Telemetry and Data Flow

The SDK provides methods to send telemetry data to SENTIENT. You can use the send_telemetry() method to send data in various formats, including key-value pairs and lists. The SDK also supports sending telemetry data grouped by timestamp, which is useful for sending historical data to SENTIENT.

1
2
3
4
5
6
# Main loop (non-blocking)
while True:
    # Non-blocking: poll for incoming MQTT packets, then continue doing other work
    safe_check_msg()
    client.send_telemetry({"CPU": 12.0})
    time.sleep_ms(50)

By placing this inside the main loop, the device continuously streams its state. Because we use a non-blocking approach, the device can simultaneously send telemetry and receive RPC commands without one interrupting the other.

Examples

You can find more examples of using the MicroPython Client SDK in the examples directory of the sentient-micropython-client-sdk repository on GitHub.

Troubleshooting

  • Mip installation failed with OSError: -202

    This error can occur when the device is not connected to the internet or when there are issues with the network connection. To resolve this issue, make sure that your device is connected to the internet and that there are no issues with the network connection. You can also try restarting your device and running the installation command again.

    Recommended firstly to establish a connection to the internet and then run the installation command:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    
      import network
      import mip
        
      # Enabling WLAN interface
      wlan = network.WLAN(network.STA_IF)
      wlan.active(True)
        
      # Establishing connection to the Wi-Fi
      if not wlan.isconnected():
          print('Connecting to network...')
          wlan.connect("YOUR_WIFI_SSID", "YOUR_WIFI_PASSWORD")
          while not wlan.isconnected():
              pass
        
      mip.install('github:sentient/sentient-micropython-client-sdk')