Skip to main content

Open-source Python library for streaming data from Muse S (Athena) EEG headbands

Project description

Amused - A Muse S Direct BLE Implementation

The first open-source BLE protocol implementation for Muse S headsets

Python 3.8+ License: MIT

Finally! Direct BLE connection to Muse S without proprietary SDKs. We're quite amused that we cracked the protocol nobody else has published online!

🎉 The Real Story

We reverse-engineered the BLE communication from scratch to provide researchers with full control over their Muse S devices.

Key breakthrough: The dc001 command must be sent TWICE to start streaming - a critical detail not in any documentation!

Features

  • EEG Streaming: 7 channels at 256 Hz (TP9, AF7, AF8, TP10, FPz, AUX_R, AUX_L)
  • PPG Heart Rate: Real-time HR and HRV from photoplethysmography sensors
  • IMU Motion: 9-axis accelerometer + gyroscope
  • Binary Recording: 10x more efficient than CSV with replay capability
  • Real-time Visualization: Multiple visualization options including band powers
  • No SDK Required: Pure Python with BLE - no proprietary libraries!

Installation

pip install amused

Or from source:

git clone https://github.com/nexon33/amused.git
cd amused
pip install -e .

Visualization Dependencies (Optional)

# For PyQtGraph visualizations
pip install pyqtgraph PyQt5

# For all visualization features
pip install -r requirements-viz.txt

Quick Start

import asyncio
from muse_stream_client import MuseStreamClient
from muse_discovery import find_muse_devices

async def stream():
    # Find Muse devices
    devices = await find_muse_devices()
    if not devices:
        print("No Muse device found!")
        return
    
    device = devices[0]
    print(f"Found: {device.name}")
    
    # Create streaming client
    client = MuseStreamClient(
        save_raw=True,      # Save to binary file
        decode_realtime=True # Decode in real-time
    )
    
    # Stream for 30 seconds
    await client.connect_and_stream(
        device.address,
        duration_seconds=30,
        preset='p1035'  # Full sensor mode
    )
    
    summary = client.get_summary()
    print(f"Collected {summary['packets_received']} packets")

asyncio.run(stream())

Core Components

MuseStreamClient

The main streaming client for real-time data collection:

  • Connects to Muse S via BLE
  • Streams all sensor data (EEG, PPG, IMU)
  • Optional binary recording
  • Real-time callbacks for data processing

MuseRawStream

Binary data storage and retrieval:

  • Efficient binary format (10x smaller than CSV)
  • Fast read/write operations
  • Packet-level access with timestamps

MuseRealtimeDecoder

Real-time packet decoding:

  • Decodes BLE packets on-the-fly
  • Extracts EEG, PPG, IMU data
  • Calculates heart rate from PPG
  • Minimal latency

MuseReplayPlayer

Replay recorded sessions:

  • Play back binary recordings
  • Variable speed playback
  • Same callback interface as live streaming

Usage Examples

1. Basic Streaming

# See examples/01_basic_streaming.py
from muse_stream_client import MuseStreamClient
from muse_discovery import find_muse_devices

client = MuseStreamClient(
    save_raw=False,  # Don't save, just stream
    decode_realtime=True,
    verbose=True
)

devices = await find_muse_devices()
if devices:
    await client.connect_and_stream(
        devices[0].address,
        duration_seconds=30,
        preset='p1035'
    )

2. Recording to Binary

# See examples/02_full_sensors.py
client = MuseStreamClient(
    save_raw=True,  # Enable binary saving
    data_dir="muse_data"
)

# Records all sensors to binary file
await client.connect_and_stream(
    device.address,
    duration_seconds=60,
    preset='p1035'
)

3. Parsing Recorded Data

# See examples/03_parse_data.py
from muse_raw_stream import MuseRawStream
from muse_realtime_decoder import MuseRealtimeDecoder

stream = MuseRawStream("muse_data/recording.bin")
stream.open_read()

decoder = MuseRealtimeDecoder()
for packet in stream.read_packets():
    decoded = decoder.decode(packet.data, packet.timestamp)
    if decoded.eeg:
        print(f"EEG data: {decoded.eeg}")
    if decoded.heart_rate:
        print(f"Heart rate: {decoded.heart_rate:.0f} BPM")

4. Real-time Callbacks

# See examples/04_stream_with_callbacks.py
def process_eeg(data):
    channels = data['channels']
    # Process EEG data in real-time
    print(f"Got EEG from {len(channels)} channels")

def process_heart_rate(hr):
    print(f"Heart Rate: {hr:.0f} BPM")

client = MuseStreamClient()
client.on_eeg(process_eeg)
client.on_heart_rate(process_heart_rate)

await client.connect_and_stream(device.address)

5. Visualization Examples

Band Power Visualization

# See examples/07_lsl_style_viz.py
# Shows Delta, Theta, Alpha, Beta, Gamma bands
# Stable bar graphs without jumpy waveforms

Simple Frequency Display

# See examples/09_frequency_display.py
# Just shows dominant frequency (Hz) for each channel
# Clean, large numbers - no graphs

Heart Rate Monitor

# See examples/06_heart_monitor.py
# Dedicated heart rate display with zones
# Shows current BPM, trend, and history

Protocol Details

The Muse S uses Bluetooth Low Energy (BLE) with a custom protocol:

Connection Sequence

  1. Connect to device
  2. Enable notifications on control characteristic
  3. Send halt command (0x02680a)
  4. Set preset (p1035 for full sensors)
  5. Enable sensor notifications
  6. Send start command (dc001) TWICE
  7. Stream data

Presets

  • p21: Basic EEG only
  • p1034: Sleep mode preset 1
  • p1035: Full sensor mode (recommended)

Packet Types

  • 0xDF: EEG + PPG combined
  • 0xF4: IMU (accelerometer + gyroscope)
  • 0xDB, 0xD9: Mixed sensor data

Troubleshooting

No data received?

  • Ensure dc001 is sent twice (critical!)
  • Check Bluetooth is enabled
  • Make sure Muse S is in pairing mode
  • Try preset p1035 for full sensor access

Heart rate not showing?

  • Heart rate requires ~2 seconds of PPG data
  • Check PPG sensor contact with skin
  • Use preset p1035 which enables PPG

Qt/Visualization errors?

  • Install PyQt5: pip install PyQt5 pyqtgraph
  • On Windows, the library handles Qt/asyncio conflicts automatically
  • Try examples 06 or 09 for simpler visualizations

Examples Directory

The examples/ folder contains working examples:

  1. 01_basic_streaming.py - Simple EEG streaming
  2. 02_full_sensors.py - Record all sensors to binary
  3. 03_parse_data.py - Parse binary recordings
  4. 04_stream_with_callbacks.py - Real-time processing
  5. 05_save_and_replay.py - Record and replay sessions
  6. 06_heart_monitor.py - Clean heart rate display
  7. 07_lsl_style_viz.py - LSL-style band power visualization
  8. 09_frequency_display.py - Simple Hz display for each channel

Contributing

This is the first open implementation! Areas to explore:

  • Additional sensor modes
  • Machine learning pipelines
  • Mobile apps
  • Advanced signal processing

License

MIT License - see LICENSE file

Citation

If you use Amused in research:

@software{amused2025,
  title = {Amused: A Muse S Direct BLE Implementation},
  author = {Your Name},
  year = {2025},
  url = {https://github.com/yourusername/amused}
}

Note: Research software for educational purposes. Probably not for medical use.

Project details


Download files

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

Source Distribution

amused-1.0.1.tar.gz (66.0 kB view details)

Uploaded Source

Built Distribution

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

amused-1.0.1-py3-none-any.whl (64.6 kB view details)

Uploaded Python 3

File details

Details for the file amused-1.0.1.tar.gz.

File metadata

  • Download URL: amused-1.0.1.tar.gz
  • Upload date:
  • Size: 66.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/4.0.2 CPython/3.12.7

File hashes

Hashes for amused-1.0.1.tar.gz
Algorithm Hash digest
SHA256 f254a11130f01de40f0a091d132761e0ab17774d46b6002201ae552233f0d22d
MD5 126d52dfda69bb449f08975cce988487
BLAKE2b-256 243dca652881e252607b709eeb0ad7dc34ba57e36a598ea0af4c5d880f25bc6c

See more details on using hashes here.

File details

Details for the file amused-1.0.1-py3-none-any.whl.

File metadata

  • Download URL: amused-1.0.1-py3-none-any.whl
  • Upload date:
  • Size: 64.6 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/4.0.2 CPython/3.12.7

File hashes

Hashes for amused-1.0.1-py3-none-any.whl
Algorithm Hash digest
SHA256 e2ba36b4a6ba4e22b1ea0efe68c8adb68d6b8e4a95017ab15038ed6e5008c68d
MD5 0f2db6c85115bc01d285a60ee34521f3
BLAKE2b-256 85687ce40895af0884a98c54edcf59739e3d3e4e699151629529eaa759d71862

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page