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
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
- Connect to device
- Enable notifications on control characteristic
- Send halt command (
0x02680a) - Set preset (
p1035for full sensors) - Enable sensor notifications
- Send start command (
dc001) TWICE - Stream data
Presets
p21: Basic EEG onlyp1034: Sleep mode preset 1p1035: Full sensor mode (recommended)
Packet Types
0xDF: EEG + PPG combined0xF4: IMU (accelerometer + gyroscope)0xDB,0xD9: Mixed sensor data
Troubleshooting
No data received?
- Ensure
dc001is sent twice (critical!) - Check Bluetooth is enabled
- Make sure Muse S is in pairing mode
- Try preset
p1035for full sensor access
Heart rate not showing?
- Heart rate requires ~2 seconds of PPG data
- Check PPG sensor contact with skin
- Use preset
p1035which 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:
01_basic_streaming.py- Simple EEG streaming02_full_sensors.py- Record all sensors to binary03_parse_data.py- Parse binary recordings04_stream_with_callbacks.py- Real-time processing05_save_and_replay.py- Record and replay sessions06_heart_monitor.py- Clean heart rate display07_lsl_style_viz.py- LSL-style band power visualization09_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
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
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
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
f254a11130f01de40f0a091d132761e0ab17774d46b6002201ae552233f0d22d
|
|
| MD5 |
126d52dfda69bb449f08975cce988487
|
|
| BLAKE2b-256 |
243dca652881e252607b709eeb0ad7dc34ba57e36a598ea0af4c5d880f25bc6c
|
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
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
e2ba36b4a6ba4e22b1ea0efe68c8adb68d6b8e4a95017ab15038ed6e5008c68d
|
|
| MD5 |
0f2db6c85115bc01d285a60ee34521f3
|
|
| BLAKE2b-256 |
85687ce40895af0884a98c54edcf59739e3d3e4e699151629529eaa759d71862
|