# Amused - A Muse S Direct BLE Implementation
**The first open-source BLE protocol implementation for Muse S headsets**
[](https://www.python.org/downloads/)
[](https://opensource.org/licenses/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
```bash
pip install amused
```
Or from source:
```bash
git clone https://github.com/nexon33/amused.git
cd amused
pip install -e .
```
### Visualization Dependencies (Optional)
```bash
# For PyQtGraph visualizations
pip install pyqtgraph PyQt5
# For all visualization features
pip install -r requirements-viz.txt
```
## Quick Start
```python
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
```python
# 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
```python
# 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
```python
# 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
```python
# 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
```python
# See examples/07_lsl_style_viz.py
# Shows Delta, Theta, Alpha, Beta, Gamma bands
# Stable bar graphs without jumpy waveforms
```
#### Simple Frequency Display
```python
# See examples/09_frequency_display.py
# Just shows dominant frequency (Hz) for each channel
# Clean, large numbers - no graphs
```
#### Heart Rate Monitor
```python
# 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 = {Adrian Tadeusz Belmans},
year = {2025},
url = {https://github.com/nexon33/amused}
}
```
---
**Note**: Research software for educational purposes. Probably not for medical use.
Raw data
{
"_id": null,
"home_page": null,
"name": "amused",
"maintainer": null,
"docs_url": null,
"requires_python": ">=3.8",
"maintainer_email": null,
"keywords": "muse, eeg, ppg, fnirs, biometrics, neuroscience, brain-computer-interface, bci, bluetooth, ble, biosignals, heart-rate, meditation, sleep-monitoring",
"author": null,
"author_email": "Adrian Tadeusz Belmans <adrian.belmans@gmail.com>",
"download_url": "https://files.pythonhosted.org/packages/ef/d9/4476f04535471560ccde88df28c4487eeb42df6fa6df71a9dfafb91c2022/amused-1.0.2.tar.gz",
"platform": null,
"description": "# Amused - A Muse S Direct BLE Implementation\r\n\r\n**The first open-source BLE protocol implementation for Muse S headsets**\r\n\r\n[](https://www.python.org/downloads/)\r\n[](https://opensource.org/licenses/MIT)\r\n\r\n> **Finally!** Direct BLE connection to Muse S without proprietary SDKs. We're quite *amused* that we cracked the protocol nobody else has published online!\r\n\r\n## \ud83c\udf89 The Real Story\r\n\r\nWe reverse-engineered the BLE communication from scratch to provide researchers with full control over their Muse S devices. \r\n\r\n**Key breakthrough:** The `dc001` command must be sent TWICE to start streaming - a critical detail not in any documentation!\r\n\r\n## Features\r\n\r\n- **EEG Streaming**: 7 channels at 256 Hz (TP9, AF7, AF8, TP10, FPz, AUX_R, AUX_L)\r\n- **PPG Heart Rate**: Real-time HR and HRV from photoplethysmography sensors \r\n- **IMU Motion**: 9-axis accelerometer + gyroscope\r\n- **Binary Recording**: 10x more efficient than CSV with replay capability\r\n- **Real-time Visualization**: Multiple visualization options including band powers\r\n- **No SDK Required**: Pure Python with BLE - no proprietary libraries!\r\n\r\n## Installation\r\n\r\n```bash\r\npip install amused\r\n```\r\n\r\nOr from source:\r\n```bash\r\ngit clone https://github.com/nexon33/amused.git\r\ncd amused\r\npip install -e .\r\n```\r\n\r\n### Visualization Dependencies (Optional)\r\n\r\n```bash\r\n# For PyQtGraph visualizations\r\npip install pyqtgraph PyQt5\r\n\r\n# For all visualization features\r\npip install -r requirements-viz.txt\r\n```\r\n\r\n## Quick Start\r\n\r\n```python\r\nimport asyncio\r\nfrom muse_stream_client import MuseStreamClient\r\nfrom muse_discovery import find_muse_devices\r\n\r\nasync def stream():\r\n # Find Muse devices\r\n devices = await find_muse_devices()\r\n if not devices:\r\n print(\"No Muse device found!\")\r\n return\r\n \r\n device = devices[0]\r\n print(f\"Found: {device.name}\")\r\n \r\n # Create streaming client\r\n client = MuseStreamClient(\r\n save_raw=True, # Save to binary file\r\n decode_realtime=True # Decode in real-time\r\n )\r\n \r\n # Stream for 30 seconds\r\n await client.connect_and_stream(\r\n device.address,\r\n duration_seconds=30,\r\n preset='p1035' # Full sensor mode\r\n )\r\n \r\n summary = client.get_summary()\r\n print(f\"Collected {summary['packets_received']} packets\")\r\n\r\nasyncio.run(stream())\r\n```\r\n\r\n## Core Components\r\n\r\n### `MuseStreamClient`\r\nThe main streaming client for real-time data collection:\r\n- Connects to Muse S via BLE\r\n- Streams all sensor data (EEG, PPG, IMU)\r\n- Optional binary recording\r\n- Real-time callbacks for data processing\r\n\r\n### `MuseRawStream`\r\nBinary data storage and retrieval:\r\n- Efficient binary format (10x smaller than CSV)\r\n- Fast read/write operations\r\n- Packet-level access with timestamps\r\n\r\n### `MuseRealtimeDecoder`\r\nReal-time packet decoding:\r\n- Decodes BLE packets on-the-fly\r\n- Extracts EEG, PPG, IMU data\r\n- Calculates heart rate from PPG\r\n- Minimal latency\r\n\r\n### `MuseReplayPlayer`\r\nReplay recorded sessions:\r\n- Play back binary recordings\r\n- Variable speed playback\r\n- Same callback interface as live streaming\r\n\r\n## Usage Examples\r\n\r\n### 1. Basic Streaming\r\n```python\r\n# See examples/01_basic_streaming.py\r\nfrom muse_stream_client import MuseStreamClient\r\nfrom muse_discovery import find_muse_devices\r\n\r\nclient = MuseStreamClient(\r\n save_raw=False, # Don't save, just stream\r\n decode_realtime=True,\r\n verbose=True\r\n)\r\n\r\ndevices = await find_muse_devices()\r\nif devices:\r\n await client.connect_and_stream(\r\n devices[0].address,\r\n duration_seconds=30,\r\n preset='p1035'\r\n )\r\n```\r\n\r\n### 2. Recording to Binary\r\n```python\r\n# See examples/02_full_sensors.py\r\nclient = MuseStreamClient(\r\n save_raw=True, # Enable binary saving\r\n data_dir=\"muse_data\"\r\n)\r\n\r\n# Records all sensors to binary file\r\nawait client.connect_and_stream(\r\n device.address,\r\n duration_seconds=60,\r\n preset='p1035'\r\n)\r\n```\r\n\r\n### 3. Parsing Recorded Data\r\n```python\r\n# See examples/03_parse_data.py\r\nfrom muse_raw_stream import MuseRawStream\r\nfrom muse_realtime_decoder import MuseRealtimeDecoder\r\n\r\nstream = MuseRawStream(\"muse_data/recording.bin\")\r\nstream.open_read()\r\n\r\ndecoder = MuseRealtimeDecoder()\r\nfor packet in stream.read_packets():\r\n decoded = decoder.decode(packet.data, packet.timestamp)\r\n if decoded.eeg:\r\n print(f\"EEG data: {decoded.eeg}\")\r\n if decoded.heart_rate:\r\n print(f\"Heart rate: {decoded.heart_rate:.0f} BPM\")\r\n```\r\n\r\n### 4. Real-time Callbacks\r\n```python\r\n# See examples/04_stream_with_callbacks.py\r\ndef process_eeg(data):\r\n channels = data['channels']\r\n # Process EEG data in real-time\r\n print(f\"Got EEG from {len(channels)} channels\")\r\n\r\ndef process_heart_rate(hr):\r\n print(f\"Heart Rate: {hr:.0f} BPM\")\r\n\r\nclient = MuseStreamClient()\r\nclient.on_eeg(process_eeg)\r\nclient.on_heart_rate(process_heart_rate)\r\n\r\nawait client.connect_and_stream(device.address)\r\n```\r\n\r\n### 5. Visualization Examples\r\n\r\n#### Band Power Visualization\r\n```python\r\n# See examples/07_lsl_style_viz.py\r\n# Shows Delta, Theta, Alpha, Beta, Gamma bands\r\n# Stable bar graphs without jumpy waveforms\r\n```\r\n\r\n#### Simple Frequency Display\r\n```python\r\n# See examples/09_frequency_display.py\r\n# Just shows dominant frequency (Hz) for each channel\r\n# Clean, large numbers - no graphs\r\n```\r\n\r\n#### Heart Rate Monitor\r\n```python\r\n# See examples/06_heart_monitor.py\r\n# Dedicated heart rate display with zones\r\n# Shows current BPM, trend, and history\r\n```\r\n\r\n## Protocol Details\r\n\r\nThe Muse S uses Bluetooth Low Energy (BLE) with a custom protocol:\r\n\r\n### Connection Sequence\r\n1. Connect to device\r\n2. Enable notifications on control characteristic\r\n3. Send halt command (`0x02680a`)\r\n4. Set preset (`p1035` for full sensors)\r\n5. Enable sensor notifications\r\n6. Send start command (`dc001`) **TWICE**\r\n7. Stream data\r\n\r\n### Presets\r\n- `p21`: Basic EEG only\r\n- `p1034`: Sleep mode preset 1\r\n- `p1035`: Full sensor mode (recommended)\r\n\r\n### Packet Types\r\n- `0xDF`: EEG + PPG combined\r\n- `0xF4`: IMU (accelerometer + gyroscope)\r\n- `0xDB`, `0xD9`: Mixed sensor data\r\n\r\n## Troubleshooting\r\n\r\n### No data received?\r\n- Ensure `dc001` is sent twice (critical!)\r\n- Check Bluetooth is enabled\r\n- Make sure Muse S is in pairing mode\r\n- Try preset `p1035` for full sensor access\r\n\r\n### Heart rate not showing?\r\n- Heart rate requires ~2 seconds of PPG data\r\n- Check PPG sensor contact with skin\r\n- Use preset `p1035` which enables PPG\r\n\r\n### Qt/Visualization errors?\r\n- Install PyQt5: `pip install PyQt5 pyqtgraph`\r\n- On Windows, the library handles Qt/asyncio conflicts automatically\r\n- Try examples 06 or 09 for simpler visualizations\r\n\r\n## Examples Directory\r\n\r\nThe `examples/` folder contains working examples:\r\n\r\n1. `01_basic_streaming.py` - Simple EEG streaming\r\n2. `02_full_sensors.py` - Record all sensors to binary\r\n3. `03_parse_data.py` - Parse binary recordings\r\n4. `04_stream_with_callbacks.py` - Real-time processing\r\n5. `05_save_and_replay.py` - Record and replay sessions\r\n6. `06_heart_monitor.py` - Clean heart rate display\r\n7. `07_lsl_style_viz.py` - LSL-style band power visualization\r\n8. `09_frequency_display.py` - Simple Hz display for each channel\r\n\r\n## Contributing\r\n\r\nThis is the first open implementation! Areas to explore:\r\n- Additional sensor modes\r\n- Machine learning pipelines\r\n- Mobile apps\r\n- Advanced signal processing\r\n\r\n## License\r\n\r\nMIT License - see LICENSE file\r\n\r\n## Citation\r\n\r\nIf you use Amused in research:\r\n```\r\n@software{amused2025,\r\n title = {Amused: A Muse S Direct BLE Implementation},\r\n author = {Adrian Tadeusz Belmans},\r\n year = {2025},\r\n url = {https://github.com/nexon33/amused}\r\n}\r\n```\r\n\r\n---\r\n\r\n**Note**: Research software for educational purposes. Probably not for medical use.\r\n",
"bugtrack_url": null,
"license": "MIT",
"summary": "Open-source Python library for streaming data from Muse S (Athena) EEG headbands",
"version": "1.0.2",
"project_urls": {
"Documentation": "https://github.com/nexon33/amused#readme",
"Homepage": "https://github.com/nexon33/amused",
"Issues": "https://github.com/nexon33/amused/issues",
"Repository": "https://github.com/nexon33/amused"
},
"split_keywords": [
"muse",
" eeg",
" ppg",
" fnirs",
" biometrics",
" neuroscience",
" brain-computer-interface",
" bci",
" bluetooth",
" ble",
" biosignals",
" heart-rate",
" meditation",
" sleep-monitoring"
],
"urls": [
{
"comment_text": "",
"digests": {
"blake2b_256": "1dad99546064613197b1844fe7caee77bac308c233ead9f611455375fea09541",
"md5": "e4efeb804be95ebdf9ed82f2ea3afd74",
"sha256": "5bfb1df799fb61bad9ddd19bf92d297e70e09d8baaa4419a0c8e7b33cbd54f72"
},
"downloads": -1,
"filename": "amused-1.0.2-py3-none-any.whl",
"has_sig": false,
"md5_digest": "e4efeb804be95ebdf9ed82f2ea3afd74",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": ">=3.8",
"size": 64590,
"upload_time": "2025-08-24T19:03:38",
"upload_time_iso_8601": "2025-08-24T19:03:38.216970Z",
"url": "https://files.pythonhosted.org/packages/1d/ad/99546064613197b1844fe7caee77bac308c233ead9f611455375fea09541/amused-1.0.2-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": "",
"digests": {
"blake2b_256": "efd94476f04535471560ccde88df28c4487eeb42df6fa6df71a9dfafb91c2022",
"md5": "a4f9ef2c7b8d058c63609dd36159fdff",
"sha256": "6e8bee09f76430f9a9a971433b1feb68f53bf22a71a248774f72175d97869135"
},
"downloads": -1,
"filename": "amused-1.0.2.tar.gz",
"has_sig": false,
"md5_digest": "a4f9ef2c7b8d058c63609dd36159fdff",
"packagetype": "sdist",
"python_version": "source",
"requires_python": ">=3.8",
"size": 65992,
"upload_time": "2025-08-24T19:03:39",
"upload_time_iso_8601": "2025-08-24T19:03:39.546848Z",
"url": "https://files.pythonhosted.org/packages/ef/d9/4476f04535471560ccde88df28c4487eeb42df6fa6df71a9dfafb91c2022/amused-1.0.2.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2025-08-24 19:03:39",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "nexon33",
"github_project": "amused#readme",
"travis_ci": false,
"coveralls": false,
"github_actions": false,
"lcname": "amused"
}