Skip to main content

LEGO® Education logo

LEGO® Education Python: What is it?

This is a Python Package for using LEGO® Education hardware via Bluetooth (BLE). The package is designed for communicating with LEGO® Education hardware from LEGO® Education Sciece, and LEGO® Education Computer Science & AI products, using RPC.

The package allows users to connect to LEGO® Education hardware, read sensor data from Color Sensors, Controllers and motors (position, speed, IMU etc.), and send various move commands to the Single Motor and Double Motor.

Relevant links:

Quick Start and Documentation

Quick start guides, documentation and example code is available on Github

Installation

Binary installers for the latest released version are available at the Python Package Index (PyPI)

pip install legoeducation

Firmware Compatibility

The Python Package requires the firmware version on the connected hardware is using the same RPC version. When connecting to LEGO® Education hardware where there is a discrepancy with the Python Package version and firmware version, an error is thrown, asking to either update the Python Package (package RPC version < firmware RPC version) or update the firmware (firmware RPC version < package RPC version) using the LEGO® Education Coding Canvas

LEGO® Education hardware

Advanced Usage

Replacing the BLE Transport Layer

The examples found on Github uses the bleak library. bleak is installed by default to give an immediately usable experience:

pip install legoeducation

Advanced: Install without bleak

If you plan to supply your own BLE stack, you can skip dependency resolution:

pip install --no-deps legoeducation

In that mode the default bleak-based transport will NOT register (bleak missing). You must either register a custom transport before creating hubs (see below), or set the LEGOEDUCATION_BLE_IMPL environment variable.

Provide a custom transport class

Implement a subclass of BLETransport with the required async methods (scan_devices, connect, send, device_disconnect, shutdown_all) and register it:

from legoeducation.ble_transport import BLETransport, register_transport

class MyTransport(BLETransport):
	async def scan_devices(self, timeout, filters=None): ...
	async def connect(self, device, notification_callback, disconnect_callback): ...
	async def send(self, device, message: bytes): ...
	async def device_disconnect(self, device): ...
	def shutdown_all(self): ...

register_transport(MyTransport)

Call register_transport before instantiating any hub classes.

Environment variable override

Set LEGOEDUCATION_BLE_IMPL="my_pkg.my_module:MyTransport" before importing the library to auto-load your implementation.

If no transport is registered you will receive a runtime warning and a null transport will be used (no BLE operations). Register or install bleak to proceed.

Method contract details

Below are the required methods with their expected signatures, argument semantics, return values, and behavioral guarantees. Implementations should be robust against spurious calls (e.g. disconnect on an already disconnected device) and must avoid leaking exceptions (log internally instead; unhandled exceptions are treated as fatal by the worker thread).

  1. async def scan_devices(timeout: float, filters: dict | None = None) -> list | None

    • Purpose: Perform a BLE scan for up to timeout seconds.
    • timeout: Maximum scan duration in seconds (float). Implementations may clamp or round but should not block longer than this.
    • filters: Optional backend-defined filtering criteria (e.g. service UUIDs, name prefixes). May be ignored if unsupported.
    • Return: A list of backend-specific device descriptors (often objects from your BLE stack) or None if scanning not supported. Empty list means the scan completed but found nothing.
    • Edge cases: Return promptly if timeout <= 0. Handle environments with no adapter gracefully (log and return empty list / None).
  2. async def connect(device: Any, notification_callback: Callable, disconnect_callback: Callable) -> bool

    • Purpose: Establish a connection and start notifications for the given device descriptor returned by scan_devices.
    • device: The descriptor/object representing the target device that was returned by scan_devices.
    • notification_callback: Callable invoked for every incoming packet: notification_callback(characteristic_id, data: bytes). Characteristic identifier may be a UUID string or backend object; pick a stable representation and keep it consistent.
    • disconnect_callback: Callable invoked exactly once when the device disconnects (whether initiated locally or due to remote/adapter events).
    • Return: True if connection + notification subscription succeeded; False if the attempt failed (do not raise for routine failures like timeout or permission issues).
    • Edge cases: Must tolerate repeated calls for an already connected device (either no-op returning True or reconnect logic). Ensure disconnect_callback fires even on failed connection attempts if partial resources were allocated.
  3. async def send(device: Any, message: bytes) -> None

    • Purpose: Write raw protocol bytes to the device's primary command characteristic.
    • device: Connected device reference.
    • message: Exact bytes to transmit; implementation must not mutate. Fragmentation/retries are transport concerns and should be hidden from caller.
    • Return: None. Raise only on truly unrecoverable programmer errors (e.g. device not connected) preferably converting them into logged warnings instead.
    • Edge cases: If the device disconnects mid-write, swallow backend errors and optionally trigger a disconnect callback if not yet fired.
  4. async def device_disconnect(device: Any) -> None

    • Purpose: Gracefully terminate an individual connection.
    • device: Connected device reference.
    • Behavior: Idempotent—calling multiple times should not raise. Should trigger the disconnect_callback once if connected.
    • Return: None.
    • Edge cases: Handle cases where the adapter already reported a disconnect between scheduling and execution of this coroutine.
  5. def shutdown_all(self) -> None

    • Purpose: Synchronously (non-async) tear down all connections and release resources (cancel scans, close adapters, stop loops as needed).
    • Behavior: Must invoke the shutdown_callback provided to the transport constructor even if there were no active devices.
    • Return: None.
    • Edge cases: Safe to call while no devices are connected or while a connection attempt is in flight (should abort attempts cleanly).

General expectations:

  • Threading/loop: All coroutines run inside the worker's asyncio loop provided by the API. Avoid creating separate event loops unless absolutely necessary.
  • Exceptions: Catch backend-specific exceptions; convert to logs and clean disconnects. Unhandled exceptions propagate and can terminate the worker.
  • Logging: Prefer using self.logger for consistency.
  • Performance: Return control quickly -> long blocking calls should be await-based.
  • Resource cleanup: Ensure device objects won't hold references after disconnect (helps GC and avoids stale callbacks).

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

legoeducation-1.1.1.tar.gz (54.9 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

legoeducation-1.1.1-py3-none-any.whl (57.4 kB view details)

Uploaded Python 3

File details

Details for the file legoeducation-1.1.1.tar.gz.

File metadata

  • Download URL: legoeducation-1.1.1.tar.gz
  • Upload date:
  • Size: 54.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/7.0.0 CPython/3.14.0

File hashes

Hashes for legoeducation-1.1.1.tar.gz
Algorithm Hash digest
SHA256 5a13afe93a5f8fbcdde49250fa1f75c8f9020a328a6a2b96a92fc444022af033
MD5 9c5782736070940f7c2f01e7e89e9ce3
BLAKE2b-256 b0fee7326b8228fbaf569f47d9a58e47b58a6b5a658b7a463b777433047f72e8

See more details on using hashes here.

File details

Details for the file legoeducation-1.1.1-py3-none-any.whl.

File metadata

  • Download URL: legoeducation-1.1.1-py3-none-any.whl
  • Upload date:
  • Size: 57.4 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/7.0.0 CPython/3.14.0

File hashes

Hashes for legoeducation-1.1.1-py3-none-any.whl
Algorithm Hash digest
SHA256 12e5494e216009cb9b04473f20dc93ea401a769ac711fbd65c37553101817f1e
MD5 44fbd97c2df3d702a976c5e930346f74
BLAKE2b-256 975f948af60b642ac91c05bd7d38939ad7f0b93c1f4c5c01c8869c773d046ef4

See more details on using hashes here.

Release history Release notifications | RSS feed

This release

1.1.1 This release

2 files

1.0.6

2 files

1.0.5

2 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