Modern Async driver for Mobvoi/Horizon treadmills (Python 3.13+)
Project description
pymvtreadmill 🏃💨
A modern Python 3.13+ library to control and read data from Mobvoi Home Treadmills and Horizon fitness devices.
Features
- Real-time Reading: Parses Speed directly from BLE notifications.
- Modern Async: Built on
asyncioandbleak. - Control: Set target speed (km/h) via Python commands.
- Auto-Reconnect: Robust connection handling for continuous use.
- Type Safe: Fully typed with modern Python 3.13+ syntax.
- MQTT Bridge: Built-in CLI to bridge treadmill data to MQTT.
Data Protocol
The treadmill sends data as BLE notifications. Currently, only Speed is parsed.
| Feature | Resolution | Protocol |
|---|---|---|
| Speed (Mobvoi) | 0.01 km/h | Bytes 3-4 (Big Endian) |
| Speed (Horizon) | 0.1 km/h | Bytes 3-4 (Big Endian) |
Note: The current implementation defaults to Mobvoi resolution (0.01 km/h).
Installation
Using uv (Recommended)
uv pip install pymvtreadmill
Using pip
pip install pymvtreadmill
MQTT Bridge (CLI)
This package includes a command-line interface (CLI) to bridge treadmill data to an MQTT broker (e.g., for Home Assistant).
Usage
pymvtreadmill --help
Arguments
| Argument | Description | Default |
|---|---|---|
--treadmill-name |
Name filter for the treadmill | Mobvoi |
--mqtt-host |
MQTT broker hostname (Required for MQTT) | - |
--mqtt-port |
MQTT broker port | 1883 |
--mqtt-username |
MQTT username | - |
--mqtt-password |
MQTT password | - |
--mqtt-topic |
MQTT topic for speed | homeassistant/sensor/treadmill/speed/state |
Running with Docker
You can run the project using Docker. This is useful if you want to run the treadmill controller in an isolated environment.
Prerequisites
- Docker installed on your machine.
- A Bluetooth adapter compatible with Linux (BlueZ).
Building the Image
docker build -t pymvtreadmill .
Running the CLI
To access the Bluetooth adapter from within the container, you need to share the DBus socket and run in privileged mode (or with NET_ADMIN capabilities).
By default, the container runs the pymvtreadmill CLI. You can pass arguments directly to it.
# Show help
docker run --rm -it pymvtreadmill --help
# Run as MQTT Bridge
docker run --rm -it \
--net=host \
--privileged \
-v /var/run/dbus:/var/run/dbus \
pymvtreadmill --mqtt-host 192.168.1.100 --mqtt-username myuser --mqtt-password mypass
Running Custom Scripts
If you want to run a custom python script (like the examples), you need to override the entrypoint:
docker run --rm -it \
--entrypoint python \
--net=host \
--privileged \
-v /var/run/dbus:/var/run/dbus \
-v $(pwd)/my_script.py:/app/my_script.py \
pymvtreadmill my_script.py
Docker Compose
For a more permanent setup, you can use the provided docker-compose.yml file.
- Edit
docker-compose.ymlto set your MQTT broker details in thecommandsection. - Run:
docker-compose up -d
Usage (Library)
import asyncio
from pymvtreadmill import TreadmillClient
async def main():
# You can connect by:
# 1. Scanning (default): TreadmillClient()
# 2. Address: TreadmillClient().connect("AA:BB:CC:DD:EE:FF")
# 3. BLEDevice: TreadmillClient().connect(ble_device)
async with TreadmillClient() as client:
print(f"Connected to {client.client.address}")
# Read properties
print(f"Speed: {client.speed} km/h")
print(f"Inclination: {client.inclination}%")
print(f"Distance: {client.distance} m")
# Set speed to 2.5 km/h
await client.set_speed(2.5)
# Keep running for a bit
await asyncio.sleep(10)
if __name__ == "__main__":
asyncio.run(main())
API Reference
TreadmillClient
Properties (Read-Only):
speed(float): Current speed in km/h.inclination(float | None): Current inclination percentage (0.0 - 15.0+).distance(int | None): Current session distance in meters.total_distance(int): Total accumulated distance in meters across sessions.last_run_distance(int | None): Distance of the last completed run session.is_running(bool): Whether the treadmill is currently active.
Methods:
connect(device: BLEDevice | str | None = None): Connects to the treadmill. Accepts ableak.backends.device.BLEDevice, a MAC address string, orNone(triggers a scan).disconnect(): Disconnects from the device.set_speed(speed_kmh: float): Sets the target speed in km/h.
Development
This project strictly requires Python 3.13 or newer. We use uv for dependency management.
Setup
./scripts/setup_env.sh
Verification
uv run ruff check .
uv run black --check .
uv run mypy .
uv run pytest
Please read AGENTS.md before contributing to understand the architectural guidelines and protocol details.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file pymvtreadmill-0.1.0.tar.gz.
File metadata
- Download URL: pymvtreadmill-0.1.0.tar.gz
- Upload date:
- Size: 44.2 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
9d7849ff96c37daa2e564550aa5a11af8ea4fab7560ffd8e1155acbbf0e1c558
|
|
| MD5 |
59a638399fc4403f49f1a76a97dc5d1c
|
|
| BLAKE2b-256 |
1da3210faf98ab950955c94cb83bc396cd35251623df9f0024fdbfd20ae366e7
|
Provenance
The following attestation bundles were made for pymvtreadmill-0.1.0.tar.gz:
Publisher:
release.yml on JohNan/pymvtreadmill
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
pymvtreadmill-0.1.0.tar.gz -
Subject digest:
9d7849ff96c37daa2e564550aa5a11af8ea4fab7560ffd8e1155acbbf0e1c558 - Sigstore transparency entry: 984699805
- Sigstore integration time:
-
Permalink:
JohNan/pymvtreadmill@0c5ef78903bb2b31f5ad9ec657dc7f31eb7dc5a5 -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/JohNan
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@0c5ef78903bb2b31f5ad9ec657dc7f31eb7dc5a5 -
Trigger Event:
release
-
Statement type:
File details
Details for the file pymvtreadmill-0.1.0-py3-none-any.whl.
File metadata
- Download URL: pymvtreadmill-0.1.0-py3-none-any.whl
- Upload date:
- Size: 11.0 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
ccc27300a1e22dc7d1bc2897857e48bcb5e3287d5b10775c14d24df9c6b8f9ec
|
|
| MD5 |
57953c8d379bd97a0d0db68b4bcd3640
|
|
| BLAKE2b-256 |
5b303037675f779ebcf75328c3022ba2814279c3b70affb34a175b06ce142c36
|
Provenance
The following attestation bundles were made for pymvtreadmill-0.1.0-py3-none-any.whl:
Publisher:
release.yml on JohNan/pymvtreadmill
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
pymvtreadmill-0.1.0-py3-none-any.whl -
Subject digest:
ccc27300a1e22dc7d1bc2897857e48bcb5e3287d5b10775c14d24df9c6b8f9ec - Sigstore transparency entry: 984699808
- Sigstore integration time:
-
Permalink:
JohNan/pymvtreadmill@0c5ef78903bb2b31f5ad9ec657dc7f31eb7dc5a5 -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/JohNan
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@0c5ef78903bb2b31f5ad9ec657dc7f31eb7dc5a5 -
Trigger Event:
release
-
Statement type: