pieeg-server 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- pieeg_server-0.1.0/LICENSE +21 -0
- pieeg_server-0.1.0/PKG-INFO +288 -0
- pieeg_server-0.1.0/README.md +233 -0
- pieeg_server-0.1.0/pieeg_server/__init__.py +3 -0
- pieeg_server-0.1.0/pieeg_server/__main__.py +365 -0
- pieeg_server-0.1.0/pieeg_server/acquisition.py +145 -0
- pieeg_server-0.1.0/pieeg_server/dashboard.py +67 -0
- pieeg_server-0.1.0/pieeg_server/doctor.py +320 -0
- pieeg_server-0.1.0/pieeg_server/filters.py +76 -0
- pieeg_server-0.1.0/pieeg_server/hardware.py +348 -0
- pieeg_server-0.1.0/pieeg_server/mock.py +67 -0
- pieeg_server-0.1.0/pieeg_server/monitor.py +102 -0
- pieeg_server-0.1.0/pieeg_server/recorder.py +85 -0
- pieeg_server-0.1.0/pieeg_server/server.py +128 -0
- pieeg_server-0.1.0/pieeg_server/static/index.html +489 -0
- pieeg_server-0.1.0/pieeg_server.egg-info/PKG-INFO +288 -0
- pieeg_server-0.1.0/pieeg_server.egg-info/SOURCES.txt +26 -0
- pieeg_server-0.1.0/pieeg_server.egg-info/dependency_links.txt +1 -0
- pieeg_server-0.1.0/pieeg_server.egg-info/entry_points.txt +2 -0
- pieeg_server-0.1.0/pieeg_server.egg-info/requires.txt +10 -0
- pieeg_server-0.1.0/pieeg_server.egg-info/top_level.txt +1 -0
- pieeg_server-0.1.0/pyproject.toml +57 -0
- pieeg_server-0.1.0/setup.cfg +4 -0
- pieeg_server-0.1.0/tests/test_acquisition.py +180 -0
- pieeg_server-0.1.0/tests/test_filters.py +227 -0
- pieeg_server-0.1.0/tests/test_hardware_logic.py +191 -0
- pieeg_server-0.1.0/tests/test_integration.py +214 -0
- pieeg_server-0.1.0/tests/test_mock.py +167 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 PiEEG Community
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,288 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: pieeg-server
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: One-command local streaming server for PiEEG-16 (16-channel EEG shield for Raspberry Pi)
|
|
5
|
+
Author: PiEEG Community
|
|
6
|
+
License: MIT License
|
|
7
|
+
|
|
8
|
+
Copyright (c) 2025 PiEEG Community
|
|
9
|
+
|
|
10
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
11
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
12
|
+
in the Software without restriction, including without limitation the rights
|
|
13
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
14
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
15
|
+
furnished to do so, subject to the following conditions:
|
|
16
|
+
|
|
17
|
+
The above copyright notice and this permission notice shall be included in all
|
|
18
|
+
copies or substantial portions of the Software.
|
|
19
|
+
|
|
20
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
21
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
22
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
23
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
24
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
25
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
26
|
+
SOFTWARE.
|
|
27
|
+
|
|
28
|
+
Project-URL: Homepage, https://github.com/yelabb/PiEEG-16-server
|
|
29
|
+
Project-URL: Documentation, https://pieeg.com/docs/docs/pieeg-16/
|
|
30
|
+
Project-URL: Repository, https://github.com/yelabb/PiEEG-16-server
|
|
31
|
+
Project-URL: Issues, https://github.com/yelabb/PiEEG-16-server/issues
|
|
32
|
+
Keywords: eeg,bci,raspberry-pi,pieeg,neuroscience,websocket,brain-computer-interface,ads1299,spi
|
|
33
|
+
Classifier: Development Status :: 3 - Alpha
|
|
34
|
+
Classifier: Intended Audience :: Science/Research
|
|
35
|
+
Classifier: Topic :: Scientific/Engineering :: Medical Science Apps.
|
|
36
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
37
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
38
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
39
|
+
Classifier: Operating System :: POSIX :: Linux
|
|
40
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
41
|
+
Classifier: Environment :: Console
|
|
42
|
+
Classifier: Framework :: AsyncIO
|
|
43
|
+
Requires-Python: >=3.11
|
|
44
|
+
Description-Content-Type: text/markdown
|
|
45
|
+
License-File: LICENSE
|
|
46
|
+
Requires-Dist: websockets>=12.0
|
|
47
|
+
Requires-Dist: scipy>=1.10
|
|
48
|
+
Requires-Dist: rich>=13.0
|
|
49
|
+
Provides-Extra: rpi
|
|
50
|
+
Requires-Dist: spidev>=3.6; extra == "rpi"
|
|
51
|
+
Provides-Extra: dev
|
|
52
|
+
Requires-Dist: pytest>=7.0; extra == "dev"
|
|
53
|
+
Requires-Dist: pytest-asyncio>=0.21; extra == "dev"
|
|
54
|
+
Dynamic: license-file
|
|
55
|
+
|
|
56
|
+
# PiEEG-16-server
|
|
57
|
+
|
|
58
|
+
A lightweight server for the [PiEEG-16](https://github.com/pieeg-club/PiEEG-16) shield that initializes the hardware, reads 16 channels at 250 Hz, streams live data over WebSocket, and serves a real-time dashboard — all on your local network.
|
|
59
|
+
|
|
60
|
+
## Install
|
|
61
|
+
|
|
62
|
+
> Pick **one** method. They all get you to the same place: `pieeg-server` ready to run.
|
|
63
|
+
|
|
64
|
+
### Option A — One-line install (recommended)
|
|
65
|
+
|
|
66
|
+
SSH into your Pi and paste:
|
|
67
|
+
|
|
68
|
+
```bash
|
|
69
|
+
curl -sSL https://raw.githubusercontent.com/yelabb/PiEEG-16-server/main/install.sh | bash
|
|
70
|
+
sudo reboot # only needed first time, to enable SPI
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
### Option B — Clone & setup
|
|
74
|
+
|
|
75
|
+
```bash
|
|
76
|
+
git clone https://github.com/yelabb/PiEEG-16-server.git
|
|
77
|
+
cd PiEEG-16-server
|
|
78
|
+
chmod +x setup.sh
|
|
79
|
+
./setup.sh
|
|
80
|
+
sudo reboot # only needed first time, to enable SPI
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
---
|
|
84
|
+
|
|
85
|
+
## Run
|
|
86
|
+
|
|
87
|
+
```bash
|
|
88
|
+
pieeg-server # start streaming
|
|
89
|
+
pieeg-server --filter # with 1–40 Hz bandpass filter
|
|
90
|
+
pieeg-server --monitor # with live terminal display
|
|
91
|
+
pieeg-server --mock # synthetic data, no hardware needed
|
|
92
|
+
pieeg-server doctor # diagnose SPI, GPIO, deps, permissions
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
That's it. LEDs turn on, data streams to `ws://raspberrypi.local:1616`.
|
|
96
|
+
|
|
97
|
+
Open **http://raspberrypi.local:1617** in any browser on your network for the real-time dashboard.
|
|
98
|
+
|
|
99
|
+
<img height="400" alt="image" src="https://github.com/user-attachments/assets/3f33bfd4-c721-4b94-a672-2a0b744d127b" />
|
|
100
|
+
|
|
101
|
+
### Terminal
|
|
102
|
+
<img width="422" height="475" alt="image" src="https://github.com/user-attachments/assets/7d58af68-85c4-41d3-b1ab-89b23e99faff" />
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
**Ports:**
|
|
106
|
+
- **`:1616`** — WebSocket data stream (PiEEG-**16** → **1616**)
|
|
107
|
+
- **`:1617`** — Web dashboard (next door)
|
|
108
|
+
|
|
109
|
+
## Record data
|
|
110
|
+
|
|
111
|
+
```bash
|
|
112
|
+
pieeg-server record session.csv # record until Ctrl-C
|
|
113
|
+
pieeg-server record session.csv --duration 300 # record 5 minutes
|
|
114
|
+
pieeg-server --record session.csv # record while streaming
|
|
115
|
+
pieeg-server --record session.csv --record-duration 60 # record 60s while streaming
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
CSV format: `timestamp, ch1, ch2, ..., ch16` (compatible with the official PiEEG-16 dataset format).
|
|
119
|
+
|
|
120
|
+
## Terminal monitor
|
|
121
|
+
|
|
122
|
+
```bash
|
|
123
|
+
pieeg-server monitor # standalone live view (no server)
|
|
124
|
+
pieeg-server --monitor # live view alongside the server
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
Displays all 16 channels with real-time µV values and sparkline waveforms directly in the terminal. Works over SSH — no browser or display needed.
|
|
128
|
+
|
|
129
|
+
> **`pieeg-server: command not found`?** Run `pieeg-server doctor` (or `./setup.sh` again).
|
|
130
|
+
> As a fallback: `cd PiEEG-16-server && .venv/bin/pieeg-server`
|
|
131
|
+
|
|
132
|
+
## Troubleshooting
|
|
133
|
+
|
|
134
|
+
```bash
|
|
135
|
+
pieeg-server doctor
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
Checks everything in one shot: Pi model, Python version, SPI devices, GPIO chips, file permissions, port availability, installed dependencies, systemd service. Returns exit code `0` (all good), `1` (warnings), or `2` (errors) — scriptable with `--quiet`.
|
|
139
|
+
|
|
140
|
+
### Windows: `Could not install packages due to an OSError`
|
|
141
|
+
|
|
142
|
+
If `pip install -e .` fails with a `WinError 2` or `Failed to write executable` error, pip can't replace an old `pieeg-server.exe` in your Python Scripts folder. Fix it:
|
|
143
|
+
|
|
144
|
+
```powershell
|
|
145
|
+
pip uninstall pieeg-server -y
|
|
146
|
+
pip install -e .
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
If that still fails, run your terminal **as Administrator** (right-click → Run as administrator).
|
|
150
|
+
|
|
151
|
+
> On Windows you can only use mock mode (`pieeg-server --mock`) since SPI/GPIO hardware is not available.
|
|
152
|
+
|
|
153
|
+
## Connect from any device
|
|
154
|
+
|
|
155
|
+
### Python
|
|
156
|
+
|
|
157
|
+
```python
|
|
158
|
+
import asyncio, json, websockets
|
|
159
|
+
|
|
160
|
+
async def main():
|
|
161
|
+
async with websockets.connect("ws://raspberrypi.local:1616") as ws:
|
|
162
|
+
async for message in ws:
|
|
163
|
+
frame = json.loads(message)
|
|
164
|
+
print(f"Sample #{frame['n']}: {frame['channels']}")
|
|
165
|
+
|
|
166
|
+
asyncio.run(main())
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
### JavaScript (browser)
|
|
170
|
+
|
|
171
|
+
```javascript
|
|
172
|
+
const ws = new WebSocket("ws://raspberrypi.local:1616");
|
|
173
|
+
ws.onmessage = (event) => {
|
|
174
|
+
const frame = JSON.parse(event.data);
|
|
175
|
+
console.log(`Sample #${frame.n}:`, frame.channels);
|
|
176
|
+
};
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
## Data Format
|
|
180
|
+
|
|
181
|
+
Each WebSocket message is a JSON frame:
|
|
182
|
+
|
|
183
|
+
```json
|
|
184
|
+
{
|
|
185
|
+
"t": 1711234567.123456,
|
|
186
|
+
"n": 42,
|
|
187
|
+
"channels": [12.34, -5.67, 8.90, ...]
|
|
188
|
+
}
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
| Field | Type | Description |
|
|
192
|
+
|-------|------|-------------|
|
|
193
|
+
| `t` | float | Unix timestamp (seconds) |
|
|
194
|
+
| `n` | int | Sample number (monotonic) |
|
|
195
|
+
| `channels` | float[16] | Voltage in microvolts (µV) per channel |
|
|
196
|
+
|
|
197
|
+
## CLI Options
|
|
198
|
+
|
|
199
|
+
```
|
|
200
|
+
pieeg-server [OPTIONS] [COMMAND]
|
|
201
|
+
|
|
202
|
+
Commands:
|
|
203
|
+
doctor Diagnose hardware, software, and configuration
|
|
204
|
+
record FILE Record EEG data to CSV (standalone, no server)
|
|
205
|
+
monitor Live terminal display (standalone, no server)
|
|
206
|
+
|
|
207
|
+
Server options:
|
|
208
|
+
--host HOST Bind address (default: 0.0.0.0)
|
|
209
|
+
--port PORT WebSocket port (default: 1616)
|
|
210
|
+
--dashboard-port PORT Dashboard HTTP port (default: 1617)
|
|
211
|
+
--no-dashboard Disable the web dashboard
|
|
212
|
+
--gpio-chip PATH GPIO chip device path (default: /dev/gpiochip4)
|
|
213
|
+
--filter Enable 1–40 Hz bandpass filter server-side
|
|
214
|
+
--lowcut HZ Filter low cutoff (default: 1.0)
|
|
215
|
+
--highcut HZ Filter high cutoff (default: 40.0)
|
|
216
|
+
--record FILE Record to CSV while streaming
|
|
217
|
+
--record-duration SEC Stop recording after N seconds
|
|
218
|
+
--monitor Show live terminal monitor alongside server
|
|
219
|
+
--mock Synthetic EEG data (no hardware needed)
|
|
220
|
+
-v, --verbose Debug logging
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
## Runtime Commands
|
|
224
|
+
|
|
225
|
+
Clients can send JSON commands over the WebSocket:
|
|
226
|
+
|
|
227
|
+
```json
|
|
228
|
+
{"cmd": "set_filter", "enabled": true, "lowcut": 1.0, "highcut": 40.0}
|
|
229
|
+
{"cmd": "set_filter", "enabled": false}
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
## Architecture
|
|
233
|
+
|
|
234
|
+
```
|
|
235
|
+
┌─────────────────────────────────────────────────────────┐
|
|
236
|
+
│ Raspberry Pi 5 + PiEEG-16 Shield │
|
|
237
|
+
│ │
|
|
238
|
+
│ hardware.py → SPI/GPIO init, ADC register config │
|
|
239
|
+
│ ↓ │
|
|
240
|
+
│ acquisition.py → 250 Hz read loop (background thread) │
|
|
241
|
+
│ ↓ pub/sub (multiple consumers) │
|
|
242
|
+
│ ├── server.py → WebSocket broadcast │
|
|
243
|
+
│ ├── recorder.py → CSV file writer │
|
|
244
|
+
│ └── monitor.py → Terminal sparkline display │
|
|
245
|
+
│ ↓ │
|
|
246
|
+
│ dashboard.py → HTTP server for real-time web UI │
|
|
247
|
+
│ ↓ │
|
|
248
|
+
│ ws://0.0.0.0:1616 │ http://0.0.0.0:1617 │
|
|
249
|
+
└──────────┬───────────────────────────────────────────────┘
|
|
250
|
+
│ Local network
|
|
251
|
+
├── Browser (JS client)
|
|
252
|
+
├── Python notebook
|
|
253
|
+
├── Mobile app
|
|
254
|
+
└── Any WebSocket client
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
## Runs as a Service
|
|
258
|
+
|
|
259
|
+
Setup creates a systemd service that auto-starts on boot:
|
|
260
|
+
|
|
261
|
+
```bash
|
|
262
|
+
sudo systemctl status pieeg-server # check status
|
|
263
|
+
sudo systemctl stop pieeg-server # stop
|
|
264
|
+
sudo systemctl restart pieeg-server # restart
|
|
265
|
+
journalctl -u pieeg-server -f # view logs
|
|
266
|
+
```
|
|
267
|
+
|
|
268
|
+
## GPIO: No `gpiod` Dependency
|
|
269
|
+
|
|
270
|
+
This server talks to GPIO directly via the Linux kernel's character device interface (`/dev/gpiochipN`) using standard `ioctl` calls — no `gpiod` pip package needed.
|
|
271
|
+
|
|
272
|
+
We only use two GPIO pins (chip-select output + data-ready input), so the ~20 lines of `struct` packing replace an entire external dependency that:
|
|
273
|
+
|
|
274
|
+
- Has **breaking API changes** between v1 and v2 (completely incompatible)
|
|
275
|
+
- Requires **system C headers** (`libgpiod-dev`) to install via pip
|
|
276
|
+
- Only works on **Linux** (blocks development/testing on macOS/Windows)
|
|
277
|
+
|
|
278
|
+
The chardev v1 ioctl ABI has been stable since Linux 4.8 (2016) and is guaranteed not to break by the kernel's userspace compatibility policy.
|
|
279
|
+
|
|
280
|
+
## Safety
|
|
281
|
+
|
|
282
|
+
> **PiEEG-16 must operate from battery power (5V) only.**
|
|
283
|
+
> Do NOT connect to mains-powered equipment via USB.
|
|
284
|
+
> PiEEG-16 is NOT a medical device.
|
|
285
|
+
|
|
286
|
+
## License
|
|
287
|
+
|
|
288
|
+
MIT
|
|
@@ -0,0 +1,233 @@
|
|
|
1
|
+
# PiEEG-16-server
|
|
2
|
+
|
|
3
|
+
A lightweight server for the [PiEEG-16](https://github.com/pieeg-club/PiEEG-16) shield that initializes the hardware, reads 16 channels at 250 Hz, streams live data over WebSocket, and serves a real-time dashboard — all on your local network.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
> Pick **one** method. They all get you to the same place: `pieeg-server` ready to run.
|
|
8
|
+
|
|
9
|
+
### Option A — One-line install (recommended)
|
|
10
|
+
|
|
11
|
+
SSH into your Pi and paste:
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
curl -sSL https://raw.githubusercontent.com/yelabb/PiEEG-16-server/main/install.sh | bash
|
|
15
|
+
sudo reboot # only needed first time, to enable SPI
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
### Option B — Clone & setup
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
git clone https://github.com/yelabb/PiEEG-16-server.git
|
|
22
|
+
cd PiEEG-16-server
|
|
23
|
+
chmod +x setup.sh
|
|
24
|
+
./setup.sh
|
|
25
|
+
sudo reboot # only needed first time, to enable SPI
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
---
|
|
29
|
+
|
|
30
|
+
## Run
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
pieeg-server # start streaming
|
|
34
|
+
pieeg-server --filter # with 1–40 Hz bandpass filter
|
|
35
|
+
pieeg-server --monitor # with live terminal display
|
|
36
|
+
pieeg-server --mock # synthetic data, no hardware needed
|
|
37
|
+
pieeg-server doctor # diagnose SPI, GPIO, deps, permissions
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
That's it. LEDs turn on, data streams to `ws://raspberrypi.local:1616`.
|
|
41
|
+
|
|
42
|
+
Open **http://raspberrypi.local:1617** in any browser on your network for the real-time dashboard.
|
|
43
|
+
|
|
44
|
+
<img height="400" alt="image" src="https://github.com/user-attachments/assets/3f33bfd4-c721-4b94-a672-2a0b744d127b" />
|
|
45
|
+
|
|
46
|
+
### Terminal
|
|
47
|
+
<img width="422" height="475" alt="image" src="https://github.com/user-attachments/assets/7d58af68-85c4-41d3-b1ab-89b23e99faff" />
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
**Ports:**
|
|
51
|
+
- **`:1616`** — WebSocket data stream (PiEEG-**16** → **1616**)
|
|
52
|
+
- **`:1617`** — Web dashboard (next door)
|
|
53
|
+
|
|
54
|
+
## Record data
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
pieeg-server record session.csv # record until Ctrl-C
|
|
58
|
+
pieeg-server record session.csv --duration 300 # record 5 minutes
|
|
59
|
+
pieeg-server --record session.csv # record while streaming
|
|
60
|
+
pieeg-server --record session.csv --record-duration 60 # record 60s while streaming
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
CSV format: `timestamp, ch1, ch2, ..., ch16` (compatible with the official PiEEG-16 dataset format).
|
|
64
|
+
|
|
65
|
+
## Terminal monitor
|
|
66
|
+
|
|
67
|
+
```bash
|
|
68
|
+
pieeg-server monitor # standalone live view (no server)
|
|
69
|
+
pieeg-server --monitor # live view alongside the server
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
Displays all 16 channels with real-time µV values and sparkline waveforms directly in the terminal. Works over SSH — no browser or display needed.
|
|
73
|
+
|
|
74
|
+
> **`pieeg-server: command not found`?** Run `pieeg-server doctor` (or `./setup.sh` again).
|
|
75
|
+
> As a fallback: `cd PiEEG-16-server && .venv/bin/pieeg-server`
|
|
76
|
+
|
|
77
|
+
## Troubleshooting
|
|
78
|
+
|
|
79
|
+
```bash
|
|
80
|
+
pieeg-server doctor
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
Checks everything in one shot: Pi model, Python version, SPI devices, GPIO chips, file permissions, port availability, installed dependencies, systemd service. Returns exit code `0` (all good), `1` (warnings), or `2` (errors) — scriptable with `--quiet`.
|
|
84
|
+
|
|
85
|
+
### Windows: `Could not install packages due to an OSError`
|
|
86
|
+
|
|
87
|
+
If `pip install -e .` fails with a `WinError 2` or `Failed to write executable` error, pip can't replace an old `pieeg-server.exe` in your Python Scripts folder. Fix it:
|
|
88
|
+
|
|
89
|
+
```powershell
|
|
90
|
+
pip uninstall pieeg-server -y
|
|
91
|
+
pip install -e .
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
If that still fails, run your terminal **as Administrator** (right-click → Run as administrator).
|
|
95
|
+
|
|
96
|
+
> On Windows you can only use mock mode (`pieeg-server --mock`) since SPI/GPIO hardware is not available.
|
|
97
|
+
|
|
98
|
+
## Connect from any device
|
|
99
|
+
|
|
100
|
+
### Python
|
|
101
|
+
|
|
102
|
+
```python
|
|
103
|
+
import asyncio, json, websockets
|
|
104
|
+
|
|
105
|
+
async def main():
|
|
106
|
+
async with websockets.connect("ws://raspberrypi.local:1616") as ws:
|
|
107
|
+
async for message in ws:
|
|
108
|
+
frame = json.loads(message)
|
|
109
|
+
print(f"Sample #{frame['n']}: {frame['channels']}")
|
|
110
|
+
|
|
111
|
+
asyncio.run(main())
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
### JavaScript (browser)
|
|
115
|
+
|
|
116
|
+
```javascript
|
|
117
|
+
const ws = new WebSocket("ws://raspberrypi.local:1616");
|
|
118
|
+
ws.onmessage = (event) => {
|
|
119
|
+
const frame = JSON.parse(event.data);
|
|
120
|
+
console.log(`Sample #${frame.n}:`, frame.channels);
|
|
121
|
+
};
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
## Data Format
|
|
125
|
+
|
|
126
|
+
Each WebSocket message is a JSON frame:
|
|
127
|
+
|
|
128
|
+
```json
|
|
129
|
+
{
|
|
130
|
+
"t": 1711234567.123456,
|
|
131
|
+
"n": 42,
|
|
132
|
+
"channels": [12.34, -5.67, 8.90, ...]
|
|
133
|
+
}
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
| Field | Type | Description |
|
|
137
|
+
|-------|------|-------------|
|
|
138
|
+
| `t` | float | Unix timestamp (seconds) |
|
|
139
|
+
| `n` | int | Sample number (monotonic) |
|
|
140
|
+
| `channels` | float[16] | Voltage in microvolts (µV) per channel |
|
|
141
|
+
|
|
142
|
+
## CLI Options
|
|
143
|
+
|
|
144
|
+
```
|
|
145
|
+
pieeg-server [OPTIONS] [COMMAND]
|
|
146
|
+
|
|
147
|
+
Commands:
|
|
148
|
+
doctor Diagnose hardware, software, and configuration
|
|
149
|
+
record FILE Record EEG data to CSV (standalone, no server)
|
|
150
|
+
monitor Live terminal display (standalone, no server)
|
|
151
|
+
|
|
152
|
+
Server options:
|
|
153
|
+
--host HOST Bind address (default: 0.0.0.0)
|
|
154
|
+
--port PORT WebSocket port (default: 1616)
|
|
155
|
+
--dashboard-port PORT Dashboard HTTP port (default: 1617)
|
|
156
|
+
--no-dashboard Disable the web dashboard
|
|
157
|
+
--gpio-chip PATH GPIO chip device path (default: /dev/gpiochip4)
|
|
158
|
+
--filter Enable 1–40 Hz bandpass filter server-side
|
|
159
|
+
--lowcut HZ Filter low cutoff (default: 1.0)
|
|
160
|
+
--highcut HZ Filter high cutoff (default: 40.0)
|
|
161
|
+
--record FILE Record to CSV while streaming
|
|
162
|
+
--record-duration SEC Stop recording after N seconds
|
|
163
|
+
--monitor Show live terminal monitor alongside server
|
|
164
|
+
--mock Synthetic EEG data (no hardware needed)
|
|
165
|
+
-v, --verbose Debug logging
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
## Runtime Commands
|
|
169
|
+
|
|
170
|
+
Clients can send JSON commands over the WebSocket:
|
|
171
|
+
|
|
172
|
+
```json
|
|
173
|
+
{"cmd": "set_filter", "enabled": true, "lowcut": 1.0, "highcut": 40.0}
|
|
174
|
+
{"cmd": "set_filter", "enabled": false}
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
## Architecture
|
|
178
|
+
|
|
179
|
+
```
|
|
180
|
+
┌─────────────────────────────────────────────────────────┐
|
|
181
|
+
│ Raspberry Pi 5 + PiEEG-16 Shield │
|
|
182
|
+
│ │
|
|
183
|
+
│ hardware.py → SPI/GPIO init, ADC register config │
|
|
184
|
+
│ ↓ │
|
|
185
|
+
│ acquisition.py → 250 Hz read loop (background thread) │
|
|
186
|
+
│ ↓ pub/sub (multiple consumers) │
|
|
187
|
+
│ ├── server.py → WebSocket broadcast │
|
|
188
|
+
│ ├── recorder.py → CSV file writer │
|
|
189
|
+
│ └── monitor.py → Terminal sparkline display │
|
|
190
|
+
│ ↓ │
|
|
191
|
+
│ dashboard.py → HTTP server for real-time web UI │
|
|
192
|
+
│ ↓ │
|
|
193
|
+
│ ws://0.0.0.0:1616 │ http://0.0.0.0:1617 │
|
|
194
|
+
└──────────┬───────────────────────────────────────────────┘
|
|
195
|
+
│ Local network
|
|
196
|
+
├── Browser (JS client)
|
|
197
|
+
├── Python notebook
|
|
198
|
+
├── Mobile app
|
|
199
|
+
└── Any WebSocket client
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
## Runs as a Service
|
|
203
|
+
|
|
204
|
+
Setup creates a systemd service that auto-starts on boot:
|
|
205
|
+
|
|
206
|
+
```bash
|
|
207
|
+
sudo systemctl status pieeg-server # check status
|
|
208
|
+
sudo systemctl stop pieeg-server # stop
|
|
209
|
+
sudo systemctl restart pieeg-server # restart
|
|
210
|
+
journalctl -u pieeg-server -f # view logs
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
## GPIO: No `gpiod` Dependency
|
|
214
|
+
|
|
215
|
+
This server talks to GPIO directly via the Linux kernel's character device interface (`/dev/gpiochipN`) using standard `ioctl` calls — no `gpiod` pip package needed.
|
|
216
|
+
|
|
217
|
+
We only use two GPIO pins (chip-select output + data-ready input), so the ~20 lines of `struct` packing replace an entire external dependency that:
|
|
218
|
+
|
|
219
|
+
- Has **breaking API changes** between v1 and v2 (completely incompatible)
|
|
220
|
+
- Requires **system C headers** (`libgpiod-dev`) to install via pip
|
|
221
|
+
- Only works on **Linux** (blocks development/testing on macOS/Windows)
|
|
222
|
+
|
|
223
|
+
The chardev v1 ioctl ABI has been stable since Linux 4.8 (2016) and is guaranteed not to break by the kernel's userspace compatibility policy.
|
|
224
|
+
|
|
225
|
+
## Safety
|
|
226
|
+
|
|
227
|
+
> **PiEEG-16 must operate from battery power (5V) only.**
|
|
228
|
+
> Do NOT connect to mains-powered equipment via USB.
|
|
229
|
+
> PiEEG-16 is NOT a medical device.
|
|
230
|
+
|
|
231
|
+
## License
|
|
232
|
+
|
|
233
|
+
MIT
|