Your wheelchair, your rules.
Python toolkit for the Alber e-motion M25 power-assist wheels. It started as a fork of roll2own/m5squared and grew into a Python-focused control and analysis stack.
Presented at 39C3 Hamburg: "Pwn2Roll: Who Needs a 595€ Remote When You Have wheelchair.py?"
This repository contains the Python control stack for the M25 protocol. It focuses on protocol handling, transport abstractions, a GUI control surface, and supporting utilities for analysis and testing.
The project keeps the control stack split into clear layers:
- Core control logic with mapper and supervisor components
- Transport abstraction for BLE, mock devices, and future transports
- GUI and CLI tools for interactive control and diagnostics
- Protocol utilities for encryption, decryption, packet framing, and analysis
- Decrypt and inspect the M25 Bluetooth protocol.
- Send protocol commands to read status and change settings.
- Provide a modular Python architecture with safer control flow.
- Support Windows and Linux Bluetooth backends.
- Offer mock and demo tooling for development and testing.
| Feature | Official ECS Remote | m5squared |
|---|---|---|
| Price | 595 euro | Free |
| Read battery | Yes | Yes |
| Change assist level | Yes | Yes |
| Toggle hill hold | Yes | Yes |
| Read raw sensor data | No | Yes |
| Adjust drive parameters | No | Yes |
| Works on Linux | No | Yes |
./setup-linux.shThat script sets up the local environment, installs the project, and prepares the common Linux dependencies.
# Windows: Double-click start.bat
# Linux/macOS: ./start.sh
# Or:
python launch.pySee QUICKSTART.md for more options and details.
# Setup (Ubuntu/Debian)
sudo apt install python3.12-venv python3-bluez
python3 -m venv .venv --system-site-packages
.venv/bin/pip install -e .
source .venv/bin/activate
# Get your AES keys (scan the QR codes on your wheel hubs)
python m25_qr_to_key.py "YourQRCodeHere"
# Talk to your wheels
python m25_ecs.py --left-addr AA:BB:CC:DD:EE:FF --right-addr 11:22:33:44:55:66 \
--left-key HEXKEY --right-key HEXKEYThis project uses a layered control architecture.
- Application layer: GUI, CLI, and demo entry points.
- Control layer: mapper, supervisor, and state handling.
- Protocol layer: m25_protocol.py and m25_crypto.py.
- Transport layer: BLE, mock, and other transport adapters.
- core/mapper.py: transforms input events into protocol commands.
- core/supervisor.py: safety state machine and control guardrails.
- core/transport/: unified interface for BLE, mock devices, and future transports.
- core/README.md: deeper reference for the shared control core.
| Script | What it does |
|---|---|
| m25_qr_to_key.py | QR code to AES key conversion |
| m25_ecs.py | Read status and change settings |
| m25_gui.py | GUI interface for the Python control stack |
| launch.py | Unified launcher for GUI and CLI entry points |
| m25_decrypt.py | Decrypt captured Bluetooth packets |
| m25_encrypt.py | Encrypt packets for transmission |
| m25_analyzer.py | Inspect packet streams |
| m25_parking.py | Remote movement control |
| m25_bluetooth.py | Linux Bluetooth scan/connect/send/receive |
| m25_bluetooth_windows.py | Windows Bluetooth support via Bleak |
Each wheel has a QR code sticker. That's your key to the kingdom.
- Scan the QR code (22 characters of proprietary encoding).
- Run
python m25_qr_to_key.py "ABCD1234...". - Get a 16-byte hex key.
- Use it with
--left-key/--right-key.
Both wheels have different keys. Yes, you need both.
Once you've saved your keys, consider taping over the QR codes.
Bluetooth SPP on channel 6. Packets look like:
[0xEF] [length:2] [IV encrypted with ECB:16] [payload encrypted with CBC:n] [CRC:2]
Why encrypt the IV with ECB first? Nobody knows. But it works.
- Python 3.8+ (3.12 recommended)
- pycryptodome for AES encryption and decryption
- python-dotenv for configuration management
- bluez / python3-bluez for native Linux Bluetooth support
- bleak for cross-platform BLE
- pygame for optional gamepad input during testing
All Python dependencies are specified in pyproject.toml and install automatically with pip install -e ..
Create a .env file from the template to store your credentials securely:
cp .env.example .envEdit .env and fill in:
M25_LEFT_MAC- Left wheel MAC addressM25_LEFT_KEY- Left wheel encryption keyM25_RIGHT_MAC- Right wheel MAC addressM25_RIGHT_KEY- Right wheel encryption key
The .env file is gitignored and won't be committed.
This is for your own wheels. Don't be creepy.
- Research and education: Yes
- Your own devices: Yes
- Other people's wheelchairs: Absolutely not
- [DE] Warum eine Multiple-Sklerose-Erkrankte ihren Rollstuhl hackte
- [DE] Wie eine Multiple-Sklerose-Erkrankte die Paywall ihres Rollstuhls knackte
- [DE] 39C3: Rollstuhl-Security – Wenn ein QR-Code alle Schutzmechanismen aushebelt
- [EN] Louis Rossmann: Wheelchairs have paywalls and digital locks now (YouTube video)
- Upstream project: roll2own/m5squared
- Supplementary resources: m5squared-resources
- Architecture docs: core/README.md
- Project docs: doc/
This is non-profit research code. No exploits, no vulnerabilities. It's just documentation and tools for interoperability with a protocol that already exists.
The security model here is identical to what the official apps use: if you don't have the QR code, you don't get access. We're not bypassing anything, just using the same protocol with our own code. Your wheels, your keys, your choice of software.
That said, this only applies to your own equipment. Using these tools on someone else's wheelchair without explicit consent isn't just unethical, it might cause serious safety issues. Also: creepy.
The author(s) take responsible disclosure seriously. These are mobility devices that people depend on every day, and that should come before making a point.
- Core protocol and transport work
- GUI and CLI improvements
- Logging and diagnostics cleanup
- Documentation updates
- Test coverage and tooling
Pull requests are welcome, especially for transport reliability improvements, protocol handling fixes, cross-platform BLE bug fixes, documentation, and examples.