Skip to content
© 2026 The ThingsBoard Authors
Try for free

ThingsBoard Cloud

Choose your data region

Your data stays in the region you choose, for residency and compliance. No credit card required.

Rather run it yourself? Install on your own servers

Python REST Client

The ThingsBoard Python REST Client wraps the Edge REST API and is auto-generated from the OpenAPI spec — every REST endpoint has a typed method. It lets Python applications manage devices, assets, dashboards, customers, and other entities on your Edge node — connect it directly to the Edge node’s local REST endpoint.

Install the edition-specific package:

Terminal window
pip install tb-ce-client==4.3.1.6

Snippets below import models from tb_ce_client.models and exceptions from tb_ce_client.exceptions. Each snippet is self-contained — open it inside a with ThingsboardClient(...) as client: block, replace placeholders like YOUR_API_KEY_VALUE and YOUR_DEVICE_ID with real values, and run it. The client is synchronous and not thread-safe — create one instance per worker.

End-to-end: authenticate with an API key, create a device, push a telemetry value, then clean up.

import json
from tb_ce_client import ThingsboardClient
from tb_ce_client.models import Device
with ThingsboardClient("http://localhost:8080", api_key="YOUR_API_KEY_VALUE") as client:
saved = client.save_device(Device(name="Quickstart Device", type="default"))
device_id = str(saved.id.id)
client.save_entity_telemetry(
entity_type="DEVICE",
entity_id=device_id,
scope="ANY",
body=json.dumps({"temperature": 22.4}),
)
print(f"Pushed telemetry to {saved.name}")
client.delete_device(device_id=device_id)

ThingsboardClient authenticates eagerly on construction. The client is a context manager — using it inside with releases the underlying connection pool on exit. JWT tokens refresh automatically; the client re-logs in transparently if the refresh token expires.

from tb_ce_client import ThingsboardClient
with ThingsboardClient("http://localhost:8080", api_key="YOUR_API_KEY_VALUE") as client:
print(f"Logged in as {client.get_user().email}")
from tb_ce_client import ThingsboardClient
with ThingsboardClient(
"http://localhost:8080",
username="tenant@thingsboard.org",
password="tenant",
) as client:
print(f"Logged in as {client.get_user().email}")

The client retries 429 Too Many Requests responses with exponential backoff by default. Tune via constructor keyword arguments (defaults shown below), or pass retry_on_rate_limit=False to disable:

from tb_ce_client import ThingsboardClient
client = ThingsboardClient(
"http://localhost:8080",
api_key="YOUR_API_KEY_VALUE",
max_retries=3, # default 3
initial_retry_delay_ms=1_000, # default 1 s
max_retry_delay_ms=30_000, # default 30 s
)

Every entity type — devices, assets, dashboards, customers, alarms — follows the same method-naming pattern: save_<entity>, get_<entity>_by_id, get_<entity>_info_by_id, delete_<entity>. Required fields differ per type; see the REST API reference for each model. The walkthrough below uses devices. To update an existing entity, mutate the model and call save_<entity> again.

from tb_ce_client import ThingsboardClient
from tb_ce_client.models import Device
with ThingsboardClient("http://localhost:8080", api_key="YOUR_API_KEY_VALUE") as client:
new_device = Device(name="Test Device", type="default")
saved = client.save_device(new_device)
device_id = str(saved.id.id) # saved.id is EntityId wrapper, .id is the UUID
fetched = client.get_device_by_id(device_id=device_id)
print("Fetched:", fetched.name)
client.delete_device(device_id=device_id)

Both save_entity_telemetry(entity_type, entity_id, scope, body) and save_entity_attributes_v2(entity_type, entity_id, scope, body) take a JSON string as body.

import json
from tb_ce_client import ThingsboardClient
with ThingsboardClient("http://localhost:8080", api_key="YOUR_API_KEY_VALUE") as client:
device_id = "YOUR_DEVICE_ID"
client.save_entity_telemetry(
entity_type="DEVICE",
entity_id=device_id,
scope="ANY", # required by URL path; server-ignored for telemetry
body=json.dumps({"temperature": 26.5, "humidity": 87}),
)

This example uses an asset with a deviceCount attribute; the same calls work for any entity type — substitute "DEVICE" / device_id for a device.

import json
from tb_ce_client import ThingsboardClient
with ThingsboardClient("http://localhost:8080", api_key="YOUR_API_KEY_VALUE") as client:
asset_id = "YOUR_ASSET_ID"
attrs = client.get_attributes_by_scope(
entity_type="ASSET",
entity_id=asset_id,
scope="SERVER_SCOPE",
keys="deviceCount", # comma-separated; pass "k1,k2,k3" for multiple
)
current = int(attrs[0].value) if attrs else 0
updated = current + 1
client.save_entity_attributes_v2(
entity_type="ASSET",
entity_id=asset_id,
scope="SERVER_SCOPE",
body=json.dumps({"deviceCount": updated}),
)
from tb_ce_client import ThingsboardClient
with ThingsboardClient("http://localhost:8080", api_key="YOUR_API_KEY_VALUE") as client:
page = 0 # pages are zero-indexed
while True:
devices = client.get_tenant_devices(page_size=100, page=page)
for device in devices.data:
print(device.name, str(device.id.id))
if not devices.has_next:
break
page += 1

For server-side filtering on attribute or telemetry values, use the Entity Data Query API. The example below counts all devices, then counts only the active ones:

from tb_ce_client import ThingsboardClient
from tb_ce_client.models import (
EntityCountQuery, EntityTypeFilter, KeyFilter, EntityKey,
BooleanFilterPredicate, FilterPredicateValueBoolean,
)
with ThingsboardClient("http://localhost:8080", api_key="YOUR_API_KEY_VALUE") as client:
type_filter = EntityTypeFilter(entity_type="DEVICE")
total = client.count_entities_by_query(
EntityCountQuery(entity_filter=type_filter)
)
print("Total devices:", total)
active_filter = KeyFilter(
key=EntityKey(type="ATTRIBUTE", key="active"),
value_type="BOOLEAN",
predicate=BooleanFilterPredicate(
operation="EQUAL",
value=FilterPredicateValueBoolean(default_value=True),
),
)
active = client.count_entities_by_query(
EntityCountQuery(entity_filter=type_filter, key_filters=[active_filter])
)
print("Active devices:", active)

For a paginated list of matching entities (not just a count), build an EntityDataQuery with an EntityDataPageLink and call client.find_entity_data_by_query(query). See the tb-examples.md catalog for full examples.

The client raises ApiException for non-2xx responses, with HTTP-status-specific subclasses (NotFoundException for 404, UnauthorizedException for 401, etc.). e.body is the raw response body (typically JSON for 4xx, may be empty for 5xx).

  • 401 Unauthorized — JWT auth auto-refreshes tokens and re-logs in using stored credentials, so you’ll only see this if credentials become invalid.
  • 429 Too Many Requests — already retried with exponential backoff by default (see Rate-limit handling). You only observe a 429 if retries are exhausted or disabled.
  • 404 Not Found — the common case worth catching explicitly:
from tb_ce_client import ThingsboardClient
from tb_ce_client.exceptions import ApiException, NotFoundException
with ThingsboardClient("http://localhost:8080", api_key="YOUR_API_KEY_VALUE") as client:
try:
device = client.get_device_by_id(device_id="nonexistent-id")
except NotFoundException:
print("Device not found")
except ApiException as e:
print(f"API error {e.status}: {e.body}")

The tb-examples.md catalog in the repository covers additional entities (assets, dashboards, customers), alarms, relations, and Entity Data Query examples with pagination and sort orders.