@switchbot/openapi-cli 3.4.0 → 3.5.0
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/README.md +110 -602
- package/dist/index.js +436 -77
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -45,44 +45,14 @@ Under the hood every surface shares the same catalog, cache, and HMAC client —
|
|
|
45
45
|
|
|
46
46
|
## Table of contents
|
|
47
47
|
|
|
48
|
-
- [Features](#features)
|
|
49
|
-
- [Requirements](#requirements)
|
|
50
|
-
- [Installation](#installation)
|
|
48
|
+
- [Features](#features) · [Requirements](#requirements) · [Installation](#installation)
|
|
51
49
|
- [Quick start](#quick-start)
|
|
52
50
|
- [Credentials](#credentials)
|
|
53
|
-
- [Policy](#policy)
|
|
51
|
+
- [Policy](#policy) · [Rules engine](#rules-engine)
|
|
54
52
|
- [Global options](#global-options)
|
|
55
|
-
- [Commands](#commands)
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
- [`devices batch`](#devices-batch--bulk-commands)
|
|
59
|
-
- [`devices watch`](#devices-watch--poll-status)
|
|
60
|
-
- [`scenes`](#scenes--run-manual-scenes)
|
|
61
|
-
- [`webhook`](#webhook--receive-device-events-over-http)
|
|
62
|
-
- [`events`](#events--receive-device-events)
|
|
63
|
-
- [`status-sync`](#status-sync--mqttopenclaw-bridge)
|
|
64
|
-
- [`plan`](#plan--declarative-batch-operations)
|
|
65
|
-
- [`mcp`](#mcp--model-context-protocol-server)
|
|
66
|
-
- [`doctor`](#doctor--self-check)
|
|
67
|
-
- [`health`](#health--runtime-health-report)
|
|
68
|
-
- [`upgrade-check`](#upgrade-check--version-check)
|
|
69
|
-
- [`quota`](#quota--api-request-counter)
|
|
70
|
-
- [`history`](#history--audit-log)
|
|
71
|
-
- [`catalog`](#catalog--device-type-catalog)
|
|
72
|
-
- [`schema`](#schema--export-catalog-as-json)
|
|
73
|
-
- [`capabilities`](#capabilities--cli-manifest)
|
|
74
|
-
- [`cache`](#cache--inspect-and-clear-local-cache)
|
|
75
|
-
- [`policy`](#policy--validate-scaffold-and-migrate-policyyaml)
|
|
76
|
-
- [`daemon`](#daemon--background-rules-engine-process)
|
|
77
|
-
- [`completion`](#completion--shell-tab-completion)
|
|
78
|
-
- [Output modes](#output-modes)
|
|
79
|
-
- [Cache](#cache)
|
|
80
|
-
- [Exit codes & error codes](#exit-codes--error-codes)
|
|
81
|
-
- [Environment variables](#environment-variables)
|
|
82
|
-
- [Scripting examples](#scripting-examples)
|
|
83
|
-
- [Development](#development)
|
|
84
|
-
- [License](#license)
|
|
85
|
-
- [References](#references)
|
|
53
|
+
- [Commands](#commands): [config](#config--credential-management) · [devices](#devices--list-status-control) · [scenes](#scenes--run-manual-scenes) · [webhook](#webhook--receive-device-events-over-http) · [events](#events--receive-device-events) · [status-sync](#status-sync--mqttopenclaw-bridge) · [daemon](#daemon--background-rules-engine-process) · [plan](#plan--declarative-batch-operations) · [mcp](#mcp--model-context-protocol-server) · [doctor](#doctor--self-check) · [health](#health--runtime-health-report) · [upgrade-check](#upgrade-check--version-check) · [quota](#quota--api-request-counter) · [history](#history--audit-log) · [catalog](#catalog--device-type-catalog) · [schema](#schema--export-catalog-as-json) · [capabilities](#capabilities--cli-manifest) · [cache](#cache--inspect-and-clear-local-cache) · [policy cmd](#policy--validate-scaffold-and-migrate-policyyaml) · [completion](#completion--shell-tab-completion)
|
|
54
|
+
- [Output modes](#output-modes) · [Cache](#cache) · [Exit codes](#exit-codes--error-codes) · [Environment variables](#environment-variables)
|
|
55
|
+
- [Scripting examples](#scripting-examples) · [Development](#development) · [License](#license)
|
|
86
56
|
|
|
87
57
|
---
|
|
88
58
|
|
|
@@ -93,7 +63,7 @@ Under the hood every surface shares the same catalog, cache, and HMAC client —
|
|
|
93
63
|
- 🎨 **Dual output modes** — colorized tables by default; `--json` passthrough for `jq` and scripting
|
|
94
64
|
- 🔐 **Secure credentials** — HMAC-SHA256 signed requests; config file written with `0600`; env-var override for CI
|
|
95
65
|
- 🔍 **Dry-run mode** — preview every mutating request before it hits the API
|
|
96
|
-
- 🧪 **Fully tested** —
|
|
66
|
+
- 🧪 **Fully tested** — 2263 Vitest tests, mocked axios, zero network in CI
|
|
97
67
|
- ⚡ **Shell completion** — Bash / Zsh / Fish / PowerShell
|
|
98
68
|
|
|
99
69
|
## Requirements
|
|
@@ -296,110 +266,44 @@ then:
|
|
|
296
266
|
template: '{"rule":"{{ rule.name }}","fired":"{{ rule.fired_at }}"}'
|
|
297
267
|
```
|
|
298
268
|
|
|
299
|
-
**LLM condition** — add an AI judgement step before actions fire
|
|
300
|
-
configured LLM provider, passes the prompt plus recent event context, and gates execution
|
|
301
|
-
on the model's yes/no answer:
|
|
269
|
+
**LLM condition** — add an AI judgement step before actions fire:
|
|
302
270
|
|
|
303
271
|
```yaml
|
|
304
272
|
conditions:
|
|
305
273
|
- llm:
|
|
306
274
|
prompt: "Is the temperature above normal comfort range?"
|
|
307
275
|
provider: auto # auto | openai | anthropic
|
|
308
|
-
cache_ttl: 5m
|
|
276
|
+
cache_ttl: 5m
|
|
309
277
|
budget:
|
|
310
278
|
max_calls_per_hour: 20
|
|
311
279
|
on_error: pass # fail | pass | skip
|
|
312
280
|
```
|
|
313
281
|
|
|
314
|
-
Set `OPENAI_API_KEY` or `ANTHROPIC_API_KEY`
|
|
315
|
-
`rules lint` flags misconfigured LLM conditions (no provider key, cache TTL too high for
|
|
316
|
-
the trigger frequency, budget zero). Evaluation decisions are recorded in the trace log.
|
|
282
|
+
Set `OPENAI_API_KEY` or `ANTHROPIC_API_KEY`. `rules lint` flags misconfigured LLM conditions.
|
|
317
283
|
|
|
318
|
-
**Decision trace** —
|
|
319
|
-
every evaluation decision (why a rule fired or was blocked):
|
|
320
|
-
|
|
321
|
-
```yaml
|
|
322
|
-
automation:
|
|
323
|
-
audit:
|
|
324
|
-
evaluate_trace: sampled # full | sampled | off (default: sampled)
|
|
325
|
-
evaluate_retention_days: 7
|
|
326
|
-
```
|
|
284
|
+
**Decision trace** — set `automation.audit.evaluate_trace: sampled` (or `full`) in `policy.yaml` to record every evaluation decision.
|
|
327
285
|
|
|
328
286
|
```bash
|
|
329
|
-
#
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
#
|
|
333
|
-
switchbot
|
|
334
|
-
switchbot rules list --json | jq . # structured summary
|
|
335
|
-
|
|
336
|
-
# 3. Inspect a single rule in full detail (trigger, conditions, actions,
|
|
337
|
-
# cooldown, hysteresis, maxFiringsPerHour, suppressIfAlreadyDesired, last fired).
|
|
338
|
-
switchbot rules explain "motion on"
|
|
339
|
-
switchbot rules explain "motion on" --json
|
|
340
|
-
|
|
341
|
-
# 4. Run the engine. --dry-run overrides every rule into audit-only mode;
|
|
342
|
-
# --max-firings bounds a demo session.
|
|
343
|
-
switchbot rules run --dry-run --max-firings 5
|
|
344
|
-
|
|
345
|
-
# 5. Edit policy.yaml in another shell, then hot-reload without restart.
|
|
346
|
-
switchbot daemon reload # managed daemon reload
|
|
347
|
-
|
|
348
|
-
# 6. Review recorded fires.
|
|
349
|
-
switchbot rules tail --follow # stream rule-* audit lines
|
|
350
|
-
switchbot rules replay --since 1h --json # per-rule fires/dries/throttled/errors
|
|
351
|
-
switchbot rules summary # aggregate fires/errors per rule (24h window)
|
|
352
|
-
switchbot rules last-fired -n 20 # 20 most recent fire entries
|
|
287
|
+
switchbot rules lint # static check: exit 0 valid, 1 error
|
|
288
|
+
switchbot rules list --json | jq . # structured rule summary
|
|
289
|
+
switchbot rules explain "motion on" # trigger, conditions, actions, last fired
|
|
290
|
+
switchbot rules run --dry-run --max-firings 5 # run engine; --dry-run = audit only
|
|
291
|
+
switchbot daemon reload # hot-reload policy without restart
|
|
353
292
|
|
|
354
|
-
#
|
|
355
|
-
switchbot rules
|
|
356
|
-
|
|
357
|
-
switchbot rules
|
|
293
|
+
switchbot rules tail --follow # stream rule-* audit lines
|
|
294
|
+
switchbot rules replay --since 1h --json # per-rule fires/dries/throttled/errors
|
|
295
|
+
switchbot rules summary # aggregate fires/errors (24h)
|
|
296
|
+
switchbot rules conflicts # opposing actions, destructive cmds, quiet-hours gaps
|
|
297
|
+
switchbot rules doctor --json # lint + conflicts; exit 0 when clean
|
|
358
298
|
|
|
359
|
-
# 8. Scaffold a new rule from natural language (heuristic or LLM-backed).
|
|
360
299
|
switchbot rules suggest --intent "turn off AC at 11pm"
|
|
361
|
-
switchbot rules suggest --intent "
|
|
362
|
-
--llm auto # routes complex intents to LLM automatically
|
|
363
|
-
switchbot rules suggest --intent "..." --llm openai # explicit backend
|
|
364
|
-
# Set OPENAI_API_KEY or ANTHROPIC_API_KEY; auto mode falls back to heuristic on failure
|
|
365
|
-
|
|
366
|
-
# 9. Explain why a specific evaluation fired or was blocked (requires evaluate_trace).
|
|
367
|
-
switchbot rules trace-explain --rule "motion on" --last
|
|
368
|
-
switchbot rules trace-explain --rule "motion on" --since 1h --json
|
|
369
|
-
switchbot rules trace-explain <fireId> # single evaluation by ID
|
|
370
|
-
|
|
371
|
-
# 10. Simulate a rule against historical events without running the engine.
|
|
372
|
-
switchbot rules simulate "motion on" # replay last 24h from audit log
|
|
373
|
-
switchbot rules simulate "motion on" --since 7d --json
|
|
374
|
-
switchbot rules simulate policy.yaml --rule "night AC" --against events.jsonl
|
|
375
|
-
```
|
|
376
|
-
|
|
377
|
-
`rules suggest` enforces several guardrails on LLM output so a model can't quietly arm
|
|
378
|
-
something unsafe:
|
|
379
|
-
|
|
380
|
-
- **`dry_run` is forced to `true`** on every LLM-generated rule. Review the output and
|
|
381
|
-
flip it yourself before running the engine without `--dry-run`.
|
|
382
|
-
- **Explicit overrides always win.** If you pass `--trigger`, the LLM's answer must match;
|
|
383
|
-
a mismatch fails fast. Within the same trigger, mismatched `--event` / `--schedule` /
|
|
384
|
-
`--days` / `--webhook-path` are rewritten to your value with a warning.
|
|
385
|
-
- **`--llm` is enum-validated at the CLI** (`auto | openai | anthropic`) — junk values
|
|
386
|
-
exit non-zero instead of falling through.
|
|
387
|
-
- **Notify URLs must be `http://` or `https://`.** `rules lint` and the runtime both
|
|
388
|
-
reject `file://`, `ftp://`, etc., so a generated webhook can't smuggle in a non-HTTP
|
|
389
|
-
scheme.
|
|
390
|
-
|
|
391
|
-
When `quiet_hours` is configured in `policy.yaml`, `rules conflicts` additionally flags event-driven (MQTT / webhook) rules that lack a `time_between` condition — they would fire uninhibited during the quiet window. The hint in each finding includes a ready-to-paste `time_between` condition to add.
|
|
300
|
+
switchbot rules suggest --intent "..." --llm auto # LLM-backed (OPENAI_API_KEY or ANTHROPIC_API_KEY)
|
|
392
301
|
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
```bash
|
|
396
|
-
switchbot rules webhook-rotate-token # rotate the bearer token for webhook triggers
|
|
397
|
-
switchbot rules webhook-show-token # print current token (creates one if absent)
|
|
302
|
+
switchbot rules trace-explain --rule "motion on" --last # why a rule fired/was blocked
|
|
303
|
+
switchbot rules simulate "motion on" --since 7d --json # replay without running the engine
|
|
398
304
|
```
|
|
399
305
|
|
|
400
|
-
See [`docs/design/phase4-rules.md`](./docs/design/phase4-rules.md) for
|
|
401
|
-
the engine's pipeline (subscribe → classify → match → conditions →
|
|
402
|
-
throttle → action → audit).
|
|
306
|
+
LLM-generated rules always have `dry_run: true` — flip it yourself after review. Notify URLs must be `http://` or `https://`. See [`docs/design/phase4-rules.md`](./docs/design/phase4-rules.md) for the full pipeline.
|
|
403
307
|
|
|
404
308
|
## Global options
|
|
405
309
|
|
|
@@ -424,23 +328,11 @@ throttle → action → audit).
|
|
|
424
328
|
- `-V`, `--version`: Print the CLI version.
|
|
425
329
|
- `-h`, `--help`: Show help for any command or subcommand.
|
|
426
330
|
|
|
427
|
-
Every subcommand supports `--help
|
|
428
|
-
|
|
429
|
-
```bash
|
|
430
|
-
switchbot --help
|
|
431
|
-
switchbot devices command --help
|
|
432
|
-
```
|
|
433
|
-
|
|
434
|
-
> **Tip — required-value flags and subcommands.** Flags like `--profile`, `--timeout`, `--max`, and `--interval` take a value. If you omit it, Commander will happily consume the next token — including a subcommand name. Since v2.2.1 the CLI rejects that eagerly (exit 2 with a clear error), but if you ever hit `unknown command 'list'` after something like `switchbot --profile list`, use the `--flag=value` form: `switchbot --profile=home devices list`.
|
|
331
|
+
Every subcommand supports `--help`. Use `--flag=value` form when a flag takes a value and is followed by a subcommand (e.g. `switchbot --profile=home devices list`).
|
|
435
332
|
|
|
436
333
|
### `--dry-run`
|
|
437
334
|
|
|
438
|
-
Intercepts every non-GET request:
|
|
439
|
-
sent, then exits `0` without contacting the API. `GET` requests (list, status,
|
|
440
|
-
query) are still executed so you can preview the state involved. Dry-run also
|
|
441
|
-
validates command names against the device catalog and rejects unknown commands
|
|
442
|
-
(exit 2) when the device type has a known catalog entry. Commands sent to
|
|
443
|
-
read-only sensors (e.g. Meter) are likewise rejected.
|
|
335
|
+
Intercepts every non-GET request: prints the URL/body it would have sent, then exits `0`. GET requests still execute. Also validates command names against the device catalog (exit 2 on unknown commands or read-only sensors).
|
|
444
336
|
|
|
445
337
|
```bash
|
|
446
338
|
switchbot devices command ABC123 turnOn --dry-run
|
|
@@ -456,127 +348,44 @@ switchbot devices command ABC123 turnOn --dry-run
|
|
|
456
348
|
switchbot config set-token <token> <secret> # Save to ~/.switchbot/config.json
|
|
457
349
|
switchbot config show # Print current source + masked secret
|
|
458
350
|
switchbot config list-profiles # List saved profiles
|
|
459
|
-
|
|
460
|
-
# Print (or write) the recommended AI-agent profile template
|
|
461
|
-
switchbot config agent-profile # print to stdout
|
|
462
|
-
switchbot config agent-profile --write # write to ~/.switchbot/profiles/agent.json (mode 0600)
|
|
463
|
-
switchbot config agent-profile --write --force # overwrite if it already exists
|
|
464
|
-
switchbot config agent-profile --json # structured JSON envelope
|
|
351
|
+
switchbot config agent-profile --write # write recommended AI-agent profile (mode 0600)
|
|
465
352
|
```
|
|
466
353
|
|
|
467
354
|
### `devices` — list, status, control
|
|
468
355
|
|
|
469
356
|
```bash
|
|
470
357
|
# List all physical devices and IR remote devices
|
|
471
|
-
#
|
|
472
|
-
|
|
473
|
-
switchbot devices list
|
|
474
|
-
switchbot devices ls # short alias for 'list'
|
|
475
|
-
switchbot devices list --wide
|
|
358
|
+
switchbot devices list # default 4 columns: deviceId, deviceName, type, category
|
|
359
|
+
switchbot devices list --wide # full 10-column operator view
|
|
476
360
|
switchbot devices list --json | jq '.deviceList[].deviceId'
|
|
477
|
-
|
|
478
|
-
# IR remotes: type = remoteType (e.g. "TV"), category = "ir"
|
|
479
|
-
# Physical: category = "physical"
|
|
480
361
|
switchbot devices list --format=tsv --fields=deviceId,type,category
|
|
481
362
|
|
|
482
|
-
# Filter
|
|
483
|
-
|
|
484
|
-
switchbot devices list --filter type=Bot
|
|
485
|
-
switchbot devices list --filter name
|
|
486
|
-
|
|
487
|
-
# Filter operators: = (substring; exact for `category`), ~ (substring),
|
|
488
|
-
# =/regex/ (case-insensitive regex). Clauses are AND-ed.
|
|
489
|
-
switchbot devices list --filter 'name~living'
|
|
490
|
-
switchbot devices list --filter 'type=/Hub.*/'
|
|
491
|
-
switchbot devices list --filter 'name~office,type=/Bulb|Strip/'
|
|
492
|
-
|
|
493
|
-
# Filter by family / room (family & room info requires the platform source
|
|
494
|
-
# header, which this CLI sends on every request)
|
|
495
|
-
switchbot devices list --json | jq '.deviceList[] | select(.familyName == "Home")'
|
|
496
|
-
switchbot devices list --json | jq '[.deviceList[], .infraredRemoteList[]] | group_by(.familyName)'
|
|
363
|
+
# Filter by type / name / category / room
|
|
364
|
+
# Operators: = (substring; exact for category), ~ (substring), =/regex/; clauses AND-ed
|
|
365
|
+
switchbot devices list --filter 'type=Bot'
|
|
366
|
+
switchbot devices list --filter 'name~living,type=/Bulb|Strip/'
|
|
367
|
+
switchbot devices list --filter 'category=physical'
|
|
497
368
|
|
|
498
|
-
# Query real-time status
|
|
369
|
+
# Query real-time status
|
|
499
370
|
switchbot devices status <deviceId>
|
|
500
|
-
switchbot devices status
|
|
371
|
+
switchbot devices status --ids ABC,DEF,GHI # batch status
|
|
372
|
+
switchbot devices status --ids ABC,DEF --fields power,battery --format jsonl
|
|
501
373
|
|
|
502
374
|
# Resolve device by fuzzy name instead of ID (status, command, describe, expand, watch)
|
|
503
375
|
switchbot devices status --name "Living Room AC"
|
|
504
376
|
switchbot devices command --name "Office Light" turnOn
|
|
505
|
-
switchbot devices describe --name "Kitchen Bot"
|
|
506
|
-
|
|
507
|
-
# Batch status across multiple devices
|
|
508
|
-
switchbot devices status --ids ABC,DEF,GHI
|
|
509
|
-
switchbot devices status --ids ABC,DEF --fields power,battery # only show specific fields
|
|
510
|
-
switchbot devices status --ids ABC,DEF --format jsonl # one JSON line per device
|
|
511
377
|
|
|
512
378
|
# Send a control command
|
|
513
379
|
switchbot devices command <deviceId> <cmd> [parameter] [--type command|customize]
|
|
514
380
|
|
|
515
|
-
#
|
|
516
|
-
switchbot devices
|
|
517
|
-
switchbot devices
|
|
518
|
-
|
|
519
|
-
# Discover what's supported (offline reference, no API call)
|
|
520
|
-
switchbot devices types # List all device types + IR remote types (incl. role column)
|
|
521
|
-
switchbot devices commands <type> # Show commands, parameter formats, and status fields
|
|
522
|
-
switchbot devices commands Bot
|
|
523
|
-
switchbot devices commands "Smart Lock"
|
|
524
|
-
switchbot devices commands curtain # Case-insensitive, substring match
|
|
381
|
+
# Offline reference (no API call)
|
|
382
|
+
switchbot devices types # all device types
|
|
383
|
+
switchbot devices commands <type> # commands, parameter formats, status fields
|
|
525
384
|
```
|
|
526
385
|
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
Three commands accept `--filter`. They share one four-operator grammar,
|
|
530
|
-
but each exposes its own key set:
|
|
531
|
-
|
|
532
|
-
- `devices list`
|
|
533
|
-
Operators: `=` (substring; **exact** for `category`), `!=` (negated),
|
|
534
|
-
`~` (substring), `=/regex/` (case-insensitive regex).
|
|
535
|
-
Keys: `type`, `name`, `category`, `room`.
|
|
536
|
-
- `devices batch`
|
|
537
|
-
Operators: same as `devices list`.
|
|
538
|
-
Keys: `type`, `family`, `room`, `category`.
|
|
539
|
-
- `events tail` / `events mqtt-tail`
|
|
540
|
-
Operators: same (tail only; mqtt-tail uses `--topic` instead).
|
|
541
|
-
Keys: `deviceId`, `type`.
|
|
386
|
+
Parameters for `setAll`, `setPosition`, `setMode`, `setBrightness`, and `setColor` are validated client-side (exit 2 on bad input). `setColor` accepts `R:G:B`, `#RRGGBB`, `#RGB`, and CSS names — all normalize to `R:G:B`. Pass `--skip-param-validation` to bypass. Unknown deviceIds exit 2 by default; pass `--allow-unknown-device` for scripted pass-through.
|
|
542
387
|
|
|
543
|
-
|
|
544
|
-
alternation (`=/A|B/`) for that. `category` is the one key that stays exact
|
|
545
|
-
under `=` / `!=` to preserve `category=physical` / `category!=ir` semantics.
|
|
546
|
-
A clause with an empty value (e.g. `name~`, `type=`) is rejected with exit 2 —
|
|
547
|
-
the parser refuses to guess whether an empty value means "no constraint" or
|
|
548
|
-
"match empty string". Drop the clause outright to remove the constraint.
|
|
549
|
-
|
|
550
|
-
#### Parameter formats
|
|
551
|
-
|
|
552
|
-
`parameter` is optional — omit it for commands like `turnOn`/`turnOff` (auto-defaults to `"default"`).
|
|
553
|
-
Numeric-only and JSON-object parameters are auto-parsed; strings with colons / commas / semicolons pass through as-is.
|
|
554
|
-
|
|
555
|
-
For the exact commands and parameter formats a specific device supports, query the built-in catalog:
|
|
556
|
-
|
|
557
|
-
```bash
|
|
558
|
-
switchbot devices commands <type> # e.g. Bot, Curtain, "Smart Lock", "Robot Vacuum Cleaner S10"
|
|
559
|
-
```
|
|
560
|
-
|
|
561
|
-
Generic parameter shapes (which one applies is decided by the device — see the catalog):
|
|
562
|
-
|
|
563
|
-
| Shape | Example |
|
|
564
|
-
| ------------------- | -------------------------------------------------------- |
|
|
565
|
-
| _(none)_ | `devices command <id> turnOn` |
|
|
566
|
-
| `<integer>` | `devices command <id> setBrightness 75` |
|
|
567
|
-
| `<R:G:B>` | `devices command <id> setColor "255:0:0"` |
|
|
568
|
-
| `<direction;angle>` | `devices command <id> setPosition "up;60"` |
|
|
569
|
-
| `<a,b,c,…>` | `devices command <id> setAll "26,1,3,on"` |
|
|
570
|
-
| `<json object>` | `'{"action":"sweep","param":{"fanLevel":2,"times":1}}'` |
|
|
571
|
-
| Custom IR button | `devices command <id> MyButton --type customize` |
|
|
572
|
-
|
|
573
|
-
Parameters for `setAll` (Air Conditioner), `setPosition` (Curtain / Blind Tilt), `setMode` (Relay Switch), `setBrightness` (dimmable lights), and `setColor` (Color Bulb / Strip Light / Ceiling Light) are validated client-side before the request — malformed shapes, out-of-range values, and JSON for CSV fields all fail fast with exit 2. `setColor` accepts `R:G:B`, `R,G,B`, `#RRGGBB`, `#RGB`, and CSS named colors (`red`, `blue`, …); all normalize to `R:G:B` before hitting the API. Pass `--skip-param-validation` to bypass (escape hatch — prefer fixing the argument). Command names are also case-normalized against the catalog (e.g. `turnon` is auto-corrected to `turnOn` with a stderr warning); unknown names still exit 2 with the supported-commands list.
|
|
574
|
-
|
|
575
|
-
Unknown deviceIds (not in the local cache) exit 2 by default so `--dry-run` is a reliable pre-flight gate. Unknown command names and commands on read-only sensors are also rejected during dry-run when the device type has a catalog entry. Run `switchbot devices list` first, or pass `--allow-unknown-device` for scripted pass-through.
|
|
576
|
-
|
|
577
|
-
Negative numeric parameters (e.g. `setBrightness -1` for a probe) are passed through to the command validator instead of being swallowed by the flag parser as an unknown option.
|
|
578
|
-
|
|
579
|
-
For the complete per-device command reference, see the [SwitchBot API docs](https://github.com/OpenWonderLabs/SwitchBotAPI#send-device-control-commands).
|
|
388
|
+
For per-device command and parameter details: `switchbot devices commands <type>` or the [SwitchBot API docs](https://github.com/OpenWonderLabs/SwitchBotAPI#send-device-control-commands).
|
|
580
389
|
|
|
581
390
|
#### `devices expand` — named flags for packed parameters
|
|
582
391
|
|
|
@@ -596,61 +405,46 @@ switchbot devices expand <blindId> setPosition --direction up --angle 50
|
|
|
596
405
|
|
|
597
406
|
# Relay Switch — setMode
|
|
598
407
|
switchbot devices expand <relayId> setMode --channel 1 --mode edge
|
|
408
|
+
|
|
409
|
+
# Color Bulb / Strip Light / Floor Lamp / Ceiling Light — setBrightness / setColor / setColorTemperature
|
|
410
|
+
switchbot devices expand <bulbId> setBrightness --brightness 80
|
|
411
|
+
switchbot devices expand <bulbId> setColor --color "#FF0000"
|
|
412
|
+
switchbot devices expand <bulbId> setColorTemperature --color-temp 4000
|
|
599
413
|
```
|
|
600
414
|
|
|
601
|
-
Run `switchbot devices expand <id> <command> --help` to see the available flags for any device command.
|
|
415
|
+
Run `switchbot devices expand <id> <command> --help` to see the available flags for any device command.
|
|
602
416
|
|
|
603
417
|
#### `devices explain` — one-shot device summary
|
|
604
418
|
|
|
605
419
|
```bash
|
|
606
|
-
#
|
|
607
|
-
switchbot devices explain <deviceId>
|
|
608
|
-
|
|
609
|
-
# Skip live status fetch (catalog-only output, no API call)
|
|
610
|
-
switchbot devices explain <deviceId> --no-live
|
|
420
|
+
switchbot devices explain <deviceId> # metadata + commands + live status
|
|
421
|
+
switchbot devices explain <deviceId> --no-live # catalog-only, no API call
|
|
611
422
|
```
|
|
612
423
|
|
|
613
|
-
Returns a combined view: static catalog info (commands, parameters, status fields) merged with the current live status. For Hub devices, also lists connected child devices. Prefer this over separate `status` + `describe` calls.
|
|
614
|
-
|
|
615
424
|
#### `devices meta` — local device metadata
|
|
616
425
|
|
|
617
426
|
```bash
|
|
618
427
|
switchbot devices meta set <deviceId> --alias "Office Light"
|
|
619
|
-
switchbot devices meta set <deviceId> --hide
|
|
428
|
+
switchbot devices meta set <deviceId> --hide # hide from `devices list`
|
|
620
429
|
switchbot devices meta get <deviceId>
|
|
621
|
-
switchbot devices meta list
|
|
430
|
+
switchbot devices meta list
|
|
622
431
|
switchbot devices meta clear <deviceId>
|
|
623
432
|
```
|
|
624
433
|
|
|
625
|
-
Stores local annotations
|
|
434
|
+
Stores local annotations in `~/.switchbot/device-meta.json`. `--show-hidden` on `devices list` reveals hidden devices.
|
|
626
435
|
|
|
627
436
|
#### `devices batch` — bulk commands
|
|
628
437
|
|
|
629
438
|
```bash
|
|
630
|
-
#
|
|
439
|
+
# Same command to every matching device
|
|
631
440
|
switchbot devices batch turnOff --filter 'type=Bot'
|
|
632
441
|
switchbot devices batch setBrightness 50 --filter 'type~Light,family=Living'
|
|
633
|
-
|
|
634
|
-
# Explicit device IDs (comma-separated)
|
|
635
442
|
switchbot devices batch turnOn --ids ID1,ID2,ID3
|
|
636
|
-
|
|
637
|
-
# Pipe device IDs from `devices list`
|
|
638
443
|
switchbot devices list --format=id --filter 'type=Bot' | switchbot devices batch toggle -
|
|
639
|
-
|
|
640
|
-
# Destructive commands require --yes
|
|
641
|
-
switchbot devices batch unlock --filter 'type=Smart Lock' --yes
|
|
642
|
-
|
|
643
|
-
# Skip devices whose cached status is offline (default: off)
|
|
644
|
-
switchbot devices batch turnOn --ids ID1,ID2 --skip-offline
|
|
645
|
-
|
|
646
|
-
# --idempotency-key is an alias for --idempotency-key-prefix; both append -<deviceId>
|
|
647
|
-
switchbot devices batch turnOn --ids ID1,ID2 --idempotency-key morning-lights
|
|
444
|
+
switchbot devices batch unlock --filter 'type=Smart Lock' --yes # destructive: requires --yes
|
|
648
445
|
```
|
|
649
446
|
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
`--skip-offline` reads from the local status cache only (no new API calls);
|
|
653
|
-
skipped devices appear under `summary.skipped` with `skippedReason:'offline'`.
|
|
447
|
+
Filter keys: `type`, `family`, `room`, `category`. Skipped-offline devices appear under `summary.skipped` when `--skip-offline` is passed.
|
|
654
448
|
|
|
655
449
|
### `scenes` — run manual scenes
|
|
656
450
|
|
|
@@ -685,140 +479,39 @@ The CLI validates that `<url>` is an absolute `http://` or `https://` URL before
|
|
|
685
479
|
|
|
686
480
|
### `events` — receive device events
|
|
687
481
|
|
|
688
|
-
Two subcommands cover the two ways SwitchBot can push state changes to you.
|
|
689
|
-
|
|
690
482
|
#### `events tail` — local webhook receiver
|
|
691
483
|
|
|
692
484
|
```bash
|
|
693
|
-
#
|
|
694
|
-
switchbot events tail
|
|
695
|
-
|
|
696
|
-
# Filter to one device
|
|
697
|
-
switchbot events tail --filter deviceId=ABC123
|
|
698
|
-
|
|
699
|
-
# Stop after 5 matching events
|
|
700
|
-
switchbot events tail --filter 'type=WoMeter' --max 5
|
|
701
|
-
|
|
702
|
-
# Stop after 10 minutes regardless of event count
|
|
703
|
-
switchbot events tail --for 10m
|
|
704
|
-
|
|
705
|
-
# Custom port / path
|
|
485
|
+
switchbot events tail # listen on port 3000
|
|
486
|
+
switchbot events tail --filter deviceId=ABC123 # filter to one device
|
|
487
|
+
switchbot events tail --filter 'type=WoMeter' --max 5 --for 10m
|
|
706
488
|
switchbot events tail --port 8080 --path /hook --json
|
|
707
489
|
```
|
|
708
490
|
|
|
709
|
-
Run `switchbot webhook setup https://your.host/hook` first
|
|
710
|
-
|
|
711
|
-
Output (one JSON line per matched event):
|
|
712
|
-
|
|
713
|
-
```json
|
|
714
|
-
{ "t": "2024-01-01T12:00:00.000Z", "remote": "1.2.3.4:54321", "path": "/", "body": {...}, "matched": true }
|
|
715
|
-
```
|
|
716
|
-
|
|
717
|
-
Filter keys: `deviceId`, `type`. Operators: `=` (substring), `~` (substring), `=/regex/` (case-insensitive regex). Clauses comma-separated and AND-ed.
|
|
491
|
+
Run `switchbot webhook setup https://your.host/hook` first. `events tail` only runs the local receiver — tunnelling (ngrok/cloudflared) is up to you.
|
|
718
492
|
|
|
719
493
|
#### `events mqtt-tail` — real-time MQTT stream
|
|
720
494
|
|
|
721
495
|
```bash
|
|
722
|
-
#
|
|
723
|
-
switchbot events mqtt-tail
|
|
724
|
-
|
|
725
|
-
# Filter to a topic subtree
|
|
726
|
-
switchbot events mqtt-tail --topic 'switchbot/#'
|
|
727
|
-
|
|
728
|
-
# Stop after 10 events
|
|
729
|
-
switchbot events mqtt-tail --max 10 --json
|
|
730
|
-
|
|
731
|
-
# Stop after a fixed duration (emits __session_start under --json before connect)
|
|
732
|
-
switchbot events mqtt-tail --for 30s --json
|
|
496
|
+
switchbot events mqtt-tail # stream all shadow events (Ctrl-C to stop)
|
|
497
|
+
switchbot events mqtt-tail --topic 'switchbot/#' # filter to topic subtree
|
|
498
|
+
switchbot events mqtt-tail --max 10 --for 30s --json
|
|
733
499
|
```
|
|
734
500
|
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
Output (one JSON line per message):
|
|
738
|
-
|
|
739
|
-
```json
|
|
740
|
-
{ "t": "2024-01-01T12:00:00.000Z", "topic": "switchbot/abc123/status", "payload": {...} }
|
|
741
|
-
```
|
|
742
|
-
|
|
743
|
-
This command runs in the foreground and streams events until you press Ctrl-C. To run it persistently in the background, use a process manager:
|
|
744
|
-
|
|
745
|
-
```bash
|
|
746
|
-
# pm2
|
|
747
|
-
pm2 start "switchbot events mqtt-tail --json" --name switchbot-events
|
|
748
|
-
|
|
749
|
-
# nohup
|
|
750
|
-
nohup switchbot events mqtt-tail --json >> ~/switchbot-events.log 2>&1 &
|
|
751
|
-
```
|
|
752
|
-
|
|
753
|
-
Run `switchbot doctor` to verify MQTT credentials are configured correctly before connecting.
|
|
501
|
+
Credentials are provisioned automatically from the REST API config. Use `--sink` to route events to external services (`file`, `webhook`, `telegram`, `homeassistant`, `openclaw`) — see `switchbot events mqtt-tail --help` for details.
|
|
754
502
|
|
|
755
503
|
### `status-sync` — MQTT/OpenClaw bridge
|
|
756
504
|
|
|
757
|
-
|
|
758
|
-
long-running bridge that forwards SwitchBot MQTT shadow events into an OpenClaw
|
|
759
|
-
gateway. Internally it reuses `events mqtt-tail --sink openclaw`, but adds a
|
|
760
|
-
stable command surface for foreground execution, background startup, status
|
|
761
|
-
inspection, and shutdown.
|
|
505
|
+
Forwards SwitchBot MQTT shadow events into an OpenClaw gateway with stable lifecycle management.
|
|
762
506
|
|
|
763
507
|
```bash
|
|
764
|
-
#
|
|
765
|
-
switchbot status-sync
|
|
766
|
-
|
|
767
|
-
# Background mode for a normal shell session
|
|
768
|
-
switchbot status-sync start --openclaw-model home-agent
|
|
769
|
-
|
|
770
|
-
# Inspect the current bridge
|
|
508
|
+
switchbot status-sync run --openclaw-model home-agent # foreground (for supervisors)
|
|
509
|
+
switchbot status-sync start --openclaw-model home-agent # background
|
|
771
510
|
switchbot status-sync status --json
|
|
772
|
-
|
|
773
|
-
# Stop the running bridge
|
|
774
511
|
switchbot status-sync stop
|
|
775
512
|
```
|
|
776
513
|
|
|
777
|
-
Required
|
|
778
|
-
|
|
779
|
-
- `OPENCLAW_MODEL` or `--openclaw-model <id>`
|
|
780
|
-
- `OPENCLAW_TOKEN` or `--openclaw-token <token>`
|
|
781
|
-
|
|
782
|
-
Optional input:
|
|
783
|
-
|
|
784
|
-
- `OPENCLAW_URL` or `--openclaw-url <url>`
|
|
785
|
-
- `--topic <pattern>` to narrow the MQTT subscription
|
|
786
|
-
- `SWITCHBOT_STATUS_SYNC_HOME` or `--state-dir <path>` for custom runtime state
|
|
787
|
-
|
|
788
|
-
Background mode writes these files under the state directory:
|
|
789
|
-
|
|
790
|
-
- `state.json` — current pid, start time, effective command
|
|
791
|
-
- `stdout.log` — child stdout
|
|
792
|
-
- `stderr.log` — child stderr
|
|
793
|
-
|
|
794
|
-
Foreground vs background:
|
|
795
|
-
|
|
796
|
-
- `status-sync run` keeps the bridge attached to the current terminal
|
|
797
|
-
- `status-sync start` detaches the bridge and returns immediately
|
|
798
|
-
- `status-sync status` reports whether the bridge is alive plus paths/logs
|
|
799
|
-
- `status-sync stop` terminates the managed bridge process tree
|
|
800
|
-
|
|
801
|
-
#### `mqtt-tail` sinks — route events to external services
|
|
802
|
-
|
|
803
|
-
By default `mqtt-tail` prints JSONL to stdout. Use `--sink` (repeatable) to route events to one or more destinations instead:
|
|
804
|
-
|
|
805
|
-
| Sink | Required flags |
|
|
806
|
-
| --- | --- |
|
|
807
|
-
| `stdout` | (default when no `--sink` given) |
|
|
808
|
-
| `file` | `--sink-file <path>` — append JSONL |
|
|
809
|
-
| `webhook` | `--webhook-url <url>` — HTTP POST each event |
|
|
810
|
-
| `telegram` | `--telegram-token` (or `$TELEGRAM_TOKEN`), `--telegram-chat <chatId>` |
|
|
811
|
-
| `homeassistant` | `--ha-url <url>` + `--ha-webhook-id` (no auth) or `--ha-token` (REST event API) |
|
|
812
|
-
|
|
813
|
-
```bash
|
|
814
|
-
# Generic webhook (n8n, Make, etc.)
|
|
815
|
-
switchbot events mqtt-tail --sink webhook --webhook-url https://n8n.local/hook/abc
|
|
816
|
-
|
|
817
|
-
# Forward to Home Assistant via webhook trigger
|
|
818
|
-
switchbot events mqtt-tail --sink homeassistant --ha-url http://homeassistant.local:8123 --ha-webhook-id switchbot
|
|
819
|
-
```
|
|
820
|
-
|
|
821
|
-
Device state is also persisted to `~/.switchbot/device-history/<deviceId>.json` (latest + 100-entry ring buffer) regardless of sink configuration. This enables the `get_device_history` MCP tool to answer state queries without an API call.
|
|
514
|
+
Required: `OPENCLAW_MODEL` (or `--openclaw-model`) and `OPENCLAW_TOKEN`. Optional: `OPENCLAW_URL`, `--topic`, `--state-dir`. Background mode writes `state.json`, `stdout.log`, and `stderr.log` under the state directory.
|
|
822
515
|
|
|
823
516
|
### `daemon` — background rules-engine process
|
|
824
517
|
|
|
@@ -917,10 +610,11 @@ switchbot mcp serve
|
|
|
917
610
|
```
|
|
918
611
|
|
|
919
612
|
Exposes MCP tools (`list_devices`, `describe_device`, `get_device_status`,
|
|
613
|
+
`get_device_history`, `query_device_history`, `aggregate_device_history`,
|
|
920
614
|
`send_command`, `list_scenes`, `run_scene`, `search_catalog`,
|
|
921
615
|
`account_overview`, `plan_suggest`, `plan_run`, `audit_query`,
|
|
922
616
|
`audit_stats`, `policy_diff`, `policy_validate`, `policy_new`,
|
|
923
|
-
`policy_migrate`, `rules_suggest`, `rule_notifications`,
|
|
617
|
+
`policy_migrate`, `policy_add_rule`, `rules_suggest`, `rule_notifications`,
|
|
924
618
|
`rules_explain`, `rules_simulate`) plus a
|
|
925
619
|
`switchbot://events` resource for real-time shadow updates.
|
|
926
620
|
`rules_suggest` accepts an optional `llm` parameter (`openai | anthropic | auto`)
|
|
@@ -939,7 +633,7 @@ switchbot doctor
|
|
|
939
633
|
switchbot doctor --json
|
|
940
634
|
```
|
|
941
635
|
|
|
942
|
-
Runs local checks (Node version, credentials, profiles, catalog, cache, quota, clock, MQTT, policy, MCP, notify-connectivity) and exits 1 if any check fails. `warn` results exit 0. The MQTT check reports `ok` when REST credentials are configured (auto-provisioned on first use). The `notify-connectivity` check probes webhook URLs declared in `type: notify` actions. Use this to diagnose connectivity or config issues before running automation.
|
|
636
|
+
Runs local checks (Node version, credentials, profiles, catalog, catalog-schema, cache, quota, clock, MQTT, policy, MCP, keychain, path, inventory, audit, daemon, health, notify-connectivity, release-notes) and exits 1 if any check fails. `warn` results exit 0. The MQTT check reports `ok` when REST credentials are configured (auto-provisioned on first use). The `notify-connectivity` check probes webhook URLs declared in `type: notify` actions. Use this to diagnose connectivity or config issues before running automation.
|
|
943
637
|
|
|
944
638
|
`--json` output includes `maturityScore` (0–100) and `maturityLabel` (`production-ready` / `mostly-ready` / `needs-work` / `not-ready`) to give an at-a-glance readiness rating:
|
|
945
639
|
|
|
@@ -970,71 +664,44 @@ Port conflicts are reported immediately with a clear hint to choose a different
|
|
|
970
664
|
### `upgrade-check` — version check
|
|
971
665
|
|
|
972
666
|
```bash
|
|
973
|
-
switchbot upgrade-check
|
|
974
|
-
switchbot upgrade-check --json
|
|
975
|
-
switchbot upgrade-check --timeout 5000 # custom registry timeout (ms)
|
|
976
|
-
```
|
|
977
|
-
|
|
978
|
-
Queries the npm registry for the latest published version and compares it against the running version. When the registry's `dist-tags.latest` is itself a prerelease (e.g. `4.0.0-rc.1`), the check is skipped and the current version is treated as up-to-date — accidental prerelease tags don't trigger spurious upgrade prompts.
|
|
979
|
-
`--json` output:
|
|
980
|
-
|
|
981
|
-
```json
|
|
982
|
-
{
|
|
983
|
-
"current": "3.3.2",
|
|
984
|
-
"latest": "4.0.0",
|
|
985
|
-
"upToDate": false,
|
|
986
|
-
"updateAvailable": true,
|
|
987
|
-
"breakingChange": true,
|
|
988
|
-
"installCommand": "npm install -g @switchbot/openapi-cli@4.0.0"
|
|
989
|
-
}
|
|
667
|
+
switchbot upgrade-check # exits 1 when update available
|
|
668
|
+
switchbot upgrade-check --json # {current, latest, upToDate, updateAvailable, breakingChange, installCommand}
|
|
990
669
|
```
|
|
991
670
|
|
|
992
|
-
`breakingChange` is `true` when the latest major version is higher than the current — useful for agents or CI that need to distinguish breaking upgrades from patch releases.
|
|
993
|
-
|
|
994
671
|
### `quota` — API request counter
|
|
995
672
|
|
|
996
673
|
```bash
|
|
997
|
-
switchbot quota status # today's usage + last 7 days
|
|
998
|
-
switchbot quota reset
|
|
674
|
+
switchbot quota status # today's usage + last 7 days (10,000/day limit)
|
|
675
|
+
switchbot quota reset
|
|
999
676
|
```
|
|
1000
677
|
|
|
1001
|
-
Tracks daily API calls against the 10,000/day account limit. The counter is stored in `~/.switchbot/quota.json` and incremented on every mutating request. Pass `--no-quota` to skip tracking for a single run.
|
|
1002
|
-
|
|
1003
678
|
### `history` — audit log
|
|
1004
679
|
|
|
1005
680
|
```bash
|
|
1006
|
-
switchbot history show
|
|
1007
|
-
switchbot history
|
|
1008
|
-
switchbot history replay 7 # re-run entry #7
|
|
681
|
+
switchbot history show --limit 20
|
|
682
|
+
switchbot history replay 7 # re-run entry #7
|
|
1009
683
|
switchbot --json history show --limit 50 | jq '.entries[] | select(.result=="error")'
|
|
1010
684
|
```
|
|
1011
685
|
|
|
1012
|
-
Reads the JSONL audit log (`~/.switchbot/audit.log` by default; override with `--audit-log --audit-log-path <path>`). Each entry records the timestamp, command, device ID, result, and dry-run flag. `replay` re-runs the original command with the original arguments.
|
|
1013
|
-
|
|
1014
686
|
### `catalog` — device type catalog
|
|
1015
687
|
|
|
1016
688
|
```bash
|
|
1017
|
-
switchbot catalog show # all
|
|
1018
|
-
switchbot catalog list # alias for `show`
|
|
689
|
+
switchbot catalog show # all built-in types
|
|
1019
690
|
switchbot catalog show Bot # one type
|
|
1020
|
-
switchbot catalog search Hub # fuzzy match
|
|
1021
|
-
switchbot catalog diff #
|
|
1022
|
-
switchbot catalog path # location of the local overlay file
|
|
1023
|
-
switchbot catalog refresh # reload local overlay (clears in-process cache)
|
|
691
|
+
switchbot catalog search Hub # fuzzy match
|
|
692
|
+
switchbot catalog diff # local overlay vs built-in
|
|
1024
693
|
```
|
|
1025
694
|
|
|
1026
|
-
|
|
695
|
+
Create `~/.switchbot/catalog-overlay.json` to extend or override type definitions without modifying the package.
|
|
1027
696
|
|
|
1028
697
|
### `schema` — export catalog as JSON
|
|
1029
698
|
|
|
1030
699
|
```bash
|
|
1031
|
-
switchbot schema export # all types
|
|
1032
|
-
switchbot schema export --type 'Strip Light'
|
|
1033
|
-
switchbot schema export --role sensor
|
|
700
|
+
switchbot schema export # all types
|
|
701
|
+
switchbot schema export --type 'Strip Light'
|
|
702
|
+
switchbot schema export --role sensor
|
|
1034
703
|
```
|
|
1035
704
|
|
|
1036
|
-
Exports the effective catalog in a machine-readable format. Pipe the output into an agent's system prompt or tool schema to give it a complete picture of controllable devices.
|
|
1037
|
-
|
|
1038
705
|
### `capabilities` — CLI manifest
|
|
1039
706
|
|
|
1040
707
|
```bash
|
|
@@ -1042,127 +709,58 @@ switchbot capabilities --json
|
|
|
1042
709
|
switchbot capabilities --used --json # only types seen in the local cache
|
|
1043
710
|
```
|
|
1044
711
|
|
|
1045
|
-
Prints a versioned
|
|
712
|
+
Prints a versioned manifest of surfaces, commands, and environment variables. Each command leaf includes `{mutating, consumesQuota, agentSafetyTier, typicalLatencyMs}`.
|
|
1046
713
|
|
|
1047
714
|
### `cache` — inspect and clear local cache
|
|
1048
715
|
|
|
1049
716
|
```bash
|
|
1050
|
-
|
|
1051
|
-
switchbot cache
|
|
1052
|
-
|
|
1053
|
-
#
|
|
1054
|
-
switchbot cache clear
|
|
1055
|
-
|
|
1056
|
-
# Clear only the device-list cache or only the status cache
|
|
1057
|
-
switchbot cache clear --key list
|
|
1058
|
-
switchbot cache clear --key status
|
|
717
|
+
switchbot cache show # paths, age, entry counts
|
|
718
|
+
switchbot cache clear # clear everything
|
|
719
|
+
switchbot cache clear --key list # list cache only
|
|
720
|
+
switchbot cache clear --key status # status cache only
|
|
1059
721
|
```
|
|
1060
722
|
|
|
1061
723
|
### `policy` — validate, scaffold, and migrate policy.yaml
|
|
1062
724
|
|
|
1063
|
-
Companion to the separate SwitchBot skill repository for third-party agent hosts. The skill reads behaviour (aliases, confirmations, quiet hours, audit path) from `policy.yaml`. This command group checks that file before the skill ever sees it, turning what used to be silent failures into line-accurate errors.
|
|
1064
|
-
|
|
1065
725
|
```bash
|
|
1066
|
-
#
|
|
1067
|
-
switchbot policy
|
|
1068
|
-
switchbot policy new ./custom/policy.yaml --force
|
|
1069
|
-
|
|
1070
|
-
# Validate (compiler-style errors with line:col + caret + hints)
|
|
1071
|
-
switchbot policy validate
|
|
1072
|
-
switchbot policy validate ./custom/policy.yaml
|
|
726
|
+
switchbot policy new # write a starter policy
|
|
727
|
+
switchbot policy validate # compiler-style errors (line:col + caret)
|
|
1073
728
|
switchbot policy validate --json | jq '.data.errors'
|
|
1074
|
-
switchbot policy
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
switchbot policy migrate
|
|
1078
|
-
|
|
1079
|
-
# Snapshot and restore the active policy
|
|
1080
|
-
switchbot policy backup # write timestamped backup alongside policy file
|
|
1081
|
-
switchbot policy backup --out ./backups/ # custom destination directory
|
|
1082
|
-
switchbot policy restore <backup-file> # overwrite active policy from backup (auto-backups first)
|
|
729
|
+
switchbot policy migrate # upgrade v0.1 → v0.2 in-place
|
|
730
|
+
switchbot policy backup # timestamped backup
|
|
731
|
+
switchbot policy restore <backup-file>
|
|
1083
732
|
```
|
|
1084
733
|
|
|
1085
|
-
Path resolution
|
|
1086
|
-
|
|
1087
|
-
**Exit codes:** `0` valid / `1` invalid / `2` file-not-found / `3` yaml-parse / `4` internal / `5` file already exists (on `new`, overridden with `--force`) / `6` unsupported schema version (on `migrate`).
|
|
1088
|
-
|
|
1089
|
-
Example — editing an alias without quoting the deviceId:
|
|
1090
|
-
|
|
1091
|
-
```console
|
|
1092
|
-
$ switchbot policy validate
|
|
1093
|
-
<policy-path>:14:11
|
|
1094
|
-
14 | bedroom light: 01-abc-12345
|
|
1095
|
-
^^^^^^^^^^^^^
|
|
1096
|
-
error: /aliases/bedroom light does not match pattern ^[A-Z0-9]{2,}-[A-Z0-9-]+$
|
|
1097
|
-
hint: paste the deviceId from `switchbot devices list --format=tsv`, e.g. 01-202407090924-26354212
|
|
1098
|
-
|
|
1099
|
-
✗ 1 error in <policy-path> (schema v0.1)
|
|
1100
|
-
```
|
|
1101
|
-
|
|
1102
|
-
The default policy schema shipped with the CLI (`src/policy/schema/v0.2.json`) is mirrored as `examples/policy.schema.json` in the companion skill repo; a CI job on every push diffs the two to prevent drift.
|
|
734
|
+
Path resolution: positional `[path]` > `SWITCHBOT_POLICY_PATH` > default. Exit codes: `0` valid / `1` invalid / `2` missing / `3` yaml-parse / `4` internal / `5` exists (use `--force`) / `6` unsupported version.
|
|
1103
735
|
|
|
1104
736
|
## Output modes
|
|
1105
737
|
|
|
1106
738
|
- **Default** — ANSI-colored tables for `list`/`status`, key-value tables for details.
|
|
1107
|
-
- **`--json`** — raw API payload passthrough.
|
|
1108
|
-
- **`--format=json`** — projected row view
|
|
1109
|
-
- **`--format=tsv|yaml|jsonl|id`** — tabular text formats
|
|
739
|
+
- **`--json`** — raw API payload passthrough. Errors are also JSON on **stdout**: `{ "schemaVersion": "1.2", "error": { "code", "kind", "message", "hint?" } }`.
|
|
740
|
+
- **`--format=json`** — projected row view; `--fields` applies.
|
|
741
|
+
- **`--format=tsv|yaml|jsonl|id`** — tabular text formats.
|
|
1110
742
|
|
|
1111
743
|
```bash
|
|
1112
|
-
# Raw API payload (--json)
|
|
1113
744
|
switchbot devices list --json | jq '.deviceList[] | {id: .deviceId, name: .deviceName}'
|
|
1114
|
-
|
|
1115
|
-
# Projected rows with field filter (--format)
|
|
1116
745
|
switchbot devices list --format tsv --fields deviceId,deviceName,type,cloud
|
|
1117
746
|
switchbot devices list --format id # one deviceId per line
|
|
1118
|
-
switchbot devices status <id> --format yaml
|
|
1119
747
|
```
|
|
1120
748
|
|
|
1121
749
|
## Cache
|
|
1122
750
|
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
- `devices.json`: Device metadata (id, name, type, category, hub, room…).
|
|
1126
|
-
Default TTL: 1 hour.
|
|
1127
|
-
- `status.json`: Per-device status bodies.
|
|
1128
|
-
Default TTL: off (0).
|
|
751
|
+
Two local disk caches under `~/.switchbot/`:
|
|
1129
752
|
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
753
|
+
| Cache | Default TTL | Purpose |
|
|
754
|
+
|---|---|---|
|
|
755
|
+
| `devices.json` | 1 hour | device metadata; powers offline validation |
|
|
756
|
+
| `status.json` | off | per-device status; GC'd after 24h |
|
|
1133
757
|
|
|
1134
758
|
```bash
|
|
1135
|
-
|
|
1136
|
-
switchbot devices
|
|
1137
|
-
|
|
1138
|
-
# Set both list and status TTL to 5 minutes
|
|
1139
|
-
switchbot devices status <id> --cache 5m
|
|
1140
|
-
|
|
1141
|
-
# Set TTLs independently
|
|
759
|
+
switchbot devices list --no-cache # bypass for one invocation
|
|
760
|
+
switchbot devices status <id> --cache 5m # set list + status TTL
|
|
1142
761
|
switchbot devices status <id> --cache-list 2h --cache-status 30s
|
|
1143
|
-
|
|
1144
|
-
# Disable only the list cache (keep status cache at its current TTL)
|
|
1145
|
-
switchbot devices list --cache-list 0
|
|
1146
762
|
```
|
|
1147
763
|
|
|
1148
|
-
### Cache management commands
|
|
1149
|
-
|
|
1150
|
-
```bash
|
|
1151
|
-
# Show paths, age, and entry counts
|
|
1152
|
-
switchbot cache show
|
|
1153
|
-
|
|
1154
|
-
# Clear all cached data
|
|
1155
|
-
switchbot cache clear
|
|
1156
|
-
|
|
1157
|
-
# Scope the clear to one store
|
|
1158
|
-
switchbot cache clear --key list
|
|
1159
|
-
switchbot cache clear --key status
|
|
1160
|
-
```
|
|
1161
|
-
|
|
1162
|
-
### Status-cache GC
|
|
1163
|
-
|
|
1164
|
-
`status.json` entries are automatically evicted after 24 hours (or 10× the configured status TTL, whichever is longer), so the file cannot grow without bound even when the status cache is left enabled long-term.
|
|
1165
|
-
|
|
1166
764
|
## Exit codes & error codes
|
|
1167
765
|
|
|
1168
766
|
- `0`: Success (including `--dry-run` intercept when validation passes).
|
|
@@ -1209,112 +807,22 @@ npm install
|
|
|
1209
807
|
|
|
1210
808
|
npm run dev -- <args> # Run from TypeScript sources via tsx
|
|
1211
809
|
npm run build # Compile to dist/
|
|
1212
|
-
npm test # Run the Vitest suite (
|
|
810
|
+
npm test # Run the Vitest suite (2225 tests)
|
|
1213
811
|
npm run test:watch # Watch mode
|
|
1214
812
|
npm run test:coverage # Coverage report (v8, HTML + text)
|
|
1215
813
|
```
|
|
1216
814
|
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
```text
|
|
1220
|
-
src/
|
|
1221
|
-
├── index.ts # Commander entry; mounts all subcommands; global flags
|
|
1222
|
-
├── auth.ts # HMAC-SHA256 signature (token + t + nonce → sign)
|
|
1223
|
-
├── config.ts # Credential load/save; env > keychain > file priority
|
|
1224
|
-
├── api/client.ts # axios instance + request/response interceptors;
|
|
1225
|
-
│ # --verbose / --dry-run / --timeout wiring
|
|
1226
|
-
├── credentials/
|
|
1227
|
-
│ ├── keychain.ts # Credential store interface + OS backend selection
|
|
1228
|
-
│ └── backends/ # macos.ts / linux.ts / windows.ts / file.ts
|
|
1229
|
-
├── devices/
|
|
1230
|
-
│ ├── catalog.ts # Static device catalog (commands, params, status fields)
|
|
1231
|
-
│ └── cache.ts # Disk + in-memory cache for device list and status
|
|
1232
|
-
├── install/
|
|
1233
|
-
│ ├── steps.ts # Generic step runner with rollback support
|
|
1234
|
-
│ ├── preflight.ts # Pre-flight checks (Node, npm, network, agent)
|
|
1235
|
-
│ └── default-steps.ts # Concrete steps: credentials, keychain, policy, skill, doctor
|
|
1236
|
-
├── policy/
|
|
1237
|
-
│ ├── validate.ts # Schema version dispatch + JSON Schema validation
|
|
1238
|
-
│ ├── migrate.ts # v0.1 → v0.2 migration
|
|
1239
|
-
│ ├── load.ts # YAML file loading + error handling
|
|
1240
|
-
│ ├── add-rule.ts # Rule injection into automation.rules[]
|
|
1241
|
-
│ ├── diff.ts # Structural + line diff
|
|
1242
|
-
│ └── schema/v0.2.json # Authoritative v0.2 JSON Schema
|
|
1243
|
-
├── rules/
|
|
1244
|
-
│ ├── engine.ts # Main orchestrator (MQTT + cron + webhook)
|
|
1245
|
-
│ ├── matcher.ts # Trigger + condition matchers
|
|
1246
|
-
│ ├── action.ts # Command renderer + executor
|
|
1247
|
-
│ ├── throttle.ts # Per-rule throttle gate
|
|
1248
|
-
│ ├── cron-scheduler.ts # 5-field cron + days filter
|
|
1249
|
-
│ ├── webhook-listener.ts # HTTP listener (bearer token, localhost-only)
|
|
1250
|
-
│ ├── pid-file.ts # Hot-reload via SIGHUP or sentinel file
|
|
1251
|
-
│ ├── audit-query.ts # Audit log filtering + aggregation
|
|
1252
|
-
│ ├── conflict-analyzer.ts # Static conflict detection (opposing actions,
|
|
1253
|
-
│ │ # high-freq MQTT, destructive cmds, quiet-hours gaps)
|
|
1254
|
-
│ ├── suggest.ts # Heuristic + LLM-backed rule YAML generation
|
|
1255
|
-
│ ├── notify.ts # notify action executor (webhook / file / openclaw)
|
|
1256
|
-
│ └── types.ts # Shared rule/trigger/condition/action types (CommandAction | NotifyAction)
|
|
1257
|
-
├── llm/
|
|
1258
|
-
│ ├── index.ts # createLLMProvider factory + LLM_AUTO_THRESHOLD
|
|
1259
|
-
│ ├── complexity.ts # Intent complexity scorer (0–10) for auto-routing
|
|
1260
|
-
│ ├── rule-prompt.ts # System prompt builder (embeds v0.2 schema snippet)
|
|
1261
|
-
│ └── providers/
|
|
1262
|
-
│ ├── openai.ts # OpenAI-compatible provider (uses Node.js https)
|
|
1263
|
-
│ └── anthropic.ts # Anthropic provider
|
|
1264
|
-
├── status-sync/
|
|
1265
|
-
│ └── manager.ts # Spawn/stop logic, state file, OpenClaw bridge
|
|
1266
|
-
├── lib/
|
|
1267
|
-
│ └── devices.ts # Shared logic: listDevices, describeDevice, isDestructiveCommand
|
|
1268
|
-
├── commands/
|
|
1269
|
-
│ ├── auth.ts # `auth keychain` subcommand group
|
|
1270
|
-
│ ├── config.ts
|
|
1271
|
-
│ ├── devices.ts
|
|
1272
|
-
│ ├── expand.ts # `devices expand` — semantic flag builder
|
|
1273
|
-
│ ├── explain.ts # `devices explain` — one-shot device summary
|
|
1274
|
-
│ ├── device-meta.ts # `devices meta` — local aliases / hide flags
|
|
1275
|
-
│ ├── install.ts # `switchbot install` / `uninstall`
|
|
1276
|
-
│ ├── policy.ts # `policy validate/new/migrate/diff/add-rule/backup/restore`
|
|
1277
|
-
│ ├── rules.ts # `rules suggest/lint/list/explain/run/reload/tail/replay/
|
|
1278
|
-
│ │ # conflicts/doctor/summary/last-fired/webhook-*/
|
|
1279
|
-
│ │ # trace-explain/simulate`
|
|
1280
|
-
│ ├── scenes.ts
|
|
1281
|
-
│ ├── health.ts # `health check/serve` — report + HTTP endpoints
|
|
1282
|
-
│ ├── upgrade-check.ts # `upgrade-check` — npm registry version check
|
|
1283
|
-
│ ├── status-sync.ts # `status-sync run/start/stop/status`
|
|
1284
|
-
│ ├── webhook.ts
|
|
1285
|
-
│ ├── watch.ts # `devices watch <deviceId>`
|
|
1286
|
-
│ ├── events.ts # `events tail` / `events mqtt-tail`
|
|
1287
|
-
│ ├── mcp.ts # `mcp serve` (MCP stdio/HTTP server)
|
|
1288
|
-
│ ├── plan.ts # `plan run/validate/suggest`
|
|
1289
|
-
│ ├── cache.ts # `cache show/clear`
|
|
1290
|
-
│ ├── history.ts # `history show/replay`
|
|
1291
|
-
│ ├── quota.ts # `quota status/reset`
|
|
1292
|
-
│ ├── catalog.ts # `catalog show/diff/path`
|
|
1293
|
-
│ ├── schema.ts # `schema export`
|
|
1294
|
-
│ ├── doctor.ts # `doctor`
|
|
1295
|
-
│ ├── capabilities.ts # `capabilities`
|
|
1296
|
-
│ └── completion.ts # `completion bash|zsh|fish|powershell`
|
|
1297
|
-
└── utils/
|
|
1298
|
-
├── flags.ts # Global flag readers (isVerbose / isDryRun / getCacheMode / …)
|
|
1299
|
-
├── output.ts # printTable / printKeyValue / printJson / handleError
|
|
1300
|
-
├── format.ts # renderRows / filterFields / output-format dispatch
|
|
1301
|
-
├── audit.ts # JSONL audit log writer
|
|
1302
|
-
└── quota.ts # Local daily-quota counter
|
|
1303
|
-
tests/ # Vitest suite (2204 tests, mocked axios, no network)
|
|
1304
|
-
```
|
|
815
|
+
Source layout: `src/commands/` (one file per command group), `src/devices/` (catalog + cache), `src/rules/` (engine, matcher, throttle, audit), `src/policy/` (validate, migrate, schema), `src/llm/` (providers), `src/utils/` (output, format, flags). Tests are in `tests/` and mirror the `src/` structure.
|
|
1305
816
|
|
|
1306
817
|
### Release flow
|
|
1307
818
|
|
|
1308
|
-
Releases are cut on tag push and published to npm by GitHub Actions:
|
|
1309
|
-
|
|
1310
819
|
```bash
|
|
1311
|
-
npm version patch # bump
|
|
820
|
+
npm version patch # bump + create git tag
|
|
1312
821
|
git push --follow-tags
|
|
822
|
+
# then: GitHub → Releases → Draft → Publish
|
|
1313
823
|
```
|
|
1314
824
|
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
See [`docs/release-pipeline.md`](./docs/release-pipeline.md) for the full pre-publish and post-publish verification flow (local hooks → CI → `publish.yml` → `npm-published-smoke.yml`).
|
|
825
|
+
See [`docs/release-pipeline.md`](./docs/release-pipeline.md) for the full CI / publish verification flow.
|
|
1318
826
|
|
|
1319
827
|
## License
|
|
1320
828
|
|