Software
API Reference
JavaScript SDK

JavaScript SDK (pieeg.js)

pieeg.js is a zero-dependency browser library that connects directly to a board — no Python server required. It talks to the hardware over Web Bluetooth or Web Serial, runs the same signal chain as the PiEEG-server dashboard (Hampel spike removal → Butterworth bandpass → IIR notch), and exposes FFT band powers plus neural-state helpers.

Web Bluetooth and Web Serial are only available in Chromium browsers (Chrome / Edge), require a secure context (HTTPS or localhost), and must be started from a user gesture (e.g. a button click).

Install

pieeg.js is a single file, distributed straight from GitHub — there is no npm account or publish step involved.

Load straight from jsDelivr — no download, no build step:

<script src="https://cdn.jsdelivr.net/gh/pieeg-club/PiEEG-server@main/pieeg.js"></script>
<script>
  const eeg = new PiEEG();
</script>
⚠️

@main always tracks the latest commit. Pin a tag or commit for reproducible builds, e.g. .../PiEEG-server@v1.2.0/pieeg.js.

The file lives in the PiEEG-server (opens in a new tab) repository (pieeg.js).

Supported devices

Pick a board with the device option on connectBLE() / connectSerial().

device idBoardADCTransportChannelsRate
ironbci-8IronBCI-81 × ADS1299Web Bluetooth8250 Hz
ironbci-16IronBCI-162 × ADS1299Web Bluetooth16250 Hz
octopus-16Octopus 162 × ADS131M08Web Bluetooth16250 Hz
ironbci-32IronBCI-32AD7771Web Serial32500 Hz

ironbci-8 is the default for connectBLE(); ironbci-32 is the default for connectSerial(). Discover the list at runtime with PiEEG.devices().

Quick start

const eeg = new PiEEG();
 
eeg.onBandPowers((powers) => {
  console.log('Alpha', powers.Alpha, 'Beta', powers.Beta);
  console.log('focus', eeg.getFocusIndex(), 'relax', eeg.getRelaxationIndex());
});
 
// Must be called from a click handler.
connectButton.addEventListener('click', async () => {
  const info = await eeg.connectBLE({ device: 'octopus-16' });
  console.log(`Connected to ${info.deviceName}: ${info.channels} ch @ ${info.sampleRate} Hz`);
});

Full example (copy-paste)

A complete, self-contained page — save as index.html, serve over localhost or HTTPS, and open it in Chrome/Edge:

<!doctype html>
<html>
  <head>
    <meta charset="utf-8" />
    <title>PiEEG demo</title>
    <script src="https://cdn.jsdelivr.net/gh/pieeg-club/PiEEG-server@main/pieeg.js"></script>
  </head>
  <body>
    <button id="connect">Connect</button>
    <pre id="out">Not connected.</pre>
 
    <script>
      const eeg = new PiEEG();
      const out = document.getElementById('out');
 
      eeg.onBandPowers((powers) => {
        out.textContent =
          `Alpha ${powers.Alpha.toFixed(2)}  Beta ${powers.Beta.toFixed(2)}\n` +
          `focus ${eeg.getFocusIndex().toFixed(2)}  ` +
          `relax ${eeg.getRelaxationIndex().toFixed(2)}`;
      });
 
      eeg.onDisconnect(() => { out.textContent = 'Disconnected.'; });
      eeg.onError((err) => { out.textContent = 'Error: ' + err.message; });
 
      document.getElementById('connect').addEventListener('click', async () => {
        const info = await eeg.connectBLE({ device: 'octopus-16' });
        out.textContent =
          `Connected to ${info.deviceName}: ${info.channels} ch @ ${info.sampleRate} Hz`;
      });
    </script>
  </body>
</html>

Connecting

connectBLE(options?)

Prompts the browser device picker and connects a Bluetooth board.

await eeg.connectBLE();                        // IronBCI-8 (default)
await eeg.connectBLE({ device: 'ironbci-16' });
await eeg.connectBLE({ device: 'octopus-16' });

connectSerial(options?)

Prompts the serial port picker and connects a USB board.

await eeg.connectSerial();                     // IronBCI-32 (default)
await eeg.connectSerial({ device: 'ironbci-32' });

Both resolve to a connection summary:

{ device: 'octopus-16', deviceName: 'bioron_16', channels: 16, sampleRate: 250 }

disconnect()

Stops notifications / the serial read loop and releases the device.

eeg.disconnect();

Constructor options

const eeg = new PiEEG({
  fftSize: 256,        // FFT window (power of 2)
  updateHz: 12,        // band-power callback rate
  bufferSeconds: 4,    // per-channel ring buffer length
  filter: true,        // browser-side DSP (see below)
});

The filter option

Filtering is on by default and mirrors the server/dashboard defaults. Pass false to receive raw samples, or an object to customise individual stages.

new PiEEG({ filter: false });                      // no filtering
 
new PiEEG({ filter: {                              // customise stages
  hampel: { enabled: true, windowSize: 5, nSigma: 3.0 },
  bandpass: { low: 1, high: 40, order: 5 },
  notch: 60,                                        // or { freq: 60, q: 30 }, or false
}});
StageDefault
hampel{ enabled: true, windowSize: 5, nSigma: 3.0 }
bandpass{ low: 1, high: 40, order: 5 }
notchfalse (disabled)

Stages can also be changed live after connecting:

eeg.setBandpass(true, 1, 40, 5);   // enabled, lowcut, highcut, order
eeg.setNotch(true, 60, 30);        // enabled, freq, Q
eeg.setHampel({ windowSize: 7 });
eeg.getFilterConfig();             // current chain config

Events

eeg.onData((channels, timestamp) => { /* raw/filtered µV per channel */ });
eeg.onBandPowers((powers) => { /* averaged across channels, at updateHz */ });
eeg.onError((err) => { /* stream/decoder error */ });
eeg.onDisconnect(() => { /* device dropped */ });

powers is keyed by band name — Delta, Theta, Alpha, Beta, Gamma (see PiEEG.FREQUENCY_BANDS).

Neural-state helpers

Derived from the latest band powers:

MethodReturns
getFocusIndex()Beta / (Beta + Theta)
getRelaxationIndex()Alpha / (Alpha + Beta)
getMeditationIndex()(Theta + Alpha) / total power
isFocused(threshold = 0.6)boolean
isRelaxed(threshold = 0.6)boolean
getBandPower(name)single band value
getBandPowers()copy of all band powers
getSpectrum()latest FFT spectrum

Status

getStats()

{
  connected: true,
  device: 'octopus-16',
  deviceLabel: 'Octopus 16',
  deviceType: 'ble',       // transport: 'ble' | 'serial'
  numChannels: 16,
  sampleRate: 250,
  samplesReceived: 12500,
  bufferFill: 1.0,         // 0..1 ring-buffer fullness
}

Static members

MemberDescription
PiEEG.VERSIONSDK version string
PiEEG.isWebBluetoothSupported()Web Bluetooth availability
PiEEG.isWebSerialSupported()Web Serial availability
PiEEG.devices(transport?)List supported devices ('ble' | 'serial')
PiEEG.FREQUENCY_BANDSBand definitions (name, range, colour)
PiEEG.devices('ble');
// [
//   { id: 'ironbci-8',  label: 'IronBCI-8',  transport: 'ble', channels: 8,  sampleRate: 250 },
//   { id: 'ironbci-16', label: 'IronBCI-16', transport: 'ble', channels: 16, sampleRate: 250 },
//   { id: 'octopus-16', label: 'Octopus 16', transport: 'ble', channels: 16, sampleRate: 250 },
// ]
💡

For a server-based setup (multiple clients, recording, webhooks, OSC) use the WebSocket API instead — it needs no browser transport permissions and works in any browser.