Skip to main content

openble-muse

The Interaxon Muse EEG headband BLE protocol, read from the Muse Android app (55.1), whose protocol library is libmuse, and from public projects (muse-js, muse-lsl, amused, OpenMuse, muse-rs).

  • openble.muse.uuids: service 0xFE8D and the 273eXXXX characteristics, named as the app names them.
  • openble.muse.models: the model from a serial number, the characteristics each model streams on, default presets and the known preset codes.
  • openble.muse.identify: matches advertisements and reads the hardware generation from the manufacturer data.
  • openble.muse.commands: the length-prefixed ASCII commands (v7, s, h, p21, dc001, …).
  • openble.muse.replies: reassembles the chunked JSON replies and reads the version and status replies.
  • openble.muse.packets, universal, ble4: the three data layouts, selected by the protocol version (pv) the headband reports. All three decode to the same Reading.
  • openble.muse.link: MuseLink keeps one command in flight, as the app does, and prepare runs the app's start-up sequence.

Pure Python 3.11+ with no dependencies and no Bluetooth stack. MuseLink takes a write coroutine and is fed notifications, so it runs over bleak, a test double, or anything else.

The library is built from static reading of the app and from public work, checked against one live headband: a Muse S on firmware 1.0.1 (pv 1) over bleak on macOS. Discovery, the start-up sequence, streaming and halting work on it, and its accelerometer, gyro, DRL/REF and battery packets decode; the tests include those bytes. The Muse S Athena (BLE4) and universal v3 decoders are still checked only against hand-packed bytes. The manual records what the run showed and what is still open, including the BLE4 time-sync message that firmware with pv 5 and up may expect.

pip install openble-muse

Layouts

pv Layout Headbands Module
1–2 Per-sensor: one characteristic per channel Muse 2016, Muse 2, Muse S packets.decode(uuid, data)
3 Universal v3: typed sub-packets on 273e0013 early Muse S Athena firmware (inferred) universal.parse_frame, universal.reading
≥ 4 BLE4: tagged sub-packets on 273e0013 and 273e0014 Muse S Athena ble4.readings(data)
from openble.muse import ble4, commands

commands.encode("s").hex(" ")
# '02 73 0a'

for reading in ble4.readings(notification):
    print(reading.kind, reading.channels, reading.samples)
# eeg ('TP9', 'AF7', 'AF8', 'TP10') ((…), (…), (…), (…))

samples has one row per time step and one column per channel. EEG is in microvolts, the IMU in g and degrees per second. Optics and PPG stay raw. Where the app and the public projects scale differently, openble.muse.readings keeps both constants.

Stream with bleak

import asyncio

from bleak import BleakClient
from openble.muse import ble4, packets, uuids
from openble.muse.link import MuseLink


async def stream(address: str, seconds: float = 10) -> None:
    async with BleakClient(address) as client:

        async def write(payload: bytes) -> None:
            await client.write_gatt_char(uuids.SERIAL, payload, response=False)

        link = MuseLink(write)
        await client.start_notify(uuids.SERIAL, lambda _, data: link.feed(data))
        session = await link.prepare()  # v7, s, h, p<preset>, s
        print(session.status.name, session.model, session.layout)

        def on_data(char, data: bytearray) -> None:
            if session.layout == "ble4":
                found = ble4.readings(data)
            else:
                found = [packets.decode(char.uuid, data)]
            for reading in found:
                print(reading)

        for uuid in session.subscribe:
            await client.start_notify(uuid, on_data)
        await link.start_streaming()  # dc001
        await asyncio.sleep(seconds)
        await link.halt()  # stop streaming before disconnecting

prepare(preset) takes a preset code such as "21" or "1045". Without one it uses the app's default for the model: 21 for most headbands, and 1021 for the Athena. Public Athena clients use 1041, 1034 or 1045 instead. A headband in its bootloader raises BootloaderError; link.boot_to_headset() restarts it, and you then reconnect.

Protocol notes

docs/muse-ble-protocol.md: models, discovery, the GATT layout, the command channel, the connection lifecycle, the three data layouts and the open questions.

Not affiliated with Interaxon. The name identifies the devices this interoperates with. Not a medical device.

License

MIT License, copyright 2026 Kadima Tech.

Metadata

Release files for openble-muse 0.1.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 openble-muse 0.1.0
File Size Uploaded Provenance
openble_muse-0.1.0.tar.gz 38.3 kB With provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for openble-muse 0.1.0
File Interpreter ABI Platform
openble_muse-0.1.0-py3-none-any.whl Python 3 none any Details

Total release size: 61.0 kB

Release files / openble_muse-0.1.0.tar.gz

Download URL openble_muse-0.1.0.tar.gz
Size 38.3 kB
Tags Source
SHA-256 checksum
How to use checksums
03b53c17b538e2959ea78c106de0ac56e5a3fe806a56fe0ef176fd39eae3ce61
BLAKE2b-256 checksum
How to use checksums
4a4eca568b99638be26b9c2bd2965d83801fbcd4ed1b1e620e9705440c576f9d
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 Oct 24, 2026.

Transparency log

Release files / openble_muse-0.1.0-py3-none-any.whl

Download URL openble_muse-0.1.0-py3-none-any.whl
Size 22.7 kB
Tags Python 3
SHA-256 checksum
How to use checksums
20e18921258403b42c76d4f2308a1abcd331f9dc53bfae60cf3d9eda3077c130
BLAKE2b-256 checksum
How to use checksums
5648e9b2807d5f74b751a69232f33b141542252b8cb80335935a838b50daec3b
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 Oct 24, 2026.

Transparency log

Security for openble-muse 0.1.0

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.

Full provenance

All 2 files in this release have been uploaded with provenance metadata.

Select from 2 files

Attestation for openble_muse-0.1.0.tar.gz

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 Oct 24, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Release history Release notifications | RSS feed

This release

0.1.0 This release

2 release files Full provenance

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