Skip to main content

tuya-ble-sdk

Python SDK for Tuya Bluetooth Low Energy devices. It speaks the Tuya BLE GATT protocol directly — handshake, session key, encrypted frames and datapoints — and knows nothing about Home Assistant. It also reads the device credentials off the Tuya account, since the handshake needs values the device never broadcasts.

Consumed by the ha-tuya-ble integration, which pins it from manifest.json.

What it does

One read is one whole session: the client connects, performs the handshake, collects the datapoint report and disconnects. Tuya BLE sensors are battery powered and only listen for a moment after they advertise, so holding a connection open would drain them and occupy a proxy slot for nothing.

The session is bounded end to end: it gives the connection back after SESSION_TIMEOUT (60 s) whatever the radio is doing, and the connection attempt itself after CONNECT_TIMEOUT (20 s). A proxy shares a handful of slots between every device behind it, so a read that cannot finish has to stop holding one.

from tuya_ble_sdk import TuyaBleClient, TuyaBleCredentials, parse_advertisement

info = parse_advertisement(service_data, manufacturer_data)
client = TuyaBleClient(
    ble_device,
    TuyaBleCredentials(uuid=info.uuid, device_id=device_id, local_key=local_key),
)
data_points = await client.async_read_data_points()

Discovery belongs to the caller: the client takes an already-resolved BLEDevice, which is what lets Home Assistant hand over a device seen through a Bluetooth proxy.

parse_advertisement reads what the advertisement discloses — every field of the result is optional. The uuid is encrypted with the product-id record broadcast beside it, so no cloud call is needed to learn it; the readable product id, however, is only there on an unbound device. One bound to a Tuya account broadcasts an obfuscated value in its place: those bytes still decrypt the uuid, but they name no product, and the caller has to learn what the device is some other way.

Credentials from the account

A session needs a device id and a local key, and no device discloses either: only the Tuya account that owns it does. TuyaBleCloudClient logs into the mobile app gateway with the account's e-mail and password and returns what it knows about every device on it.

from tuya_ble_sdk import TuyaBleCloudClient

async with TuyaBleCloudClient(email, password, country_code, region="us") as cloud:
    devices = await cloud.async_list_devices()

paired = next(device for device in devices if device.uuid == info.uuid)
credentials = TuyaBleCredentials(
    uuid=paired.uuid, device_id=paired.device_id, local_key=paired.local_key
)

The account describes a Bluetooth device with the same uuid its advertisement carries and with its mac, so either one ties an account record to a device seen over the air. The record also names the product_id a bound device stops broadcasting.

Region is the account's data centre — one of us, eu, cn, in, we — and country_code is the calling code the account was registered with (55 for Brazil). Nothing is cached: one client is one login.

Command line

The optional cli extra installs a tuya-ble command:

uv run --extra cli tuya-ble scan
uv run --extra cli tuya-ble read \
    --address AA:BB:CC:DD:EE:FF --device-id <id> --local-key <key>

scan lists every nearby Tuya BLE device with its product id and uuid; read runs one session and prints the datapoints it reported. credentials logs into a Tuya account and prints the device id and local key it holds for each device:

uv run --extra cli tuya-ble credentials --email you@example.com --country-code 55

Not implemented

The device may report datapoints in a signed form (0x8004 / 0x8005) instead of the plain one this SDK reads. Those two commands are recognised and logged, not parsed: the reference implementation disagrees with itself about where the records start inside them, and no device was available to settle it. A device that uses them shows up as a read that reports no datapoint, with the command name in the debug log.

Development

uv sync                     # create .venv and install dependencies
uv run ruff format --check .
uv run ruff check .
uv run mypy src
uv run pytest               # 90 % coverage gate

Runtime dependencies carry a >= floor and nothing else: Home Assistant pins its own transitive dependencies exactly, so an == pin here eventually contradicts HA's pin and the integration stops installing.

Credits

The protocol implementation is derived from PlusPlus-ua/ha_tuya_ble (MIT), itself based on redphx/poc-tuya-ble-fingerbot.

License

MIT

Metadata

Release files for tuya-ble-sdk 0.1.3

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for tuya-ble-sdk 0.1.3
File Size Uploaded
tuya_ble_sdk-0.1.3.tar.gz 143.1 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for tuya-ble-sdk 0.1.3
File Interpreter ABI Platform
tuya_ble_sdk-0.1.3-py3-none-any.whl Python 3 none any Details

Total release size: 185.5 kB

Release files / tuya_ble_sdk-0.1.3.tar.gz

Download URL tuya_ble_sdk-0.1.3.tar.gz
Size 143.1 kB
Tags Source
SHA-256 checksum
How to use checksums
e22b6c7468f495b71ca6ea74c1fd9dbb723ef7d05de0431aa50b643998e934ab
BLAKE2b-256 checksum
How to use checksums
00f50ec926b8b865bb429669c7ab4b0f82e7453462f8071559124d762ecb23eb
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.14

Release files / tuya_ble_sdk-0.1.3-py3-none-any.whl

Download URL tuya_ble_sdk-0.1.3-py3-none-any.whl
Size 42.3 kB
Tags Python 3
SHA-256 checksum
How to use checksums
1bfee35f5cc7dfab1bde7de2771a47add203203c8547d2c71970c39aac5cfffc
BLAKE2b-256 checksum
How to use checksums
8210592ca6198b3c1b8d6cc17b1b8a18cd379a157f1d8f46a13eb4ccf4dbbafd
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.14

Release history Release notifications | RSS feed

This release

0.1.3 This release

2 release files

0.1.2

2 release files

0.1.1

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page