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.
Metadata
Release files for pymvtreadmill 0.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| pymvtreadmill-0.1.0.tar.gz | 44.2 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| pymvtreadmill-0.1.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 55.2 kB
Release files / pymvtreadmill-0.1.0.tar.gz
| Download URL | pymvtreadmill-0.1.0.tar.gz |
|---|---|
| Size | 44.2 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
9d7849ff96c37daa2e564550aa5a11af8ea4fab7560ffd8e1155acbbf0e1c558
|
|
BLAKE2b-256 checksum How to use checksums |
1da3210faf98ab950955c94cb83bc396cd35251623df9f0024fdbfd20ae366e7
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.7
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Feb 24, 2026.
Transparency logRelease files / pymvtreadmill-0.1.0-py3-none-any.whl
| Download URL | pymvtreadmill-0.1.0-py3-none-any.whl |
|---|---|
| Size | 11.0 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
ccc27300a1e22dc7d1bc2897857e48bcb5e3287d5b10775c14d24df9c6b8f9ec
|
|
BLAKE2b-256 checksum How to use checksums |
5b303037675f779ebcf75328c3022ba2814279c3b70affb34a175b06ce142c36
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.7
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Feb 24, 2026.
Transparency log