@ctrlpi/ctrlpi-lab 0.0.0-stage → 0.9.25
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.
- package/LICENSE +21 -0
- package/README.md +232 -2
- package/ctrlpi-lab.js +585 -0
- package/package.json +32 -4
- package/pages/Pico Pinout.html +186 -0
- package/pages/Raspberry Pi Pinout.html +184 -0
- package/pages/api.html +148 -0
- package/pages/api_curl.html +60 -0
- package/pages/logs.html +86 -0
- package/pages/main.html +5080 -0
- package/pages/webhooks.html +52 -0
- package/pages/welcome.html +83 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 ctrlPi
|
|
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.
|
package/README.md
CHANGED
|
@@ -1,3 +1,233 @@
|
|
|
1
|
-
#
|
|
1
|
+
# ctrlPi Lab
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
[](#quick-start)
|
|
4
|
+
[](https://github.com/ctrlpi/ctrlpi-lab/tags)
|
|
5
|
+
[](https://nodejs.org/)
|
|
6
|
+
[](#usage)
|
|
7
|
+
[](LICENSE)
|
|
8
|
+

|
|
9
|
+
[](https://github.com/ctrlpi/ctrlpi-lab/actions/workflows/ci.yml)
|
|
10
|
+
|
|
11
|
+
A local browser dashboard for your ctrlPi setup. Test GPIO and sensor endpoints,
|
|
12
|
+
watch webhook events, and tail agent logs, with zero dependencies.
|
|
13
|
+
|
|
14
|
+
Runs on **macOS, Linux, and Windows** with **Node.js 20+**. The dashboard connects
|
|
15
|
+
to an agent’s REST API; install `pi-gpio-api` or `pico-gpio-api` on your board separately.
|
|
16
|
+
|
|
17
|
+
## Quick start
|
|
18
|
+
|
|
19
|
+
Requires Node.js 20 or newer.
|
|
20
|
+
|
|
21
|
+
```sh
|
|
22
|
+
npx @ctrlpi/ctrlpi-lab
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
Your browser will open automatically at [http://localhost:7474](http://localhost:7474).
|
|
26
|
+
|
|
27
|
+
Or clone and run directly (no `npm install` needed):
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
git clone https://github.com/ctrlpi/ctrlpi-lab.git
|
|
31
|
+
cd ctrlpi-lab
|
|
32
|
+
node ctrlpi-lab.js
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
You can also start it with `npm start`. Python is needed only for the mock-agent tests.
|
|
36
|
+
By default, the dashboard listens only on this computer (`127.0.0.1`). To allow LAN
|
|
37
|
+
devices to connect, start it with `--host 0.0.0.0`:
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
npx @ctrlpi/ctrlpi-lab --host 0.0.0.0
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
LAN access also exposes the dashboard’s agent credentials and unrestricted proxy to those devices.
|
|
44
|
+
|
|
45
|
+
To skip opening a browser:
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
npx @ctrlpi/ctrlpi-lab --no-open
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
To change the port on macOS/Linux:
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
PORT=9000 npx @ctrlpi/ctrlpi-lab
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
Or in Windows PowerShell:
|
|
58
|
+
|
|
59
|
+
```powershell
|
|
60
|
+
$env:PORT = "9000"
|
|
61
|
+
npx @ctrlpi/ctrlpi-lab
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
## Discovery
|
|
65
|
+
|
|
66
|
+
At startup, ctrlpi-lab scans the local /24 for agents. If the shared config was updated within
|
|
67
|
+
the last five minutes, it checks saved agents for reachability instead. On page load, the dashboard selects localhost on the configured agent port if `/hello` responds;
|
|
68
|
+
otherwise it connects to the first responding agent immediately and keeps scanning in the background.
|
|
69
|
+
Agent choices remain sorted alphabetically.
|
|
70
|
+
Automatically discovered agents are saved with the default `Api-Key` only if that key works
|
|
71
|
+
(otherwise with none). Scanning preserves existing saved keys. The **+** form checks reachability
|
|
72
|
+
and verifies a supplied key through the backend proxy before saving.
|
|
73
|
+
|
|
74
|
+
## Usage
|
|
75
|
+
|
|
76
|
+
1. Select an agent from the header dropdown, scan with the network icon, or click
|
|
77
|
+
**+** to enter its IP/hostname, port (default **8314**), and API key.
|
|
78
|
+
2. Choose an endpoint in the **API** sidebar. Fill in its parameters and send the
|
|
79
|
+
request to see the response. The key icon edits the saved connection key.
|
|
80
|
+
3. Open **Logs** to search the agent’s output, or **Webhooks** to inspect the public
|
|
81
|
+
ctrlpi.com test feed when that target is configured on your agent.
|
|
82
|
+
|
|
83
|
+
The **Welcome to ctrlPi** panel includes Pi and Pico installation steps.
|
|
84
|
+
**API - cURL Examples** provides nine commands using your selected address and key.
|
|
85
|
+
|
|
86
|
+
### Examples
|
|
87
|
+
|
|
88
|
+
| Task | API endpoint | Parameters or body |
|
|
89
|
+
|---|---|---|
|
|
90
|
+
| Check whether an agent is online | `GET /hello` | No API key required |
|
|
91
|
+
| Read configured GPIO pins | `GET /gpio/read` | No body |
|
|
92
|
+
| Set GPIO 26 HIGH | `POST /gpio/write/26` | `{"value": 1}` |
|
|
93
|
+
| Pulse GPIO 26 for two seconds | `POST /gpio/write/26` | `{"value": 1, "duration": 2}` |
|
|
94
|
+
| Configure a watched input | `POST /gpio/config/6` | `{"type": "input", "watched": true}` |
|
|
95
|
+
| Configure a Pi sensor | `POST /sensor/config/cpu_temp` | `{"script": "cpu-temp.sh"}` |
|
|
96
|
+
| Read that sensor | `GET /sensor/read/cpu_temp` | No body |
|
|
97
|
+
|
|
98
|
+
All endpoints except `/hello` require the agent’s API key. On a Pico, use
|
|
99
|
+
`cpu-temp.py` for the example sensor. Watched inputs send events when a webhook or
|
|
100
|
+
bridge target is configured; otherwise, the agent logs the events.
|
|
101
|
+
|
|
102
|
+
## Configuration
|
|
103
|
+
|
|
104
|
+
Saved agents are stored in the shared `config.json`'s `agents[]` (`{name, ip, port, api_key}`), the
|
|
105
|
+
one list every ctrlpi project reads - add an agent here and `mcp-bridge`, `studio-bridge` and the
|
|
106
|
+
smart-home bridges all see it. This dashboard's own `lab-config.json` holds the rest: the agent it
|
|
107
|
+
is currently pointed at (`selected_agent: {ip, port}`, its key coming from that agent's `agents[]`
|
|
108
|
+
entry), the MCP server (`mcp: {ip, port, api_key}`), and `online_agents` (what the last network scan
|
|
109
|
+
reached, retained as scan history; saved agents remain selectable), as `ip:port` strings. Every host uses the same
|
|
110
|
+
`ip` + `port` pair, never a URL, and `mcp-bridge`'s own key is `mcp.api_key`, so no two keys mean
|
|
111
|
+
the same thing.
|
|
112
|
+
|
|
113
|
+
> **Where the config lives:** in `~/.ctrlpi/`, always - never next to `ctrlpi-lab.js`, whatever way you
|
|
114
|
+
> started it. Two files: the shared **`~/.ctrlpi/config.json`** holds `agents[]` (every ctrlpi project
|
|
115
|
+
> reads and updates that one list), and **`~/.ctrlpi/lab-config.json`** holds what only this dashboard
|
|
116
|
+
> owns (`selected_agent`, the `mcp` section, `online_agents`). Pass `--config <path>` (a `.json` file,
|
|
117
|
+
> or a directory to hold both) to put them anywhere else.
|
|
118
|
+
|
|
119
|
+
Both files are optional. For example, the shared `~/.ctrlpi/config.json` can contain:
|
|
120
|
+
|
|
121
|
+
```json
|
|
122
|
+
{
|
|
123
|
+
"agents": [
|
|
124
|
+
{ "name": "garage-pi", "ip": "192.168.1.50", "port": 8314, "api_key": "your-secret-key" }
|
|
125
|
+
]
|
|
126
|
+
}
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
The dashboard’s `~/.ctrlpi/lab-config.json` stores its selected agent and scan history:
|
|
130
|
+
|
|
131
|
+
```json
|
|
132
|
+
{
|
|
133
|
+
"selected_agent": { "ip": "192.168.1.50", "port": 8314 },
|
|
134
|
+
"online_agents": ["192.168.1.50:8314"]
|
|
135
|
+
}
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
The backend also preserves optional MCP settings as
|
|
139
|
+
`mcp: {ip, port, api_key}` for compatibility; the current dashboard has no MCP tab
|
|
140
|
+
or registered stdio MCP routes. Use `mcp-bridge` separately for MCP tools.
|
|
141
|
+
|
|
142
|
+
- The header shows the selected agent’s IP and port after its model. Use the arrow to choose a saved agent,
|
|
143
|
+
or the **+** button to add an IP/hostname, port, and API key. The key icon edits the selected agent’s key.
|
|
144
|
+
- Environment overrides: `API_KEY` (agent key), `MCP_API_KEY` (MCP HTTP key).
|
|
145
|
+
- Discovered and last-used agents are saved back to the shared `~/.ctrlpi/config.json` automatically,
|
|
146
|
+
so you don't have to edit it by hand.
|
|
147
|
+
|
|
148
|
+
## Tabs
|
|
149
|
+
|
|
150
|
+
- **API**: test GPIO, sensor, and configuration endpoints. The sidebar includes board pinouts,
|
|
151
|
+
**Welcome to ctrlPi** with Pi/Pico installation instructions, and nine **API - cURL Examples**
|
|
152
|
+
aligned with the Pi API README and populated with the selected address/key. Changing the
|
|
153
|
+
agent’s API key is available only in the red Danger Zone of Config Update.
|
|
154
|
+
- **Logs**: compact log viewer with text search. Webhook tags are orange.
|
|
155
|
+
Red trash and refresh icons sit immediately after the search box. Reset Log
|
|
156
|
+
asks for confirmation, sets the agent’s `log_days` to `0`, then restores the previous value.
|
|
157
|
+
- **Webhooks**: **Webhook Events** displays the public ctrlpi.com test feed when the selected
|
|
158
|
+
agent’s configured webhook URL contains `ctrlpi.com`. The refresh icon sits after the title.
|
|
159
|
+
This is a shared test feed, not a private per-agent event store.
|
|
160
|
+
|
|
161
|
+
Logs and Webhooks offer **3s, 10s, 20s (default), 30s, and Manual** polling, plus auto-scroll.
|
|
162
|
+
The header includes the agent picker, **+** button, saved-key editor, light/dark toggle,
|
|
163
|
+
status indicator, and network scan button.
|
|
164
|
+
|
|
165
|
+
## How it works
|
|
166
|
+
|
|
167
|
+
Agent requests, including the + form’s health/key checks, pass through
|
|
168
|
+
`/api/proxy/url` using `piApiFetch`, avoiding browser CORS restrictions. The backend uses
|
|
169
|
+
Node’s built-in `http` and `fetch`, assembles HTML from `pages/`, and caches it in memory.
|
|
170
|
+
The Logs tab fetches the selected agent’s `/logs` through that proxy and filters in the browser;
|
|
171
|
+
`/api/logs` remains available as a separate backend helper. Webhook feed requests also use the proxy.
|
|
172
|
+
|
|
173
|
+
After editing HTML, restart the server and refresh the browser. In development mode
|
|
174
|
+
(`npm run dev`), the header’s **Reload page cache** icon rebuilds the cache and reloads the page.
|
|
175
|
+
The day/night toggle only changes the theme; it does not rebuild the cache.
|
|
176
|
+
|
|
177
|
+
### Backend endpoints
|
|
178
|
+
|
|
179
|
+
| Method | Path | Description |
|
|
180
|
+
|--------|------|-------------|
|
|
181
|
+
| `GET` | `/` | The dashboard HTML (assembled from `pages/` and cached in memory) |
|
|
182
|
+
| `GET` | `/api/default-config` | Connection defaults plus `local_network_prefix` and `dev_mode` |
|
|
183
|
+
| `POST` | `/api/save-config` | Saves `api_host` / `api_port` and/or the `mcp` section to `lab-config.json` |
|
|
184
|
+
| `GET` · `POST` | `/api/servers` | List / add saved agents (kept in the shared `config.json`) |
|
|
185
|
+
| `GET` | `/api/scan?port=` | Scans the local subnet via `/hello`; port defaults to 8314. Add `stream=1` for incremental NDJSON results |
|
|
186
|
+
| `GET` | `/api/logs` | Proxies the agent's `GET /logs`; supports `?limit=`, `?search=`, `?category=` |
|
|
187
|
+
| `*` | `/api/proxy/url?url=` | General HTTP proxy for the browser's GPIO / MCP-HTTP calls (also relays the `Mcp-Session-Id` header) |
|
|
188
|
+
| `POST` | `/api/reload-cache` | Rebuilds cached dashboard HTML from disk |
|
|
189
|
+
| `GET` | `/images/{file}` · `/pages/{file}` | Serves image and page files |
|
|
190
|
+
|
|
191
|
+
## Tests and CI
|
|
192
|
+
|
|
193
|
+
Requires Node 20+ and Python 3 (`python3`, or set `PYTHON` to its executable).
|
|
194
|
+
|
|
195
|
+
```bash
|
|
196
|
+
npm test # unit tests + mock-agent HTTP integration tests
|
|
197
|
+
npm run test:ci # CI entry point; runs the same tests
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
Integration tests launch the real lab server and a local copy of
|
|
201
|
+
`ctrlpi-cli/mock_agent.py` on OS-assigned loopback ports. They use a temporary
|
|
202
|
+
`--config` directory, preserve unrelated shared-config fields, and stop child
|
|
203
|
+
processes and delete temporary configs after each run. No Pi, Pico, public webhook
|
|
204
|
+
service, real credentials, or user configuration is needed. The fixture differs
|
|
205
|
+
from the CLI copy only in its header and reporting the actual allocated port.
|
|
206
|
+
|
|
207
|
+
The lab supports `--no-open` to skip opening a browser and `--no-startup-scan`
|
|
208
|
+
to skip automatic discovery. Tests use both, plus `HOST=127.0.0.1` and `PORT=0`;
|
|
209
|
+
normal startup still opens the browser and discovers agents as before.
|
|
210
|
+
|
|
211
|
+
No npm installation is needed for the app or tests. CI runs all nine combinations
|
|
212
|
+
of Node 22, 24, and 26 with macOS, Linux (Ubuntu), and Windows. Each job starts the
|
|
213
|
+
real lab server and the mock agent. There is no coverage reporting or coverage gate.
|
|
214
|
+
|
|
215
|
+
Tests cover agent discovery/selection, adding agents, credentials, real proxy
|
|
216
|
+
requests, GPIO write/read state, sensors, configuration persistence, logs, and
|
|
217
|
+
webhook rendering. Dashboard tests use a small DOM stub, not a browser. Hardware
|
|
218
|
+
timing/electrical behavior, real LAN discovery, external webhook delivery, MCP
|
|
219
|
+
bridge interoperability, and visual layout remain outside this suite. The mock
|
|
220
|
+
agent approximates the REST contract; it does not replace tests on real hardware.
|
|
221
|
+
|
|
222
|
+
## Related projects
|
|
223
|
+
|
|
224
|
+
- **[`pi-gpio-api`](https://github.com/ctrlpi/pi-gpio-api)**: Raspberry Pi GPIO REST server that reads inputs and drives outputs (and named sensors) over an HTTP API.
|
|
225
|
+
- **[`pico-gpio-api`](https://github.com/ctrlpi/pico-gpio-api)**: Raspberry Pi Pico W port of the GPIO REST server, with the same endpoints, wire format, and auth.
|
|
226
|
+
- **[`ctrlpi-cli`](https://github.com/ctrlpi/ctrlpi-cli)**: Command-line interface to the same agents, with shared agent configuration.
|
|
227
|
+
- **`mcp-bridge`**: MCP server that exposes GPIO control as tools for AI agents (e.g. Claude), executing them over the agents' REST API.
|
|
228
|
+
- **`homekit-bridge`**: native Apple HomeKit bridge that exposes GPIO pins and sensors as HomeKit accessories, driven over the agents' REST API.
|
|
229
|
+
- **`matter-bridge`**: Matter bridge that exposes GPIO pins and sensors to any Matter platform (Apple Home, Google Home, Alexa, Home Assistant), driven over the agents' REST API.
|
|
230
|
+
|
|
231
|
+
## License
|
|
232
|
+
|
|
233
|
+
[MIT](LICENSE)
|