Skip to main content

Python library for communicating with Specialized Turbo e-bikes over Bluetooth Low Energy

Project description

specialized-turbo

Python library for talking to Specialized Turbo e-bikes (Vado, Levo, Creo) over Bluetooth Low Energy. Reads speed, power, cadence, battery, motor temp, odometer, assist level, range. Can also write settings like assist level and acceleration.

Async, built on bleak. Includes a CLI. Protocol docs in docs/protocol.md.

Installation

pip install specialized-turbo

Quick start

Stream telemetry

import asyncio
from specialized_turbo import SpecializedConnection, TelemetryMonitor

async def main():
    async with SpecializedConnection("DC:DD:BB:4A:D6:55", pin="946166") as conn:
        monitor = TelemetryMonitor(conn)
        await monitor.start()

        async for msg in monitor.stream():
            print(f"{msg.field_name} = {msg.converted_value} {msg.unit}")

asyncio.run(main())

Read the snapshot

async with SpecializedConnection("DC:DD:BB:4A:D6:55", pin="946166") as conn:
    monitor = TelemetryMonitor(conn)
    await monitor.start()
    await asyncio.sleep(5)

    snap = monitor.snapshot
    print(f"Speed: {snap.motor.speed_kmh} km/h")
    print(f"Battery: {snap.battery.charge_pct}%")
    print(f"Power: {snap.motor.rider_power_w} W (rider) + {snap.motor.motor_power_w} W (motor)")
    print(f"Cadence: {snap.motor.cadence_rpm} RPM")
    print(f"Assist: {snap.motor.assist_level}")

Query a single value

from specialized_turbo import SpecializedConnection, Sender, BatteryChannel

async with SpecializedConnection("DC:DD:BB:4A:D6:55", pin="946166") as conn:
    msg = await conn.request_value(Sender.BATTERY, BatteryChannel.CHARGE_PERCENT)
    print(f"Battery: {msg.converted_value}%")

Write commands

async with SpecializedConnection("DC:DD:BB:4A:D6:55", pin="946166") as conn:
    await conn.set_assist_level(2)          # TRAIL
    await conn.set_acceleration(50.0)       # 50%
    await conn.set_shuttle(25)
    await conn.set_assist_percentage(0, 35) # ECO = 35%

CLI

Scan for bikes:

specialized-turbo scan
specialized-turbo scan --timeout 15

Stream telemetry:

specialized-turbo telemetry DC:DD:BB:4A:D6:55 --pin 946166
specialized-turbo telemetry DC:DD:BB:4A:D6:55 --pin 946166 --format json
specialized-turbo telemetry DC:DD:BB:4A:D6:55 --pin 946166 --duration 30

Read a single value:

specialized-turbo read list                                             # show available fields
specialized-turbo read battery_charge_percent DC:DD:BB:4A:D6:55 --pin 946166
specialized-turbo read speed DC:DD:BB:4A:D6:55 --pin 946166 --format json

Write a value:

specialized-turbo write list                                            # show writable fields
specialized-turbo write assist_level 2 DC:DD:BB:4A:D6:55 --pin 946166  # set to TRAIL
specialized-turbo write acceleration 50 DC:DD:BB:4A:D6:55 --pin 946166 # 50% sensitivity

Dump GATT services (debugging):

specialized-turbo services DC:DD:BB:4A:D6:55 --pin 946166

Capture complete TCX writes and notifications for protocol debugging:

specialized-turbo capture DC:DD:BB:4A:D6:55 --duration 60 > tcx-capture.tsv

Available fields

Field Unit Writable Description
battery_capacity_wh Wh Total battery capacity
battery_remaining_wh Wh Remaining energy
battery_health % Battery health
battery_temp °C Battery temperature
battery_charge_cycles cycles Number of charge cycles
battery_voltage V Battery voltage
battery_current A Battery current draw
battery_charge_percent % State of charge
rider_power W Rider pedal power
cadence RPM Pedaling cadence
speed km/h Current speed
odometer km Total distance
assist_level -- yes OFF / ECO / TRAIL / TURBO
motor_temp °C Motor temperature
motor_power W Electric motor power
peak_assist % ECO / TRAIL / TURBO percentages
shuttle -- yes Shuttle mode value (0-100)
wheel_circumference mm yes Wheel circumference setting
assist_lev1_pct % yes ECO assist percentage
assist_lev2_pct % yes TRAIL assist percentage
assist_lev3_pct % yes TURBO assist percentage
fake_channel -- Bit-coded internal channel
acceleration % yes Acceleration sensitivity

TCX2+ bikes have additional fields (range, altitude, gradient, calories, system temperature, and more). See docs/protocol.md for the full list.

Protocol support

Four protocol generations exist:

Protocol Message format Encryption
TCU1 [sender][channel][data] None
TCX2 2-byte parameter ID + CRC-16 Optional AES-128-CTR
TCX3 Same as TCX2 Optional AES-128-CTR
TCX4 Same as TCX2 Optional AES-128-CTR

TCX2/3/4 share one wire format and differ only in which parameters the bike supports. The BLEProfile enum (TCU1 / TCX) controls which GATT UUIDs to use.

See docs/protocol.md for the full spec.

Pairing

The bike needs a 6-digit PIN for BLE pairing, shown on its TCU screen. Pass it via --pin (CLI) or pin= (Python).

On Windows, bleak's WinRT backend can handle passkey pairing programmatically. If that doesn't work, pair through Windows Bluetooth Settings first, then connect without --pin.

Some newer bikes use numeric comparison instead of passkey entry. On those, pair through your OS Bluetooth settings first.

Development

uv sync --extra dev
uv run pytest

License

MIT

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

specialized_turbo-0.6.1.tar.gz (65.2 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

specialized_turbo-0.6.1-py3-none-any.whl (41.8 kB view details)

Uploaded Python 3

File details

Details for the file specialized_turbo-0.6.1.tar.gz.

File metadata

  • Download URL: specialized_turbo-0.6.1.tar.gz
  • Upload date:
  • Size: 65.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.13

File hashes

Hashes for specialized_turbo-0.6.1.tar.gz
Algorithm Hash digest
SHA256 a79b683fc47e22639e6ee9106965a88c7ec3f676c256bc48143b8251423998e0
MD5 4a1ef740e53fd1b20bc480f5c0e786e3
BLAKE2b-256 da97bf123afa58e1540e8d7fb756846f265f687c8fbff2e09bc2df2b06894279

See more details on using hashes here.

Provenance

The following attestation bundles were made for specialized_turbo-0.6.1.tar.gz:

Publisher: publish.yml on JamieMagee/specialized-turbo

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file specialized_turbo-0.6.1-py3-none-any.whl.

File metadata

File hashes

Hashes for specialized_turbo-0.6.1-py3-none-any.whl
Algorithm Hash digest
SHA256 d15748f4b34fed0a7ae96e5d5c462bdf7de0d7fa07561a67a42440f95208368c
MD5 7103873af1de9ee02bf17b01fcc7028e
BLAKE2b-256 533ab3f86a05a08c52ef6c35d39255576814192308d9b8588b5bfa4075a6c1da

See more details on using hashes here.

Provenance

The following attestation bundles were made for specialized_turbo-0.6.1-py3-none-any.whl:

Publisher: publish.yml on JamieMagee/specialized-turbo

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page