概述
CircuitPython Client SDK是用于CircuitPython项目客户端集成的软件开发套件。CircuitPython是面向微控制器的简化版MicroPython。它允许您使用MQTT协议将CircuitPython设备连接到ThingsBoard,发送遥测数据、属性并接收RPC调用。提供简洁、易用的API,便于将CircuitPython设备与平台集成。
CircuitPython Client SDK支持以下功能:
- 使用MQTT协议连接ThingsBoard。
- 向ThingsBoard发送属性。
- 向ThingsBoard发送遥测数据。
- 从ThingsBoard接收RPC调用。
- 从ThingsBoard请求客户端和共享属性。
- 订阅ThingsBoard的属性更新。
- 设备认领。
安装
首先需具备CircuitPython兼容设备并配置开发环境。可参考CircuitPython入门指南完成准备工作。 要安装CircuitPython Client SDK,可使用circup包管理器。 在终端中运行以下命令:
1
circup install thingsboard-circuitpython-client-sdk
若circup install命令出现问题,可尝试使用Web-Workflow安装:
1
circup --host <your_device_ip> --password <your_password> install thingsboard-circuitpython-client-sdk
方法
简介
CircuitPython Client SDK提供TBDeviceMqttClient类,用于连接ThingsBoard并发送数据。
该类设计简洁,便于CircuitPython或ThingsBoard新手使用。
connect
使用MQTT协议连接ThingsBoard。在向ThingsBoard发送任何数据前需调用此方法。
创建TBDeviceMqttClient实例时需提供连接凭证。调用connect方法后,客户端的self.connected属性将设为True。
方法语法
client.connect()
使用示例
1
2
3
4
5
# Default connecting
client.connect()
# Connecting and waiting for the connection result
response = client.connect()
disconnect
断开与ThingsBoard的连接。连接后即可调用此方法。建议在不再需要向ThingsBoard发送数据或需释放资源时调用。
调用此方法后,需再次调用connect才能向ThingsBoard发送数据。调用disconnect后,客户端的self.connected属性将设为False。
方法语法
client.disconnect()
使用示例
1
2
3
4
5
client.connect()
# some tasks with ThingsBoard
client.disconnect()
send_attributes
向ThingsBoard发送属性。连接后即可调用。支持以键值对形式发送属性。
方法语法
client.send_attributes(data)
参数
| Arguments | Description |
|---|---|
| data | (必填)将作为属性发送至ThingsBoard的数据。 |
使用示例
1
2
attributes = {"sensorModel": "DHT-22", "attribute_2": "value"}
client.send_attributes(attributes)
send_telemetry
向ThingsBoard发送遥测数据。连接后即可调用。支持以键值对、列表等多种格式发送遥测。也支持按时间戳分组发送,便于发送历史数据。
方法语法
client.send_telemetry(data)
参数
| Arguments | Description |
|---|---|
| data | (必填)将作为遥测发送至ThingsBoard的数据。 |
使用示例
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
从ThingsBoard请求客户端和共享属性。连接后即可调用。支持同时请求两种属性。可通过属性键列表指定要请求的属性。收到请求的属性后,将调用提供的回调函数并传入结果;若未找到,则传入空结果。
方法语法
client.request_attributes(client_keys=None, shared_keys=None, callback=None)
参数
| Arguments | Description |
|---|---|
| client_keys | (可选)要从ThingsBoard请求的客户端属性键列表。 |
| shared_keys | (可选)要从ThingsBoard请求的共享属性键列表。 |
| callback | (可选)收到请求属性时调用的回调函数,应接受result和exception两个参数。 |
使用示例
1
2
3
4
5
6
7
8
9
10
def on_attributes_change(result, exception=None):
# Callback is called when the attributes response arrives
if exception is not None:
print("Exception:", exception)
else:
print("Attributes response:", result)
# Request client/shared attributes by keys (your SDK forms attributes/request/<id>)
client.request_attributes(client_keys=["atr1", "atr2"], callback=on_attributes_change)
claim_device
使用此方法触发设备认领流程。通过传入唯一密钥,设备将自动关联到用户账户。这简化了设备上线流程,用户无需平台级别权限即可激活硬件。
更多信息请参见文档的设备认领章节。
方法语法
client.claim_device(secret_key, duration_ms=None)
Arguments
| Arguments | Description |
|---|---|
| secret_key | (必填)在ThingsBoard上用于认领设备的密钥。 |
| duration_ms | (可选)认领码有效时长(毫秒)。不提供则有效期为无限,直至被用于认领设备。 |
使用示例
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
订阅ThingsBoard的属性更新。通过属性键指定要订阅的共享属性。订阅的属性值更新时,将调用提供的回调并传入新值。
方法返回订阅ID,可用于unsubscribe_from_attribute取消订阅。
方法语法
client.subscribe_to_attribute(key, callback)
参数
| Arguments | Description |
|---|---|
| key | (必填)要订阅的ThingsBoard共享属性键。 |
| callback | (必填)订阅属性在ThingsBoard上更新时触发的回调,须接受result和 *args两个参数。 |
使用示例
1
2
3
4
5
6
def callback(result, *args):
# Called when subscribed attribute update arrive
print("Received data: %r", result)
sub_id = client.subscribe_to_attribute("frequency", callback)
subscribe_to_all_attributes
订阅ThingsBoard全部共享属性更新。服务端任意共享属性修改时,SDK会触发指定回调并传入更新后的数据。
方法返回订阅ID,可用于unsubscribe_from_attribute取消订阅。
方法语法
client.subscribe_to_all_attributes(callback)
参数
| Arguments | Description |
|---|---|
| callback | (必填)服务端推送共享属性变更时触发,回调接收包含修改后键值对的result对象及*args。 |
使用示例
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
终止共享属性更新的现有订阅。需传入subscribe_to_attribute或subscribe_to_all_attributes返回的subscription_id。取消后,相关回调在服务端变更时不再触发。
方法语法
client.unsubscribe_from_attribute(subscription_id)
参数
| Arguments | Description |
|---|---|
| subscription_id | (必填)通过subscribe_to_attribute或subscribe_to_all_attributes订阅时返回的订阅ID。 |
使用示例
1
2
3
4
5
6
7
8
# 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
配置处理ThingsBoard发起的远程过程调用请求的处理器。应在建立连接后调用。收到请求时,SDK执行指定处理器并传入:
request_id- RPC请求的唯一标识符,用于发送响应。request_body- 包含命令详情的字典,通常含方法名和params。
方法语法
client.set_server_side_rpc_request_handler(handler)
参数
| Arguments | Description |
|---|---|
| handler | 定义ThingsBoard发起远程命令时执行的逻辑,函数接收request_id和request_body两个参数。 |
使用示例
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.set_server_side_rpc_request_handler(handler)
send_rpc_reply
响应来自ThingsBoard的RPC请求。在RPC处理器中使用此方法向服务器返回数据。需要初始请求的request_id和包含结果的response对象。不调用此方法可能导致ThingsBoard仪表板上出现request timeout错误。
方法语法
client.send_rpc_reply(request_id, response)
参数
| Arguments | Description |
|---|---|
| request_id | (必填)收到的RPC请求ID,用于发送回复。 |
| response | (必填)作为RPC回复发送的数据。 |
使用示例
1
2
3
4
5
6
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)
send_rpc_reply
响应来自ThingsBoard的RPC请求。在RPC处理器中使用此方法向服务器返回数据。需要初始请求的request_id和包含结果的response对象。不调用此方法可能导致ThingsBoard仪表板上出现request timeout错误。
方法语法
client.send_rpc_reply(request_id, response)
参数
| Arguments | Description |
|---|---|
| request_id | (必填)收到的RPC请求ID,用于发送回复。 |
| response | (必填)作为RPC回复发送的数据。 |
使用示例
1
2
3
4
5
6
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)
Concepts
简介
在本部分中,我们将涵盖CircuitPython Client SDK的核心概念:
- 通过MQTT将设备连接到ThingsBoard。
- 非阻塞循环。
- 遥测、属性和数据流。
- 属性请求。
- 属性更新。
- 处理服务端RPC。
让我们回顾一下CircuitPython Client SDK的这些概念:
连接ThingsBoard
使用CircuitPython Client SDK连接ThingsBoard时,实例化TBDeviceMqttClient并传入服务器凭证:host、port和access token。初始化后调用connect()建立MQTT会话。连接成功后即可发送遥测或订阅更新。推荐使用以下最小代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import time
import wifi # CircuitPython Wi-Fi module
from tb_device_mqtt import TBDeviceMqttClient # ThingsBoard MQTT client wrapper (your SDK)
# Quick sanity-check that Wi-Fi is up before using MQTT
print("WiFi connected:", wifi.radio.connected)
print("IP:", wifi.radio.ipv4_address)
# ThingsBoard connection settings
HOST = "YOUR_HOST" # e.g. "thingsboard.cloud" or "192.168.1.10"
PORT = "YOUR_PORT" # e.g. 1883 (use an int)
TOKEN = "YOUR_ACCESS_TOKEN" # device access token from ThingsBoard
# Create MQTT client instance
client = TBDeviceMqttClient(host=HOST, port=PORT, access_token=TOKEN)
print("Connecting...")
client.connect() # open MQTT connection to ThingsBoard
time.sleep(1) # small delay to ensure connection stabilizes on some boards
while True:
# some tasks with ThingsBoard
与ThingsBoard通信前,请确保设备已接入网络。上述代码假设Wi-Fi已连接。Wi-Fi连接方法详见CircuitPython网络。
- 首先确认Wi-Fi已连接并打印设备IP,MQTT客户端需要有效网络连接才能与ThingsBoard通信。
TBDeviceMqttClient是主类,需要ThingsBoard host和在设备页面生成的唯一Access Token。- 使用这些连接设置创建MQTT客户端实例,SDK据此确定连接地址和设备标识。
- 调用client.connect()后,可加短暂延迟,使部分板卡的连接更稳定。
非阻塞循环
SDK实现中最关键的是主循环。在CircuitPython中,time.sleep()在等待事件时可降低CPU占用,但会阻塞代码。
要让设备持续处理传入的MQTT消息,需定期轮询客户端。
client.check_for_msg()是通信的“心跳”:
- 检查MQTT缓冲区中的传入消息。
- 处理收到的消息并触发相应回调(如RPC请求或属性更新)。
遥测、属性与数据流
SDK提供向ThingsBoard发送遥测的方法,可使用send_telemetry()以键值对、列表等格式发送。SDK也支持按时间戳分组发送,便于发送历史数据。
1
2
3
4
5
6
7
# Main loop (non-blocking)
while True:
# Non-blocking: poll for incoming MQTT packets, then continue doing other work
client.check_for_msg()
client.send_telemetry({"CPU": 12.0})
client.send_attributes({"status": "ok"})
time.sleep(0.05) # small delay to prevent overwhelming the CPU and allow other tasks to run
将其置于主循环后,设备将持续上报状态。采用非阻塞方式,设备可同时发送遥测和接收RPC命令,互不阻塞。
属性请求
SDK提供操作ThingsBoard设备属性的方法,可使用request_attributes()按键请求客户端和/或共享属性。 ThingsBoard响应后,SDK会调用回调并传入收到数据(或错误)。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
TIMEOUT = 20 # how long we keep pumping MQTT loop (seconds)
def on_attributes_change(result, exception=None):
# Callback is called when the attributes response arrives
if exception is not None:
print("Exception:", exception)
else:
print("Attributes response:", result)
# Request client/shared attributes by keys (your SDK forms attributes/request/<id>)
client.request_attributes(client_keys=["atr1", "atr2"], callback=on_attributes_change)
# IMPORTANT: CircuitPython needs a loop to receive/process MQTT packets
deadline = time.monotonic() + TIMEOUT
while time.monotonic() < deadline:
client.check_for_msg() # wraps MiniMQTT.loop() -> triggers callbacks
time.sleep(0.05) # small sleep to reduce CPU usagesks to run
在主循环中加入轮询逻辑,设备可保持响应:既能请求/接收属性,又能处理其他MQTT事件(如RPC调用)而不阻塞整个应用。
- 定义回调
on_attributes_change,在收到属性响应时触发。 - 对指定键(”atr1”、”atr2”)发起属性请求,SDK发布请求并等待ThingsBoard响应。
- 使用
time.monotonic()控制循环在TIMEOUT内运行,若未收到响应不会无限等待。
属性更新
SDK提供订阅属性更新的方法,可使用subscribe_to_attribute()按键订阅客户端和/或共享属性的更新。 ThingsBoard发布该属性更新时,SDK将调用回调并传入收到的数据(或错误)。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
TIMEOUT = 20 # how long we keep pumping MQTT loop (seconds)
def callback(result, *args): # noqa: F841
# Called when subscribed attribute update arrives
# (extra args may contain metadata depending on your SDK design)
print("Received data:", result)
# Subscribe to updates of a single attribute key (e.g. shared attribute "frequency")
sub_id = client.subscribe_to_attribute("frequency", callback) # returns subscription id (optional)
# IMPORTANT: keep looping so incoming MQTT messages are processed
deadline = time.monotonic() + TIMEOUT
while time.monotonic() < deadline:
client.check_for_msg() # wraps MiniMQTT.loop() -> triggers callbacks
time.sleep(0.05) # small sleep to reduce CPU usage
在主循环中加入轮询逻辑,设备可保持响应:既能请求/接收属性,又能处理其他MQTT事件(如RPC调用)而不阻塞整个应用。
- 定义回调
callback,每次收到订阅属性更新时触发。 - 订阅单个属性键(如共享属性”frequency”)的更新,方法可能返回后续用于管理订阅的subscription id。
- 使用
time.monotonic()限制循环在TIMEOUT内运行,示例不会无限执行。
处理服务端RPC
远程过程调用允许ThingsBoard向设备发送命令(如“打开LED”或“重置”)。要处理这些命令,需通过set_server_side_rpc_request_handler设置处理器。收到服务端RPC请求时,该处理器会被调用,并传入request_id和request_body(分别对应请求ID和请求数据)。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# This callback will be called when an RPC request is received from ThingsBoard.
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)
while True:
# Non-blocking: poll for incoming MQTT packets
client.check_for_msg()
time.sleep(0.1) # small delay to avoid busy-waiting (adjust as need)
SDK不会“等待”命令,而是通过回调on_server_side_rpc_request处理:
- 使用set_server_side_rpc_request_handler()指定收到RPC时执行的函数。
- 收到RPC时,SDK自动将
request_id(用于回复)和request_body传入处理器。 - send_rpc_reply()告知服务器RPC已收到并处理成功。
示例
更多CircuitPython Client SDK使用示例见GitHub上thingsboard-circuitpython-client-sdk仓库的examples目录。
故障排查
-
内存不足、SDK不稳定
常见于板子CircuitPython可用RAM有限,或应用及其依赖占用内存过多。 可尝试减少代码内存占用(如避免大块分配、精简import)。建议阅读CircuitPython内存优化指南。
-
circup安装错误
部分板子在使用USB/串口工作流时
circup install可能失败。此时可改用Web-Workflow安装库。 该方法通过指定设备IP(host)和Web Workflow密码,直接在网络上目标设备安装,常可解决上传/权限问题。1
circup --host <your_device_ip> --password <your_password> install thingsboard-circuitpython-client-sdk