@switchbot/openapi-cli 3.2.0 → 3.2.1
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/dist/api/client.d.ts +31 -0
- package/dist/api/client.js +236 -0
- package/dist/api/client.js.map +1 -0
- package/dist/auth.d.ts +1 -0
- package/dist/auth.js +21 -0
- package/dist/auth.js.map +1 -0
- package/dist/commands/agent-bootstrap.d.ts +10 -0
- package/dist/commands/agent-bootstrap.js +200 -0
- package/dist/commands/agent-bootstrap.js.map +1 -0
- package/dist/commands/auth.d.ts +18 -0
- package/dist/commands/auth.js +355 -0
- package/dist/commands/auth.js.map +1 -0
- package/dist/commands/batch.d.ts +2 -0
- package/dist/commands/batch.js +414 -0
- package/dist/commands/batch.js.map +1 -0
- package/dist/commands/cache.d.ts +2 -0
- package/dist/commands/cache.js +127 -0
- package/dist/commands/cache.js.map +1 -0
- package/dist/commands/capabilities.d.ts +31 -0
- package/dist/commands/capabilities.js +383 -0
- package/dist/commands/capabilities.js.map +1 -0
- package/dist/commands/catalog.d.ts +2 -0
- package/dist/commands/catalog.js +360 -0
- package/dist/commands/catalog.js.map +1 -0
- package/dist/commands/completion.d.ts +2 -0
- package/dist/commands/completion.js +386 -0
- package/dist/commands/completion.js.map +1 -0
- package/dist/commands/config.d.ts +21 -0
- package/dist/commands/config.js +377 -0
- package/dist/commands/config.js.map +1 -0
- package/dist/commands/daemon.d.ts +2 -0
- package/dist/commands/daemon.js +411 -0
- package/dist/commands/daemon.js.map +1 -0
- package/dist/commands/device-meta.d.ts +2 -0
- package/dist/commands/device-meta.js +160 -0
- package/dist/commands/device-meta.js.map +1 -0
- package/dist/commands/devices.d.ts +2 -0
- package/dist/commands/devices.js +949 -0
- package/dist/commands/devices.js.map +1 -0
- package/dist/commands/doctor.d.ts +3 -0
- package/dist/commands/doctor.js +1016 -0
- package/dist/commands/doctor.js.map +1 -0
- package/dist/commands/events.d.ts +31 -0
- package/dist/commands/events.js +564 -0
- package/dist/commands/events.js.map +1 -0
- package/dist/commands/expand.d.ts +2 -0
- package/dist/commands/expand.js +131 -0
- package/dist/commands/expand.js.map +1 -0
- package/dist/commands/explain.d.ts +2 -0
- package/dist/commands/explain.js +140 -0
- package/dist/commands/explain.js.map +1 -0
- package/dist/commands/health.d.ts +8 -0
- package/dist/commands/health.js +114 -0
- package/dist/commands/health.js.map +1 -0
- package/dist/commands/history.d.ts +2 -0
- package/dist/commands/history.js +321 -0
- package/dist/commands/history.js.map +1 -0
- package/dist/commands/identity.d.ts +45 -0
- package/dist/commands/identity.js +60 -0
- package/dist/commands/identity.js.map +1 -0
- package/dist/commands/install.d.ts +20 -0
- package/dist/commands/install.js +247 -0
- package/dist/commands/install.js.map +1 -0
- package/dist/commands/mcp.d.ts +14 -0
- package/dist/commands/mcp.js +2018 -0
- package/dist/commands/mcp.js.map +1 -0
- package/dist/commands/plan.d.ts +51 -0
- package/dist/commands/plan.js +654 -0
- package/dist/commands/plan.js.map +1 -0
- package/dist/commands/policy.d.ts +24 -0
- package/dist/commands/policy.js +587 -0
- package/dist/commands/policy.js.map +1 -0
- package/dist/commands/quota.d.ts +2 -0
- package/dist/commands/quota.js +79 -0
- package/dist/commands/quota.js.map +1 -0
- package/dist/commands/rules.d.ts +2 -0
- package/dist/commands/rules.js +876 -0
- package/dist/commands/rules.js.map +1 -0
- package/dist/commands/scenes.d.ts +2 -0
- package/dist/commands/scenes.js +265 -0
- package/dist/commands/scenes.js.map +1 -0
- package/dist/commands/schema.d.ts +2 -0
- package/dist/commands/schema.js +185 -0
- package/dist/commands/schema.js.map +1 -0
- package/dist/commands/status-sync.d.ts +2 -0
- package/dist/commands/status-sync.js +132 -0
- package/dist/commands/status-sync.js.map +1 -0
- package/dist/commands/uninstall.d.ts +20 -0
- package/dist/commands/uninstall.js +238 -0
- package/dist/commands/uninstall.js.map +1 -0
- package/dist/commands/upgrade-check.d.ts +2 -0
- package/dist/commands/upgrade-check.js +107 -0
- package/dist/commands/upgrade-check.js.map +1 -0
- package/dist/commands/watch.d.ts +2 -0
- package/dist/commands/watch.js +195 -0
- package/dist/commands/watch.js.map +1 -0
- package/dist/commands/webhook.d.ts +2 -0
- package/dist/commands/webhook.js +183 -0
- package/dist/commands/webhook.js.map +1 -0
- package/dist/config.d.ts +57 -0
- package/dist/config.js +259 -0
- package/dist/config.js.map +1 -0
- package/dist/credentials/backends/file.d.ts +18 -0
- package/dist/credentials/backends/file.js +102 -0
- package/dist/credentials/backends/file.js.map +1 -0
- package/dist/credentials/backends/linux.d.ts +16 -0
- package/dist/credentials/backends/linux.js +130 -0
- package/dist/credentials/backends/linux.js.map +1 -0
- package/dist/credentials/backends/macos.d.ts +18 -0
- package/dist/credentials/backends/macos.js +130 -0
- package/dist/credentials/backends/macos.js.map +1 -0
- package/dist/credentials/backends/windows.d.ts +23 -0
- package/dist/credentials/backends/windows.js +216 -0
- package/dist/credentials/backends/windows.js.map +1 -0
- package/dist/credentials/keychain.d.ts +83 -0
- package/dist/credentials/keychain.js +89 -0
- package/dist/credentials/keychain.js.map +1 -0
- package/dist/credentials/prime.d.ts +32 -0
- package/dist/credentials/prime.js +53 -0
- package/dist/credentials/prime.js.map +1 -0
- package/dist/devices/cache.d.ts +79 -0
- package/dist/devices/cache.js +294 -0
- package/dist/devices/cache.js.map +1 -0
- package/dist/devices/catalog.d.ts +138 -0
- package/dist/devices/catalog.js +768 -0
- package/dist/devices/catalog.js.map +1 -0
- package/dist/devices/device-meta.d.ts +15 -0
- package/dist/devices/device-meta.js +57 -0
- package/dist/devices/device-meta.js.map +1 -0
- package/dist/devices/history-agg.d.ts +37 -0
- package/dist/devices/history-agg.js +139 -0
- package/dist/devices/history-agg.js.map +1 -0
- package/dist/devices/history-query.d.ts +45 -0
- package/dist/devices/history-query.js +182 -0
- package/dist/devices/history-query.js.map +1 -0
- package/dist/devices/param-validator.d.ts +40 -0
- package/dist/devices/param-validator.js +434 -0
- package/dist/devices/param-validator.js.map +1 -0
- package/dist/devices/resources.d.ts +74 -0
- package/dist/devices/resources.js +271 -0
- package/dist/devices/resources.js.map +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +170 -56946
- package/dist/index.js.map +1 -0
- package/dist/install/default-steps.d.ts +66 -0
- package/dist/install/default-steps.js +258 -0
- package/dist/install/default-steps.js.map +1 -0
- package/dist/install/preflight.d.ts +60 -0
- package/dist/install/preflight.js +213 -0
- package/dist/install/preflight.js.map +1 -0
- package/dist/install/steps.d.ts +61 -0
- package/dist/install/steps.js +68 -0
- package/dist/install/steps.js.map +1 -0
- package/dist/lib/command-keywords.d.ts +5 -0
- package/dist/lib/command-keywords.js +18 -0
- package/dist/lib/command-keywords.js.map +1 -0
- package/dist/lib/daemon-state.d.ts +24 -0
- package/dist/lib/daemon-state.js +47 -0
- package/dist/lib/daemon-state.js.map +1 -0
- package/dist/lib/destructive-mode.d.ts +2 -0
- package/dist/lib/destructive-mode.js +13 -0
- package/dist/lib/destructive-mode.js.map +1 -0
- package/dist/lib/devices.d.ts +151 -0
- package/dist/lib/devices.js +383 -0
- package/dist/lib/devices.js.map +1 -0
- package/dist/lib/idempotency.d.ts +46 -0
- package/dist/lib/idempotency.js +107 -0
- package/dist/lib/idempotency.js.map +1 -0
- package/dist/lib/plan-store.d.ts +19 -0
- package/dist/lib/plan-store.js +69 -0
- package/dist/lib/plan-store.js.map +1 -0
- package/dist/lib/request-context.d.ts +7 -0
- package/dist/lib/request-context.js +13 -0
- package/dist/lib/request-context.js.map +1 -0
- package/dist/lib/scenes.d.ts +7 -0
- package/dist/lib/scenes.js +11 -0
- package/dist/lib/scenes.js.map +1 -0
- package/dist/logger.d.ts +4 -0
- package/dist/logger.js +17 -0
- package/dist/logger.js.map +1 -0
- package/dist/mcp/device-history.d.ts +36 -0
- package/dist/mcp/device-history.js +146 -0
- package/dist/mcp/device-history.js.map +1 -0
- package/dist/mcp/events-subscription.d.ts +45 -0
- package/dist/mcp/events-subscription.js +214 -0
- package/dist/mcp/events-subscription.js.map +1 -0
- package/dist/mqtt/client.d.ts +25 -0
- package/dist/mqtt/client.js +181 -0
- package/dist/mqtt/client.js.map +1 -0
- package/dist/mqtt/credential.d.ts +16 -0
- package/dist/mqtt/credential.js +31 -0
- package/dist/mqtt/credential.js.map +1 -0
- package/dist/policy/add-rule.d.ts +21 -0
- package/dist/policy/add-rule.js +125 -0
- package/dist/policy/add-rule.js.map +1 -0
- package/dist/policy/diff.d.ts +21 -0
- package/dist/policy/diff.js +92 -0
- package/dist/policy/diff.js.map +1 -0
- package/dist/policy/format.d.ts +6 -0
- package/dist/policy/format.js +58 -0
- package/dist/policy/format.js.map +1 -0
- package/dist/policy/load.d.ts +32 -0
- package/dist/policy/load.js +62 -0
- package/dist/policy/load.js.map +1 -0
- package/dist/policy/migrate.d.ts +21 -0
- package/dist/policy/migrate.js +68 -0
- package/dist/policy/migrate.js.map +1 -0
- package/dist/policy/schema.d.ts +5 -0
- package/dist/policy/schema.js +19 -0
- package/dist/policy/schema.js.map +1 -0
- package/dist/policy/validate.d.ts +19 -0
- package/dist/policy/validate.js +263 -0
- package/dist/policy/validate.js.map +1 -0
- package/dist/rules/action.d.ts +65 -0
- package/dist/rules/action.js +217 -0
- package/dist/rules/action.js.map +1 -0
- package/dist/rules/audit-query.d.ts +51 -0
- package/dist/rules/audit-query.js +90 -0
- package/dist/rules/audit-query.js.map +1 -0
- package/dist/rules/conflict-analyzer.d.ts +57 -0
- package/dist/rules/conflict-analyzer.js +215 -0
- package/dist/rules/conflict-analyzer.js.map +1 -0
- package/dist/rules/cron-scheduler.d.ts +62 -0
- package/dist/rules/cron-scheduler.js +187 -0
- package/dist/rules/cron-scheduler.js.map +1 -0
- package/dist/rules/destructive.d.ts +20 -0
- package/dist/rules/destructive.js +53 -0
- package/dist/rules/destructive.js.map +1 -0
- package/dist/rules/engine.d.ts +193 -0
- package/dist/rules/engine.js +758 -0
- package/dist/rules/engine.js.map +1 -0
- package/dist/rules/matcher.d.ts +56 -0
- package/dist/rules/matcher.js +231 -0
- package/dist/rules/matcher.js.map +1 -0
- package/dist/rules/pid-file.d.ts +43 -0
- package/dist/rules/pid-file.js +96 -0
- package/dist/rules/pid-file.js.map +1 -0
- package/dist/rules/quiet-hours.d.ts +26 -0
- package/dist/rules/quiet-hours.js +46 -0
- package/dist/rules/quiet-hours.js.map +1 -0
- package/dist/rules/suggest.d.ts +20 -0
- package/dist/rules/suggest.js +96 -0
- package/dist/rules/suggest.js.map +1 -0
- package/dist/rules/throttle.d.ts +61 -0
- package/dist/rules/throttle.js +117 -0
- package/dist/rules/throttle.js.map +1 -0
- package/dist/rules/types.d.ts +117 -0
- package/dist/rules/types.js +35 -0
- package/dist/rules/types.js.map +1 -0
- package/dist/rules/webhook-listener.d.ts +63 -0
- package/dist/rules/webhook-listener.js +224 -0
- package/dist/rules/webhook-listener.js.map +1 -0
- package/dist/rules/webhook-token.d.ts +50 -0
- package/dist/rules/webhook-token.js +91 -0
- package/dist/rules/webhook-token.js.map +1 -0
- package/dist/schema/field-aliases.d.ts +34 -0
- package/dist/schema/field-aliases.js +132 -0
- package/dist/schema/field-aliases.js.map +1 -0
- package/dist/sinks/dispatcher.d.ts +7 -0
- package/dist/sinks/dispatcher.js +13 -0
- package/dist/sinks/dispatcher.js.map +1 -0
- package/dist/sinks/file.d.ts +6 -0
- package/dist/sinks/file.js +20 -0
- package/dist/sinks/file.js.map +1 -0
- package/dist/sinks/format.d.ts +20 -0
- package/dist/sinks/format.js +57 -0
- package/dist/sinks/format.js.map +1 -0
- package/dist/sinks/homeassistant.d.ts +18 -0
- package/dist/sinks/homeassistant.js +45 -0
- package/dist/sinks/homeassistant.js.map +1 -0
- package/dist/sinks/openclaw.d.ts +13 -0
- package/dist/sinks/openclaw.js +34 -0
- package/dist/sinks/openclaw.js.map +1 -0
- package/dist/sinks/stdout.d.ts +4 -0
- package/dist/sinks/stdout.js +6 -0
- package/dist/sinks/stdout.js.map +1 -0
- package/dist/sinks/telegram.d.ts +11 -0
- package/dist/sinks/telegram.js +29 -0
- package/dist/sinks/telegram.js.map +1 -0
- package/dist/sinks/types.d.ts +13 -0
- package/dist/sinks/types.js +2 -0
- package/dist/sinks/types.js.map +1 -0
- package/dist/sinks/webhook.d.ts +6 -0
- package/dist/sinks/webhook.js +23 -0
- package/dist/sinks/webhook.js.map +1 -0
- package/dist/status-sync/manager.d.ts +48 -0
- package/dist/status-sync/manager.js +269 -0
- package/dist/status-sync/manager.js.map +1 -0
- package/dist/utils/arg-parsers.d.ts +16 -0
- package/dist/utils/arg-parsers.js +67 -0
- package/dist/utils/arg-parsers.js.map +1 -0
- package/dist/utils/audit.d.ts +69 -0
- package/dist/utils/audit.js +122 -0
- package/dist/utils/audit.js.map +1 -0
- package/dist/utils/filter.d.ts +81 -0
- package/dist/utils/filter.js +190 -0
- package/dist/utils/filter.js.map +1 -0
- package/dist/utils/flags.d.ts +72 -0
- package/dist/utils/flags.js +187 -0
- package/dist/utils/flags.js.map +1 -0
- package/dist/utils/format.d.ts +9 -0
- package/dist/utils/format.js +118 -0
- package/dist/utils/format.js.map +1 -0
- package/dist/utils/health.d.ts +48 -0
- package/dist/utils/health.js +102 -0
- package/dist/utils/health.js.map +1 -0
- package/dist/utils/help-json.d.ts +39 -0
- package/dist/utils/help-json.js +55 -0
- package/dist/utils/help-json.js.map +1 -0
- package/dist/utils/name-resolver.d.ts +26 -0
- package/dist/utils/name-resolver.js +138 -0
- package/dist/utils/name-resolver.js.map +1 -0
- package/dist/utils/output.d.ts +73 -0
- package/dist/utils/output.js +405 -0
- package/dist/utils/output.js.map +1 -0
- package/dist/utils/quota.d.ts +61 -0
- package/dist/utils/quota.js +228 -0
- package/dist/utils/quota.js.map +1 -0
- package/dist/utils/redact.d.ts +23 -0
- package/dist/utils/redact.js +69 -0
- package/dist/utils/redact.js.map +1 -0
- package/dist/utils/retry.d.ts +72 -0
- package/dist/utils/retry.js +141 -0
- package/dist/utils/retry.js.map +1 -0
- package/dist/utils/string.d.ts +2 -0
- package/dist/utils/string.js +23 -0
- package/dist/utils/string.js.map +1 -0
- package/dist/version.d.ts +2 -0
- package/dist/version.js +5 -0
- package/dist/version.js.map +1 -0
- package/package.json +2 -2
|
@@ -0,0 +1,564 @@
|
|
|
1
|
+
import http from 'node:http';
|
|
2
|
+
import crypto from 'node:crypto';
|
|
3
|
+
import { printJson, isJsonMode, handleError, UsageError, emitStreamHeader } from '../utils/output.js';
|
|
4
|
+
import { intArg, stringArg, durationArg } from '../utils/arg-parsers.js';
|
|
5
|
+
import { parseDurationToMs } from '../utils/flags.js';
|
|
6
|
+
import { parseFilterExpr, matchClause, FilterSyntaxError } from '../utils/filter.js';
|
|
7
|
+
import { SwitchBotMqttClient } from '../mqtt/client.js';
|
|
8
|
+
import { fetchMqttCredential } from '../mqtt/credential.js';
|
|
9
|
+
import { tryLoadConfig } from '../config.js';
|
|
10
|
+
import { SinkDispatcher } from '../sinks/dispatcher.js';
|
|
11
|
+
import { StdoutSink } from '../sinks/stdout.js';
|
|
12
|
+
import { FileSink } from '../sinks/file.js';
|
|
13
|
+
import { WebhookSink } from '../sinks/webhook.js';
|
|
14
|
+
import { OpenClawSink } from '../sinks/openclaw.js';
|
|
15
|
+
import { TelegramSink } from '../sinks/telegram.js';
|
|
16
|
+
import { HomeAssistantSink } from '../sinks/homeassistant.js';
|
|
17
|
+
import { parseSinkEvent } from '../sinks/format.js';
|
|
18
|
+
import { deviceHistoryStore } from '../mcp/device-history.js';
|
|
19
|
+
const DEFAULT_PORT = 3000;
|
|
20
|
+
const DEFAULT_PATH = '/';
|
|
21
|
+
const MAX_BODY_BYTES = 1_000_000;
|
|
22
|
+
/**
|
|
23
|
+
* P6: unified-envelope schema version shared by webhook and MQTT event output.
|
|
24
|
+
*
|
|
25
|
+
* The same key set now appears on both `events tail` (webhook) and
|
|
26
|
+
* `events mqtt-tail` (MQTT) output lines so downstream JSONL consumers can
|
|
27
|
+
* use a single parser regardless of source. Old fields are kept for one
|
|
28
|
+
* minor window so existing consumers keep working — see README and
|
|
29
|
+
* CHANGELOG for the deprecation schedule.
|
|
30
|
+
*/
|
|
31
|
+
export const EVENTS_SCHEMA_VERSION = '1';
|
|
32
|
+
function extractEventId(parsed) {
|
|
33
|
+
if (!parsed || typeof parsed !== 'object')
|
|
34
|
+
return null;
|
|
35
|
+
const p = parsed;
|
|
36
|
+
if (typeof p.eventId === 'string' && p.eventId.length > 0)
|
|
37
|
+
return p.eventId;
|
|
38
|
+
const ctx = p.context;
|
|
39
|
+
if (ctx && typeof ctx.eventId === 'string' && ctx.eventId.length > 0)
|
|
40
|
+
return ctx.eventId;
|
|
41
|
+
return null;
|
|
42
|
+
}
|
|
43
|
+
function extractDeviceId(parsed) {
|
|
44
|
+
if (!parsed || typeof parsed !== 'object')
|
|
45
|
+
return null;
|
|
46
|
+
const p = parsed;
|
|
47
|
+
const ctx = p.context ?? p;
|
|
48
|
+
const mac = ctx.deviceMac;
|
|
49
|
+
if (typeof mac === 'string' && mac.length > 0)
|
|
50
|
+
return mac;
|
|
51
|
+
const id = ctx.deviceId;
|
|
52
|
+
if (typeof id === 'string' && id.length > 0)
|
|
53
|
+
return id;
|
|
54
|
+
return null;
|
|
55
|
+
}
|
|
56
|
+
function matchFilterDetail(body, clauses) {
|
|
57
|
+
if (!clauses || clauses.length === 0)
|
|
58
|
+
return { matched: true, matchedKeys: [] };
|
|
59
|
+
if (!body || typeof body !== 'object')
|
|
60
|
+
return { matched: false, matchedKeys: [] };
|
|
61
|
+
const b = body;
|
|
62
|
+
const ctx = (b.context ?? b);
|
|
63
|
+
const hitKeys = [];
|
|
64
|
+
for (const c of clauses) {
|
|
65
|
+
let candidate;
|
|
66
|
+
if (c.key === 'deviceId') {
|
|
67
|
+
const mac = ctx.deviceMac;
|
|
68
|
+
const id = ctx.deviceId;
|
|
69
|
+
candidate = String(typeof mac === 'string' && mac ? mac : typeof id === 'string' ? id : '');
|
|
70
|
+
}
|
|
71
|
+
else {
|
|
72
|
+
const t = ctx.deviceType;
|
|
73
|
+
candidate = typeof t === 'string' ? t : '';
|
|
74
|
+
}
|
|
75
|
+
if (!matchClause(candidate, c))
|
|
76
|
+
return { matched: false, matchedKeys: [] };
|
|
77
|
+
hitKeys.push(c.key);
|
|
78
|
+
}
|
|
79
|
+
return { matched: true, matchedKeys: hitKeys };
|
|
80
|
+
}
|
|
81
|
+
const EVENT_FILTER_KEYS = ['deviceId', 'type'];
|
|
82
|
+
function parseFilter(flag) {
|
|
83
|
+
if (!flag)
|
|
84
|
+
return null;
|
|
85
|
+
try {
|
|
86
|
+
return parseFilterExpr(flag, EVENT_FILTER_KEYS);
|
|
87
|
+
}
|
|
88
|
+
catch (e) {
|
|
89
|
+
if (e instanceof FilterSyntaxError) {
|
|
90
|
+
throw new UsageError(e.message);
|
|
91
|
+
}
|
|
92
|
+
throw e;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
export function startReceiver(port, pathMatch, filter, onEvent) {
|
|
96
|
+
const server = http.createServer((req, res) => {
|
|
97
|
+
if (req.method !== 'POST') {
|
|
98
|
+
res.statusCode = 405;
|
|
99
|
+
res.end('method not allowed');
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
if (req.url !== pathMatch && pathMatch !== '*') {
|
|
103
|
+
res.statusCode = 404;
|
|
104
|
+
res.end('not found');
|
|
105
|
+
return;
|
|
106
|
+
}
|
|
107
|
+
const chunks = [];
|
|
108
|
+
let size = 0;
|
|
109
|
+
let bailed = false;
|
|
110
|
+
req.on('data', (c) => {
|
|
111
|
+
if (bailed)
|
|
112
|
+
return;
|
|
113
|
+
size += c.length;
|
|
114
|
+
if (size > MAX_BODY_BYTES) {
|
|
115
|
+
bailed = true;
|
|
116
|
+
res.statusCode = 413;
|
|
117
|
+
res.end('payload too large');
|
|
118
|
+
// Drain remaining upload so the client can read the 413 response before
|
|
119
|
+
// the connection closes naturally (avoids ECONNRESET racing the response).
|
|
120
|
+
req.resume();
|
|
121
|
+
return;
|
|
122
|
+
}
|
|
123
|
+
chunks.push(c);
|
|
124
|
+
});
|
|
125
|
+
req.on('end', () => {
|
|
126
|
+
if (bailed)
|
|
127
|
+
return;
|
|
128
|
+
const raw = Buffer.concat(chunks).toString('utf-8');
|
|
129
|
+
let body = raw;
|
|
130
|
+
try {
|
|
131
|
+
body = JSON.parse(raw);
|
|
132
|
+
}
|
|
133
|
+
catch {
|
|
134
|
+
// keep raw
|
|
135
|
+
}
|
|
136
|
+
const { matched, matchedKeys } = matchFilterDetail(body, filter);
|
|
137
|
+
const t = new Date().toISOString();
|
|
138
|
+
const urlPath = req.url ?? '/';
|
|
139
|
+
onEvent({
|
|
140
|
+
schemaVersion: EVENTS_SCHEMA_VERSION,
|
|
141
|
+
source: 'webhook',
|
|
142
|
+
kind: 'event',
|
|
143
|
+
t,
|
|
144
|
+
eventId: extractEventId(body),
|
|
145
|
+
deviceId: extractDeviceId(body),
|
|
146
|
+
topic: urlPath,
|
|
147
|
+
payload: body,
|
|
148
|
+
matchedKeys,
|
|
149
|
+
// Legacy mirror:
|
|
150
|
+
remote: `${req.socket.remoteAddress ?? ''}:${req.socket.remotePort ?? ''}`,
|
|
151
|
+
path: urlPath,
|
|
152
|
+
body,
|
|
153
|
+
matched,
|
|
154
|
+
});
|
|
155
|
+
res.statusCode = 204;
|
|
156
|
+
res.end();
|
|
157
|
+
});
|
|
158
|
+
});
|
|
159
|
+
server.listen(port);
|
|
160
|
+
return server;
|
|
161
|
+
}
|
|
162
|
+
export function registerEventsCommand(program) {
|
|
163
|
+
const events = program
|
|
164
|
+
.command('events')
|
|
165
|
+
.description('Receive SwitchBot device events — webhook receiver (tail) or MQTT stream (mqtt-tail)');
|
|
166
|
+
events
|
|
167
|
+
.command('tail')
|
|
168
|
+
.description('Run a local HTTP receiver and print incoming webhook events as JSONL')
|
|
169
|
+
.option('--port <n>', `Local port to listen on (default ${DEFAULT_PORT})`, intArg('--port', { min: 1, max: 65535 }), String(DEFAULT_PORT))
|
|
170
|
+
.option('--path <p>', `HTTP path to match (default "${DEFAULT_PATH}"; use "*" for all paths)`, stringArg('--path'), DEFAULT_PATH)
|
|
171
|
+
.option('--filter <expr>', 'Filter events by deviceId / type. Grammar: "key=value" (substring), "key~value" (substring), "key=/regex/" (regex). Comma-separated clauses are AND-ed.', stringArg('--filter'))
|
|
172
|
+
.option('--max <n>', 'Stop after N matching events (default: run until Ctrl-C)', intArg('--max', { min: 1 }))
|
|
173
|
+
.option('--for <dur>', 'Stop after elapsed time (e.g. "5m", "30s"). Combines with --max: first limit wins.', durationArg('--for'))
|
|
174
|
+
.addHelpText('after', `
|
|
175
|
+
SwitchBot posts events to a single webhook URL configured via:
|
|
176
|
+
$ switchbot webhook setup https://<your-public-host>/<path>
|
|
177
|
+
|
|
178
|
+
'events tail' only runs the LOCAL receiver — it does not tunnel. Expose
|
|
179
|
+
the port to the internet yourself (ngrok/cloudflared/reverse proxy) and
|
|
180
|
+
point the SwitchBot webhook at that public URL.
|
|
181
|
+
|
|
182
|
+
Output (JSONL, one event per line; P6 unified envelope v2.7+):
|
|
183
|
+
{ "schemaVersion": "1", "source": "webhook", "kind": "event",
|
|
184
|
+
"t": "<ISO>", "eventId": <string|null>, "deviceId": <string|null>,
|
|
185
|
+
"topic": "/", // = path
|
|
186
|
+
"payload": <parsed JSON or raw string>,
|
|
187
|
+
"matchedKeys": ["deviceId"], // which filter clauses matched
|
|
188
|
+
// Legacy fields kept for one minor window (removed in v3.0):
|
|
189
|
+
"remote": "<ip:port>", "path": "/", "body": <payload>, "matched": true }
|
|
190
|
+
|
|
191
|
+
Filter grammar: comma-separated clauses (AND-ed). Each clause is one of
|
|
192
|
+
key=value — case-insensitive substring
|
|
193
|
+
key~value — explicit case-insensitive substring
|
|
194
|
+
key=/regex/ — case-insensitive regex
|
|
195
|
+
|
|
196
|
+
Supported keys:
|
|
197
|
+
deviceId match by context.deviceMac / context.deviceId
|
|
198
|
+
type match by context.deviceType (e.g. "Bot", "WoMeter")
|
|
199
|
+
|
|
200
|
+
Examples:
|
|
201
|
+
$ switchbot events tail --port 3000
|
|
202
|
+
$ switchbot events tail --port 3000 --filter deviceId=ABC123
|
|
203
|
+
$ switchbot events tail --filter 'type~Meter' --max 5 --json
|
|
204
|
+
$ switchbot events tail --filter 'type=/Bot|Meter/'
|
|
205
|
+
`)
|
|
206
|
+
.action(async (options) => {
|
|
207
|
+
try {
|
|
208
|
+
const port = Number(options.port);
|
|
209
|
+
if (!Number.isInteger(port) || port <= 0 || port > 65535) {
|
|
210
|
+
throw new UsageError(`Invalid --port "${options.port}". Must be 1..65535.`);
|
|
211
|
+
}
|
|
212
|
+
const maxMatched = options.max !== undefined ? Number(options.max) : null;
|
|
213
|
+
if (maxMatched !== null && (!Number.isFinite(maxMatched) || maxMatched < 1)) {
|
|
214
|
+
throw new UsageError(`Invalid --max "${options.max}". Must be a positive integer.`);
|
|
215
|
+
}
|
|
216
|
+
const forMs = options.for ? parseDurationToMs(options.for) : null;
|
|
217
|
+
const filter = parseFilter(options.filter);
|
|
218
|
+
let matchedCount = 0;
|
|
219
|
+
const ac = new AbortController();
|
|
220
|
+
const forTimer = forMs !== null && forMs > 0
|
|
221
|
+
? setTimeout(() => ac.abort(), forMs)
|
|
222
|
+
: null;
|
|
223
|
+
// P7: streaming JSON contract — first line under --json is the
|
|
224
|
+
// stream header (webhook events arrive via push cadence).
|
|
225
|
+
if (isJsonMode())
|
|
226
|
+
emitStreamHeader({ eventKind: 'event', cadence: 'push' });
|
|
227
|
+
await new Promise((resolve, reject) => {
|
|
228
|
+
let server = null;
|
|
229
|
+
try {
|
|
230
|
+
server = startReceiver(port, options.path, filter, (ev) => {
|
|
231
|
+
if (!ev.matched)
|
|
232
|
+
return;
|
|
233
|
+
matchedCount++;
|
|
234
|
+
if (isJsonMode()) {
|
|
235
|
+
printJson(ev);
|
|
236
|
+
}
|
|
237
|
+
else {
|
|
238
|
+
const when = new Date(ev.t).toLocaleTimeString();
|
|
239
|
+
console.log(`[${when}] ${ev.remote} ${ev.path} ${JSON.stringify(ev.body)}`);
|
|
240
|
+
}
|
|
241
|
+
if (maxMatched !== null && matchedCount >= maxMatched) {
|
|
242
|
+
ac.abort();
|
|
243
|
+
}
|
|
244
|
+
});
|
|
245
|
+
server.on('error', (err) => reject(err));
|
|
246
|
+
}
|
|
247
|
+
catch (err) {
|
|
248
|
+
reject(err);
|
|
249
|
+
return;
|
|
250
|
+
}
|
|
251
|
+
const startMsg = `Listening on http://127.0.0.1:${port}${options.path} (Ctrl-C to stop)`;
|
|
252
|
+
if (!isJsonMode())
|
|
253
|
+
console.error(startMsg);
|
|
254
|
+
const cleanup = () => {
|
|
255
|
+
if (forTimer)
|
|
256
|
+
clearTimeout(forTimer);
|
|
257
|
+
server?.close();
|
|
258
|
+
resolve();
|
|
259
|
+
};
|
|
260
|
+
process.once('SIGINT', cleanup);
|
|
261
|
+
process.once('SIGTERM', cleanup);
|
|
262
|
+
ac.signal.addEventListener('abort', cleanup, { once: true });
|
|
263
|
+
});
|
|
264
|
+
}
|
|
265
|
+
catch (error) {
|
|
266
|
+
handleError(error);
|
|
267
|
+
}
|
|
268
|
+
});
|
|
269
|
+
events
|
|
270
|
+
.command('mqtt-tail')
|
|
271
|
+
.description('Subscribe to SwitchBot MQTT shadow events and stream them as JSONL')
|
|
272
|
+
.option('--topic <pattern>', 'MQTT topic filter (default: SwitchBot shadow topic from credential)', stringArg('--topic'))
|
|
273
|
+
.option('--max <n>', 'Stop after N events (default: run until Ctrl-C)', intArg('--max', { min: 1 }))
|
|
274
|
+
.option('--for <dur>', 'Stop after elapsed time (e.g. "5m", "30s"). Combines with --max: first limit wins.', durationArg('--for'))
|
|
275
|
+
.option('--sink <type>', 'Output sink: stdout (default), file, webhook, openclaw, telegram, homeassistant (repeatable)', (val, prev) => [...prev, val], [])
|
|
276
|
+
.option('--sink-file <path>', 'File path for file sink', stringArg('--sink-file'))
|
|
277
|
+
.option('--webhook-url <url>', 'Webhook URL for webhook sink', stringArg('--webhook-url'))
|
|
278
|
+
.option('--openclaw-url <url>', 'OpenClaw gateway URL (default: http://localhost:18789)', stringArg('--openclaw-url'))
|
|
279
|
+
.option('--openclaw-token <token>', 'Bearer token for OpenClaw (or env OPENCLAW_TOKEN)', stringArg('--openclaw-token'))
|
|
280
|
+
.option('--openclaw-model <id>', 'OpenClaw agent model ID to route events to', stringArg('--openclaw-model'))
|
|
281
|
+
.option('--telegram-token <token>', 'Telegram bot token (or env TELEGRAM_TOKEN)', stringArg('--telegram-token'))
|
|
282
|
+
.option('--telegram-chat <id>', 'Telegram chat/channel ID to send messages to', stringArg('--telegram-chat'))
|
|
283
|
+
.option('--ha-url <url>', 'Home Assistant base URL (e.g. http://homeassistant.local:8123)', stringArg('--ha-url'))
|
|
284
|
+
.option('--ha-token <token>', 'HA long-lived access token (for REST event API)', stringArg('--ha-token'))
|
|
285
|
+
.option('--ha-webhook-id <id>', 'HA webhook ID (no auth; takes priority over --ha-token)', stringArg('--ha-webhook-id'))
|
|
286
|
+
.option('--ha-event-type <type>', 'HA event type for REST API (default: switchbot_event)', stringArg('--ha-event-type'))
|
|
287
|
+
.addHelpText('after', `
|
|
288
|
+
Connects to the SwitchBot MQTT service using your existing credentials
|
|
289
|
+
(SWITCHBOT_TOKEN + SWITCHBOT_SECRET or ~/.switchbot/config.json).
|
|
290
|
+
No additional MQTT configuration required.
|
|
291
|
+
|
|
292
|
+
Output (JSONL, one event per line; P6 unified envelope v2.7+):
|
|
293
|
+
{ "schemaVersion": "1", "source": "mqtt", "kind": "event",
|
|
294
|
+
"t": "<ISO>", "eventId": "<uuid>", "deviceId": <string|null>,
|
|
295
|
+
"topic": "<mqtt-topic>",
|
|
296
|
+
"payload": <parsed JSON or raw string> }
|
|
297
|
+
|
|
298
|
+
Control records (interleaved, kind: "control" — filter by the "kind" field):
|
|
299
|
+
{ "schemaVersion": "1", "source": "mqtt", "kind": "control",
|
|
300
|
+
"controlKind": "session_start"|"connect"|"reconnect"|"disconnect"|"heartbeat",
|
|
301
|
+
"t": "<ISO>", "eventId": "<uuid>",
|
|
302
|
+
"state": "connecting" // present on session_start only
|
|
303
|
+
// Legacy fields kept for one minor window (removed in v3.0):
|
|
304
|
+
"type": "__session_start"|"__connect"|"__reconnect"|"__disconnect",
|
|
305
|
+
"at": "<ISO>" }
|
|
306
|
+
|
|
307
|
+
Reconnect policy: the MQTT client retries with exponential backoff
|
|
308
|
+
(1s → 30s capped, forever) while the credential is still valid; if the
|
|
309
|
+
credential is rejected or 5 consecutive reconnects fail, state goes to
|
|
310
|
+
'failed' and the command exits non-zero so supervisors can restart it.
|
|
311
|
+
QoS is 0 (at-most-once); agents requiring at-least-once delivery should
|
|
312
|
+
fan-out via --sink file and deduplicate by eventId on the consumer side.
|
|
313
|
+
|
|
314
|
+
Sink types (--sink, repeatable):
|
|
315
|
+
stdout Print JSONL to stdout (default when no --sink given)
|
|
316
|
+
file Append JSONL to --sink-file <path>
|
|
317
|
+
webhook HTTP POST to --webhook-url <url>
|
|
318
|
+
openclaw POST to OpenClaw via --openclaw-url / --openclaw-token / --openclaw-model
|
|
319
|
+
telegram Send to Telegram via --telegram-token / --telegram-chat
|
|
320
|
+
homeassistant POST to HA via --ha-url + --ha-webhook-id (or --ha-token)
|
|
321
|
+
|
|
322
|
+
Device state is also persisted to ~/.switchbot/device-history/<deviceId>.json
|
|
323
|
+
regardless of sink configuration.
|
|
324
|
+
|
|
325
|
+
Examples:
|
|
326
|
+
$ switchbot events mqtt-tail
|
|
327
|
+
$ switchbot events mqtt-tail --max 10 --json
|
|
328
|
+
$ switchbot events mqtt-tail --sink file --sink-file ~/.switchbot/events.jsonl
|
|
329
|
+
$ switchbot events mqtt-tail --sink openclaw --openclaw-token abc --openclaw-model home-agent
|
|
330
|
+
$ switchbot events mqtt-tail --sink telegram --telegram-token <token> --telegram-chat <chatId>
|
|
331
|
+
$ switchbot events mqtt-tail --sink homeassistant --ha-url http://ha.local:8123 --ha-webhook-id switchbot
|
|
332
|
+
$ switchbot events mqtt-tail --sink stdout --sink openclaw --openclaw-token abc --openclaw-model home
|
|
333
|
+
`)
|
|
334
|
+
.action(async (options) => {
|
|
335
|
+
try {
|
|
336
|
+
const maxEvents = options.max !== undefined ? Number(options.max) : null;
|
|
337
|
+
if (maxEvents !== null && (!Number.isInteger(maxEvents) || maxEvents < 1)) {
|
|
338
|
+
throw new UsageError(`Invalid --max "${options.max}". Must be a positive integer.`);
|
|
339
|
+
}
|
|
340
|
+
const forMs = options.for ? parseDurationToMs(options.for) : null;
|
|
341
|
+
const loaded = tryLoadConfig();
|
|
342
|
+
if (!loaded) {
|
|
343
|
+
throw new UsageError('No credentials found. Run \'switchbot config set-token\' or set SWITCHBOT_TOKEN and SWITCHBOT_SECRET.');
|
|
344
|
+
}
|
|
345
|
+
const sinkTypes = options.sink;
|
|
346
|
+
let dispatcher = null;
|
|
347
|
+
if (sinkTypes.length > 0) {
|
|
348
|
+
const sinks = sinkTypes.map((type) => {
|
|
349
|
+
switch (type) {
|
|
350
|
+
case 'stdout':
|
|
351
|
+
return new StdoutSink();
|
|
352
|
+
case 'file': {
|
|
353
|
+
if (!options.sinkFile)
|
|
354
|
+
throw new UsageError('--sink file requires --sink-file <path>');
|
|
355
|
+
return new FileSink(options.sinkFile);
|
|
356
|
+
}
|
|
357
|
+
case 'webhook': {
|
|
358
|
+
if (!options.webhookUrl)
|
|
359
|
+
throw new UsageError('--sink webhook requires --webhook-url <url>');
|
|
360
|
+
return new WebhookSink(options.webhookUrl);
|
|
361
|
+
}
|
|
362
|
+
case 'openclaw': {
|
|
363
|
+
const token = options.openclawToken ?? process.env.OPENCLAW_TOKEN;
|
|
364
|
+
if (!token)
|
|
365
|
+
throw new UsageError('--sink openclaw requires --openclaw-token or env OPENCLAW_TOKEN');
|
|
366
|
+
if (!options.openclawModel)
|
|
367
|
+
throw new UsageError('--sink openclaw requires --openclaw-model <id>');
|
|
368
|
+
return new OpenClawSink({ url: options.openclawUrl, token, model: options.openclawModel });
|
|
369
|
+
}
|
|
370
|
+
case 'telegram': {
|
|
371
|
+
const token = options.telegramToken ?? process.env.TELEGRAM_TOKEN;
|
|
372
|
+
if (!token)
|
|
373
|
+
throw new UsageError('--sink telegram requires --telegram-token or env TELEGRAM_TOKEN');
|
|
374
|
+
if (!options.telegramChat)
|
|
375
|
+
throw new UsageError('--sink telegram requires --telegram-chat <id>');
|
|
376
|
+
return new TelegramSink({ token, chatId: options.telegramChat });
|
|
377
|
+
}
|
|
378
|
+
case 'homeassistant': {
|
|
379
|
+
if (!options.haUrl)
|
|
380
|
+
throw new UsageError('--sink homeassistant requires --ha-url <url>');
|
|
381
|
+
if (!options.haWebhookId && !options.haToken) {
|
|
382
|
+
throw new UsageError('--sink homeassistant requires --ha-webhook-id or --ha-token');
|
|
383
|
+
}
|
|
384
|
+
return new HomeAssistantSink({
|
|
385
|
+
url: options.haUrl,
|
|
386
|
+
token: options.haToken,
|
|
387
|
+
webhookId: options.haWebhookId,
|
|
388
|
+
eventType: options.haEventType,
|
|
389
|
+
});
|
|
390
|
+
}
|
|
391
|
+
default:
|
|
392
|
+
throw new UsageError(`Unknown --sink type "${type}". Supported: stdout, file, webhook, openclaw, telegram, homeassistant`);
|
|
393
|
+
}
|
|
394
|
+
});
|
|
395
|
+
dispatcher = new SinkDispatcher(sinks);
|
|
396
|
+
}
|
|
397
|
+
if (!isJsonMode()) {
|
|
398
|
+
console.error('Fetching MQTT credentials from SwitchBot service…');
|
|
399
|
+
}
|
|
400
|
+
// P7: streaming JSON contract — first line under --json is the stream
|
|
401
|
+
// header (mqtt events arrive via push cadence). Must emit BEFORE
|
|
402
|
+
// __session_start so header is always the very first line.
|
|
403
|
+
if (isJsonMode())
|
|
404
|
+
emitStreamHeader({ eventKind: 'event', cadence: 'push' });
|
|
405
|
+
// Emit a __session_start envelope immediately (before any credential
|
|
406
|
+
// fetch) so JSON consumers can distinguish "connecting" from "never
|
|
407
|
+
// connected" even when mqtt-tail exits before the broker connects.
|
|
408
|
+
if (isJsonMode()) {
|
|
409
|
+
const sessionStartAt = new Date().toISOString();
|
|
410
|
+
printJson({
|
|
411
|
+
schemaVersion: EVENTS_SCHEMA_VERSION,
|
|
412
|
+
source: 'mqtt',
|
|
413
|
+
kind: 'control',
|
|
414
|
+
controlKind: 'session_start',
|
|
415
|
+
t: sessionStartAt,
|
|
416
|
+
eventId: crypto.randomUUID(),
|
|
417
|
+
state: 'connecting',
|
|
418
|
+
// Legacy (deprecated as of v2.7; removed in v3.0):
|
|
419
|
+
type: '__session_start',
|
|
420
|
+
at: sessionStartAt,
|
|
421
|
+
});
|
|
422
|
+
}
|
|
423
|
+
const credential = await fetchMqttCredential(loaded.token, loaded.secret);
|
|
424
|
+
const topic = options.topic ?? credential.topics.status;
|
|
425
|
+
let eventCount = 0;
|
|
426
|
+
const ac = new AbortController();
|
|
427
|
+
const forTimer = forMs !== null && forMs > 0
|
|
428
|
+
? setTimeout(() => ac.abort(), forMs)
|
|
429
|
+
: null;
|
|
430
|
+
const client = new SwitchBotMqttClient(credential, () => fetchMqttCredential(loaded.token, loaded.secret));
|
|
431
|
+
const unsub = client.onMessage((msgTopic, payload) => {
|
|
432
|
+
let parsed;
|
|
433
|
+
try {
|
|
434
|
+
parsed = JSON.parse(payload.toString('utf-8'));
|
|
435
|
+
}
|
|
436
|
+
catch {
|
|
437
|
+
parsed = payload.toString('utf-8');
|
|
438
|
+
}
|
|
439
|
+
const t = new Date().toISOString();
|
|
440
|
+
// Every event carries an eventId so downstream sinks / replay tools
|
|
441
|
+
// can dedupe. If the broker supplied one (some providers do via a
|
|
442
|
+
// header), prefer that; otherwise synth a UUID locally.
|
|
443
|
+
const existingId = extractEventId(parsed);
|
|
444
|
+
const eventId = existingId ?? crypto.randomUUID();
|
|
445
|
+
if (dispatcher) {
|
|
446
|
+
const { deviceId, deviceType, text } = parseSinkEvent(parsed);
|
|
447
|
+
const sinkEvent = { t, topic: msgTopic, deviceId, deviceType, payload: parsed, text, eventId };
|
|
448
|
+
deviceHistoryStore.record(deviceId, msgTopic, deviceType, parsed, t);
|
|
449
|
+
dispatcher.dispatch(sinkEvent).catch(() => { });
|
|
450
|
+
}
|
|
451
|
+
else {
|
|
452
|
+
// Default behavior: record history + print to stdout
|
|
453
|
+
const { deviceId, deviceType } = parseSinkEvent(parsed);
|
|
454
|
+
deviceHistoryStore.record(deviceId, msgTopic, deviceType, parsed, t);
|
|
455
|
+
const record = {
|
|
456
|
+
schemaVersion: EVENTS_SCHEMA_VERSION,
|
|
457
|
+
source: 'mqtt',
|
|
458
|
+
kind: 'event',
|
|
459
|
+
t,
|
|
460
|
+
eventId,
|
|
461
|
+
deviceId: deviceId ?? null,
|
|
462
|
+
topic: msgTopic,
|
|
463
|
+
payload: parsed,
|
|
464
|
+
};
|
|
465
|
+
if (isJsonMode()) {
|
|
466
|
+
printJson(record);
|
|
467
|
+
}
|
|
468
|
+
else {
|
|
469
|
+
console.log(JSON.stringify(record));
|
|
470
|
+
}
|
|
471
|
+
}
|
|
472
|
+
eventCount++;
|
|
473
|
+
if (maxEvents !== null && eventCount >= maxEvents) {
|
|
474
|
+
ac.abort();
|
|
475
|
+
}
|
|
476
|
+
});
|
|
477
|
+
let mqttFailed = false;
|
|
478
|
+
let hasConnectedBefore = false;
|
|
479
|
+
const emitControl = (kind) => {
|
|
480
|
+
const at = new Date().toISOString();
|
|
481
|
+
const controlKindMap = {
|
|
482
|
+
__connect: 'connect',
|
|
483
|
+
__reconnect: 'reconnect',
|
|
484
|
+
__disconnect: 'disconnect',
|
|
485
|
+
__heartbeat: 'heartbeat',
|
|
486
|
+
};
|
|
487
|
+
const ctl = {
|
|
488
|
+
schemaVersion: EVENTS_SCHEMA_VERSION,
|
|
489
|
+
source: 'mqtt',
|
|
490
|
+
kind: 'control',
|
|
491
|
+
controlKind: controlKindMap[kind],
|
|
492
|
+
t: at,
|
|
493
|
+
eventId: crypto.randomUUID(),
|
|
494
|
+
// Legacy (deprecated as of v2.7; removed in v3.0):
|
|
495
|
+
type: kind,
|
|
496
|
+
at,
|
|
497
|
+
};
|
|
498
|
+
// Control events always go to stdout as JSONL so consumers that
|
|
499
|
+
// filter real events by presence of `payload` can skip them.
|
|
500
|
+
if (isJsonMode()) {
|
|
501
|
+
printJson(ctl);
|
|
502
|
+
}
|
|
503
|
+
else {
|
|
504
|
+
console.log(JSON.stringify(ctl));
|
|
505
|
+
}
|
|
506
|
+
// Persist to __control.jsonl — best-effort, never blocks the stream.
|
|
507
|
+
try {
|
|
508
|
+
deviceHistoryStore.recordControl(ctl);
|
|
509
|
+
}
|
|
510
|
+
catch {
|
|
511
|
+
// swallow
|
|
512
|
+
}
|
|
513
|
+
};
|
|
514
|
+
const unsubState = client.onStateChange((state) => {
|
|
515
|
+
if (!isJsonMode()) {
|
|
516
|
+
console.error(`[${new Date().toLocaleTimeString()}] MQTT state: ${state}`);
|
|
517
|
+
}
|
|
518
|
+
if (state === 'connected') {
|
|
519
|
+
emitControl(hasConnectedBefore ? '__reconnect' : '__connect');
|
|
520
|
+
hasConnectedBefore = true;
|
|
521
|
+
}
|
|
522
|
+
else if (state === 'reconnecting') {
|
|
523
|
+
emitControl('__disconnect');
|
|
524
|
+
}
|
|
525
|
+
else if (state === 'failed') {
|
|
526
|
+
mqttFailed = true;
|
|
527
|
+
emitControl('__disconnect');
|
|
528
|
+
if (!isJsonMode()) {
|
|
529
|
+
console.error('MQTT connection failed permanently (credential expired or reconnect exhausted) — exiting.');
|
|
530
|
+
}
|
|
531
|
+
ac.abort();
|
|
532
|
+
}
|
|
533
|
+
});
|
|
534
|
+
await client.connect();
|
|
535
|
+
client.subscribe(topic);
|
|
536
|
+
if (!isJsonMode()) {
|
|
537
|
+
console.error(`Connected to ${credential.brokerUrl} (Ctrl-C to stop)`);
|
|
538
|
+
}
|
|
539
|
+
await new Promise((resolve) => {
|
|
540
|
+
const cleanup = () => {
|
|
541
|
+
if (forTimer)
|
|
542
|
+
clearTimeout(forTimer);
|
|
543
|
+
process.removeListener('SIGINT', cleanup);
|
|
544
|
+
process.removeListener('SIGTERM', cleanup);
|
|
545
|
+
unsub();
|
|
546
|
+
unsubState();
|
|
547
|
+
dispatcher?.close().catch(() => { });
|
|
548
|
+
client.disconnect().then(resolve).catch(resolve);
|
|
549
|
+
};
|
|
550
|
+
process.once('SIGINT', cleanup);
|
|
551
|
+
process.once('SIGTERM', cleanup);
|
|
552
|
+
ac.signal.addEventListener('abort', cleanup, { once: true });
|
|
553
|
+
});
|
|
554
|
+
if (mqttFailed) {
|
|
555
|
+
// Surface as a runtime error so supervisors (pm2, systemd) can restart.
|
|
556
|
+
process.exit(1);
|
|
557
|
+
}
|
|
558
|
+
}
|
|
559
|
+
catch (error) {
|
|
560
|
+
handleError(error);
|
|
561
|
+
}
|
|
562
|
+
});
|
|
563
|
+
}
|
|
564
|
+
//# sourceMappingURL=events.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"events.js","sourceRoot":"","sources":["../../src/commands/events.ts"],"names":[],"mappings":"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"}
|