NeuroSky.MindWave.Sdk 2.0.4

dotnet add package NeuroSky.MindWave.Sdk --version 2.0.4
                    
NuGet\Install-Package NeuroSky.MindWave.Sdk -Version 2.0.4
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="NeuroSky.MindWave.Sdk" Version="2.0.4" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="NeuroSky.MindWave.Sdk" Version="2.0.4" />
                    
Directory.Packages.props
<PackageReference Include="NeuroSky.MindWave.Sdk" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add NeuroSky.MindWave.Sdk --version 2.0.4
                    
#r "nuget: NeuroSky.MindWave.Sdk, 2.0.4"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package NeuroSky.MindWave.Sdk@2.0.4
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=NeuroSky.MindWave.Sdk&version=2.0.4
                    
Install as a Cake Addin
#tool nuget:?package=NeuroSky.MindWave.Sdk&version=2.0.4
                    
Install as a Cake Tool

NeuroSky MindWave Mobile Windows SDK

NuGet .NET License

Modern C# SDK for NeuroSky MindWave Mobile EEG headsets — BLE + BT Classic via WinRT.


Getting Started

Before diving into the steps — read the Developer Guide (PDF) first.
It covers the full connection flow, BLE vs BT Classic internals, signal quality handling, packet timing, advanced patterns, and the complete API reference. Most integration questions are answered there.

Step 1 — Add the NuGet package

Visual Studio — Package Manager UI

Tools → NuGet Package Manager → Manage NuGet Packages
Search: NeuroSky.MindWave.Sdk → Install

Edit .csproj directly (recommended)

<PackageReference Include="NeuroSky.MindWave.Sdk" Version="2.0.3" />

.NET CLI

dotnet add package NeuroSky.MindWave.Sdk

Step 2 — Set the Windows target framework

WinRT Bluetooth APIs require a Windows-specific TFM. Open your .csproj and confirm:

<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    
    <TargetFramework>net8.0-windows10.0.19041.0</TargetFramework>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="NeuroSky.MindWave.Sdk" Version="2.0.3" />
  </ItemGroup>
</Project>

Plain net8.0 will not work — WinRT types (Windows.Devices.Bluetooth) are only available with the Windows TFM suffix.

Step 3 — Find your headset's MAC address

Settings → Bluetooth & other devices → MindWave Mobile → More info

Or via PowerShell:

Get-PnpDevice -Class Bluetooth | Where-Object { $_.FriendlyName -like "*MindWave*" }

Step 4 — Connect and stream

using NeuroSky.Sdk;

await using var sdk = new NeuroSkySdk();
sdk.StateChanged += (_, state) => Console.WriteLine($"[State] {state}");

using var cts = new CancellationTokenSource();
Console.CancelKeyPress += (_, e) => { e.Cancel = true; cts.Cancel(); };

// Connect — BLE by default
await sdk.ConnectAsync("AA:BB:CC:DD:EE:FF");

// Set notch filter for your region (removes power-line noise)
await sdk.SendCommandAsync(NeuroSkyCommand.Notch60Hz);  // Korea/USA
// await sdk.SendCommandAsync(NeuroSkyCommand.Notch50Hz);  // Europe/China

await foreach (var data in sdk.DataStream(cts.Token))
{
    Console.WriteLine($"Attention  : {data.Attention}");
    Console.WriteLine($"Meditation : {data.Meditation}");
    Console.WriteLine($"Signal     : {data.SignalQuality}");
}

That's it — four steps from zero to streaming EEG data.


Requirements

Minimum
OS Windows 10 version 1903 (build 18362)
.NET .NET 8.0
Bluetooth BLE adapter (BLE mode) or Classic BT adapter (BT Classic mode)
Device pairing Not required for BLE; required for BT Classic

Connection Modes

Choose how to connect via the TransportMode parameter:

Mode Behavior Pairing required?
TransportMode.Ble BLE — fastest, no pairing needed (default) No
TransportMode.BtClassic BT Classic — more stable in noisy RF environments Yes
// BLE (default)
await sdk.ConnectAsync("AA:BB:CC:DD:EE:FF");

// BT Classic only — pair the device first in Windows Settings
await sdk.ConnectAsync("AA:BB:CC:DD:EE:FF", TransportMode.BtClassic);

Connection States

Subscribe to StateChanged to observe the lifecycle. ConnectAsync() never throws on connection failure — it transitions to Error instead, so always check the final state.

State Meaning
Disconnected Initial state, or after DisconnectAsync() / link drop
Scanning BLE only — resolving the MAC address
Connecting GATT service discovery (BLE) or RFCOMM socket open (BT Classic) in progress
Connected Notifications enabled and handshake sent — DataStream will emit packets
Error Device not found, GATT discovery failed, handshake characteristic missing, or RFCOMM service unavailable. DataStream will not emit; call DisconnectAsync() and retry.
sdk.StateChanged += (_, state) =>
{
    if (state == ConnectionState.Error)
    {
        Console.WriteLine("Connection failed — verify pairing / power / MAC address.");
    }
};

Simulator (without a real device)

using NeuroSky.Sdk;

var simulator = new SimulatorTransport();
simulator.SetMode(SimulatorTransport.Mode.Focused);

await simulator.ConnectAsync("simulator");

await foreach (var data in simulator.DataStream(cts.Token))
{
    Console.WriteLine($"Attention: {data.Attention}");
}
Mode Attention Meditation Use case
Random 0~100 (random) 0~100 (random) General testing
Focused 70~100 40~60 Focused state UI testing
Relaxed 20~50 70~100 Relaxed state UI testing
PoorSignal 0 0 Signal loss / error handling test

BrainWaveData

Property Type Range Description
Timestamp long Unix ms Time of reception
PoorSignal int 0~200 0=perfect, 200=no signal
Attention int 0~100 eSense attention level
Meditation int 0~100 eSense meditation level
Delta int 0~∞ 0.5~2.75 Hz
Theta int 0~∞ 3.5~6.75 Hz
LowAlpha int 0~∞ 7.5~9.25 Hz
HighAlpha int 0~∞ 10~11.75 Hz
LowBeta int 0~∞ 13~16.75 Hz
HighBeta int 0~∞ 18~29.75 Hz
LowGamma int 0~∞ 31~39.75 Hz
MidGamma int 0~∞ 41~49.75 Hz
RawEeg IReadOnlyList<int> -32768~32767 512Hz, 10 samples/packet
EyeBlink int 0~255 Eye blink intensity
SignalQuality SignalQuality enum NoSignal/Poor/Fair/Good

Finding Your Device Address

ConnectAsync() takes a Bluetooth MAC address. Use FindDeviceAddressAsync() once on first launch to discover it, then store it (e.g., in app settings) for faster subsequent connections.

await using var sdk = new NeuroSkySdk();

// Discover by name — scans BLE advertisements for up to 10 s
var cached = Properties.Settings.Default.DeviceMac;
var address = !string.IsNullOrEmpty(cached)
    ? cached
    : await sdk.FindDeviceAddressAsync("MindWave Mobile");

if (address is null)
{
    Console.WriteLine("Device not found — check power and BLE adapter.");
    return;
}

Properties.Settings.Default.DeviceMac = address;
Properties.Settings.Default.Save();   // cache — skips scan next launch

await sdk.ConnectAsync(address);

Working with DataStream

Packet timing

In BLE mode, two characteristics transmit packets at different rates.

Characteristic Fields Rate
eSense 039afff8 Attention, Meditation, EEG bands ~1 Hz
RawEEG 039afff4 RawEeg (10 samples) ~51 Hz (512 Hz ÷ 10)

ThinkGearParser accumulates state. Regardless of which characteristic triggered the emit, each BrainWaveData object contains the latest accumulated value of every field.

Caution — attention-based filter

// Wrong pattern — drops all packets in RawEEG-only sessions
await foreach (var data in sdk.DataStream(ct))
{
    if (data.Attention == 0) continue;  // Attention is always 0 when eSense is off
    // ...
}

If StopESense is sent or StartESense is never called, the device does not transmit attention data. Attention stays at 0 and this guard silently drops every packet.

Correct patterns:

// eSense session — filter by signal quality, not value
await foreach (var data in sdk.DataStream(ct))
{
    if (data.SignalQuality == SignalQuality.NoSignal) continue;
    Console.WriteLine($"Attention: {data.Attention}");
}

// RawEEG-only session
await sdk.SendCommandAsync(NeuroSkyCommand.StopESense);
await sdk.SendCommandAsync(NeuroSkyCommand.StartRawEeg);
await foreach (var data in sdk.DataStream(ct))
{
    if (data.RawEeg.Count > 0)
        foreach (var sample in data.RawEeg) ProcessRawSample(sample);
}

// eSense + RawEEG simultaneously — process only the populated fields in each packet
await sdk.SendCommandAsync(NeuroSkyCommand.StartRawEeg);  // eSense is active by default
await foreach (var data in sdk.DataStream(ct))
{
    if (data.RawEeg.Count > 0)  UpdateRawEegChart(data.RawEeg);
    if (data.Attention > 0)     UpdateEsenseUI(data);
}

Commands

// Notch filter — removes power-line noise (call after connecting)
await sdk.SendCommandAsync(NeuroSkyCommand.Notch60Hz);  // Korea/USA (60Hz)
await sdk.SendCommandAsync(NeuroSkyCommand.Notch50Hz);  // China/Europe (50Hz)

// Raw EEG stream (disabled by default)
await sdk.SendCommandAsync(NeuroSkyCommand.StartRawEeg);
await sdk.SendCommandAsync(NeuroSkyCommand.StopRawEeg);

Transport

Transport Method Requirement
BleTransport WinRT BLE GATT Windows 10 1903+, BLE adapter
BtClassicTransport WinRT RFCOMM SPP Paired device in Windows Settings
SimulatorTransport Virtual data For development/testing

Project Structure

NeuroSky.Sdk/
├── NeuroSkySdk.cs              Entry point (BLE by default)
├── NeuroSkyUuid.cs             BLE UUID constants, command byte constants
├── Model/
│   └── BrainWaveData.cs        EEG data model
├── Transport/
│   ├── ITransport.cs           Common interface, ConnectionState enum
│   ├── BleTransport.cs         WinRT BLE GATT implementation
│   └── BtClassicTransport.cs   WinRT RFCOMM SPP implementation
├── Parser/
│   └── ThinkGearParser.cs      ThinkGear packet parser
└── Simulator/
    └── SimulatorTransport.cs   Simulator for development

NeuroSky.Sample/
└── Program.cs                  Console sample app

Trimming / Self-contained / AOT

The package is marked IsTrimmable=true and ships an internal TrimmerRootDescriptor.xml that preserves the BLE/BT transports, parser, and public API surface. WinRT GATT callbacks are dispatched by the Windows Bluetooth stack via reflection-like mechanisms, so without these roots the trimmer would silently strip the handlers and BLE data would never arrive.

No consumer action is required — publishing with PublishTrimmed=true, self-contained, or PublishAot=true works out of the box.

<PropertyGroup>
  <PublishTrimmed>true</PublishTrimmed>
  <SelfContained>true</SelfContained>
</PropertyGroup>

Build

dotnet build
dotnet run --project NeuroSky.Sample

Changelog

v2.0.3

  • Fix: TrimmerRootDescriptor.xml updated to flattened NeuroSky.Sdk FQNs — previous entries still referenced the pre-v2.0.1 nested namespaces (NeuroSky.Sdk.Transport.*, NeuroSky.Sdk.Parser.*, NeuroSky.Sdk.Model.*), so the trimmer silently dropped BLE/BT/parser types in trimmed / AOT builds despite the descriptor being shipped
  • Fix: BleTransport.ConnectAsync no longer reports Connected when the handshake characteristic is missing — it now transitions to Error so the caller doesn't wait forever on a stream that will never emit

v2.0.2

  • ThinkGearParser — BT Classic default case now correctly skips extended codes (>= 0x80) by reading len and skipping len bytes; previously caused parser desync
  • ThinkGearParser — BT Classic case 0x83 bounds guard: prevents IndexOutOfRangeException on truncated payloads

v2.0.1

  • Fix: all types flattened into NeuroSky.Sdk — using NeuroSky.Sdk; is now sufficient

v2.0.0

  • WinRT BLE GATT implementation (Windows.Devices.Bluetooth)
  • WinRT RFCOMM SPP implementation (Windows.Devices.Bluetooth.Rfcomm)
  • TransportMode enum: Ble (default), BtClassic
  • IAsyncEnumerable<BrainWaveData> stream API
  • Simulator modes: Random / Focused / Relaxed / PoorSignal
  • .NET 8, C# 12
  • Published to NuGet.org

License

Apache License 2.0

Product Compatible and additional computed target framework versions.
.NET net8.0-windows10.0.19041 is compatible.  net9.0-windows was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.
  • net8.0-windows10.0.19041

    • No dependencies.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
2.0.4 142 6/5/2026
2.0.3 117 5/11/2026
2.0.2 123 4/14/2026
2.0.1 121 4/8/2026
2.0.0 121 4/2/2026