Skip to main content

apitor-ble

PyPI Python versions CI License: MIT Bluetooth LE Code style: black Ruff

A small, dependency-light Python library for driving Apitor toy robots over Bluetooth Low Energy — hardware tested using Robot J — plus a test/demo CLI and full protocol documentation.

The protocol was reverse-engineered from the official Apitor Kit Android app. See docs/PROTOCOL.md for the byte-level details.

⚠️ Unofficial. Not affiliated with or endorsed by Apitor. For use with hardware you own, for interoperability and educational purposes.

Why?

Apitor doesn't publish a public Bluetooth protocol for its robots, so there's no official way to control them from your own code. This library fills that gap: the protocol was independently reverse-engineered from the official app purely for interoperability — so people can experiment, learn, teach, and build their own robotics projects with hardware they already own.

Features

  • Async API built on bleak (Windows/macOS/Linux).
  • Scan + name-filter for Apitor devices, connect, and perform the required authorization handshake automatically.
  • Motor control, LED control, raw frame access, and notification callbacks.
  • Pure, hardware-free protocol layer (apitor_ble.protocol) with unit tests.

Demo

See a real robot driven straight from Python — no app required.

Install

pip install apitor-ble

From source

pip install -e .

Requirements

  • Python 3.10+
  • A Bluetooth Low Energy adapter
  • Supported on Windows, macOS, and Linux (via bleak)

New to programming? Start here 🤖

There's a beginner-friendly API — no async, no Bluetooth setup, just plain commands. See docs/EASY.md.

from apitor_ble.easy import Robot

robot = Robot()            # Robot J by default; Robot(product="s") for others
robot.connect()

robot.forward(2)       # drive forward for 2 seconds
robot.color("blue")    # make the lights blue
robot.wait(1)
robot.lights_off()

robot.disconnect()

Works with every Apitor BLE kit (Robot J, S, Q, R, X, and Wheels). Driving directions can be calibrated per build in a few lines — see Setting up a different robot. For the official motor tables of every buildable model, see docs/ROBOTS.md.

Teaching with this? There's a classroom quickstart with lesson ideas and tips in docs/TEACHERS.md.

Use it in your project

import asyncio
from apitor_ble import ApitorRobot, Motor, Direction, Color

async def main():
    robot = await ApitorRobot.discover(product="j")
    async with robot:
        await robot.run_motor(Motor.M1, Direction.D1, speed=8)
        await asyncio.sleep(2)
        await robot.stop_all_motors()
        await robot.all_leds(Color.BLUE)

asyncio.run(main())

A fuller example is in examples/use_in_another_project.py.

Try it from the command line

Installing the package provides an apitor command:

apitor scan        # find nearby Robot J devices
apitor demo        # connect and run a motor + LED routine
apitor listen      # print incoming notification frames
apitor drive       # keyboard-driven live control

apitor demo --address AA:BB:CC:DD:EE:FF   # skip scanning
apitor scan --product s                   # a different Apitor product
apitor demo --verbose                     # log raw TX/RX frames

(The older python main.py <command> invocation still works too.)

How it fits together

Each layer talks only to the one below it, so you can plug in at whatever level you need:

Your code
│
├── easy.py        Beginner synchronous API  (uses profiles.py)
│
├── robot.py       Async BLE driver          (decodes via sensor.py)
│
├── protocol.py    Packet encoding
│
├── bleak          Bluetooth library
│
├── Bluetooth LE   Your computer's radio
│
└── Apitor Robot   Robot J / S / Q / R / X / Wheels

Beginners start at easy.py. Advanced users can drop straight to robot.py for the full async API, or to protocol.py to build frames by hand.

Project layout

apitor-ble/
├── apitor_ble/
│   ├── __init__.py        # public API
│   ├── protocol.py        # pure byte-level protocol (no I/O)
│   ├── sensor.py          # notification / telemetry decoding
│   ├── robot.py           # async BLE driver (bleak)
│   ├── profiles.py        # per-robot driving profiles
│   └── easy.py            # beginner-friendly synchronous API
├── main.py                # test / demo CLI
├── examples/
│   ├── use_in_another_project.py
│   └── first_program.py
├── tests/
│   ├── test_protocol.py   # hardware-free frame tests
│   ├── test_sensor.py     # notification decoding tests
│   ├── test_easy.py       # easy-API helper tests
│   └── test_profiles.py   # driving-profile tests
├── docs/
│   ├── PROTOCOL.md        # reverse-engineered protocol reference
│   ├── USAGE.md           # library + CLI usage guide
│   ├── EASY.md            # beginner guide + calibration steps
│   ├── ROBOTS.md          # official motor tables per model
│   └── TEACHERS.md        # classroom quickstart
├── CHANGELOG.md
├── CONTRIBUTING.md
├── LICENSE
├── pyproject.toml
└── requirements.txt

Tests

The protocol layer needs no hardware or bleak:

pip install pytest
pytest

Robot J at a glance

Item Value Notes
Service 0000f0ff-0000-1000-8000-00805f9b34fb GATT service
Write 0000f001-... phone → robot, split into 20-byte chunks
Notify 0000f002-... robot → phone
Name ApitorTJ... advertised name, case-insensitive
Auth 55AA1120 436E354174675A4C4A7671723863447A send right after connect
Motor 55AA03 <port> <dir> <speed> e.g. M1 fwd spd8 = 55AA03 06 01 08
Stop 55AA03 10 00 00 stop all motors
LED 55AA04 <index> <color> 00 00 index 4 = all LEDs

Roadmap

Planned future improvements:

  • Publish to PyPI
  • Add GitHub Actions CI
  • Add coverage reporting
  • Support additional Apitor firmware revisions
  • More example programs
  • Additional classroom resources

Changelog

See CHANGELOG.md for release notes.

Contributing

Contributions are welcome — see CONTRIBUTING.md. Especially valuable:

  • Testing on additional robots (and calibrating them on real hardware)
  • Protocol verification
  • Documentation improvements
  • New example programs
  • Bug reports

Disclaimer

This project was independently reverse-engineered for interoperability.

It is not affiliated with, endorsed by, or supported by Apitor.

All trademarks belong to their respective owners.

License

MIT — see LICENSE.

Metadata

Release files for apitor-ble 0.3.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for apitor-ble 0.3.0
File Size Uploaded
apitor_ble-0.3.0.tar.gz 30.0 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for apitor-ble 0.3.0
File Interpreter ABI Platform
apitor_ble-0.3.0-py3-none-any.whl Python 3 none any Details

Total release size: 57.2 kB

Release files / apitor_ble-0.3.0.tar.gz

Download URL apitor_ble-0.3.0.tar.gz
Size 30.0 kB
Tags Source
SHA-256 checksum
How to use checksums
3295d83647b7a9fed2e6930e1654a26806c58f3c2812ec4cbbbb69ba53d0a360
BLAKE2b-256 checksum
How to use checksums
3b6b672a0ef63ed4a070e995b0433a726f4b3b1578a56608f2860cfd26fcc6c7
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

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 Aug 2, 2026.

Transparency log

Release files / apitor_ble-0.3.0-py3-none-any.whl

Download URL apitor_ble-0.3.0-py3-none-any.whl
Size 27.2 kB
Tags Python 3
SHA-256 checksum
How to use checksums
c5ce97842a1f1a93e6f94923989a25b7538e72757e9c98998a564ec37d41d162
BLAKE2b-256 checksum
How to use checksums
0658423dcd15a3a5e77b24e95edf1a549486118452577eb6731212c56a8de3b0
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

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 Aug 2, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.3.0 This release

2 release files

0.2.1

2 release files

0.2.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page