Skip to content

About

Async Rust library and stateless CLI for KingSmith WalkingPad treadmills

Resources

Contributing

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Repository files navigation

walkingpad

walkingpad is an asynchronous Rust library and stateless command-line tool for KingSmith WalkingPad treadmills. It connects, performs one operation, and disconnects; no background daemon or persistent interactive shell is needed.

The protocol was tested with a WalkingPad A1. Other models that expose the same FE00/FE01/FE02 GATT service and characteristics may work, but should be tested carefully at low speed.

Install

cargo install walkingpad

Bluetooth access must be allowed for your terminal application. The original phone app must be disconnected because the belt accepts only one client at a time.

CLI

Discover once and save the platform-specific device identifier:

walkingpad scan

Subsequent commands reopen that known peripheral without scanning, connect, perform the operation, and disconnect:

walkingpad start
walkingpad speed 2.0
walkingpad status
walkingpad status --json
walkingpad mode automatic
walkingpad stop

Plain walkingpad stop requests zero speed and leaves the belt ready for a later command. walkingpad stop --standby also powers down into standby; depending on the model, physical wake-up may then be required before another Bluetooth command can connect.

If the saved identifier is no longer known to the operating system, a command automatically scans for the proprietary WalkingPad service and refreshes the saved selection. Use walkingpad device to inspect it or walkingpad forget to remove it.

The saved identifier lives in the platform-native per-user application data directory. Only one CLI process can control the belt at a time; a process lock prevents overlapping commands.

Library

The library keeps Bluetooth transport and packet parsing behind a small async API suitable for adding controls to a desktop or mobile application:

use std::time::Duration;

use walkingpad::WalkingPad;

# async fn run(id: walkingpad::DeviceId) -> walkingpad::Result<()> {
let timeout = Duration::from_secs(5);
let mut pad = WalkingPad::open(&id, timeout).await?;
pad.start().await?;
let status = pad.status(timeout).await?;
println!("{} steps", status.steps);
pad.disconnect().await?;
# Ok(())
# }

For first-run setup, call WalkingPad::discover, persist DiscoveredPad::id, and call DiscoveredPad::connect. DeviceStore provides the same atomic JSON persistence and command lock used by the CLI, but apps may manage identifiers themselves.

The protocol module exposes packet UUIDs and parsers for integrations that need lower-level access.

Diagnostics and long-lived connections

Every connection enables the notification characteristic once and keeps it active until disconnect. This lets long-lived applications receive and inspect notifications emitted outside an explicit status request.

The connection retains the newest 128 transmitted commands and received notifications in memory. The history is bounded, starts empty for every new connection, and can be copied into an application's incident record before it reconnects:

use std::time::Duration;

use walkingpad::WalkingPad;

async fn poll(pad: &mut WalkingPad) {
    if let Err(error) = pad.status(Duration::from_secs(2)).await {
        eprintln!("status failed: {error}");
        for packet in pad.packet_history() {
            eprintln!("{:?} {}", packet.direction, packet.hex());
        }
    }
}

With a tracing subscriber installed, malformed or unrecognized notifications are warnings containing their complete raw hexadecimal packet. Request and disconnect failures include the retained packet history. Valid status packets produce an info event for the initial operational state and whenever the belt state, mode, current speed, target speed, controller button, or either currently unclassified status byte changes; counter-only updates remain quiet.

WalkingPad::disconnect waits at most three seconds for the Bluetooth stack. Use disconnect_with_timeout to choose a different limit. Dropping a connection also stops its notification task, but applications should still disconnect explicitly when possible.

Applications that manage device identifiers themselves can avoid compiling the CLI and persistence dependencies:

[dependencies]
walkingpad = { version = "0.3", default-features = false }

Reconnection model

bluest::Adapter::open_device is the fast path. On macOS, it maps to CoreBluetooth's retrievePeripherals(withIdentifiers:), so a saved device can be reopened without waiting for an advertisement scan. Linux and Windows use their corresponding persistent platform identifiers through the same API.

The belt must still be powered on and reachable for the new process to create a BLE connection. Stateless commands trade a short connection setup delay for simple automation and no continuously running process.

Safety

This software controls moving equipment. The start command lets the belt choose its retained or configured starting target, which may be faster than 0.5 km/h. Keep the belt clear, remain ready to step off, and keep the hardware remote or emergency stop within reach. A CLI command cannot stop a belt if Bluetooth is unavailable.

Development

The MSRV is Rust 1.85.

cargo fmt --all -- --check
cargo clippy --locked --all-targets --all-features -- -D warnings
cargo test --locked --all-targets --all-features
cargo package --locked

License and protocol ancestry

MIT. The packet protocol was derived from the MIT-licensed ph4r05/ph4-walkingpad; see THIRD_PARTY_NOTICES.md.

About

Async Rust library and stateless CLI for KingSmith WalkingPad treadmills

Resources

Contributing

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages