@switchbot/openapi-cli 3.2.1 → 3.2.2
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 +3 -1
- package/dist/index.js +57349 -170
- package/package.json +9 -5
- package/dist/api/client.d.ts +0 -31
- package/dist/api/client.js +0 -236
- package/dist/api/client.js.map +0 -1
- package/dist/auth.d.ts +0 -1
- package/dist/auth.js +0 -21
- package/dist/auth.js.map +0 -1
- package/dist/commands/agent-bootstrap.d.ts +0 -10
- package/dist/commands/agent-bootstrap.js +0 -200
- package/dist/commands/agent-bootstrap.js.map +0 -1
- package/dist/commands/auth.d.ts +0 -18
- package/dist/commands/auth.js +0 -355
- package/dist/commands/auth.js.map +0 -1
- package/dist/commands/batch.d.ts +0 -2
- package/dist/commands/batch.js +0 -414
- package/dist/commands/batch.js.map +0 -1
- package/dist/commands/cache.d.ts +0 -2
- package/dist/commands/cache.js +0 -127
- package/dist/commands/cache.js.map +0 -1
- package/dist/commands/capabilities.d.ts +0 -31
- package/dist/commands/capabilities.js +0 -383
- package/dist/commands/capabilities.js.map +0 -1
- package/dist/commands/catalog.d.ts +0 -2
- package/dist/commands/catalog.js +0 -360
- package/dist/commands/catalog.js.map +0 -1
- package/dist/commands/completion.d.ts +0 -2
- package/dist/commands/completion.js +0 -386
- package/dist/commands/completion.js.map +0 -1
- package/dist/commands/config.d.ts +0 -21
- package/dist/commands/config.js +0 -377
- package/dist/commands/config.js.map +0 -1
- package/dist/commands/daemon.d.ts +0 -2
- package/dist/commands/daemon.js +0 -411
- package/dist/commands/daemon.js.map +0 -1
- package/dist/commands/device-meta.d.ts +0 -2
- package/dist/commands/device-meta.js +0 -160
- package/dist/commands/device-meta.js.map +0 -1
- package/dist/commands/devices.d.ts +0 -2
- package/dist/commands/devices.js +0 -949
- package/dist/commands/devices.js.map +0 -1
- package/dist/commands/doctor.d.ts +0 -3
- package/dist/commands/doctor.js +0 -1016
- package/dist/commands/doctor.js.map +0 -1
- package/dist/commands/events.d.ts +0 -31
- package/dist/commands/events.js +0 -564
- package/dist/commands/events.js.map +0 -1
- package/dist/commands/expand.d.ts +0 -2
- package/dist/commands/expand.js +0 -131
- package/dist/commands/expand.js.map +0 -1
- package/dist/commands/explain.d.ts +0 -2
- package/dist/commands/explain.js +0 -140
- package/dist/commands/explain.js.map +0 -1
- package/dist/commands/health.d.ts +0 -8
- package/dist/commands/health.js +0 -114
- package/dist/commands/health.js.map +0 -1
- package/dist/commands/history.d.ts +0 -2
- package/dist/commands/history.js +0 -321
- package/dist/commands/history.js.map +0 -1
- package/dist/commands/identity.d.ts +0 -45
- package/dist/commands/identity.js +0 -60
- package/dist/commands/identity.js.map +0 -1
- package/dist/commands/install.d.ts +0 -20
- package/dist/commands/install.js +0 -247
- package/dist/commands/install.js.map +0 -1
- package/dist/commands/mcp.d.ts +0 -14
- package/dist/commands/mcp.js +0 -2018
- package/dist/commands/mcp.js.map +0 -1
- package/dist/commands/plan.d.ts +0 -51
- package/dist/commands/plan.js +0 -654
- package/dist/commands/plan.js.map +0 -1
- package/dist/commands/policy.d.ts +0 -24
- package/dist/commands/policy.js +0 -587
- package/dist/commands/policy.js.map +0 -1
- package/dist/commands/quota.d.ts +0 -2
- package/dist/commands/quota.js +0 -79
- package/dist/commands/quota.js.map +0 -1
- package/dist/commands/rules.d.ts +0 -2
- package/dist/commands/rules.js +0 -876
- package/dist/commands/rules.js.map +0 -1
- package/dist/commands/scenes.d.ts +0 -2
- package/dist/commands/scenes.js +0 -265
- package/dist/commands/scenes.js.map +0 -1
- package/dist/commands/schema.d.ts +0 -2
- package/dist/commands/schema.js +0 -185
- package/dist/commands/schema.js.map +0 -1
- package/dist/commands/status-sync.d.ts +0 -2
- package/dist/commands/status-sync.js +0 -132
- package/dist/commands/status-sync.js.map +0 -1
- package/dist/commands/uninstall.d.ts +0 -20
- package/dist/commands/uninstall.js +0 -238
- package/dist/commands/uninstall.js.map +0 -1
- package/dist/commands/upgrade-check.d.ts +0 -2
- package/dist/commands/upgrade-check.js +0 -107
- package/dist/commands/upgrade-check.js.map +0 -1
- package/dist/commands/watch.d.ts +0 -2
- package/dist/commands/watch.js +0 -195
- package/dist/commands/watch.js.map +0 -1
- package/dist/commands/webhook.d.ts +0 -2
- package/dist/commands/webhook.js +0 -183
- package/dist/commands/webhook.js.map +0 -1
- package/dist/config.d.ts +0 -57
- package/dist/config.js +0 -259
- package/dist/config.js.map +0 -1
- package/dist/credentials/backends/file.d.ts +0 -18
- package/dist/credentials/backends/file.js +0 -102
- package/dist/credentials/backends/file.js.map +0 -1
- package/dist/credentials/backends/linux.d.ts +0 -16
- package/dist/credentials/backends/linux.js +0 -130
- package/dist/credentials/backends/linux.js.map +0 -1
- package/dist/credentials/backends/macos.d.ts +0 -18
- package/dist/credentials/backends/macos.js +0 -130
- package/dist/credentials/backends/macos.js.map +0 -1
- package/dist/credentials/backends/windows.d.ts +0 -23
- package/dist/credentials/backends/windows.js +0 -216
- package/dist/credentials/backends/windows.js.map +0 -1
- package/dist/credentials/keychain.d.ts +0 -83
- package/dist/credentials/keychain.js +0 -89
- package/dist/credentials/keychain.js.map +0 -1
- package/dist/credentials/prime.d.ts +0 -32
- package/dist/credentials/prime.js +0 -53
- package/dist/credentials/prime.js.map +0 -1
- package/dist/devices/cache.d.ts +0 -79
- package/dist/devices/cache.js +0 -294
- package/dist/devices/cache.js.map +0 -1
- package/dist/devices/catalog.d.ts +0 -138
- package/dist/devices/catalog.js +0 -768
- package/dist/devices/catalog.js.map +0 -1
- package/dist/devices/device-meta.d.ts +0 -15
- package/dist/devices/device-meta.js +0 -57
- package/dist/devices/device-meta.js.map +0 -1
- package/dist/devices/history-agg.d.ts +0 -37
- package/dist/devices/history-agg.js +0 -139
- package/dist/devices/history-agg.js.map +0 -1
- package/dist/devices/history-query.d.ts +0 -45
- package/dist/devices/history-query.js +0 -182
- package/dist/devices/history-query.js.map +0 -1
- package/dist/devices/param-validator.d.ts +0 -40
- package/dist/devices/param-validator.js +0 -434
- package/dist/devices/param-validator.js.map +0 -1
- package/dist/devices/resources.d.ts +0 -74
- package/dist/devices/resources.js +0 -271
- package/dist/devices/resources.js.map +0 -1
- package/dist/index.d.ts +0 -1
- package/dist/index.js.map +0 -1
- package/dist/install/default-steps.d.ts +0 -66
- package/dist/install/default-steps.js +0 -258
- package/dist/install/default-steps.js.map +0 -1
- package/dist/install/preflight.d.ts +0 -60
- package/dist/install/preflight.js +0 -213
- package/dist/install/preflight.js.map +0 -1
- package/dist/install/steps.d.ts +0 -61
- package/dist/install/steps.js +0 -68
- package/dist/install/steps.js.map +0 -1
- package/dist/lib/command-keywords.d.ts +0 -5
- package/dist/lib/command-keywords.js +0 -18
- package/dist/lib/command-keywords.js.map +0 -1
- package/dist/lib/daemon-state.d.ts +0 -24
- package/dist/lib/daemon-state.js +0 -47
- package/dist/lib/daemon-state.js.map +0 -1
- package/dist/lib/destructive-mode.d.ts +0 -2
- package/dist/lib/destructive-mode.js +0 -13
- package/dist/lib/destructive-mode.js.map +0 -1
- package/dist/lib/devices.d.ts +0 -151
- package/dist/lib/devices.js +0 -383
- package/dist/lib/devices.js.map +0 -1
- package/dist/lib/idempotency.d.ts +0 -46
- package/dist/lib/idempotency.js +0 -107
- package/dist/lib/idempotency.js.map +0 -1
- package/dist/lib/plan-store.d.ts +0 -19
- package/dist/lib/plan-store.js +0 -69
- package/dist/lib/plan-store.js.map +0 -1
- package/dist/lib/request-context.d.ts +0 -7
- package/dist/lib/request-context.js +0 -13
- package/dist/lib/request-context.js.map +0 -1
- package/dist/lib/scenes.d.ts +0 -7
- package/dist/lib/scenes.js +0 -11
- package/dist/lib/scenes.js.map +0 -1
- package/dist/logger.d.ts +0 -4
- package/dist/logger.js +0 -17
- package/dist/logger.js.map +0 -1
- package/dist/mcp/device-history.d.ts +0 -36
- package/dist/mcp/device-history.js +0 -146
- package/dist/mcp/device-history.js.map +0 -1
- package/dist/mcp/events-subscription.d.ts +0 -45
- package/dist/mcp/events-subscription.js +0 -214
- package/dist/mcp/events-subscription.js.map +0 -1
- package/dist/mqtt/client.d.ts +0 -25
- package/dist/mqtt/client.js +0 -181
- package/dist/mqtt/client.js.map +0 -1
- package/dist/mqtt/credential.d.ts +0 -16
- package/dist/mqtt/credential.js +0 -31
- package/dist/mqtt/credential.js.map +0 -1
- package/dist/policy/add-rule.d.ts +0 -21
- package/dist/policy/add-rule.js +0 -125
- package/dist/policy/add-rule.js.map +0 -1
- package/dist/policy/diff.d.ts +0 -21
- package/dist/policy/diff.js +0 -92
- package/dist/policy/diff.js.map +0 -1
- package/dist/policy/format.d.ts +0 -6
- package/dist/policy/format.js +0 -58
- package/dist/policy/format.js.map +0 -1
- package/dist/policy/load.d.ts +0 -32
- package/dist/policy/load.js +0 -62
- package/dist/policy/load.js.map +0 -1
- package/dist/policy/migrate.d.ts +0 -21
- package/dist/policy/migrate.js +0 -68
- package/dist/policy/migrate.js.map +0 -1
- package/dist/policy/schema.d.ts +0 -5
- package/dist/policy/schema.js +0 -19
- package/dist/policy/schema.js.map +0 -1
- package/dist/policy/validate.d.ts +0 -19
- package/dist/policy/validate.js +0 -263
- package/dist/policy/validate.js.map +0 -1
- package/dist/rules/action.d.ts +0 -65
- package/dist/rules/action.js +0 -217
- package/dist/rules/action.js.map +0 -1
- package/dist/rules/audit-query.d.ts +0 -51
- package/dist/rules/audit-query.js +0 -90
- package/dist/rules/audit-query.js.map +0 -1
- package/dist/rules/conflict-analyzer.d.ts +0 -57
- package/dist/rules/conflict-analyzer.js +0 -215
- package/dist/rules/conflict-analyzer.js.map +0 -1
- package/dist/rules/cron-scheduler.d.ts +0 -62
- package/dist/rules/cron-scheduler.js +0 -187
- package/dist/rules/cron-scheduler.js.map +0 -1
- package/dist/rules/destructive.d.ts +0 -20
- package/dist/rules/destructive.js +0 -53
- package/dist/rules/destructive.js.map +0 -1
- package/dist/rules/engine.d.ts +0 -193
- package/dist/rules/engine.js +0 -758
- package/dist/rules/engine.js.map +0 -1
- package/dist/rules/matcher.d.ts +0 -56
- package/dist/rules/matcher.js +0 -231
- package/dist/rules/matcher.js.map +0 -1
- package/dist/rules/pid-file.d.ts +0 -43
- package/dist/rules/pid-file.js +0 -96
- package/dist/rules/pid-file.js.map +0 -1
- package/dist/rules/quiet-hours.d.ts +0 -26
- package/dist/rules/quiet-hours.js +0 -46
- package/dist/rules/quiet-hours.js.map +0 -1
- package/dist/rules/suggest.d.ts +0 -20
- package/dist/rules/suggest.js +0 -96
- package/dist/rules/suggest.js.map +0 -1
- package/dist/rules/throttle.d.ts +0 -61
- package/dist/rules/throttle.js +0 -117
- package/dist/rules/throttle.js.map +0 -1
- package/dist/rules/types.d.ts +0 -117
- package/dist/rules/types.js +0 -35
- package/dist/rules/types.js.map +0 -1
- package/dist/rules/webhook-listener.d.ts +0 -63
- package/dist/rules/webhook-listener.js +0 -224
- package/dist/rules/webhook-listener.js.map +0 -1
- package/dist/rules/webhook-token.d.ts +0 -50
- package/dist/rules/webhook-token.js +0 -91
- package/dist/rules/webhook-token.js.map +0 -1
- package/dist/schema/field-aliases.d.ts +0 -34
- package/dist/schema/field-aliases.js +0 -132
- package/dist/schema/field-aliases.js.map +0 -1
- package/dist/sinks/dispatcher.d.ts +0 -7
- package/dist/sinks/dispatcher.js +0 -13
- package/dist/sinks/dispatcher.js.map +0 -1
- package/dist/sinks/file.d.ts +0 -6
- package/dist/sinks/file.js +0 -20
- package/dist/sinks/file.js.map +0 -1
- package/dist/sinks/format.d.ts +0 -20
- package/dist/sinks/format.js +0 -57
- package/dist/sinks/format.js.map +0 -1
- package/dist/sinks/homeassistant.d.ts +0 -18
- package/dist/sinks/homeassistant.js +0 -45
- package/dist/sinks/homeassistant.js.map +0 -1
- package/dist/sinks/openclaw.d.ts +0 -13
- package/dist/sinks/openclaw.js +0 -34
- package/dist/sinks/openclaw.js.map +0 -1
- package/dist/sinks/stdout.d.ts +0 -4
- package/dist/sinks/stdout.js +0 -6
- package/dist/sinks/stdout.js.map +0 -1
- package/dist/sinks/telegram.d.ts +0 -11
- package/dist/sinks/telegram.js +0 -29
- package/dist/sinks/telegram.js.map +0 -1
- package/dist/sinks/types.d.ts +0 -13
- package/dist/sinks/types.js +0 -2
- package/dist/sinks/types.js.map +0 -1
- package/dist/sinks/webhook.d.ts +0 -6
- package/dist/sinks/webhook.js +0 -23
- package/dist/sinks/webhook.js.map +0 -1
- package/dist/status-sync/manager.d.ts +0 -48
- package/dist/status-sync/manager.js +0 -269
- package/dist/status-sync/manager.js.map +0 -1
- package/dist/utils/arg-parsers.d.ts +0 -16
- package/dist/utils/arg-parsers.js +0 -67
- package/dist/utils/arg-parsers.js.map +0 -1
- package/dist/utils/audit.d.ts +0 -69
- package/dist/utils/audit.js +0 -122
- package/dist/utils/audit.js.map +0 -1
- package/dist/utils/filter.d.ts +0 -81
- package/dist/utils/filter.js +0 -190
- package/dist/utils/filter.js.map +0 -1
- package/dist/utils/flags.d.ts +0 -72
- package/dist/utils/flags.js +0 -187
- package/dist/utils/flags.js.map +0 -1
- package/dist/utils/format.d.ts +0 -9
- package/dist/utils/format.js +0 -118
- package/dist/utils/format.js.map +0 -1
- package/dist/utils/health.d.ts +0 -48
- package/dist/utils/health.js +0 -102
- package/dist/utils/health.js.map +0 -1
- package/dist/utils/help-json.d.ts +0 -39
- package/dist/utils/help-json.js +0 -55
- package/dist/utils/help-json.js.map +0 -1
- package/dist/utils/name-resolver.d.ts +0 -26
- package/dist/utils/name-resolver.js +0 -138
- package/dist/utils/name-resolver.js.map +0 -1
- package/dist/utils/output.d.ts +0 -73
- package/dist/utils/output.js +0 -405
- package/dist/utils/output.js.map +0 -1
- package/dist/utils/quota.d.ts +0 -61
- package/dist/utils/quota.js +0 -228
- package/dist/utils/quota.js.map +0 -1
- package/dist/utils/redact.d.ts +0 -23
- package/dist/utils/redact.js +0 -69
- package/dist/utils/redact.js.map +0 -1
- package/dist/utils/retry.d.ts +0 -72
- package/dist/utils/retry.js +0 -141
- package/dist/utils/retry.js.map +0 -1
- package/dist/utils/string.d.ts +0 -2
- package/dist/utils/string.js +0 -23
- package/dist/utils/string.js.map +0 -1
- package/dist/version.d.ts +0 -2
- package/dist/version.js +0 -5
- package/dist/version.js.map +0 -1
package/dist/devices/catalog.js
DELETED
|
@@ -1,768 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Static catalog of SwitchBot device types, control commands and status fields.
|
|
3
|
-
* Sourced from https://github.com/OpenWonderLabs/SwitchBotAPI — keep in sync
|
|
4
|
-
* when the upstream API adds new device types.
|
|
5
|
-
*
|
|
6
|
-
* Field conventions:
|
|
7
|
-
* - CommandSpec.idempotent: repeat-safe — calling it N times ends in the
|
|
8
|
-
* same state as calling it once (turnOn, setBrightness 50). Agents can
|
|
9
|
-
* retry these freely. Counter-examples: toggle, press, volumeAdd.
|
|
10
|
-
* - CommandSpec.safetyTier: explicit action safety classification. See
|
|
11
|
-
* SafetyTier for the 5-tier enum. Built-in entries set this on the
|
|
12
|
-
* destructive tier; other tiers are derived (see deriveSafetyTier).
|
|
13
|
-
* - DeviceCatalogEntry.role: functional grouping for filter/search
|
|
14
|
-
* ("all lighting", "all security"). Does not affect API behavior.
|
|
15
|
-
* - DeviceCatalogEntry.readOnly: the device has no control commands; it
|
|
16
|
-
* can only be queried via 'devices status'.
|
|
17
|
-
*/
|
|
18
|
-
/**
|
|
19
|
-
* Catalog shape version. Bump when any of the exported interfaces
|
|
20
|
-
* (CommandSpec / DeviceCatalogEntry / SafetyTier) gain/lose/rename a
|
|
21
|
-
* load-bearing field. The agent-bootstrap payload's schemaVersion must
|
|
22
|
-
* stay pinned to this value; `doctor` fails the `catalog-schema` check
|
|
23
|
-
* when they drift.
|
|
24
|
-
*/
|
|
25
|
-
export const CATALOG_SCHEMA_VERSION = '1.0';
|
|
26
|
-
/**
|
|
27
|
-
* Human-readable descriptions for common status fields. Populated from
|
|
28
|
-
* the SwitchBot API v1.1 docs. Used by deriveStatusQueries() so every
|
|
29
|
-
* query has a meaningful description even when the entry itself only
|
|
30
|
-
* declares the field name.
|
|
31
|
-
*/
|
|
32
|
-
const STATUS_FIELD_DESCRIPTIONS = {
|
|
33
|
-
power: 'Power state (on/off)',
|
|
34
|
-
battery: 'Battery percentage (0-100)',
|
|
35
|
-
version: 'Firmware version string',
|
|
36
|
-
temperature: 'Ambient temperature (°C)',
|
|
37
|
-
humidity: 'Ambient humidity (% RH)',
|
|
38
|
-
CO2: 'CO2 concentration (ppm)',
|
|
39
|
-
brightness: 'Current brightness (0-100)',
|
|
40
|
-
color: 'Current RGB color (r:g:b)',
|
|
41
|
-
colorTemperature: 'Color temperature in Kelvin',
|
|
42
|
-
mode: 'Operating mode',
|
|
43
|
-
deviceMode: 'Hardware mode (Bot-specific)',
|
|
44
|
-
lockState: 'Lock state (locked/unlocked)',
|
|
45
|
-
doorState: 'Door contact state (open/closed)',
|
|
46
|
-
calibrate: 'Calibration status',
|
|
47
|
-
moving: 'Motion in progress (boolean)',
|
|
48
|
-
slidePosition: 'Slide position (0-100)',
|
|
49
|
-
group: 'Multi-device group membership',
|
|
50
|
-
direction: 'Tilt direction',
|
|
51
|
-
voltage: 'Line voltage',
|
|
52
|
-
electricCurrent: 'Instantaneous current draw',
|
|
53
|
-
electricityOfDay: 'kWh consumed today',
|
|
54
|
-
usedElectricity: 'Cumulative kWh',
|
|
55
|
-
useTime: 'Total runtime (seconds)',
|
|
56
|
-
weight: 'Load / weight reading',
|
|
57
|
-
switchStatus: 'Relay state (integer encoded)',
|
|
58
|
-
switch1Status: 'Channel 1 relay state',
|
|
59
|
-
switch2Status: 'Channel 2 relay state',
|
|
60
|
-
workingStatus: 'Device working status (vacuum/purifier)',
|
|
61
|
-
onlineStatus: 'Online / offline (string)',
|
|
62
|
-
online: 'Online / offline (boolean or int)',
|
|
63
|
-
taskType: 'Current task identifier',
|
|
64
|
-
nightStatus: 'Night-mode status',
|
|
65
|
-
oscillation: 'Horizontal oscillation on/off',
|
|
66
|
-
verticalOscillation: 'Vertical oscillation on/off',
|
|
67
|
-
chargingStatus: 'Charging (boolean)',
|
|
68
|
-
fanSpeed: 'Current fan speed level',
|
|
69
|
-
nebulizationEfficiency: 'Humidifier mist level',
|
|
70
|
-
childLock: 'Child-lock engaged',
|
|
71
|
-
sound: 'Beep / audio feedback enabled',
|
|
72
|
-
lackWater: 'Water tank low (boolean)',
|
|
73
|
-
filterElement: 'Filter life remaining',
|
|
74
|
-
auto: 'Auto mode enabled',
|
|
75
|
-
targetTemperature: 'Thermostat target temperature',
|
|
76
|
-
moveDetected: 'Motion detected (boolean)',
|
|
77
|
-
openState: 'Contact sensor open/closed',
|
|
78
|
-
status: 'Device-specific status word',
|
|
79
|
-
lightLevel: 'Ambient light level',
|
|
80
|
-
};
|
|
81
|
-
/**
|
|
82
|
-
* P11: derive the read-only query list for an entry. If the entry has
|
|
83
|
-
* explicit `statusQueries`, return them as-is; otherwise synthesize one
|
|
84
|
-
* ReadOnlyQuerySpec per `statusFields` entry, all keyed to the `status`
|
|
85
|
-
* endpoint. IR-category entries have no status channel so return [].
|
|
86
|
-
*/
|
|
87
|
-
export function deriveStatusQueries(entry) {
|
|
88
|
-
if (entry.statusQueries && entry.statusQueries.length > 0)
|
|
89
|
-
return entry.statusQueries;
|
|
90
|
-
if (entry.category === 'ir')
|
|
91
|
-
return [];
|
|
92
|
-
const fields = entry.statusFields ?? [];
|
|
93
|
-
return fields.map((f) => ({
|
|
94
|
-
field: f,
|
|
95
|
-
description: STATUS_FIELD_DESCRIPTIONS[f] ?? `${f} (see API docs)`,
|
|
96
|
-
endpoint: 'status',
|
|
97
|
-
safetyTier: 'read',
|
|
98
|
-
}));
|
|
99
|
-
}
|
|
100
|
-
// ---- Command fragments (reused across entries) -------------------------
|
|
101
|
-
const onOff = [
|
|
102
|
-
{ command: 'turnOn', parameter: '—', description: 'Power on', idempotent: true },
|
|
103
|
-
{ command: 'turnOff', parameter: '—', description: 'Power off', idempotent: true },
|
|
104
|
-
];
|
|
105
|
-
const onOffToggle = [
|
|
106
|
-
...onOff,
|
|
107
|
-
{ command: 'toggle', parameter: '—', description: 'Toggle power', idempotent: false },
|
|
108
|
-
];
|
|
109
|
-
const lightControls = [
|
|
110
|
-
{ command: 'setBrightness', parameter: '1-100', description: 'Set brightness percentage', idempotent: true, exampleParams: ['50', '80'] },
|
|
111
|
-
{ command: 'setColor', parameter: 'R:G:B (0-255 each)', description: 'Set RGB color, e.g. "255:0:0"', idempotent: true, exampleParams: ['255:0:0', '255:255:255'] },
|
|
112
|
-
{ command: 'setColorTemperature', parameter: '2700-6500', description: 'Set color temperature (Kelvin)', idempotent: true, exampleParams: ['2700', '4000', '6500'] },
|
|
113
|
-
];
|
|
114
|
-
export const DEVICE_CATALOG = [
|
|
115
|
-
// ---------- Physical devices ----------
|
|
116
|
-
{
|
|
117
|
-
type: 'Bot',
|
|
118
|
-
category: 'physical',
|
|
119
|
-
description: 'Mechanical arm robot that physically presses a button or toggles a switch on demand.',
|
|
120
|
-
role: 'other',
|
|
121
|
-
commands: [
|
|
122
|
-
...onOff,
|
|
123
|
-
{ command: 'press', parameter: '—', description: 'Press the button (momentary)', idempotent: false },
|
|
124
|
-
],
|
|
125
|
-
statusFields: ['power', 'battery', 'deviceMode', 'version'],
|
|
126
|
-
},
|
|
127
|
-
{
|
|
128
|
-
type: 'Curtain',
|
|
129
|
-
category: 'physical',
|
|
130
|
-
description: 'Motorized curtain track runner that opens/closes curtains by slide position (0=open, 100=closed).',
|
|
131
|
-
role: 'curtain',
|
|
132
|
-
aliases: ['Curtain3', 'Curtain 3'],
|
|
133
|
-
commands: [
|
|
134
|
-
...onOff,
|
|
135
|
-
{ command: 'pause', parameter: '—', description: 'Stop movement', idempotent: true },
|
|
136
|
-
{ command: 'setPosition', parameter: '0-100 (0=open, 100=closed)', description: 'Move to a position', idempotent: true, exampleParams: ['0', '50', '100'] },
|
|
137
|
-
{ command: 'setPosition', parameter: 'index,mode,position (e.g. "0,ff,80")', description: 'Multi-arg form: mode=0 Performance | 1 Silent | ff default', idempotent: true, exampleParams: ['0,ff,50'] },
|
|
138
|
-
],
|
|
139
|
-
statusFields: ['calibrate', 'group', 'moving', 'slidePosition', 'battery', 'version'],
|
|
140
|
-
},
|
|
141
|
-
{
|
|
142
|
-
type: 'Smart Lock',
|
|
143
|
-
category: 'physical',
|
|
144
|
-
description: 'Bluetooth/Wi-Fi electronic deadbolt that locks and unlocks a door via cloud API.',
|
|
145
|
-
role: 'security',
|
|
146
|
-
aliases: ['Smart Lock Pro'],
|
|
147
|
-
commands: [
|
|
148
|
-
{ command: 'lock', parameter: '—', description: 'Lock the door', idempotent: true },
|
|
149
|
-
{ command: 'unlock', parameter: '—', description: 'Unlock the door', idempotent: true, safetyTier: 'destructive', safetyReason: 'Physically unlocks the door — anyone nearby can open it.' },
|
|
150
|
-
{ command: 'deadbolt', parameter: '—', description: 'Pro only: engage deadbolt', idempotent: true },
|
|
151
|
-
],
|
|
152
|
-
statusFields: ['battery', 'version', 'lockState', 'doorState', 'calibrate'],
|
|
153
|
-
},
|
|
154
|
-
{
|
|
155
|
-
type: 'Smart Lock Lite',
|
|
156
|
-
category: 'physical',
|
|
157
|
-
description: 'Compact electronic deadbolt with lock and unlock control; no deadbolt mode.',
|
|
158
|
-
role: 'security',
|
|
159
|
-
commands: [
|
|
160
|
-
{ command: 'lock', parameter: '—', description: 'Lock the door', idempotent: true },
|
|
161
|
-
{ command: 'unlock', parameter: '—', description: 'Unlock the door', idempotent: true, safetyTier: 'destructive', safetyReason: 'Physically unlocks the door — anyone nearby can open it.' },
|
|
162
|
-
],
|
|
163
|
-
statusFields: ['battery', 'version', 'lockState', 'doorState', 'calibrate'],
|
|
164
|
-
},
|
|
165
|
-
{
|
|
166
|
-
type: 'Smart Lock Ultra',
|
|
167
|
-
category: 'physical',
|
|
168
|
-
description: 'Premium electronic deadbolt with full lock, unlock, and deadbolt control.',
|
|
169
|
-
role: 'security',
|
|
170
|
-
commands: [
|
|
171
|
-
{ command: 'lock', parameter: '—', description: 'Lock the door', idempotent: true },
|
|
172
|
-
{ command: 'unlock', parameter: '—', description: 'Unlock the door', idempotent: true, safetyTier: 'destructive', safetyReason: 'Physically unlocks the door — anyone nearby can open it.' },
|
|
173
|
-
{ command: 'deadbolt', parameter: '—', description: 'Engage deadbolt', idempotent: true },
|
|
174
|
-
],
|
|
175
|
-
statusFields: ['battery', 'version', 'lockState', 'doorState', 'calibrate'],
|
|
176
|
-
},
|
|
177
|
-
{
|
|
178
|
-
type: 'Plug',
|
|
179
|
-
category: 'physical',
|
|
180
|
-
description: 'Smart wall outlet plug with on/off/toggle control and basic power status.',
|
|
181
|
-
role: 'power',
|
|
182
|
-
commands: onOffToggle,
|
|
183
|
-
statusFields: ['power', 'version'],
|
|
184
|
-
},
|
|
185
|
-
{
|
|
186
|
-
type: 'Plug Mini (US)',
|
|
187
|
-
category: 'physical',
|
|
188
|
-
description: 'Compact smart plug with voltage, current, and daily energy consumption reporting.',
|
|
189
|
-
role: 'power',
|
|
190
|
-
aliases: ['Plug Mini (JP)'],
|
|
191
|
-
commands: onOffToggle,
|
|
192
|
-
statusFields: ['voltage', 'weight', 'electricityOfDay', 'electricCurrent', 'power', 'version'],
|
|
193
|
-
},
|
|
194
|
-
{
|
|
195
|
-
type: 'Relay Switch 1',
|
|
196
|
-
category: 'physical',
|
|
197
|
-
description: 'In-wall relay switch with configurable modes (toggle/edge/detached/momentary) and power metering.',
|
|
198
|
-
role: 'power',
|
|
199
|
-
aliases: ['Relay Switch 1PM'],
|
|
200
|
-
commands: [
|
|
201
|
-
...onOffToggle,
|
|
202
|
-
{ command: 'setMode', parameter: '0=toggle | 1=edge | 2=detached | 3=momentary', description: 'Switch operating mode', idempotent: true, exampleParams: ['0', '1', '2', '3'] },
|
|
203
|
-
],
|
|
204
|
-
statusFields: ['switchStatus', 'voltage', 'version', 'useTime', 'electricCurrent', 'power', 'usedElectricity'],
|
|
205
|
-
},
|
|
206
|
-
{
|
|
207
|
-
type: 'Relay Switch 2PM',
|
|
208
|
-
category: 'physical',
|
|
209
|
-
description: 'Dual-channel relay switch with per-channel on/off/toggle and optional roller-shade mode.',
|
|
210
|
-
role: 'power',
|
|
211
|
-
commands: [
|
|
212
|
-
{ command: 'turnOn', parameter: '1 | 2 (channel)', description: 'Turn on channel 1 or 2', idempotent: true, exampleParams: ['1', '2'] },
|
|
213
|
-
{ command: 'turnOff', parameter: '1 | 2 (channel)', description: 'Turn off channel 1 or 2', idempotent: true, exampleParams: ['1', '2'] },
|
|
214
|
-
{ command: 'toggle', parameter: '1 | 2 (channel)', description: 'Toggle channel 1 or 2', idempotent: false, exampleParams: ['1', '2'] },
|
|
215
|
-
{ command: 'setMode', parameter: '"<channel>;<mode>" e.g. "1;0"', description: 'Per-channel mode (see Relay Switch 1 modes)', idempotent: true, exampleParams: ['1;0', '2;3'] },
|
|
216
|
-
{ command: 'setPosition', parameter: '0-100 (roller percentage)', description: 'Roller-shade-pair mode only', idempotent: true, exampleParams: ['0', '50', '100'] },
|
|
217
|
-
],
|
|
218
|
-
statusFields: ['switch1Status', 'switch2Status', 'voltage', 'electricCurrent', 'power', 'usedElectricity'],
|
|
219
|
-
},
|
|
220
|
-
{
|
|
221
|
-
type: 'Humidifier',
|
|
222
|
-
category: 'physical',
|
|
223
|
-
description: 'Ultrasonic humidifier with auto and preset humidity level control.',
|
|
224
|
-
role: 'climate',
|
|
225
|
-
commands: [
|
|
226
|
-
...onOff,
|
|
227
|
-
{ command: 'setMode', parameter: 'auto | 101 (34%) | 102 (67%) | 103 (100%) | 0-100', description: 'Set preset or target humidity', idempotent: true, exampleParams: ['auto', '101', '50'] },
|
|
228
|
-
],
|
|
229
|
-
statusFields: ['power', 'humidity', 'temperature', 'nebulizationEfficiency', 'auto', 'childLock', 'sound', 'lackWater'],
|
|
230
|
-
},
|
|
231
|
-
{
|
|
232
|
-
type: 'Humidifier2',
|
|
233
|
-
category: 'physical',
|
|
234
|
-
description: 'Evaporative humidifier with multiple speed/auto/sleep/humidity modes and child lock.',
|
|
235
|
-
role: 'climate',
|
|
236
|
-
aliases: ['Evaporative Humidifier'],
|
|
237
|
-
commands: [
|
|
238
|
-
...onOff,
|
|
239
|
-
{ command: 'setMode', parameter: '\'{"mode":1-8,"targetHumidify":0-100}\'', description: 'mode: 1=lv4 2=lv3 3=lv2 4=lv1 5=humidity 6=sleep 7=auto 8=drying', idempotent: true, exampleParams: ['{"mode":7,"targetHumidify":50}'] },
|
|
240
|
-
{ command: 'setChildLock', parameter: 'true | false', description: 'Enable or disable child lock', idempotent: true, exampleParams: ['true', 'false'] },
|
|
241
|
-
],
|
|
242
|
-
statusFields: ['power', 'humidity', 'temperature', 'mode', 'childLock', 'filterElement'],
|
|
243
|
-
},
|
|
244
|
-
{
|
|
245
|
-
type: 'Air Purifier VOC',
|
|
246
|
-
category: 'physical',
|
|
247
|
-
description: 'HEPA air purifier with VOC or PM2.5 sensing, multiple fan modes, and child lock.',
|
|
248
|
-
role: 'climate',
|
|
249
|
-
aliases: ['Air Purifier PM2.5', 'Air Purifier Table VOC', 'Air Purifier Table PM2.5'],
|
|
250
|
-
commands: [
|
|
251
|
-
...onOff,
|
|
252
|
-
{ command: 'setMode', parameter: '\'{"mode":1-4,"fanGear":1-3}\'', description: 'mode: 1=normal 2=auto 3=sleep 4=pet; fanGear only when mode=1', idempotent: true, exampleParams: ['{"mode":2}', '{"mode":1,"fanGear":2}'] },
|
|
253
|
-
{ command: 'setChildLock', parameter: '0 | 1', description: 'Disable / enable child lock', idempotent: true, exampleParams: ['0', '1'] },
|
|
254
|
-
],
|
|
255
|
-
statusFields: ['power', 'mode', 'childLock', 'filterElement'],
|
|
256
|
-
},
|
|
257
|
-
{
|
|
258
|
-
type: 'Color Bulb',
|
|
259
|
-
category: 'physical',
|
|
260
|
-
description: 'Wi-Fi smart bulb with tunable brightness, RGB color, and color temperature.',
|
|
261
|
-
role: 'lighting',
|
|
262
|
-
commands: [...onOffToggle, ...lightControls],
|
|
263
|
-
statusFields: ['power', 'brightness', 'color', 'colorTemperature', 'version'],
|
|
264
|
-
},
|
|
265
|
-
{
|
|
266
|
-
type: 'Strip Light',
|
|
267
|
-
category: 'physical',
|
|
268
|
-
description: 'Addressable LED strip with on/off, brightness, RGB color, and color temperature control.',
|
|
269
|
-
role: 'lighting',
|
|
270
|
-
aliases: ['Strip Light 3'],
|
|
271
|
-
commands: [...onOffToggle, ...lightControls],
|
|
272
|
-
statusFields: ['power', 'brightness', 'color', 'colorTemperature', 'version'],
|
|
273
|
-
},
|
|
274
|
-
{
|
|
275
|
-
type: 'Ceiling Light',
|
|
276
|
-
category: 'physical',
|
|
277
|
-
description: 'Smart ceiling fixture with brightness and color-temperature adjustment (no RGB).',
|
|
278
|
-
role: 'lighting',
|
|
279
|
-
aliases: ['Ceiling Light Pro'],
|
|
280
|
-
commands: [
|
|
281
|
-
...onOffToggle,
|
|
282
|
-
{ command: 'setBrightness', parameter: '1-100', description: 'Set brightness percentage', idempotent: true, exampleParams: ['50', '80'] },
|
|
283
|
-
{ command: 'setColorTemperature', parameter: '2700-6500', description: 'Set color temperature (Kelvin)', idempotent: true, exampleParams: ['2700', '4000', '6500'] },
|
|
284
|
-
],
|
|
285
|
-
statusFields: ['power', 'brightness', 'colorTemperature', 'version'],
|
|
286
|
-
},
|
|
287
|
-
{
|
|
288
|
-
type: 'Smart Radiator Thermostat',
|
|
289
|
-
category: 'physical',
|
|
290
|
-
description: 'Motorized thermostatic valve for radiators with schedule, manual, eco, and comfort modes.',
|
|
291
|
-
role: 'climate',
|
|
292
|
-
commands: [
|
|
293
|
-
...onOff,
|
|
294
|
-
{ command: 'setMode', parameter: '0=schedule 1=manual 2=off 3=eco 4=comfort 5=quickHeat', description: 'Operating mode', idempotent: true, exampleParams: ['1', '3'] },
|
|
295
|
-
{ command: 'setManualModeTemperature', parameter: '5-30 (°C)', description: 'Target temperature in manual mode', idempotent: true, exampleParams: ['20', '22'] },
|
|
296
|
-
],
|
|
297
|
-
statusFields: ['power', 'temperature', 'humidity', 'battery', 'version', 'mode', 'targetTemperature'],
|
|
298
|
-
},
|
|
299
|
-
{
|
|
300
|
-
type: 'Robot Vacuum Cleaner S1',
|
|
301
|
-
category: 'physical',
|
|
302
|
-
description: 'Entry-level robot vacuum with start/stop/dock and four suction power levels.',
|
|
303
|
-
role: 'cleaning',
|
|
304
|
-
aliases: ['Robot Vacuum', 'Robot Vacuum Cleaner S1 Plus', 'K10+'],
|
|
305
|
-
commands: [
|
|
306
|
-
{ command: 'start', parameter: '—', description: 'Start cleaning', idempotent: true },
|
|
307
|
-
{ command: 'stop', parameter: '—', description: 'Stop cleaning', idempotent: true },
|
|
308
|
-
{ command: 'dock', parameter: '—', description: 'Return to dock', idempotent: true },
|
|
309
|
-
{ command: 'PowLevel', parameter: '0-3', description: '0=Quiet 1=Standard 2=Strong 3=Max', idempotent: true, exampleParams: ['0', '1', '2', '3'] },
|
|
310
|
-
],
|
|
311
|
-
statusFields: ['workingStatus', 'onlineStatus', 'battery', 'version'],
|
|
312
|
-
},
|
|
313
|
-
{
|
|
314
|
-
type: 'K10+ Pro Combo',
|
|
315
|
-
category: 'physical',
|
|
316
|
-
description: 'Compact robot vacuum and mop combo with sweep/mop sessions, fan level, and water level.',
|
|
317
|
-
role: 'cleaning',
|
|
318
|
-
aliases: ['K20+ Pro'],
|
|
319
|
-
commands: [
|
|
320
|
-
{ command: 'startClean', parameter: '\'{"action":"sweep"|"mop","param":{"fanLevel":1-4,"times":1-2639999}}\'', description: 'Begin a cleaning session', idempotent: false, exampleParams: ['{"action":"sweep","param":{"fanLevel":2,"times":1}}'] },
|
|
321
|
-
{ command: 'pause', parameter: '—', description: 'Pause cleaning', idempotent: true },
|
|
322
|
-
{ command: 'dock', parameter: '—', description: 'Return to dock', idempotent: true },
|
|
323
|
-
{ command: 'setVolume', parameter: '0-100', description: 'Set voice volume', idempotent: true, exampleParams: ['0', '50', '100'] },
|
|
324
|
-
{ command: 'changeParam', parameter: '\'{"fanLevel":1-4,"waterLevel":1-2,"times":1-2639999}\'', description: 'Change parameters mid-run', idempotent: true, exampleParams: ['{"fanLevel":3,"waterLevel":1,"times":1}'] },
|
|
325
|
-
],
|
|
326
|
-
statusFields: ['workingStatus', 'onlineStatus', 'battery', 'taskType'],
|
|
327
|
-
},
|
|
328
|
-
{
|
|
329
|
-
type: 'Floor Cleaning Robot S10',
|
|
330
|
-
category: 'physical',
|
|
331
|
-
description: 'Advanced floor cleaning robot with sweep/mop modes, self-wash dock, and humidifier refill.',
|
|
332
|
-
role: 'cleaning',
|
|
333
|
-
aliases: ['Robot Vacuum Cleaner S10', 'Robot Vacuum Cleaner S20'],
|
|
334
|
-
commands: [
|
|
335
|
-
{ command: 'startClean', parameter: '\'{"action":"sweep"|"sweep_mop","param":{"fanLevel":1-4,"waterLevel":1-2,"times":1-2639999}}\'', description: 'Begin a cleaning session', idempotent: false, exampleParams: ['{"action":"sweep","param":{"fanLevel":2,"waterLevel":1,"times":1}}'] },
|
|
336
|
-
{ command: 'pause', parameter: '—', description: 'Pause cleaning', idempotent: true },
|
|
337
|
-
{ command: 'dock', parameter: '—', description: 'Return to dock', idempotent: true },
|
|
338
|
-
{ command: 'addWaterForHumi', parameter: '—', description: 'Refill the humidifier water tank', idempotent: false },
|
|
339
|
-
{ command: 'selfClean', parameter: '1 | 2 | 3', description: '1=wash mop | 2=dry | 3=terminate self-clean', idempotent: false, exampleParams: ['1', '2', '3'] },
|
|
340
|
-
{ command: 'setVolume', parameter: '0-100', description: 'Set voice volume', idempotent: true, exampleParams: ['0', '50', '100'] },
|
|
341
|
-
{ command: 'changeParam', parameter: '\'{"fanLevel":1-4,"waterLevel":1-2,"times":1-2639999}\'', description: 'Change parameters mid-run', idempotent: true, exampleParams: ['{"fanLevel":3,"waterLevel":1,"times":1}'] },
|
|
342
|
-
],
|
|
343
|
-
statusFields: ['workingStatus', 'onlineStatus', 'battery', 'taskType'],
|
|
344
|
-
},
|
|
345
|
-
{
|
|
346
|
-
type: 'Battery Circulator Fan',
|
|
347
|
-
category: 'physical',
|
|
348
|
-
description: 'Rechargeable table/floor fan with wind modes, speed control, night-light, and auto-off timer.',
|
|
349
|
-
role: 'fan',
|
|
350
|
-
aliases: ['Circulator Fan'],
|
|
351
|
-
commands: [
|
|
352
|
-
...onOffToggle,
|
|
353
|
-
{ command: 'setNightLightMode', parameter: 'off | 1 | 2', description: 'Night-light mode', idempotent: true, exampleParams: ['off', '1', '2'] },
|
|
354
|
-
{ command: 'setWindMode', parameter: 'direct | natural | sleep | baby', description: 'Wind mode', idempotent: true, exampleParams: ['natural', 'sleep'] },
|
|
355
|
-
{ command: 'setWindSpeed', parameter: '1-100', description: 'Fan speed', idempotent: true, exampleParams: ['50', '100'] },
|
|
356
|
-
{ command: 'closeDelay', parameter: 'seconds', description: 'Auto-off timer in seconds', idempotent: true, exampleParams: ['1800', '3600'] },
|
|
357
|
-
],
|
|
358
|
-
statusFields: ['mode', 'version', 'battery', 'power', 'nightStatus', 'oscillation', 'verticalOscillation', 'chargingStatus', 'fanSpeed'],
|
|
359
|
-
},
|
|
360
|
-
{
|
|
361
|
-
type: 'Blind Tilt',
|
|
362
|
-
category: 'physical',
|
|
363
|
-
description: 'Motorized tilt rod for horizontal blinds; controls slat angle (0=closed, 100=open).',
|
|
364
|
-
role: 'curtain',
|
|
365
|
-
commands: [
|
|
366
|
-
...onOff,
|
|
367
|
-
{ command: 'setPosition', parameter: '"<direction>;<angle>" (up|down; 0,2,...,100)', description: 'Tilt direction + angle (0=closed, 100=open)', idempotent: true, exampleParams: ['up;50', 'down;80'] },
|
|
368
|
-
{ command: 'fullyOpen', parameter: '—', description: 'Open fully', idempotent: true },
|
|
369
|
-
{ command: 'closeUp', parameter: '—', description: 'Close up', idempotent: true },
|
|
370
|
-
{ command: 'closeDown', parameter: '—', description: 'Close down', idempotent: true },
|
|
371
|
-
],
|
|
372
|
-
statusFields: ['version', 'calibrate', 'group', 'moving', 'direction', 'slidePosition', 'battery'],
|
|
373
|
-
},
|
|
374
|
-
{
|
|
375
|
-
type: 'Roller Shade',
|
|
376
|
-
category: 'physical',
|
|
377
|
-
description: 'Motorized roller blind that moves to a set position (0=open, 100=closed).',
|
|
378
|
-
role: 'curtain',
|
|
379
|
-
commands: [
|
|
380
|
-
...onOff,
|
|
381
|
-
{ command: 'setPosition', parameter: '0-100 (0=open, 100=closed)', description: 'Move to a position', idempotent: true, exampleParams: ['0', '50', '100'] },
|
|
382
|
-
],
|
|
383
|
-
statusFields: ['slidePosition', 'battery', 'version', 'moving'],
|
|
384
|
-
},
|
|
385
|
-
{
|
|
386
|
-
type: 'Garage Door Opener',
|
|
387
|
-
category: 'physical',
|
|
388
|
-
description: 'Cloud-connected garage door controller; turnOn opens and turnOff closes the door.',
|
|
389
|
-
role: 'security',
|
|
390
|
-
commands: [
|
|
391
|
-
{ command: 'turnOn', parameter: '—', description: 'Open the garage door', idempotent: true, safetyTier: 'destructive', safetyReason: 'Opens the garage door — anyone nearby can enter the space.' },
|
|
392
|
-
{ command: 'turnOff', parameter: '—', description: 'Close the garage door', idempotent: true, safetyTier: 'destructive', safetyReason: 'Closes the garage door — verify no person or obstacle is in the way.' },
|
|
393
|
-
],
|
|
394
|
-
statusFields: ['switchStatus', 'version', 'online'],
|
|
395
|
-
},
|
|
396
|
-
{
|
|
397
|
-
type: 'Video Doorbell',
|
|
398
|
-
category: 'physical',
|
|
399
|
-
description: 'Wi-Fi video doorbell with motion detection enable/disable control.',
|
|
400
|
-
role: 'security',
|
|
401
|
-
commands: [
|
|
402
|
-
{ command: 'enableMotionDetection', parameter: '—', description: 'Enable motion detection', idempotent: true },
|
|
403
|
-
{ command: 'disableMotionDetection', parameter: '—', description: 'Disable motion detection', idempotent: true },
|
|
404
|
-
],
|
|
405
|
-
statusFields: ['battery', 'version'],
|
|
406
|
-
},
|
|
407
|
-
{
|
|
408
|
-
type: 'Keypad',
|
|
409
|
-
category: 'physical',
|
|
410
|
-
description: 'PIN-pad access controller that creates and deletes door passcodes for a Smart Lock.',
|
|
411
|
-
role: 'security',
|
|
412
|
-
aliases: ['Keypad Touch'],
|
|
413
|
-
commands: [
|
|
414
|
-
{ command: 'createKey', parameter: '\'{"name":"...","type":"permanent|timeLimit|disposable|urgent","password":"6-12 digits","startTime":<s>,"endTime":<s>}\'', description: 'Create a passcode (async; result via webhook)', idempotent: false, safetyTier: 'destructive', safetyReason: 'Provisions a new access credential — anyone with this passcode can unlock the door.' },
|
|
415
|
-
{ command: 'deleteKey', parameter: '\'{"id":<passcode_id>}\'', description: 'Delete a passcode (async; result via webhook)', idempotent: true, safetyTier: 'destructive', safetyReason: 'Permanently removes a passcode — the holder immediately loses door access.' },
|
|
416
|
-
],
|
|
417
|
-
statusFields: ['version'],
|
|
418
|
-
},
|
|
419
|
-
{
|
|
420
|
-
type: 'Candle Warmer Lamp',
|
|
421
|
-
category: 'physical',
|
|
422
|
-
description: 'Decorative candle-warmer lamp with adjustable brightness and color temperature.',
|
|
423
|
-
role: 'lighting',
|
|
424
|
-
commands: [
|
|
425
|
-
...onOffToggle,
|
|
426
|
-
{ command: 'setBrightness', parameter: '1-100', description: 'Set brightness percentage', idempotent: true, exampleParams: ['50', '80'] },
|
|
427
|
-
{ command: 'setColorTemperature', parameter: '2700-6500', description: 'Set color temperature (Kelvin)', idempotent: true, exampleParams: ['2700', '4000'] },
|
|
428
|
-
],
|
|
429
|
-
statusFields: ['power', 'brightness', 'colorTemperature', 'version'],
|
|
430
|
-
},
|
|
431
|
-
// Status-only devices (no commands)
|
|
432
|
-
{
|
|
433
|
-
type: 'Meter',
|
|
434
|
-
category: 'physical',
|
|
435
|
-
description: 'Battery-powered temperature and humidity sensor; read-only, no control commands.',
|
|
436
|
-
role: 'sensor',
|
|
437
|
-
readOnly: true,
|
|
438
|
-
aliases: ['Meter Plus', 'MeterPro', 'MeterPro(CO2)', 'WoIOSensor', 'Hub 2'],
|
|
439
|
-
commands: [],
|
|
440
|
-
statusFields: ['temperature', 'humidity', 'CO2', 'battery', 'version'],
|
|
441
|
-
},
|
|
442
|
-
{
|
|
443
|
-
type: 'Motion Sensor',
|
|
444
|
-
category: 'physical',
|
|
445
|
-
description: 'PIR motion detector that reports movement and ambient brightness; read-only.',
|
|
446
|
-
role: 'sensor',
|
|
447
|
-
readOnly: true,
|
|
448
|
-
commands: [],
|
|
449
|
-
statusFields: ['battery', 'version', 'moveDetected', 'brightness', 'openState'],
|
|
450
|
-
},
|
|
451
|
-
{
|
|
452
|
-
type: 'Contact Sensor',
|
|
453
|
-
category: 'physical',
|
|
454
|
-
description: 'Door or window open/close sensor that also reports movement and brightness; read-only.',
|
|
455
|
-
role: 'sensor',
|
|
456
|
-
readOnly: true,
|
|
457
|
-
commands: [],
|
|
458
|
-
statusFields: ['battery', 'version', 'moveDetected', 'openState', 'brightness'],
|
|
459
|
-
},
|
|
460
|
-
{
|
|
461
|
-
type: 'Water Leak Detector',
|
|
462
|
-
category: 'physical',
|
|
463
|
-
description: 'Water sensor that reports leak status; read-only, no control commands.',
|
|
464
|
-
role: 'sensor',
|
|
465
|
-
readOnly: true,
|
|
466
|
-
commands: [],
|
|
467
|
-
statusFields: ['battery', 'version', 'status'],
|
|
468
|
-
},
|
|
469
|
-
// Status-only hub-class devices (no control commands)
|
|
470
|
-
{
|
|
471
|
-
type: 'Hub Mini',
|
|
472
|
-
category: 'physical',
|
|
473
|
-
description: 'IR hub that bridges BLE devices to the cloud and learns IR remotes; no direct control commands.',
|
|
474
|
-
role: 'hub',
|
|
475
|
-
readOnly: true,
|
|
476
|
-
aliases: ['Hub Mini2'],
|
|
477
|
-
commands: [],
|
|
478
|
-
statusFields: ['version'],
|
|
479
|
-
},
|
|
480
|
-
{
|
|
481
|
-
type: 'Hub 3',
|
|
482
|
-
category: 'physical',
|
|
483
|
-
description: 'Wi-Fi hub with built-in temperature, humidity, and light sensors; manages local BLE devices.',
|
|
484
|
-
role: 'hub',
|
|
485
|
-
readOnly: true,
|
|
486
|
-
commands: [],
|
|
487
|
-
statusFields: ['version', 'temperature', 'humidity', 'lightLevel'],
|
|
488
|
-
},
|
|
489
|
-
{
|
|
490
|
-
type: 'AI Hub',
|
|
491
|
-
category: 'physical',
|
|
492
|
-
description: 'Advanced hub with AI-based automations; bridges BLE devices to the cloud; read-only status.',
|
|
493
|
-
role: 'hub',
|
|
494
|
-
readOnly: true,
|
|
495
|
-
commands: [],
|
|
496
|
-
statusFields: ['version'],
|
|
497
|
-
},
|
|
498
|
-
{
|
|
499
|
-
type: 'Home Climate Panel',
|
|
500
|
-
category: 'physical',
|
|
501
|
-
description: 'Wall-mounted display showing temperature and humidity; sensor-only, no control.',
|
|
502
|
-
role: 'climate',
|
|
503
|
-
readOnly: true,
|
|
504
|
-
commands: [],
|
|
505
|
-
statusFields: ['temperature', 'humidity', 'version'],
|
|
506
|
-
},
|
|
507
|
-
{
|
|
508
|
-
type: 'Wallet Finder Card',
|
|
509
|
-
category: 'physical',
|
|
510
|
-
description: 'Slim Bluetooth tracker card for locating wallets; reports battery status only.',
|
|
511
|
-
role: 'sensor',
|
|
512
|
-
readOnly: true,
|
|
513
|
-
commands: [],
|
|
514
|
-
statusFields: ['battery', 'version'],
|
|
515
|
-
},
|
|
516
|
-
{
|
|
517
|
-
type: 'Outdoor Spotlight Cam',
|
|
518
|
-
category: 'physical',
|
|
519
|
-
description: 'Battery-powered outdoor security camera with spotlight; status-only via cloud API.',
|
|
520
|
-
role: 'security',
|
|
521
|
-
readOnly: true,
|
|
522
|
-
commands: [],
|
|
523
|
-
statusFields: ['battery', 'version'],
|
|
524
|
-
},
|
|
525
|
-
// ---------- Virtual IR remotes ----------
|
|
526
|
-
{
|
|
527
|
-
type: 'Air Conditioner',
|
|
528
|
-
category: 'ir',
|
|
529
|
-
description: 'IR-controlled air conditioner with on/off and full HVAC parameter control (mode, fan, temp).',
|
|
530
|
-
role: 'climate',
|
|
531
|
-
commands: [
|
|
532
|
-
...onOff,
|
|
533
|
-
{ command: 'setAll', parameter: '"<temp>,<mode>,<fan>,<on|off>"', description: 'mode: 1=auto 2=cool 3=dry 4=fan 5=heat; fan: 1=auto 2=low 3=mid 4=high', idempotent: true, exampleParams: ['26,2,3,on', '22,5,2,on'] },
|
|
534
|
-
],
|
|
535
|
-
},
|
|
536
|
-
{
|
|
537
|
-
type: 'TV',
|
|
538
|
-
category: 'ir',
|
|
539
|
-
description: 'IR-controlled television or streaming device with channel, volume, and power commands.',
|
|
540
|
-
role: 'media',
|
|
541
|
-
aliases: ['IPTV', 'Streamer', 'Set Top Box'],
|
|
542
|
-
commands: [
|
|
543
|
-
...onOff,
|
|
544
|
-
{ command: 'SetChannel', parameter: '1-999 (channel number)', description: 'Switch to a specific channel', idempotent: true, exampleParams: ['1', '15'] },
|
|
545
|
-
{ command: 'volumeAdd', parameter: '—', description: 'Volume up', idempotent: false },
|
|
546
|
-
{ command: 'volumeSub', parameter: '—', description: 'Volume down', idempotent: false },
|
|
547
|
-
{ command: 'channelAdd', parameter: '—', description: 'Channel up', idempotent: false },
|
|
548
|
-
{ command: 'channelSub', parameter: '—', description: 'Channel down', idempotent: false },
|
|
549
|
-
],
|
|
550
|
-
},
|
|
551
|
-
{
|
|
552
|
-
type: 'DVD',
|
|
553
|
-
category: 'ir',
|
|
554
|
-
description: 'IR-controlled disc player or speaker with playback, track navigation, and volume commands.',
|
|
555
|
-
role: 'media',
|
|
556
|
-
aliases: ['Speaker'],
|
|
557
|
-
commands: [
|
|
558
|
-
...onOff,
|
|
559
|
-
{ command: 'setMute', parameter: '—', description: 'Toggle mute', idempotent: false },
|
|
560
|
-
{ command: 'FastForward', parameter: '—', description: 'Fast forward', idempotent: false },
|
|
561
|
-
{ command: 'Rewind', parameter: '—', description: 'Rewind', idempotent: false },
|
|
562
|
-
{ command: 'Next', parameter: '—', description: 'Next track', idempotent: false },
|
|
563
|
-
{ command: 'Previous', parameter: '—', description: 'Previous track', idempotent: false },
|
|
564
|
-
{ command: 'Pause', parameter: '—', description: 'Pause', idempotent: true },
|
|
565
|
-
{ command: 'Play', parameter: '—', description: 'Play', idempotent: true },
|
|
566
|
-
{ command: 'Stop', parameter: '—', description: 'Stop', idempotent: true },
|
|
567
|
-
{ command: 'volumeAdd', parameter: '—', description: 'Volume up', idempotent: false },
|
|
568
|
-
{ command: 'volumeSub', parameter: '—', description: 'Volume down', idempotent: false },
|
|
569
|
-
],
|
|
570
|
-
},
|
|
571
|
-
{
|
|
572
|
-
type: 'Fan',
|
|
573
|
-
category: 'ir',
|
|
574
|
-
description: 'IR-controlled fan with on/off, swing, timer, and speed preset commands.',
|
|
575
|
-
role: 'fan',
|
|
576
|
-
commands: [
|
|
577
|
-
...onOff,
|
|
578
|
-
{ command: 'swing', parameter: '—', description: 'Toggle swing', idempotent: false },
|
|
579
|
-
{ command: 'timer', parameter: '—', description: 'Toggle timer', idempotent: false },
|
|
580
|
-
{ command: 'lowSpeed', parameter: '—', description: 'Low speed', idempotent: true },
|
|
581
|
-
{ command: 'middleSpeed', parameter: '—', description: 'Medium speed', idempotent: true },
|
|
582
|
-
{ command: 'highSpeed', parameter: '—', description: 'High speed', idempotent: true },
|
|
583
|
-
],
|
|
584
|
-
},
|
|
585
|
-
{
|
|
586
|
-
type: 'Light',
|
|
587
|
-
category: 'ir',
|
|
588
|
-
description: 'IR-controlled light fixture with on/off and relative brightness adjustment commands.',
|
|
589
|
-
role: 'lighting',
|
|
590
|
-
commands: [
|
|
591
|
-
...onOff,
|
|
592
|
-
{ command: 'brightnessUp', parameter: '—', description: 'Brightness up', idempotent: false },
|
|
593
|
-
{ command: 'brightnessDown', parameter: '—', description: 'Brightness down', idempotent: false },
|
|
594
|
-
],
|
|
595
|
-
},
|
|
596
|
-
{
|
|
597
|
-
type: 'Others',
|
|
598
|
-
category: 'ir',
|
|
599
|
-
description: 'Catch-all for custom IR remotes with user-defined button names learned by a Hub.',
|
|
600
|
-
role: 'other',
|
|
601
|
-
commands: [
|
|
602
|
-
{ command: '<buttonName>', parameter: '—', description: 'User-defined custom IR button (requires --type customize)', commandType: 'customize' },
|
|
603
|
-
],
|
|
604
|
-
},
|
|
605
|
-
];
|
|
606
|
-
/** Find a catalog entry by exact name, alias, or case-insensitive substring. */
|
|
607
|
-
export function findCatalogEntry(query) {
|
|
608
|
-
const q = query.trim().toLowerCase();
|
|
609
|
-
if (!q)
|
|
610
|
-
return null;
|
|
611
|
-
const names = (e) => [e.type, ...(e.aliases ?? [])];
|
|
612
|
-
const catalog = getEffectiveCatalog();
|
|
613
|
-
const exact = catalog.find((e) => names(e).some((n) => n.toLowerCase() === q));
|
|
614
|
-
if (exact)
|
|
615
|
-
return exact;
|
|
616
|
-
const matches = catalog.filter((e) => names(e).some((n) => n.toLowerCase().includes(q)));
|
|
617
|
-
if (matches.length === 0)
|
|
618
|
-
return null;
|
|
619
|
-
if (matches.length === 1)
|
|
620
|
-
return matches[0];
|
|
621
|
-
return matches;
|
|
622
|
-
}
|
|
623
|
-
/**
|
|
624
|
-
* Derive the safety tier for a catalog command, honouring an explicit
|
|
625
|
-
* `safetyTier` when present and falling back to heuristic inference.
|
|
626
|
-
*
|
|
627
|
-
* The inference order is:
|
|
628
|
-
* 1. Explicit `spec.safetyTier`.
|
|
629
|
-
* 2. IR context (customize command OR entry.category === 'ir')
|
|
630
|
-
* → `'ir-fire-forget'`.
|
|
631
|
-
* 3. Default → `'mutation'`.
|
|
632
|
-
*/
|
|
633
|
-
export function deriveSafetyTier(spec, entry) {
|
|
634
|
-
if (spec.safetyTier)
|
|
635
|
-
return spec.safetyTier;
|
|
636
|
-
if (spec.commandType === 'customize')
|
|
637
|
-
return 'ir-fire-forget';
|
|
638
|
-
if (entry?.category === 'ir')
|
|
639
|
-
return 'ir-fire-forget';
|
|
640
|
-
return 'mutation';
|
|
641
|
-
}
|
|
642
|
-
/** Read the safety reason for a command. */
|
|
643
|
-
export function getCommandSafetyReason(spec) {
|
|
644
|
-
return spec.safetyReason ?? null;
|
|
645
|
-
}
|
|
646
|
-
/**
|
|
647
|
-
* Pick up to 3 non-destructive, idempotent commands an agent can safely invoke
|
|
648
|
-
* to explore or exercise a device. Used by `devices describe --json` to hint
|
|
649
|
-
* at concrete next steps.
|
|
650
|
-
*/
|
|
651
|
-
export function suggestedActions(entry) {
|
|
652
|
-
const safe = entry.commands.filter((c) => c.idempotent === true &&
|
|
653
|
-
deriveSafetyTier(c, entry) !== 'destructive' &&
|
|
654
|
-
c.commandType !== 'customize');
|
|
655
|
-
const picks = [];
|
|
656
|
-
const seen = new Set();
|
|
657
|
-
for (const c of safe) {
|
|
658
|
-
if (seen.has(c.command))
|
|
659
|
-
continue;
|
|
660
|
-
seen.add(c.command);
|
|
661
|
-
picks.push(c);
|
|
662
|
-
if (picks.length >= 3)
|
|
663
|
-
break;
|
|
664
|
-
}
|
|
665
|
-
return picks.map((c) => ({
|
|
666
|
-
command: c.command,
|
|
667
|
-
parameter: c.exampleParams?.[0],
|
|
668
|
-
description: c.description,
|
|
669
|
-
}));
|
|
670
|
-
}
|
|
671
|
-
// ---- Overlay loader ----------------------------------------------------
|
|
672
|
-
//
|
|
673
|
-
// Users can drop a `~/.switchbot/catalog.json` file to override or extend
|
|
674
|
-
// the built-in catalog without waiting on a CLI release. The overlay is a
|
|
675
|
-
// list of DeviceCatalogEntry objects; each entry matches on `type`:
|
|
676
|
-
// - Entry with `type` matching a built-in replaces that built-in entry.
|
|
677
|
-
// - Entry with a new `type` is appended.
|
|
678
|
-
// - Entry with `{ type: "X", remove: true }` deletes the built-in.
|
|
679
|
-
//
|
|
680
|
-
// The overlay is loaded once per process and cached. Malformed JSON or
|
|
681
|
-
// files that don't match the expected shape are ignored (with a warning
|
|
682
|
-
// to stderr in verbose mode).
|
|
683
|
-
import fs from 'node:fs';
|
|
684
|
-
import path from 'node:path';
|
|
685
|
-
import os from 'node:os';
|
|
686
|
-
function overlayFilePath() {
|
|
687
|
-
return path.join(os.homedir(), '.switchbot', 'catalog.json');
|
|
688
|
-
}
|
|
689
|
-
export function getCatalogOverlayPath() {
|
|
690
|
-
return overlayFilePath();
|
|
691
|
-
}
|
|
692
|
-
/** Read the overlay file. Never throws — returns `error` on bad files. */
|
|
693
|
-
export function loadCatalogOverlay() {
|
|
694
|
-
const file = overlayFilePath();
|
|
695
|
-
if (!fs.existsSync(file)) {
|
|
696
|
-
return { path: file, exists: false, entries: [] };
|
|
697
|
-
}
|
|
698
|
-
try {
|
|
699
|
-
const raw = fs.readFileSync(file, 'utf-8');
|
|
700
|
-
const parsed = JSON.parse(raw);
|
|
701
|
-
if (!Array.isArray(parsed)) {
|
|
702
|
-
return {
|
|
703
|
-
path: file,
|
|
704
|
-
exists: true,
|
|
705
|
-
entries: [],
|
|
706
|
-
error: 'overlay must be a JSON array of device catalog entries',
|
|
707
|
-
};
|
|
708
|
-
}
|
|
709
|
-
const entries = [];
|
|
710
|
-
for (const item of parsed) {
|
|
711
|
-
if (!item || typeof item !== 'object' || typeof item.type !== 'string') {
|
|
712
|
-
return {
|
|
713
|
-
path: file,
|
|
714
|
-
exists: true,
|
|
715
|
-
entries: [],
|
|
716
|
-
error: 'every overlay entry must be an object with a string `type`',
|
|
717
|
-
};
|
|
718
|
-
}
|
|
719
|
-
entries.push(item);
|
|
720
|
-
}
|
|
721
|
-
return { path: file, exists: true, entries };
|
|
722
|
-
}
|
|
723
|
-
catch (err) {
|
|
724
|
-
return {
|
|
725
|
-
path: file,
|
|
726
|
-
exists: true,
|
|
727
|
-
entries: [],
|
|
728
|
-
error: err instanceof Error ? err.message : String(err),
|
|
729
|
-
};
|
|
730
|
-
}
|
|
731
|
-
}
|
|
732
|
-
let overlayCache = null;
|
|
733
|
-
function overlayOnce() {
|
|
734
|
-
if (overlayCache === null)
|
|
735
|
-
overlayCache = loadCatalogOverlay();
|
|
736
|
-
return overlayCache;
|
|
737
|
-
}
|
|
738
|
-
/** Clear the overlay cache (test helper; also useful for `catalog refresh`). */
|
|
739
|
-
export function resetCatalogOverlayCache() {
|
|
740
|
-
overlayCache = null;
|
|
741
|
-
}
|
|
742
|
-
/** Merge built-in catalog with the on-disk overlay. */
|
|
743
|
-
export function getEffectiveCatalog() {
|
|
744
|
-
const overlay = overlayOnce();
|
|
745
|
-
if (!overlay.entries.length)
|
|
746
|
-
return DEVICE_CATALOG;
|
|
747
|
-
const byType = new Map();
|
|
748
|
-
for (const e of DEVICE_CATALOG)
|
|
749
|
-
byType.set(e.type, e);
|
|
750
|
-
for (const entry of overlay.entries) {
|
|
751
|
-
if (entry.remove) {
|
|
752
|
-
byType.delete(entry.type);
|
|
753
|
-
continue;
|
|
754
|
-
}
|
|
755
|
-
const existing = byType.get(entry.type);
|
|
756
|
-
if (existing) {
|
|
757
|
-
byType.set(entry.type, { ...existing, ...entry });
|
|
758
|
-
}
|
|
759
|
-
else if (entry.category && entry.commands) {
|
|
760
|
-
// New entry — require the fields the renderer needs. Missing fields
|
|
761
|
-
// would make the new entry crash later, so skip silently rather than
|
|
762
|
-
// ship half-valid data to the user.
|
|
763
|
-
byType.set(entry.type, entry);
|
|
764
|
-
}
|
|
765
|
-
}
|
|
766
|
-
return Array.from(byType.values());
|
|
767
|
-
}
|
|
768
|
-
//# sourceMappingURL=catalog.js.map
|