@switchbot/homebridge-switchbot 5.0.0-beta.98 → 5.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.changeset/config.json +14 -0
- package/.github/copilot-instructions.md +39 -0
- package/.github/workflows/ci.yml +4 -1
- package/.github/workflows/manual-e2e.yml +6 -3
- package/.github/workflows/release.yml +64 -15
- package/.github/workflows/stale.yml +2 -4
- package/.husky/pre-push +15 -0
- package/CHANGELOG.md +126 -134
- package/MIGRATION.md +16 -6
- package/README.md +84 -3
- package/TODO.md +263 -0
- package/config.schema.json +229 -36
- package/dist/SwitchBotHAPPlatform.d.ts +133 -0
- package/dist/SwitchBotHAPPlatform.d.ts.map +1 -0
- package/dist/SwitchBotHAPPlatform.js +555 -0
- package/dist/SwitchBotHAPPlatform.js.map +1 -0
- package/dist/SwitchBotMatterPlatform.d.ts +141 -0
- package/dist/SwitchBotMatterPlatform.d.ts.map +1 -0
- package/dist/SwitchBotMatterPlatform.js +536 -0
- package/dist/SwitchBotMatterPlatform.js.map +1 -0
- package/dist/device-types.d.ts +31 -0
- package/dist/device-types.d.ts.map +1 -0
- package/dist/device-types.js +246 -0
- package/dist/device-types.js.map +1 -0
- package/dist/deviceCommandMapper.d.ts +10 -0
- package/dist/deviceCommandMapper.d.ts.map +1 -0
- package/dist/deviceCommandMapper.js +319 -0
- package/dist/deviceCommandMapper.js.map +1 -0
- package/dist/deviceFactory.d.ts +3 -2
- package/dist/deviceFactory.d.ts.map +1 -1
- package/dist/deviceFactory.js +107 -29
- package/dist/deviceFactory.js.map +1 -1
- package/dist/devices/genericDevice.d.ts +59 -37
- package/dist/devices/genericDevice.d.ts.map +1 -1
- package/dist/devices/genericDevice.js +376 -78
- package/dist/devices/genericDevice.js.map +1 -1
- package/dist/errors.d.ts +38 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +32 -0
- package/dist/errors.js.map +1 -0
- package/dist/homebridge-ui/device-types.js +246 -0
- package/dist/homebridge-ui/device-types.js.map +1 -0
- package/dist/homebridge-ui/deviceCommandMapper.js +319 -0
- package/dist/homebridge-ui/deviceCommandMapper.js.map +1 -0
- package/dist/homebridge-ui/endpoints/config.d.ts +3 -0
- package/dist/homebridge-ui/endpoints/config.d.ts.map +1 -0
- package/dist/homebridge-ui/endpoints/config.js +90 -0
- package/dist/homebridge-ui/endpoints/config.js.map +1 -0
- package/dist/homebridge-ui/endpoints/devices.d.ts +6 -0
- package/dist/homebridge-ui/endpoints/devices.d.ts.map +1 -0
- package/dist/homebridge-ui/endpoints/devices.js +144 -0
- package/dist/homebridge-ui/endpoints/devices.js.map +1 -0
- package/dist/homebridge-ui/endpoints/discovery.d.ts +7 -0
- package/dist/homebridge-ui/endpoints/discovery.d.ts.map +1 -0
- package/dist/homebridge-ui/endpoints/discovery.js +219 -0
- package/dist/homebridge-ui/endpoints/discovery.js.map +1 -0
- package/dist/homebridge-ui/errors.js +32 -0
- package/dist/homebridge-ui/errors.js.map +1 -0
- package/dist/homebridge-ui/homebridge-ui/endpoints/config.js +90 -0
- package/dist/homebridge-ui/homebridge-ui/endpoints/config.js.map +1 -0
- package/dist/homebridge-ui/homebridge-ui/endpoints/devices.js +144 -0
- package/dist/homebridge-ui/homebridge-ui/endpoints/devices.js.map +1 -0
- package/dist/homebridge-ui/homebridge-ui/endpoints/discovery.js +219 -0
- package/dist/homebridge-ui/homebridge-ui/endpoints/discovery.js.map +1 -0
- package/dist/homebridge-ui/homebridge-ui/server.js +11 -0
- package/dist/homebridge-ui/homebridge-ui/server.js.map +1 -0
- package/dist/homebridge-ui/homebridge-ui/utils/config-parser.js +108 -0
- package/dist/homebridge-ui/homebridge-ui/utils/config-parser.js.map +1 -0
- package/dist/homebridge-ui/homebridge-ui/utils/device-migration.js +111 -0
- package/dist/homebridge-ui/homebridge-ui/utils/device-migration.js.map +1 -0
- package/dist/homebridge-ui/homebridge-ui/utils/logger.js +17 -0
- package/dist/homebridge-ui/homebridge-ui/utils/logger.js.map +1 -0
- package/dist/homebridge-ui/public/css/styles.css +483 -0
- package/dist/homebridge-ui/public/index.html +197 -621
- package/dist/homebridge-ui/public/js/advanced-settings.d.ts +3 -0
- package/dist/homebridge-ui/public/js/advanced-settings.d.ts.map +1 -0
- package/dist/homebridge-ui/public/js/advanced-settings.js +95 -0
- package/dist/homebridge-ui/public/js/advanced-settings.js.map +1 -0
- package/dist/homebridge-ui/public/js/advanced-settings.ts +94 -0
- package/dist/homebridge-ui/public/js/api.d.ts +66 -0
- package/dist/homebridge-ui/public/js/api.d.ts.map +1 -0
- package/dist/homebridge-ui/public/js/api.js +295 -0
- package/dist/homebridge-ui/public/js/api.js.map +1 -0
- package/dist/homebridge-ui/public/js/api.ts +355 -0
- package/dist/homebridge-ui/public/js/app.d.ts +2 -0
- package/dist/homebridge-ui/public/js/app.d.ts.map +1 -0
- package/dist/homebridge-ui/public/js/app.js +3722 -0
- package/dist/homebridge-ui/public/js/app.js.map +7 -0
- package/dist/homebridge-ui/public/js/app.ts +22 -0
- package/dist/homebridge-ui/public/js/constants.d.ts +2 -0
- package/dist/homebridge-ui/public/js/constants.d.ts.map +1 -0
- package/dist/homebridge-ui/public/js/constants.js +2 -0
- package/dist/homebridge-ui/public/js/constants.js.map +1 -0
- package/dist/homebridge-ui/public/js/constants.ts +1 -0
- package/dist/homebridge-ui/public/js/credentials.d.ts +3 -0
- package/dist/homebridge-ui/public/js/credentials.d.ts.map +1 -0
- package/dist/homebridge-ui/public/js/credentials.js +99 -0
- package/dist/homebridge-ui/public/js/credentials.js.map +1 -0
- package/dist/homebridge-ui/public/js/credentials.ts +105 -0
- package/dist/homebridge-ui/public/js/devices-delete.d.ts +3 -0
- package/dist/homebridge-ui/public/js/devices-delete.d.ts.map +1 -0
- package/dist/homebridge-ui/public/js/devices-delete.js +199 -0
- package/dist/homebridge-ui/public/js/devices-delete.js.map +1 -0
- package/dist/homebridge-ui/public/js/devices-delete.ts +227 -0
- package/dist/homebridge-ui/public/js/devices.d.ts +9 -0
- package/dist/homebridge-ui/public/js/devices.d.ts.map +1 -0
- package/dist/homebridge-ui/public/js/devices.js +98 -0
- package/dist/homebridge-ui/public/js/devices.js.map +1 -0
- package/dist/homebridge-ui/public/js/devices.ts +106 -0
- package/dist/homebridge-ui/public/js/discovery.d.ts +9 -0
- package/dist/homebridge-ui/public/js/discovery.d.ts.map +1 -0
- package/dist/homebridge-ui/public/js/discovery.js +1201 -0
- package/dist/homebridge-ui/public/js/discovery.js.map +1 -0
- package/dist/homebridge-ui/public/js/discovery.ts +1335 -0
- package/dist/homebridge-ui/public/js/logger.d.ts +7 -0
- package/dist/homebridge-ui/public/js/logger.d.ts.map +1 -0
- package/dist/homebridge-ui/public/js/logger.js +17 -0
- package/dist/homebridge-ui/public/js/logger.js.map +1 -0
- package/dist/homebridge-ui/public/js/logger.ts +17 -0
- package/dist/homebridge-ui/public/js/modal.d.ts +5 -0
- package/dist/homebridge-ui/public/js/modal.d.ts.map +1 -0
- package/dist/homebridge-ui/public/js/modal.js +35 -0
- package/dist/homebridge-ui/public/js/modal.js.map +1 -0
- package/dist/homebridge-ui/public/js/modal.ts +35 -0
- package/dist/homebridge-ui/public/js/modals.d.ts +15 -0
- package/dist/homebridge-ui/public/js/modals.d.ts.map +1 -0
- package/dist/homebridge-ui/public/js/modals.js +675 -0
- package/dist/homebridge-ui/public/js/modals.js.map +1 -0
- package/dist/homebridge-ui/public/js/modals.ts +765 -0
- package/dist/homebridge-ui/public/js/render.d.ts +71 -0
- package/dist/homebridge-ui/public/js/render.d.ts.map +1 -0
- package/dist/homebridge-ui/public/js/render.js +960 -0
- package/dist/homebridge-ui/public/js/render.js.map +1 -0
- package/dist/homebridge-ui/public/js/render.ts +1084 -0
- package/dist/homebridge-ui/public/js/toast.d.ts +6 -0
- package/dist/homebridge-ui/public/js/toast.d.ts.map +1 -0
- package/dist/homebridge-ui/public/js/toast.js +38 -0
- package/dist/homebridge-ui/public/js/toast.js.map +1 -0
- package/dist/homebridge-ui/public/js/toast.ts +44 -0
- package/dist/homebridge-ui/public/js/types.d.ts +23 -0
- package/dist/homebridge-ui/public/js/types.d.ts.map +1 -0
- package/dist/homebridge-ui/public/js/types.js +2 -0
- package/dist/homebridge-ui/public/js/types.js.map +1 -0
- package/dist/homebridge-ui/public/js/types.ts +26 -0
- package/dist/homebridge-ui/server.d.ts +1 -3
- package/dist/homebridge-ui/server.d.ts.map +1 -1
- package/dist/homebridge-ui/server.js +8 -450
- package/dist/homebridge-ui/server.js.map +1 -1
- package/dist/homebridge-ui/settings.js +8 -0
- package/dist/homebridge-ui/settings.js.map +1 -0
- package/dist/homebridge-ui/switchbotClient.js +247 -0
- package/dist/homebridge-ui/switchbotClient.js.map +1 -0
- package/dist/homebridge-ui/utils/config-parser.d.ts +39 -0
- package/dist/homebridge-ui/utils/config-parser.d.ts.map +1 -0
- package/dist/homebridge-ui/utils/config-parser.js +108 -0
- package/dist/homebridge-ui/utils/config-parser.js.map +1 -0
- package/dist/homebridge-ui/utils/device-migration.d.ts +35 -0
- package/dist/homebridge-ui/utils/device-migration.d.ts.map +1 -0
- package/dist/homebridge-ui/utils/device-migration.js +111 -0
- package/dist/homebridge-ui/utils/device-migration.js.map +1 -0
- package/dist/homebridge-ui/utils/logger.d.ts +7 -0
- package/dist/homebridge-ui/utils/logger.d.ts.map +1 -0
- package/dist/homebridge-ui/utils/logger.js +17 -0
- package/dist/homebridge-ui/utils/logger.js.map +1 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +12 -2
- package/dist/index.js.map +1 -1
- package/dist/settings.d.ts +1 -0
- package/dist/settings.d.ts.map +1 -1
- package/dist/settings.js +1 -0
- package/dist/settings.js.map +1 -1
- package/dist/switchbotClient.d.ts +12 -10
- package/dist/switchbotClient.d.ts.map +1 -1
- package/dist/switchbotClient.js +156 -103
- package/dist/switchbotClient.js.map +1 -1
- package/dist/utils.d.ts +76 -1
- package/dist/utils.d.ts.map +1 -1
- package/dist/utils.js +1121 -4
- package/dist/utils.js.map +1 -1
- package/docs/assets/highlight.css +16 -2
- package/docs/assets/main.js +1 -1
- package/docs/index.html +82 -5
- package/docs/variables/default.html +3 -1
- package/eslint.config.js +9 -5
- package/nodemon.json +2 -2
- package/package.json +34 -21
- package/scripts/build-ui.js +37 -0
- package/scripts/free-dev-ports.mjs +105 -0
- package/scripts/generate-matter-maps.js +34 -17
- package/scripts/sync-device-types.mjs +31 -0
- package/src/SwitchBotHAPPlatform.ts +558 -0
- package/src/SwitchBotMatterPlatform.ts +538 -0
- package/src/device-types.js +246 -0
- package/src/device-types.js.map +1 -0
- package/src/device-types.ts +261 -0
- package/src/deviceCommandMapper.js +319 -0
- package/src/deviceCommandMapper.js.map +1 -0
- package/src/deviceCommandMapper.ts +333 -0
- package/src/deviceFactory.ts +125 -45
- package/src/devices/genericDevice.ts +411 -69
- package/src/errors.js +32 -0
- package/src/errors.js.map +1 -0
- package/src/errors.ts +35 -0
- package/src/homebridge-ui/endpoints/config.ts +110 -0
- package/src/homebridge-ui/endpoints/devices.ts +153 -0
- package/src/homebridge-ui/endpoints/discovery.ts +240 -0
- package/src/homebridge-ui/public/css/styles.css +483 -0
- package/src/homebridge-ui/public/index.html +197 -621
- package/src/homebridge-ui/public/js/advanced-settings.ts +94 -0
- package/src/homebridge-ui/public/js/api.ts +355 -0
- package/src/homebridge-ui/public/js/app.ts +22 -0
- package/src/homebridge-ui/public/js/constants.ts +1 -0
- package/src/homebridge-ui/public/js/credentials.ts +105 -0
- package/src/homebridge-ui/public/js/devices-delete.ts +227 -0
- package/src/homebridge-ui/public/js/devices.ts +106 -0
- package/src/homebridge-ui/public/js/discovery.ts +1335 -0
- package/src/homebridge-ui/public/js/logger.ts +17 -0
- package/src/homebridge-ui/public/js/modal.ts +35 -0
- package/src/homebridge-ui/public/js/modals.ts +765 -0
- package/src/homebridge-ui/public/js/render.ts +1084 -0
- package/src/homebridge-ui/public/js/toast.ts +44 -0
- package/src/homebridge-ui/public/js/types.ts +26 -0
- package/src/homebridge-ui/server.ts +9 -526
- package/src/homebridge-ui/utils/config-parser.ts +125 -0
- package/src/homebridge-ui/utils/device-migration.ts +144 -0
- package/src/homebridge-ui/utils/logger.ts +17 -0
- package/src/index.ts +12 -2
- package/src/settings.js +8 -0
- package/src/settings.js.map +1 -0
- package/src/settings.ts +2 -0
- package/src/switchbotClient.js +247 -0
- package/src/switchbotClient.js.map +1 -0
- package/src/switchbotClient.ts +177 -114
- package/src/utils.ts +1133 -5
- package/test/client/switchbot-client-debounce.spec.ts +35 -0
- package/test/client/switchbot-client-openapi.spec.ts +19 -0
- package/test/client/switchbotClient.spec.ts +64 -0
- package/test/device/device-mapping.spec.ts +23 -0
- package/test/device/deviceBase.spec.ts +26 -0
- package/test/device/deviceFactory-edge.spec.ts +15 -0
- package/test/device/deviceFactory.spec.ts +33 -0
- package/test/device/fan-swing.spec.ts +34 -0
- package/test/device/genericDevice-blepoll.spec.ts +47 -0
- package/test/device/irdevice.spec.ts +9 -0
- package/test/device/lock-users.spec.ts +35 -0
- package/test/device/matter-descriptors.spec.ts +22 -0
- package/test/device/matter-device-state.spec.ts +37 -0
- package/test/e2e/run-e2e.spec.ts +18 -19
- package/test/errors/errors.spec.ts +10 -0
- package/test/helpers/matter-harness.ts +20 -9
- package/test/homebridge-ui/server.spec.ts +9 -0
- package/test/platform/accessory-restore.spec.ts +37 -0
- package/test/platform/matter-childbridge.spec.ts +34 -0
- package/test/platform/matter-integration.spec.ts +33 -0
- package/test/platform/platform-edge.spec.ts +73 -0
- package/test/platform/platform.integration.spec.ts +34 -0
- package/test/utils/utils-extra.spec.ts +10 -0
- package/test/utils/utils.spec.ts +53 -0
- package/todo/TODO.md +80 -0
- package/tsconfig.ui.json +11 -0
- package/.github/npm-version-script-esm.js +0 -97
- package/.github/workflows/beta-release.yml +0 -52
- package/dist/platform.d.ts +0 -35
- package/dist/platform.d.ts.map +0 -1
- package/dist/platform.js +0 -850
- package/dist/platform.js.map +0 -1
- package/src/platform.ts +0 -867
- package/test/accessory-restore.spec.ts +0 -73
- package/test/device-mapping.spec.ts +0 -37
- package/test/deviceFactory.spec.ts +0 -18
- package/test/fan-swing.spec.ts +0 -29
- package/test/lock-users.spec.ts +0 -44
- package/test/matter-childbridge.spec.ts +0 -55
- package/test/matter-descriptors.spec.ts +0 -97
- package/test/matter-device-state.spec.ts +0 -101
- package/test/matter-integration.spec.ts +0 -70
- package/test/platform.integration.spec.ts +0 -55
- package/test/switchbot-client-debounce.spec.ts +0 -131
- package/test/switchbot-client-openapi.spec.ts +0 -56
- package/test/switchbotClient.spec.ts +0 -10
- package/test/utils.spec.ts +0 -20
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
import { RequestError } from '@homebridge/plugin-ui-utils';
|
|
2
|
+
import { getCredential, getSwitchBotPlatformConfig } from '../utils/config-parser.js';
|
|
3
|
+
import { uiLog } from '../utils/logger.js';
|
|
4
|
+
/**
|
|
5
|
+
* Register discovery endpoint
|
|
6
|
+
* Discovers SwitchBot devices via BLE and OpenAPI
|
|
7
|
+
*/
|
|
8
|
+
export function registerDiscoveryEndpoint(server) {
|
|
9
|
+
server.onRequest('/ble-status', async () => {
|
|
10
|
+
try {
|
|
11
|
+
const { platform } = await getSwitchBotPlatformConfig(server);
|
|
12
|
+
const token = getCredential(platform, 'openApiToken') || platform.token;
|
|
13
|
+
const secret = getCredential(platform, 'openApiSecret') || platform.secret;
|
|
14
|
+
const { SwitchBot } = await import('node-switchbot');
|
|
15
|
+
const switchbot = new SwitchBot({
|
|
16
|
+
token: token || undefined,
|
|
17
|
+
secret: secret || undefined,
|
|
18
|
+
enableBLE: true,
|
|
19
|
+
enableFallback: true,
|
|
20
|
+
enableRetry: true,
|
|
21
|
+
enableCircuitBreaker: true,
|
|
22
|
+
enableConnectionIntelligence: true,
|
|
23
|
+
});
|
|
24
|
+
await switchbot.discover({ timeout: 1000 });
|
|
25
|
+
return { success: true, data: { available: true, message: 'adapter ready' } };
|
|
26
|
+
}
|
|
27
|
+
catch (e) {
|
|
28
|
+
const message = e instanceof Error ? e.message : String(e);
|
|
29
|
+
uiLog.warn(`GET /ble-status failed: ${message}`);
|
|
30
|
+
return { success: true, data: { available: false, message } };
|
|
31
|
+
}
|
|
32
|
+
});
|
|
33
|
+
server.onRequest('/discover', async (payload) => {
|
|
34
|
+
uiLog.debug(`[SwitchBot UI/Server] /discover incoming payload: ${JSON.stringify(payload)}`);
|
|
35
|
+
try {
|
|
36
|
+
const { platform } = await getSwitchBotPlatformConfig(server);
|
|
37
|
+
const mode = String(payload?.mode || 'all').toLowerCase();
|
|
38
|
+
// Only run BLE if mode is all/ble AND bleEnabled is not false (default true if missing)
|
|
39
|
+
const bleEnabled = payload?.bleEnabled !== false;
|
|
40
|
+
const runBle = (mode === 'all' || mode === 'ble') && bleEnabled;
|
|
41
|
+
const runOpenApi = mode === 'all' || mode === 'openapi';
|
|
42
|
+
const bleScanDurationSeconds = Math.max(3, Math.min(15, Number(payload?.bleScanDurationSeconds || 5)));
|
|
43
|
+
const bleTimeoutSeconds = Math.max(3, Math.min(30, Number(payload?.bleTimeoutSeconds || 8)));
|
|
44
|
+
uiLog.debug(`GET /discover - Platform config keys: ${Object.keys(platform).join(', ')}`);
|
|
45
|
+
const token = getCredential(platform, 'openApiToken') || platform.token;
|
|
46
|
+
const secret = getCredential(platform, 'openApiSecret') || platform.secret;
|
|
47
|
+
const hasOpenAPICredentials = !!(token && secret);
|
|
48
|
+
if (!hasOpenAPICredentials) {
|
|
49
|
+
uiLog.warn('GET /discover - No OpenAPI credentials found, will attempt BLE-only discovery');
|
|
50
|
+
}
|
|
51
|
+
else {
|
|
52
|
+
uiLog.info('GET /discover - Using OpenAPI credentials for discovery');
|
|
53
|
+
}
|
|
54
|
+
// Import and initialize node-switchbot
|
|
55
|
+
const { SwitchBot } = await import('node-switchbot');
|
|
56
|
+
const switchbot = new SwitchBot({
|
|
57
|
+
token: token || undefined,
|
|
58
|
+
secret: secret || undefined,
|
|
59
|
+
enableBLE: true,
|
|
60
|
+
enableFallback: true,
|
|
61
|
+
enableRetry: true,
|
|
62
|
+
enableCircuitBreaker: true,
|
|
63
|
+
enableConnectionIntelligence: true,
|
|
64
|
+
});
|
|
65
|
+
const deviceMap = new Map();
|
|
66
|
+
// 1. Try BLE discovery first (with timeout)
|
|
67
|
+
if (runBle) {
|
|
68
|
+
uiLog.info('GET /discover - Starting BLE scan...');
|
|
69
|
+
try {
|
|
70
|
+
const bleTimeout = bleTimeoutSeconds * 1000;
|
|
71
|
+
const bleDiscoveryPromise = switchbot.discover({ timeout: bleScanDurationSeconds * 1000 });
|
|
72
|
+
const bleDevices = await Promise.race([
|
|
73
|
+
bleDiscoveryPromise,
|
|
74
|
+
new Promise(resolve => setTimeout(resolve, bleTimeout, [])),
|
|
75
|
+
]);
|
|
76
|
+
if (Array.isArray(bleDevices) && bleDevices.length > 0) {
|
|
77
|
+
uiLog.info(`GET /discover - Found ${bleDevices.length} BLE devices`);
|
|
78
|
+
for (const [index, d] of bleDevices.entries()) {
|
|
79
|
+
const info = typeof d?.getInfo === 'function' ? d.getInfo() : undefined;
|
|
80
|
+
const id = d?.id
|
|
81
|
+
|| (typeof d?.getId === 'function' ? d.getId() : undefined)
|
|
82
|
+
|| info?.id;
|
|
83
|
+
const mac = d?.mac
|
|
84
|
+
|| (typeof d?.getMAC === 'function' ? d.getMAC() : undefined)
|
|
85
|
+
|| info?.mac;
|
|
86
|
+
if (!id) {
|
|
87
|
+
uiLog.warn(`GET /discover - BLE device at index ${index} has no id, skipping`);
|
|
88
|
+
continue;
|
|
89
|
+
}
|
|
90
|
+
const connectionTypes = Array.isArray(info?.connectionTypes) ? info.connectionTypes : [];
|
|
91
|
+
const isHybrid = connectionTypes.includes('api');
|
|
92
|
+
deviceMap.set(id, {
|
|
93
|
+
id,
|
|
94
|
+
name: d?.name || (typeof d?.getName === 'function' ? d.getName() : undefined) || info?.name || d?.deviceName || id,
|
|
95
|
+
type: d?.deviceType || (typeof d?.getDeviceType === 'function' ? d.getDeviceType() : undefined) || info?.deviceType || d?.type || d?.model || 'unknown',
|
|
96
|
+
model: info?.model || d?.model || d?.deviceModel,
|
|
97
|
+
address: mac,
|
|
98
|
+
connectionType: isHybrid ? 'Both' : 'BLE',
|
|
99
|
+
rssi: info?.rssi || d?.rssi,
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
else {
|
|
104
|
+
uiLog.info('GET /discover - No BLE devices found or scan timed out');
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
catch (bleErr) {
|
|
108
|
+
uiLog.warn(`GET /discover - BLE discovery failed: ${bleErr instanceof Error ? bleErr.message : String(bleErr)}`);
|
|
109
|
+
// Continue with OpenAPI even if BLE fails
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
// 2. Get devices from OpenAPI (only if credentials are available)
|
|
113
|
+
if (runOpenApi && hasOpenAPICredentials) {
|
|
114
|
+
uiLog.info('GET /discover - Fetching devices from OpenAPI...');
|
|
115
|
+
try {
|
|
116
|
+
const apiClient = switchbot.getAPIClient();
|
|
117
|
+
if (!apiClient) {
|
|
118
|
+
throw new Error('API client not available - token/secret may be missing');
|
|
119
|
+
}
|
|
120
|
+
const apiData = await apiClient.getDevices();
|
|
121
|
+
uiLog.debug(`GET /discover - OpenAPI response: ${JSON.stringify(apiData)}`);
|
|
122
|
+
// Parse physical devices - apiData is DeviceListResponse with deviceList and infraredRemoteList
|
|
123
|
+
const devices = apiData.deviceList || [];
|
|
124
|
+
const irDevices = apiData.infraredRemoteList || [];
|
|
125
|
+
uiLog.info(`GET /discover - Found ${devices.length} OpenAPI physical devices and ${irDevices.length} IR devices`);
|
|
126
|
+
// Process physical devices from OpenAPI
|
|
127
|
+
for (const d of devices) {
|
|
128
|
+
const id = d.deviceId;
|
|
129
|
+
if (!id) {
|
|
130
|
+
continue;
|
|
131
|
+
}
|
|
132
|
+
const existing = deviceMap.get(id);
|
|
133
|
+
if (existing) {
|
|
134
|
+
// Device found via both BLE and OpenAPI
|
|
135
|
+
existing.connectionType = 'Both';
|
|
136
|
+
existing.name = d.deviceName || existing.name;
|
|
137
|
+
existing.type = d.deviceType || existing.type;
|
|
138
|
+
// Note: APIDevice doesn't have a model property
|
|
139
|
+
existing.enabled = d.enableCloudService !== false;
|
|
140
|
+
existing.hubDeviceId = d.hubDeviceId;
|
|
141
|
+
}
|
|
142
|
+
else {
|
|
143
|
+
// Device only found via OpenAPI
|
|
144
|
+
deviceMap.set(id, {
|
|
145
|
+
id,
|
|
146
|
+
name: d.deviceName || id,
|
|
147
|
+
type: d.deviceType || 'unknown',
|
|
148
|
+
enabled: d.enableCloudService !== false,
|
|
149
|
+
hubDeviceId: d.hubDeviceId,
|
|
150
|
+
connectionType: 'OpenAPI',
|
|
151
|
+
});
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
// Process IR devices (OpenAPI only)
|
|
155
|
+
for (const d of irDevices) {
|
|
156
|
+
const id = d.deviceId;
|
|
157
|
+
if (!id) {
|
|
158
|
+
continue;
|
|
159
|
+
}
|
|
160
|
+
deviceMap.set(id, {
|
|
161
|
+
id,
|
|
162
|
+
name: d.deviceName || id,
|
|
163
|
+
type: d.remoteType || 'unknown',
|
|
164
|
+
enabled: true,
|
|
165
|
+
hubDeviceId: d.hubDeviceId,
|
|
166
|
+
connectionType: 'OpenAPI',
|
|
167
|
+
isIR: true,
|
|
168
|
+
});
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
catch (apiErr) {
|
|
172
|
+
uiLog.error(`GET /discover - OpenAPI discovery failed: ${apiErr instanceof Error ? apiErr.message : String(apiErr)}`);
|
|
173
|
+
// If we have BLE devices, we can still return those
|
|
174
|
+
if (deviceMap.size === 0) {
|
|
175
|
+
throw apiErr;
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
else if (runOpenApi) {
|
|
180
|
+
uiLog.info('GET /discover - Skipping OpenAPI discovery (no credentials configured)');
|
|
181
|
+
}
|
|
182
|
+
const normalizedBleDevices = [...deviceMap.values()].filter(d => d.connectionType === 'BLE' || d.connectionType === 'Both');
|
|
183
|
+
const firstNormalizedBleId = normalizedBleDevices[0]?.id || 'none';
|
|
184
|
+
uiLog.info(`GET /discover - Normalized BLE devices: ${normalizedBleDevices.length} (firstId: ${firstNormalizedBleId})`);
|
|
185
|
+
// Check if we found any devices
|
|
186
|
+
if (deviceMap.size === 0 && mode === 'openapi' && !hasOpenAPICredentials) {
|
|
187
|
+
return { success: true, data: [] };
|
|
188
|
+
}
|
|
189
|
+
if (deviceMap.size === 0) {
|
|
190
|
+
const errorMsg = hasOpenAPICredentials
|
|
191
|
+
? 'No devices found via BLE or OpenAPI. Make sure devices are powered on and in range.'
|
|
192
|
+
: 'No devices found via BLE. OpenAPI credentials not configured. Please save your credentials in settings to discover cloud-connected devices, or ensure BLE devices are powered on and in range.';
|
|
193
|
+
uiLog.error(`GET /discover - ${errorMsg}`);
|
|
194
|
+
throw new Error(errorMsg);
|
|
195
|
+
}
|
|
196
|
+
// Convert map to array
|
|
197
|
+
const allDiscovered = [...deviceMap.values()];
|
|
198
|
+
const bleCount = allDiscovered.filter(d => d.connectionType === 'BLE').length;
|
|
199
|
+
const apiCount = allDiscovered.filter(d => d.connectionType === 'OpenAPI').length;
|
|
200
|
+
const bothCount = allDiscovered.filter(d => d.connectionType === 'Both').length;
|
|
201
|
+
uiLog.info(`GET /discover - Total: ${allDiscovered.length} devices (BLE: ${bleCount}, OpenAPI: ${apiCount}, Both: ${bothCount})`);
|
|
202
|
+
return { success: true, data: allDiscovered };
|
|
203
|
+
}
|
|
204
|
+
catch (e) {
|
|
205
|
+
if (e instanceof Error) {
|
|
206
|
+
uiLog.error(`Error in /discover: ${e.message}`);
|
|
207
|
+
if (e.stack) {
|
|
208
|
+
uiLog.error(`[Stack] ${e.stack}`);
|
|
209
|
+
}
|
|
210
|
+
uiLog.error(`[Object]`, e);
|
|
211
|
+
}
|
|
212
|
+
else {
|
|
213
|
+
uiLog.error(`Error in /discover: ${String(e)}`);
|
|
214
|
+
}
|
|
215
|
+
throw new RequestError(`Failed to discover devices: ${e instanceof Error ? e.message : String(e)}`, e);
|
|
216
|
+
}
|
|
217
|
+
});
|
|
218
|
+
}
|
|
219
|
+
//# sourceMappingURL=discovery.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"discovery.js","sourceRoot":"","sources":["../../../../src/homebridge-ui/endpoints/discovery.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { HomebridgePluginUiServer } from '@homebridge/plugin-ui-utils';
|
|
2
|
+
import { registerConfigEndpoints } from './endpoints/config.js';
|
|
3
|
+
import { registerDeviceEndpoints } from './endpoints/devices.js';
|
|
4
|
+
import { registerDiscoveryEndpoint } from './endpoints/discovery.js';
|
|
5
|
+
const server = new HomebridgePluginUiServer();
|
|
6
|
+
// Register all endpoints
|
|
7
|
+
registerConfigEndpoints(server);
|
|
8
|
+
registerDiscoveryEndpoint(server);
|
|
9
|
+
registerDeviceEndpoints(server);
|
|
10
|
+
server.ready();
|
|
11
|
+
//# sourceMappingURL=server.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server.js","sourceRoot":"","sources":["../../../src/homebridge-ui/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,wBAAwB,EAAE,MAAM,6BAA6B,CAAA;AAEtE,OAAO,EAAE,uBAAuB,EAAE,MAAM,uBAAuB,CAAA;AAC/D,OAAO,EAAE,uBAAuB,EAAE,MAAM,wBAAwB,CAAA;AAChE,OAAO,EAAE,yBAAyB,EAAE,MAAM,0BAA0B,CAAA;AAEpE,MAAM,MAAM,GAAG,IAAI,wBAAwB,EAAE,CAAA;AAE7C,yBAAyB;AACzB,uBAAuB,CAAC,MAAM,CAAC,CAAA;AAC/B,yBAAyB,CAAC,MAAM,CAAC,CAAA;AACjC,uBAAuB,CAAC,MAAM,CAAC,CAAA;AAE/B,MAAM,CAAC,KAAK,EAAE,CAAA"}
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Ensure required fields are present on the SwitchBot platform config
|
|
3
|
+
*/
|
|
4
|
+
export function enforcePlatformConfigFields(platform) {
|
|
5
|
+
if (!platform)
|
|
6
|
+
return;
|
|
7
|
+
if (!platform.platform)
|
|
8
|
+
platform.platform = 'SwitchBot';
|
|
9
|
+
if (!platform.name)
|
|
10
|
+
platform.name = 'SwitchBot';
|
|
11
|
+
if (!Array.isArray(platform.devices))
|
|
12
|
+
platform.devices = [];
|
|
13
|
+
}
|
|
14
|
+
import fs from 'node:fs/promises';
|
|
15
|
+
import { uiLog } from './logger.js';
|
|
16
|
+
// Module-scope regex pattern to avoid recompilation
|
|
17
|
+
export const SWITCHBOT_PLATFORM_REGEX = /switchbot/i;
|
|
18
|
+
/**
|
|
19
|
+
* Get reference to the devices array in platform config
|
|
20
|
+
*/
|
|
21
|
+
export function getDevicesRef(platform) {
|
|
22
|
+
if (!platform || typeof platform !== 'object') {
|
|
23
|
+
return [];
|
|
24
|
+
}
|
|
25
|
+
if (Array.isArray(platform.devices)) {
|
|
26
|
+
return platform.devices;
|
|
27
|
+
}
|
|
28
|
+
platform.devices = [];
|
|
29
|
+
return platform.devices;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Get all device arrays from platform config
|
|
33
|
+
*/
|
|
34
|
+
export function getDeviceArrays(platform) {
|
|
35
|
+
const rootDevices = getDevicesRef(platform);
|
|
36
|
+
return [rootDevices];
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Get all unique devices from platform config
|
|
40
|
+
*/
|
|
41
|
+
export function getAllDevices(platform) {
|
|
42
|
+
const all = getDevicesRef(platform);
|
|
43
|
+
const seen = new Set();
|
|
44
|
+
return all.filter((d) => {
|
|
45
|
+
const id = String(d?.deviceId ?? d?.id ?? '').trim().toLowerCase();
|
|
46
|
+
if (!id || seen.has(id)) {
|
|
47
|
+
return false;
|
|
48
|
+
}
|
|
49
|
+
seen.add(id);
|
|
50
|
+
return true;
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Get credential from platform config
|
|
55
|
+
*/
|
|
56
|
+
export function getCredential(platform, key) {
|
|
57
|
+
return platform?.[key];
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Set credential in platform config
|
|
61
|
+
*/
|
|
62
|
+
export function setCredential(platform, key, value) {
|
|
63
|
+
if (!platform || typeof platform !== 'object') {
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
platform[key] = value;
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Find and parse the SwitchBot platform config from Homebridge config file
|
|
70
|
+
*/
|
|
71
|
+
export async function getSwitchBotPlatformConfig(server) {
|
|
72
|
+
const cfgPath = server.homebridgeConfigPath;
|
|
73
|
+
if (!cfgPath) {
|
|
74
|
+
throw new Error('HOMEBRIDGE_CONFIG_PATH not set');
|
|
75
|
+
}
|
|
76
|
+
const raw = await fs.readFile(cfgPath, 'utf-8');
|
|
77
|
+
const cfg = JSON.parse(raw);
|
|
78
|
+
const platforms = Array.isArray(cfg.platforms) ? cfg.platforms : [];
|
|
79
|
+
const candidates = platforms.filter((p) => {
|
|
80
|
+
const platformName = p.platform || p.name || '';
|
|
81
|
+
return !!platformName && (SWITCHBOT_PLATFORM_REGEX.test(String(platformName)) || String(platformName).toLowerCase() === '@switchbot/homebridge-switchbot');
|
|
82
|
+
});
|
|
83
|
+
uiLog.info(`Found ${candidates.length} SwitchBot candidate(s)`);
|
|
84
|
+
const platform = candidates.find((p) => {
|
|
85
|
+
const name = String(p.platform || '').toLowerCase();
|
|
86
|
+
return name === 'switchbot' || name.includes('switchbot');
|
|
87
|
+
});
|
|
88
|
+
if (!platform) {
|
|
89
|
+
throw new Error('SwitchBot platform not found in config. Please add the plugin configuration first.');
|
|
90
|
+
}
|
|
91
|
+
uiLog.info(`Using SwitchBot platform: ${platform.name || platform.platform || 'SwitchBot'}`);
|
|
92
|
+
return { platform, cfg, cfgPath };
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Save the Homebridge config file
|
|
96
|
+
*/
|
|
97
|
+
export async function saveConfig(cfgPath, cfg) {
|
|
98
|
+
// Defensive: enforce required fields on all SwitchBot platform blocks before saving
|
|
99
|
+
if (cfg && Array.isArray(cfg.platforms)) {
|
|
100
|
+
for (const p of cfg.platforms) {
|
|
101
|
+
if (p && (String(p.platform || '').toLowerCase() === 'switchbot' || String(p.name || '').toLowerCase() === 'switchbot')) {
|
|
102
|
+
enforcePlatformConfigFields(p);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
await fs.writeFile(cfgPath, JSON.stringify(cfg, null, 2), 'utf-8');
|
|
107
|
+
}
|
|
108
|
+
//# sourceMappingURL=config-parser.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config-parser.js","sourceRoot":"","sources":["../../../../src/homebridge-ui/utils/config-parser.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import { DEVICE_TYPES, isValidDeviceType, normalizeDeviceType } from '../../device-types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Validate and optionally correct a device's configDeviceType
|
|
4
|
+
* @param device Device object from config
|
|
5
|
+
* @param autoCorrect Whether to auto-correct invalid types
|
|
6
|
+
* @returns Migration result with details
|
|
7
|
+
*/
|
|
8
|
+
export function validateAndMigrateDeviceType(device, autoCorrect = false) {
|
|
9
|
+
const originalType = device.configDeviceType;
|
|
10
|
+
const deviceId = device.deviceId || device.id || 'unknown';
|
|
11
|
+
// Check if type is valid
|
|
12
|
+
if (isValidDeviceType(originalType)) {
|
|
13
|
+
return {
|
|
14
|
+
migrated: false,
|
|
15
|
+
originalType,
|
|
16
|
+
correctedType: originalType,
|
|
17
|
+
message: `Device "${device.configDeviceName || deviceId}" type is valid`,
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
// Try to find a valid mapping
|
|
21
|
+
const correctedType = normalizeDeviceType(originalType);
|
|
22
|
+
if (!correctedType) {
|
|
23
|
+
return {
|
|
24
|
+
migrated: false,
|
|
25
|
+
originalType,
|
|
26
|
+
correctedType: null,
|
|
27
|
+
message: `Device "${device.configDeviceName || deviceId}" has invalid type "${originalType}" with no valid mapping`,
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
// Found a valid mapping
|
|
31
|
+
if (autoCorrect) {
|
|
32
|
+
device.configDeviceType = correctedType;
|
|
33
|
+
return {
|
|
34
|
+
migrated: true,
|
|
35
|
+
originalType,
|
|
36
|
+
correctedType,
|
|
37
|
+
message: `Device "${device.configDeviceName || deviceId}" type auto-corrected: "${originalType}" → "${correctedType}"`,
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
else {
|
|
41
|
+
return {
|
|
42
|
+
migrated: false,
|
|
43
|
+
originalType,
|
|
44
|
+
correctedType,
|
|
45
|
+
message: `Device "${device.configDeviceName || deviceId}" requires migration: "${originalType}" → "${correctedType}"`,
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Validate all devices in config and optionally auto-correct invalid types
|
|
51
|
+
* @param config Configuration object containing devices array
|
|
52
|
+
* @param autoCorrect Whether to auto-correct invalid types
|
|
53
|
+
* @returns Array of migration results with statistics
|
|
54
|
+
*/
|
|
55
|
+
export function validateAndMigrateConfig(config, autoCorrect = false) {
|
|
56
|
+
const results = [];
|
|
57
|
+
const warnings = [];
|
|
58
|
+
let validCount = 0;
|
|
59
|
+
let correctedCount = 0;
|
|
60
|
+
let invalidCount = 0;
|
|
61
|
+
if (!config?.devices || !Array.isArray(config.devices)) {
|
|
62
|
+
return {
|
|
63
|
+
results,
|
|
64
|
+
statistics: {
|
|
65
|
+
total: 0,
|
|
66
|
+
valid: 0,
|
|
67
|
+
corrected: 0,
|
|
68
|
+
invalid: 0,
|
|
69
|
+
},
|
|
70
|
+
warnings: ['No devices found in config'],
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
for (const device of config.devices) {
|
|
74
|
+
const result = validateAndMigrateDeviceType(device, autoCorrect);
|
|
75
|
+
results.push(result);
|
|
76
|
+
if (!result.originalType || isValidDeviceType(result.originalType)) {
|
|
77
|
+
validCount++;
|
|
78
|
+
}
|
|
79
|
+
else if (result.migrated) {
|
|
80
|
+
correctedCount++;
|
|
81
|
+
}
|
|
82
|
+
else if (result.correctedType) {
|
|
83
|
+
warnings.push(`Device "${device.configDeviceName || device.deviceId}" needs correction: "${result.originalType}" → "${result.correctedType}"`);
|
|
84
|
+
invalidCount++;
|
|
85
|
+
}
|
|
86
|
+
else {
|
|
87
|
+
invalidCount++;
|
|
88
|
+
warnings.push(`Device "${device.configDeviceName || device.deviceId}" has INVALID type "${result.originalType}" with no mapping`);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
// Validation complete - results and warnings are returned via return value
|
|
92
|
+
// Caller (config endpoint) will handle logging/reporting
|
|
93
|
+
return {
|
|
94
|
+
results,
|
|
95
|
+
statistics: {
|
|
96
|
+
total: config.devices.length,
|
|
97
|
+
valid: validCount,
|
|
98
|
+
corrected: correctedCount,
|
|
99
|
+
invalid: invalidCount,
|
|
100
|
+
},
|
|
101
|
+
warnings,
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Get list of all valid device types for error messages
|
|
106
|
+
* @returns Array of valid device types grouped by category
|
|
107
|
+
*/
|
|
108
|
+
export function getValidDeviceTypesList() {
|
|
109
|
+
return DEVICE_TYPES;
|
|
110
|
+
}
|
|
111
|
+
//# sourceMappingURL=device-migration.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"device-migration.js","sourceRoot":"","sources":["../../../../src/homebridge-ui/utils/device-migration.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/* eslint-disable no-console */
|
|
2
|
+
const PREFIX = '[SwitchBot UI/Server]';
|
|
3
|
+
export const uiLog = {
|
|
4
|
+
info: (message, ...parameters) => {
|
|
5
|
+
console.log(PREFIX, message, ...parameters);
|
|
6
|
+
},
|
|
7
|
+
warn: (message, ...parameters) => {
|
|
8
|
+
console.warn(PREFIX, message, ...parameters);
|
|
9
|
+
},
|
|
10
|
+
error: (message, ...parameters) => {
|
|
11
|
+
console.error(PREFIX, message, ...parameters);
|
|
12
|
+
},
|
|
13
|
+
debug: (message, ...parameters) => {
|
|
14
|
+
console.debug(PREFIX, message, ...parameters);
|
|
15
|
+
},
|
|
16
|
+
};
|
|
17
|
+
//# sourceMappingURL=logger.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logger.js","sourceRoot":"","sources":["../../../../src/homebridge-ui/utils/logger.ts"],"names":[],"mappings":"AAAA,+BAA+B;AAC/B,MAAM,MAAM,GAAG,uBAAuB,CAAA;AAEtC,MAAM,CAAC,MAAM,KAAK,GAAG;IACnB,IAAI,EAAE,CAAC,OAAe,EAAE,GAAG,UAAiB,EAAE,EAAE;QAC9C,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,OAAO,EAAE,GAAG,UAAU,CAAC,CAAA;IAC7C,CAAC;IACD,IAAI,EAAE,CAAC,OAAe,EAAE,GAAG,UAAiB,EAAE,EAAE;QAC9C,OAAO,CAAC,IAAI,CAAC,MAAM,EAAE,OAAO,EAAE,GAAG,UAAU,CAAC,CAAA;IAC9C,CAAC;IACD,KAAK,EAAE,CAAC,OAAe,EAAE,GAAG,UAAiB,EAAE,EAAE;QAC/C,OAAO,CAAC,KAAK,CAAC,MAAM,EAAE,OAAO,EAAE,GAAG,UAAU,CAAC,CAAA;IAC/C,CAAC;IACD,KAAK,EAAE,CAAC,OAAe,EAAE,GAAG,UAAiB,EAAE,EAAE;QAC/C,OAAO,CAAC,KAAK,CAAC,MAAM,EAAE,OAAO,EAAE,GAAG,UAAU,CAAC,CAAA;IAC/C,CAAC;CACF,CAAA"}
|