@switchbot/homebridge-switchbot 5.1.0-beta.0 → 5.1.0-beta.10
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/.github/copilot-instructions.md +63 -0
- package/.github/scripts/normalize-changelog-header.cjs +86 -0
- package/.github/scripts/npm-version-script-esm-auto.js +201 -0
- package/.github/scripts/resolve-version-bump-esm.js +118 -0
- package/.github/workflows/release.yml +62 -13
- package/CHANGELOG.md +18 -0
- package/dist/{SwitchBotHAPPlatform.d.ts → Platform.HAP.d.ts} +2 -2
- package/dist/Platform.HAP.d.ts.map +1 -0
- package/dist/{SwitchBotHAPPlatform.js → Platform.HAP.js} +4 -2
- package/dist/Platform.HAP.js.map +1 -0
- package/dist/{SwitchBotMatterPlatform.d.ts → Platform.Matter.d.ts} +3 -2
- package/dist/Platform.Matter.d.ts.map +1 -0
- package/dist/{SwitchBotMatterPlatform.js → Platform.Matter.js} +24 -1
- package/dist/Platform.Matter.js.map +1 -0
- package/dist/homebridge-ui/endpoints/config.d.ts.map +1 -1
- package/dist/homebridge-ui/endpoints/config.js +9 -2
- package/dist/homebridge-ui/endpoints/config.js.map +1 -1
- package/dist/homebridge-ui/homebridge-ui/endpoints/config.js +9 -2
- package/dist/homebridge-ui/homebridge-ui/endpoints/config.js.map +1 -1
- package/dist/homebridge-ui/homebridge-ui/utils/config-parser.js +8 -0
- package/dist/homebridge-ui/homebridge-ui/utils/config-parser.js.map +1 -1
- package/dist/homebridge-ui/homebridge-ui/utils/v4-detection.js +23 -0
- package/dist/homebridge-ui/homebridge-ui/utils/v4-detection.js.map +1 -0
- package/dist/homebridge-ui/public/css/styles.css +62 -2
- package/dist/homebridge-ui/public/index.html +61 -6
- package/dist/homebridge-ui/public/js/advanced-settings.d.ts.map +1 -1
- package/dist/homebridge-ui/public/js/advanced-settings.js +4 -3
- package/dist/homebridge-ui/public/js/advanced-settings.js.map +1 -1
- package/dist/homebridge-ui/public/js/advanced-settings.ts +4 -3
- package/dist/homebridge-ui/public/js/api.d.ts +11 -0
- package/dist/homebridge-ui/public/js/api.d.ts.map +1 -1
- package/dist/homebridge-ui/public/js/api.js +44 -1
- package/dist/homebridge-ui/public/js/api.js.map +1 -1
- package/dist/homebridge-ui/public/js/api.ts +46 -1
- package/dist/homebridge-ui/public/js/app.js +241 -182
- package/dist/homebridge-ui/public/js/app.js.map +4 -4
- package/dist/homebridge-ui/public/js/app.ts +47 -4
- package/dist/homebridge-ui/public/js/credentials.d.ts.map +1 -1
- package/dist/homebridge-ui/public/js/credentials.js +11 -5
- package/dist/homebridge-ui/public/js/credentials.js.map +1 -1
- package/dist/homebridge-ui/public/js/credentials.ts +11 -5
- package/dist/homebridge-ui/public/js/discovery.d.ts.map +1 -1
- package/dist/homebridge-ui/public/js/discovery.js +0 -36
- package/dist/homebridge-ui/public/js/discovery.js.map +1 -1
- package/dist/homebridge-ui/public/js/discovery.ts +0 -37
- package/dist/homebridge-ui/public/js/legacy-view.d.ts +3 -0
- package/dist/homebridge-ui/public/js/legacy-view.d.ts.map +1 -0
- package/dist/homebridge-ui/public/js/legacy-view.js +152 -0
- package/dist/homebridge-ui/public/js/legacy-view.js.map +1 -0
- package/dist/homebridge-ui/public/js/legacy-view.ts +107 -0
- package/dist/homebridge-ui/public/js/render.d.ts.map +1 -1
- package/dist/homebridge-ui/public/js/render.js +38 -31
- package/dist/homebridge-ui/public/js/render.js.map +1 -1
- package/dist/homebridge-ui/public/js/render.ts +39 -34
- package/dist/homebridge-ui/public/js/toast.d.ts.map +1 -1
- package/dist/homebridge-ui/public/js/toast.js +2 -3
- package/dist/homebridge-ui/public/js/toast.js.map +1 -1
- package/dist/homebridge-ui/public/js/toast.ts +2 -3
- package/dist/homebridge-ui/utils/config-parser.d.ts +8 -0
- package/dist/homebridge-ui/utils/config-parser.d.ts.map +1 -1
- package/dist/homebridge-ui/utils/config-parser.js +8 -0
- package/dist/homebridge-ui/utils/config-parser.js.map +1 -1
- package/dist/homebridge-ui/utils/v4-detection.d.ts +12 -0
- package/dist/homebridge-ui/utils/v4-detection.d.ts.map +1 -0
- package/dist/homebridge-ui/utils/v4-detection.js +23 -0
- package/dist/homebridge-ui/utils/v4-detection.js.map +1 -0
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/docs/assets/icons.js +1 -1
- package/docs/assets/icons.svg +1 -1
- package/docs/assets/main.js +3 -3
- package/docs/variables/default.html +1 -1
- package/package.json +12 -18
- package/scripts/build-ui.js +30 -0
- package/src/{SwitchBotHAPPlatform.ts → Platform.HAP.ts} +5 -2
- package/src/{SwitchBotMatterPlatform.ts → Platform.Matter.ts} +28 -1
- package/src/homebridge-ui/endpoints/config.ts +10 -2
- package/src/homebridge-ui/public/css/styles.css +62 -2
- package/src/homebridge-ui/public/index.html +59 -4
- package/src/homebridge-ui/public/js/advanced-settings.ts +4 -3
- package/src/homebridge-ui/public/js/api.ts +46 -1
- package/src/homebridge-ui/public/js/app.ts +47 -4
- package/src/homebridge-ui/public/js/credentials.ts +11 -5
- package/src/homebridge-ui/public/js/discovery.ts +0 -37
- package/src/homebridge-ui/public/js/legacy-view.js +152 -0
- package/src/homebridge-ui/public/js/legacy-view.ts +107 -0
- package/src/homebridge-ui/public/js/render.ts +39 -34
- package/src/homebridge-ui/public/js/toast.ts +2 -3
- package/src/homebridge-ui/utils/config-parser.ts +9 -0
- package/src/homebridge-ui/utils/v4-detection.ts +23 -0
- package/src/index.ts +2 -2
- package/test/homebridge-ui/config-parser.spec.ts +61 -0
- package/test/platform/accessory-restore.spec.ts +2 -2
- package/test/platform/matter-childbridge.spec.ts +1 -1
- package/test/platform/matter-integration.spec.ts +51 -1
- package/test/platform/platform-edge.spec.ts +2 -2
- package/test/platform/platform.integration.spec.ts +1 -1
- package/dist/SwitchBotHAPPlatform.d.ts.map +0 -1
- package/dist/SwitchBotHAPPlatform.js.map +0 -1
- package/dist/SwitchBotMatterPlatform.d.ts.map +0 -1
- package/dist/SwitchBotMatterPlatform.js.map +0 -1
|
@@ -8,111 +8,6 @@ var __export = (target, all) => {
|
|
|
8
8
|
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
9
|
};
|
|
10
10
|
|
|
11
|
-
// src/homebridge-ui/public/js/logger.ts
|
|
12
|
-
var PREFIX, uiLog;
|
|
13
|
-
var init_logger = __esm({
|
|
14
|
-
"src/homebridge-ui/public/js/logger.ts"() {
|
|
15
|
-
"use strict";
|
|
16
|
-
PREFIX = "[SwitchBot UI/html]";
|
|
17
|
-
uiLog = {
|
|
18
|
-
info: (message, ...parameters) => {
|
|
19
|
-
console.log(PREFIX, message, ...parameters);
|
|
20
|
-
},
|
|
21
|
-
warn: (message, ...parameters) => {
|
|
22
|
-
console.warn(PREFIX, message, ...parameters);
|
|
23
|
-
},
|
|
24
|
-
error: (message, ...parameters) => {
|
|
25
|
-
console.error(PREFIX, message, ...parameters);
|
|
26
|
-
},
|
|
27
|
-
debug: (message, ...parameters) => {
|
|
28
|
-
console.debug(PREFIX, message, ...parameters);
|
|
29
|
-
}
|
|
30
|
-
};
|
|
31
|
-
}
|
|
32
|
-
});
|
|
33
|
-
|
|
34
|
-
// src/homebridge-ui/public/js/types.ts
|
|
35
|
-
var init_types = __esm({
|
|
36
|
-
"src/homebridge-ui/public/js/types.ts"() {
|
|
37
|
-
"use strict";
|
|
38
|
-
}
|
|
39
|
-
});
|
|
40
|
-
|
|
41
|
-
// src/homebridge-ui/public/js/modal.ts
|
|
42
|
-
function callUiMethod(name, ...args) {
|
|
43
|
-
try {
|
|
44
|
-
if (typeof homebridge?.[name] === "function") {
|
|
45
|
-
uiLog.info(`[callUiMethod] Invoking homebridge.${String(name)}()`);
|
|
46
|
-
const fn = homebridge?.[name];
|
|
47
|
-
if (typeof fn === "function") {
|
|
48
|
-
uiLog.info(`[callUiMethod] Invoking homebridge.${String(name)}()`);
|
|
49
|
-
fn.apply(homebridge, args);
|
|
50
|
-
} else {
|
|
51
|
-
uiLog.warn(`[callUiMethod] homebridge[${String(name)}] is not a function.`);
|
|
52
|
-
}
|
|
53
|
-
} else {
|
|
54
|
-
uiLog.warn(`[callUiMethod] homebridge[${String(name)}] is not a function.`);
|
|
55
|
-
}
|
|
56
|
-
} catch (e) {
|
|
57
|
-
uiLog.warn(`Homebridge UI method ${String(name)} failed:`, e);
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
function showBusyUi() {
|
|
61
|
-
callUiMethod("disableSaveButton");
|
|
62
|
-
callUiMethod("showSpinner");
|
|
63
|
-
}
|
|
64
|
-
function hideBusyUi() {
|
|
65
|
-
callUiMethod("hideSpinner");
|
|
66
|
-
callUiMethod("enableSaveButton");
|
|
67
|
-
}
|
|
68
|
-
var init_modal = __esm({
|
|
69
|
-
"src/homebridge-ui/public/js/modal.ts"() {
|
|
70
|
-
"use strict";
|
|
71
|
-
init_types();
|
|
72
|
-
init_logger();
|
|
73
|
-
}
|
|
74
|
-
});
|
|
75
|
-
|
|
76
|
-
// src/homebridge-ui/public/js/toast.ts
|
|
77
|
-
function showToast(method, message, title = "SwitchBot") {
|
|
78
|
-
try {
|
|
79
|
-
const hb = typeof window !== "undefined" ? window.homebridge : void 0;
|
|
80
|
-
const toast = hb && typeof hb.toast === "object" ? hb.toast : void 0;
|
|
81
|
-
const fn = toast && typeof toast[method] === "function" ? toast[method] : void 0;
|
|
82
|
-
if (fn) {
|
|
83
|
-
try {
|
|
84
|
-
fn(message, title);
|
|
85
|
-
return;
|
|
86
|
-
} catch (err) {
|
|
87
|
-
uiLog.warn(`Toast ${method} threw:`, err);
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
uiLog.info(`[Toast:${method}] ${title} - ${message}`);
|
|
91
|
-
} catch (e) {
|
|
92
|
-
uiLog.warn(`Toast ${method} outer error:`, e);
|
|
93
|
-
uiLog.info(`[Toast:${method}] ${title} - ${message}`);
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
function toastSuccess(message, title) {
|
|
97
|
-
showToast("success", message, title);
|
|
98
|
-
}
|
|
99
|
-
function toastError(message, title) {
|
|
100
|
-
showToast("error", message, title);
|
|
101
|
-
}
|
|
102
|
-
function toastWarning(message, title) {
|
|
103
|
-
showToast("warning", message, title);
|
|
104
|
-
}
|
|
105
|
-
function toastInfo(message, title) {
|
|
106
|
-
showToast("info", message, title);
|
|
107
|
-
}
|
|
108
|
-
var init_toast = __esm({
|
|
109
|
-
"src/homebridge-ui/public/js/toast.ts"() {
|
|
110
|
-
"use strict";
|
|
111
|
-
init_types();
|
|
112
|
-
init_logger();
|
|
113
|
-
}
|
|
114
|
-
});
|
|
115
|
-
|
|
116
11
|
// src/device-types.js
|
|
117
12
|
function getValidDeviceTypes() {
|
|
118
13
|
const validTypes = /* @__PURE__ */ new Set();
|
|
@@ -354,6 +249,90 @@ var init_device_types = __esm({
|
|
|
354
249
|
}
|
|
355
250
|
});
|
|
356
251
|
|
|
252
|
+
// src/homebridge-ui/utils/v4-detection.ts
|
|
253
|
+
function isV4Config(platform) {
|
|
254
|
+
if (!platform || typeof platform !== "object") {
|
|
255
|
+
return false;
|
|
256
|
+
}
|
|
257
|
+
const hasCredentials = platform.credentials !== void 0 && typeof platform.credentials === "object";
|
|
258
|
+
const hasOptionsDevices = platform.options !== void 0 && typeof platform.options === "object" && Array.isArray(platform.options.devices);
|
|
259
|
+
return hasCredentials || hasOptionsDevices;
|
|
260
|
+
}
|
|
261
|
+
var init_v4_detection = __esm({
|
|
262
|
+
"src/homebridge-ui/utils/v4-detection.ts"() {
|
|
263
|
+
"use strict";
|
|
264
|
+
}
|
|
265
|
+
});
|
|
266
|
+
|
|
267
|
+
// src/homebridge-ui/public/js/types.ts
|
|
268
|
+
var init_types = __esm({
|
|
269
|
+
"src/homebridge-ui/public/js/types.ts"() {
|
|
270
|
+
"use strict";
|
|
271
|
+
}
|
|
272
|
+
});
|
|
273
|
+
|
|
274
|
+
// src/homebridge-ui/public/js/logger.ts
|
|
275
|
+
var PREFIX, uiLog;
|
|
276
|
+
var init_logger = __esm({
|
|
277
|
+
"src/homebridge-ui/public/js/logger.ts"() {
|
|
278
|
+
"use strict";
|
|
279
|
+
PREFIX = "[SwitchBot UI/html]";
|
|
280
|
+
uiLog = {
|
|
281
|
+
info: (message, ...parameters) => {
|
|
282
|
+
console.log(PREFIX, message, ...parameters);
|
|
283
|
+
},
|
|
284
|
+
warn: (message, ...parameters) => {
|
|
285
|
+
console.warn(PREFIX, message, ...parameters);
|
|
286
|
+
},
|
|
287
|
+
error: (message, ...parameters) => {
|
|
288
|
+
console.error(PREFIX, message, ...parameters);
|
|
289
|
+
},
|
|
290
|
+
debug: (message, ...parameters) => {
|
|
291
|
+
console.debug(PREFIX, message, ...parameters);
|
|
292
|
+
}
|
|
293
|
+
};
|
|
294
|
+
}
|
|
295
|
+
});
|
|
296
|
+
|
|
297
|
+
// src/homebridge-ui/public/js/toast.ts
|
|
298
|
+
function showToast(method, message, title = "SwitchBot") {
|
|
299
|
+
try {
|
|
300
|
+
const hb = typeof window !== "undefined" ? window.homebridge : void 0;
|
|
301
|
+
const toast = hb && typeof hb.toast === "object" ? hb.toast : void 0;
|
|
302
|
+
if (toast && typeof toast[method] === "function") {
|
|
303
|
+
try {
|
|
304
|
+
toast[method](message, title);
|
|
305
|
+
return;
|
|
306
|
+
} catch (err) {
|
|
307
|
+
uiLog.warn(`Toast ${method} threw:`, err);
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
uiLog.info(`[Toast:${method}] ${title} - ${message}`);
|
|
311
|
+
} catch (e) {
|
|
312
|
+
uiLog.warn(`Toast ${method} outer error:`, e);
|
|
313
|
+
uiLog.info(`[Toast:${method}] ${title} - ${message}`);
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
function toastSuccess(message, title) {
|
|
317
|
+
showToast("success", message, title);
|
|
318
|
+
}
|
|
319
|
+
function toastError(message, title) {
|
|
320
|
+
showToast("error", message, title);
|
|
321
|
+
}
|
|
322
|
+
function toastWarning(message, title) {
|
|
323
|
+
showToast("warning", message, title);
|
|
324
|
+
}
|
|
325
|
+
function toastInfo(message, title) {
|
|
326
|
+
showToast("info", message, title);
|
|
327
|
+
}
|
|
328
|
+
var init_toast = __esm({
|
|
329
|
+
"src/homebridge-ui/public/js/toast.ts"() {
|
|
330
|
+
"use strict";
|
|
331
|
+
init_types();
|
|
332
|
+
init_logger();
|
|
333
|
+
}
|
|
334
|
+
});
|
|
335
|
+
|
|
357
336
|
// src/homebridge-ui/public/js/api.ts
|
|
358
337
|
var api_exports = {};
|
|
359
338
|
__export(api_exports, {
|
|
@@ -361,11 +340,13 @@ __export(api_exports, {
|
|
|
361
340
|
addDevicesInBulk: () => addDevicesInBulk,
|
|
362
341
|
deleteAllDevices: () => deleteAllDevices,
|
|
363
342
|
deleteDevice: () => deleteDevice,
|
|
343
|
+
detectV4Config: () => detectV4Config,
|
|
364
344
|
discoverDevices: () => discoverDevices,
|
|
365
345
|
fetchBluetoothStatus: () => fetchBluetoothStatus,
|
|
366
346
|
fetchCredentialStatus: () => fetchCredentialStatus,
|
|
367
347
|
fetchDevices: () => fetchDevices,
|
|
368
|
-
|
|
348
|
+
normalizeBulkAddDevicesResponse: () => normalizeBulkAddDevicesResponse,
|
|
349
|
+
saveCredentials: () => saveCredentials,
|
|
369
350
|
syncParentPluginConfigFromDisk: () => syncParentPluginConfigFromDisk,
|
|
370
351
|
testDeviceConnection: () => testDeviceConnection,
|
|
371
352
|
updateDevice: () => updateDevice,
|
|
@@ -388,6 +369,25 @@ async function fetchDevices() {
|
|
|
388
369
|
return [];
|
|
389
370
|
}
|
|
390
371
|
}
|
|
372
|
+
async function detectV4Config() {
|
|
373
|
+
try {
|
|
374
|
+
if (typeof homebridge.getPluginConfig !== "function") {
|
|
375
|
+
return false;
|
|
376
|
+
}
|
|
377
|
+
const configArr = await homebridge.getPluginConfig();
|
|
378
|
+
if (!Array.isArray(configArr)) {
|
|
379
|
+
return false;
|
|
380
|
+
}
|
|
381
|
+
const config = configArr.find(isSwitchBotPlatformConfig);
|
|
382
|
+
if (!config || typeof config !== "object") {
|
|
383
|
+
return false;
|
|
384
|
+
}
|
|
385
|
+
return isV4Config(config);
|
|
386
|
+
} catch (e) {
|
|
387
|
+
uiLog.warn("Error detecting v4 config:", e);
|
|
388
|
+
return false;
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
391
|
function validateAndFixDeviceTypes(devices) {
|
|
392
392
|
const errors = [];
|
|
393
393
|
for (const d of devices) {
|
|
@@ -457,7 +457,7 @@ async function fetchCredentialStatus() {
|
|
|
457
457
|
return null;
|
|
458
458
|
}
|
|
459
459
|
}
|
|
460
|
-
async function
|
|
460
|
+
async function saveCredentials(token, secret) {
|
|
461
461
|
uiLog.info("Saving credentials...");
|
|
462
462
|
const resp = await homebridge.request("/credentials", { token, secret });
|
|
463
463
|
uiLog.info("Save response:", resp);
|
|
@@ -563,7 +563,20 @@ async function addDevicesInBulk(devices) {
|
|
|
563
563
|
if (!resp || resp.success === false) {
|
|
564
564
|
throw new Error(resp?.data?.message || "Bulk add failed");
|
|
565
565
|
}
|
|
566
|
-
return resp
|
|
566
|
+
return normalizeBulkAddDevicesResponse(resp);
|
|
567
|
+
}
|
|
568
|
+
function normalizeBulkAddDevicesResponse(resp) {
|
|
569
|
+
const payload = resp?.data && typeof resp.data === "object" ? resp.data : resp;
|
|
570
|
+
const addedCount = Number(payload?.addedCount ?? payload?.added ?? 0);
|
|
571
|
+
const skippedCount = Number(payload?.skippedCount ?? payload?.skipped ?? 0);
|
|
572
|
+
const updatedCount = Number(payload?.updatedCount ?? payload?.updated ?? 0);
|
|
573
|
+
return {
|
|
574
|
+
...payload,
|
|
575
|
+
success: resp?.success ?? true,
|
|
576
|
+
addedCount,
|
|
577
|
+
skippedCount,
|
|
578
|
+
updatedCount
|
|
579
|
+
};
|
|
567
580
|
}
|
|
568
581
|
async function updateDevice(deviceId, configDeviceName, configDeviceType, options) {
|
|
569
582
|
if (typeof homebridge.getPluginConfig !== "function" || typeof homebridge.updatePluginConfig !== "function") {
|
|
@@ -657,12 +670,48 @@ var init_api = __esm({
|
|
|
657
670
|
"src/homebridge-ui/public/js/api.ts"() {
|
|
658
671
|
"use strict";
|
|
659
672
|
init_device_types();
|
|
673
|
+
init_v4_detection();
|
|
660
674
|
init_types();
|
|
661
675
|
init_logger();
|
|
662
676
|
init_toast();
|
|
663
677
|
}
|
|
664
678
|
});
|
|
665
679
|
|
|
680
|
+
// src/homebridge-ui/public/js/modal.ts
|
|
681
|
+
function callUiMethod(name, ...args) {
|
|
682
|
+
try {
|
|
683
|
+
if (typeof homebridge?.[name] === "function") {
|
|
684
|
+
uiLog.info(`[callUiMethod] Invoking homebridge.${String(name)}()`);
|
|
685
|
+
const fn = homebridge?.[name];
|
|
686
|
+
if (typeof fn === "function") {
|
|
687
|
+
uiLog.info(`[callUiMethod] Invoking homebridge.${String(name)}()`);
|
|
688
|
+
fn.apply(homebridge, args);
|
|
689
|
+
} else {
|
|
690
|
+
uiLog.warn(`[callUiMethod] homebridge[${String(name)}] is not a function.`);
|
|
691
|
+
}
|
|
692
|
+
} else {
|
|
693
|
+
uiLog.warn(`[callUiMethod] homebridge[${String(name)}] is not a function.`);
|
|
694
|
+
}
|
|
695
|
+
} catch (e) {
|
|
696
|
+
uiLog.warn(`Homebridge UI method ${String(name)} failed:`, e);
|
|
697
|
+
}
|
|
698
|
+
}
|
|
699
|
+
function showBusyUi() {
|
|
700
|
+
callUiMethod("disableSaveButton");
|
|
701
|
+
callUiMethod("showSpinner");
|
|
702
|
+
}
|
|
703
|
+
function hideBusyUi() {
|
|
704
|
+
callUiMethod("hideSpinner");
|
|
705
|
+
callUiMethod("enableSaveButton");
|
|
706
|
+
}
|
|
707
|
+
var init_modal = __esm({
|
|
708
|
+
"src/homebridge-ui/public/js/modal.ts"() {
|
|
709
|
+
"use strict";
|
|
710
|
+
init_types();
|
|
711
|
+
init_logger();
|
|
712
|
+
}
|
|
713
|
+
});
|
|
714
|
+
|
|
666
715
|
// src/homebridge-ui/public/js/discovery.ts
|
|
667
716
|
var discovery_exports = {};
|
|
668
717
|
__export(discovery_exports, {
|
|
@@ -963,7 +1012,6 @@ function setDiscoveryGroupExpanded(groupKey, expanded) {
|
|
|
963
1012
|
}
|
|
964
1013
|
async function discoverDevices2() {
|
|
965
1014
|
const btn = document.getElementById("discoverBtn");
|
|
966
|
-
const cancelBtn = document.getElementById("cancelDiscoverBtn");
|
|
967
1015
|
const status = document.getElementById("discoverStatus");
|
|
968
1016
|
const phaseProgress = document.getElementById("discoverPhaseProgress");
|
|
969
1017
|
const phaseFill = document.getElementById("discoverPhaseFill");
|
|
@@ -991,7 +1039,6 @@ async function discoverDevices2() {
|
|
|
991
1039
|
const startedAt = Date.now();
|
|
992
1040
|
let phaseStartedAt = startedAt;
|
|
993
1041
|
let phase = "Preparing discovery...";
|
|
994
|
-
let cancelled = false;
|
|
995
1042
|
const setPhase = (nextPhase) => {
|
|
996
1043
|
phase = nextPhase;
|
|
997
1044
|
phaseStartedAt = Date.now();
|
|
@@ -1428,31 +1475,8 @@ async function discoverDevices2() {
|
|
|
1428
1475
|
devicesFoundDisplay.style.display = "none";
|
|
1429
1476
|
devicesFoundDisplay.classList.remove("discovery-scanning-pulse");
|
|
1430
1477
|
}
|
|
1431
|
-
if (cancelBtn) {
|
|
1432
|
-
cancelBtn.style.display = "inline-block";
|
|
1433
|
-
cancelBtn.disabled = false;
|
|
1434
|
-
cancelBtn.onclick = () => {
|
|
1435
|
-
cancelled = true;
|
|
1436
|
-
const totalSeconds = Math.max(0, Math.floor((Date.now() - startedAt) / 1e3));
|
|
1437
|
-
status.textContent = `Discovery cancelled (${totalSeconds}s total)`;
|
|
1438
|
-
if (phaseProgress) {
|
|
1439
|
-
phaseProgress.style.display = "none";
|
|
1440
|
-
}
|
|
1441
|
-
if (devicesFoundDisplay) {
|
|
1442
|
-
devicesFoundDisplay.style.display = "none";
|
|
1443
|
-
devicesFoundDisplay.classList.remove("discovery-scanning-pulse");
|
|
1444
|
-
}
|
|
1445
|
-
cancelBtn.style.display = "none";
|
|
1446
|
-
btn.disabled = false;
|
|
1447
|
-
btn.textContent = "\u{1F50D} Discover Devices";
|
|
1448
|
-
hideBusyUi();
|
|
1449
|
-
};
|
|
1450
|
-
}
|
|
1451
1478
|
if (bleSettings.bleEnabled) {
|
|
1452
1479
|
const bleDevicesRaw = await discoverDevices("ble", bleSettings);
|
|
1453
|
-
if (cancelled) {
|
|
1454
|
-
return;
|
|
1455
|
-
}
|
|
1456
1480
|
discoveredDevices = dedupeById(bleDevicesRaw);
|
|
1457
1481
|
uiLog.info("BLE discover response:", bleDevicesRaw);
|
|
1458
1482
|
if (devicesFoundDisplay && bleDevicesRaw.length > 0) {
|
|
@@ -1473,9 +1497,6 @@ async function discoverDevices2() {
|
|
|
1473
1497
|
renderProgress();
|
|
1474
1498
|
try {
|
|
1475
1499
|
const openApiDevicesRaw = await discoverDevices("openapi");
|
|
1476
|
-
if (cancelled) {
|
|
1477
|
-
return;
|
|
1478
|
-
}
|
|
1479
1500
|
uiLog.info("OpenAPI discover response:", openApiDevicesRaw);
|
|
1480
1501
|
discoveredDevices = mergeDiscoveredDevices(discoveredDevices, openApiDevicesRaw);
|
|
1481
1502
|
if (devicesFoundDisplay && discoveredDevices.length > 0) {
|
|
@@ -1555,9 +1576,6 @@ async function discoverDevices2() {
|
|
|
1555
1576
|
setDiscoveryCache(discoveredDevices);
|
|
1556
1577
|
updateLastScannedStatus();
|
|
1557
1578
|
} catch (e) {
|
|
1558
|
-
if (cancelled) {
|
|
1559
|
-
return;
|
|
1560
|
-
}
|
|
1561
1579
|
uiLog.error("Discovery error:", e);
|
|
1562
1580
|
status.textContent = `Error: ${e instanceof Error ? e.message : "Discovery failed"}`;
|
|
1563
1581
|
status.classList.add("error");
|
|
@@ -1582,11 +1600,6 @@ async function discoverDevices2() {
|
|
|
1582
1600
|
}
|
|
1583
1601
|
btn.disabled = false;
|
|
1584
1602
|
btn.textContent = "\u{1F50D} Discover Devices";
|
|
1585
|
-
if (cancelBtn) {
|
|
1586
|
-
cancelBtn.disabled = false;
|
|
1587
|
-
cancelBtn.style.display = "none";
|
|
1588
|
-
cancelBtn.onclick = null;
|
|
1589
|
-
}
|
|
1590
1603
|
}
|
|
1591
1604
|
}
|
|
1592
1605
|
async function updateDiscoveryView(allDevices, preferences, groupBy, hideAdded, selectedIds) {
|
|
@@ -2714,6 +2727,21 @@ __export(render_exports, {
|
|
|
2714
2727
|
setDiscoveryPreferences: () => setDiscoveryPreferences,
|
|
2715
2728
|
sortDevices: () => sortDevices
|
|
2716
2729
|
});
|
|
2730
|
+
async function copyTextWithFallback(text) {
|
|
2731
|
+
try {
|
|
2732
|
+
await navigator.clipboard.writeText(text);
|
|
2733
|
+
} catch {
|
|
2734
|
+
const textarea = document.createElement("textarea");
|
|
2735
|
+
textarea.value = text;
|
|
2736
|
+
textarea.setAttribute("readonly", "");
|
|
2737
|
+
textarea.style.cssText = "position:fixed;left:-9999px;opacity:0;pointer-events:none";
|
|
2738
|
+
document.body.appendChild(textarea);
|
|
2739
|
+
textarea.select();
|
|
2740
|
+
textarea.setSelectionRange(0, textarea.value.length);
|
|
2741
|
+
document.execCommand("copy");
|
|
2742
|
+
textarea.remove();
|
|
2743
|
+
}
|
|
2744
|
+
}
|
|
2717
2745
|
function getRssiSignalQuality(rssi) {
|
|
2718
2746
|
if (!rssi || rssi === 0) {
|
|
2719
2747
|
return {
|
|
@@ -2794,7 +2822,6 @@ function renderSignalQualityBadge(rssi) {
|
|
|
2794
2822
|
border-radius: 3px;
|
|
2795
2823
|
font-size: 10px;
|
|
2796
2824
|
font-weight: 600;
|
|
2797
|
-
margin-left: 8px;
|
|
2798
2825
|
`;
|
|
2799
2826
|
badge.title = quality.description;
|
|
2800
2827
|
return badge;
|
|
@@ -3439,6 +3466,7 @@ function renderDeviceList(list) {
|
|
|
3439
3466
|
}
|
|
3440
3467
|
status.textContent = `Found ${list.length} device(s)`;
|
|
3441
3468
|
ul.classList.add("device-grid");
|
|
3469
|
+
ul.style.padding = "0";
|
|
3442
3470
|
ul.innerHTML = "";
|
|
3443
3471
|
if (removeAllContainer) {
|
|
3444
3472
|
removeAllContainer.style.display = "block";
|
|
@@ -3450,6 +3478,7 @@ function renderDeviceList(list) {
|
|
|
3450
3478
|
li.style.display = "flex";
|
|
3451
3479
|
li.style.flexDirection = "column";
|
|
3452
3480
|
li.style.alignItems = "stretch";
|
|
3481
|
+
li.style.padding = "5px 8px";
|
|
3453
3482
|
li.style.marginBottom = "0";
|
|
3454
3483
|
const info = document.createElement("div");
|
|
3455
3484
|
info.style.flex = "1 1 auto";
|
|
@@ -3457,13 +3486,14 @@ function renderDeviceList(list) {
|
|
|
3457
3486
|
info.style.minWidth = "0";
|
|
3458
3487
|
const nameContainer = document.createElement("div");
|
|
3459
3488
|
nameContainer.style.display = "flex";
|
|
3460
|
-
nameContainer.style.
|
|
3461
|
-
nameContainer.style.
|
|
3462
|
-
nameContainer.style.
|
|
3489
|
+
nameContainer.style.alignItems = "center";
|
|
3490
|
+
nameContainer.style.marginBottom = "0";
|
|
3491
|
+
nameContainer.style.flexWrap = "wrap";
|
|
3492
|
+
nameContainer.style.gap = "4px";
|
|
3463
3493
|
const name = document.createElement("div");
|
|
3464
3494
|
name.style.fontWeight = "500";
|
|
3465
3495
|
name.style.fontSize = "13px";
|
|
3466
|
-
name.textContent = d.name || d.id;
|
|
3496
|
+
name.textContent = d.configDeviceName || d.name || d.id;
|
|
3467
3497
|
const expandedDetails = document.createElement("div");
|
|
3468
3498
|
expandedDetails.style.display = "none";
|
|
3469
3499
|
expandedDetails.appendChild(renderDeviceDetailsPanel(d));
|
|
@@ -3481,36 +3511,23 @@ function renderDeviceList(list) {
|
|
|
3481
3511
|
expandedDetails.style.display = isHidden ? "block" : "none";
|
|
3482
3512
|
expandBtn.style.transform = isHidden ? "rotate(180deg)" : "rotate(0deg)";
|
|
3483
3513
|
};
|
|
3484
|
-
|
|
3485
|
-
|
|
3486
|
-
code.style.fontSize = "10px";
|
|
3487
|
-
code.style.opacity = "0.75";
|
|
3488
|
-
code.style.marginLeft = "0";
|
|
3489
|
-
code.style.whiteSpace = "normal";
|
|
3490
|
-
code.style.overflowWrap = "anywhere";
|
|
3491
|
-
code.style.wordBreak = "break-word";
|
|
3492
|
-
code.style.maxWidth = "100%";
|
|
3493
|
-
const headerRow = document.createElement("div");
|
|
3494
|
-
headerRow.style.display = "inline-flex";
|
|
3495
|
-
headerRow.style.alignItems = "center";
|
|
3496
|
-
headerRow.style.gap = "4px";
|
|
3497
|
-
headerRow.appendChild(name);
|
|
3498
|
-
headerRow.appendChild(expandBtn);
|
|
3499
|
-
nameContainer.appendChild(headerRow);
|
|
3500
|
-
nameContainer.appendChild(code);
|
|
3514
|
+
nameContainer.appendChild(name);
|
|
3515
|
+
nameContainer.appendChild(expandBtn);
|
|
3501
3516
|
if (d.rssi !== void 0 && d.rssi !== null && d.rssi !== 0) {
|
|
3502
3517
|
nameContainer.appendChild(renderSignalBars(d.rssi));
|
|
3503
3518
|
nameContainer.appendChild(renderSignalQualityBadge(d.rssi));
|
|
3504
3519
|
}
|
|
3505
3520
|
const meta = document.createElement("div");
|
|
3506
|
-
meta.style.opacity = "0.
|
|
3507
|
-
meta.style.
|
|
3508
|
-
meta.style.
|
|
3509
|
-
const
|
|
3510
|
-
const
|
|
3521
|
+
meta.style.opacity = "0.7";
|
|
3522
|
+
meta.style.fontSize = "10px";
|
|
3523
|
+
meta.style.fontFamily = "monospace";
|
|
3524
|
+
const deviceIdentifier = d.deviceId || d.id;
|
|
3525
|
+
const id = `ID: ${deviceIdentifier}`;
|
|
3526
|
+
const typeText = d.configDeviceType || d.type ? `Type: ${d.configDeviceType || d.type}` : "";
|
|
3527
|
+
const connText = d.connectionPreference ? `Conn: ${d.connectionPreference}` : "";
|
|
3511
3528
|
const extText = d.externalPublishProtocol && d.externalPublishProtocol !== "none" ? `external: ${d.externalPublishProtocol}` : "";
|
|
3512
|
-
const roomText = d.room ? `
|
|
3513
|
-
meta.textContent = [typeText, connText, extText, roomText].filter(Boolean).join(" | ");
|
|
3529
|
+
const roomText = d.room ? `Room: ${d.room}` : "";
|
|
3530
|
+
meta.textContent = [id, typeText, connText, extText, roomText].filter(Boolean).join(" | ");
|
|
3514
3531
|
info.appendChild(nameContainer);
|
|
3515
3532
|
info.appendChild(meta);
|
|
3516
3533
|
info.appendChild(expandedDetails);
|
|
@@ -3537,7 +3554,9 @@ function renderDeviceList(list) {
|
|
|
3537
3554
|
copyBtn.style.fontSize = "11px";
|
|
3538
3555
|
copyBtn.addEventListener("click", async () => {
|
|
3539
3556
|
try {
|
|
3540
|
-
|
|
3557
|
+
if (deviceIdentifier) {
|
|
3558
|
+
await copyTextWithFallback(deviceIdentifier);
|
|
3559
|
+
}
|
|
3541
3560
|
copyBtn.textContent = "Copied";
|
|
3542
3561
|
copyBtn.classList.add("success");
|
|
3543
3562
|
setTimeout(() => {
|
|
@@ -3564,8 +3583,8 @@ function renderDeviceList(list) {
|
|
|
3564
3583
|
};
|
|
3565
3584
|
buttons.appendChild(editBtn);
|
|
3566
3585
|
buttons.appendChild(copyBtn);
|
|
3567
|
-
buttons.appendChild(createConnectionTestControls(d));
|
|
3568
3586
|
buttons.appendChild(deleteBtn);
|
|
3587
|
+
buttons.appendChild(createConnectionTestControls(d));
|
|
3569
3588
|
li.appendChild(info);
|
|
3570
3589
|
li.appendChild(buttons);
|
|
3571
3590
|
ul.appendChild(li);
|
|
@@ -3685,6 +3704,9 @@ var init_devices = __esm({
|
|
|
3685
3704
|
}
|
|
3686
3705
|
});
|
|
3687
3706
|
|
|
3707
|
+
// src/homebridge-ui/public/js/app.ts
|
|
3708
|
+
init_api();
|
|
3709
|
+
|
|
3688
3710
|
// src/homebridge-ui/public/js/credentials.ts
|
|
3689
3711
|
init_logger();
|
|
3690
3712
|
init_modal();
|
|
@@ -3722,7 +3744,7 @@ async function loadCredentialStatus() {
|
|
|
3722
3744
|
uiLog.error("Error loading credentials:", e);
|
|
3723
3745
|
}
|
|
3724
3746
|
}
|
|
3725
|
-
async function
|
|
3747
|
+
async function saveCredentials2() {
|
|
3726
3748
|
const token = document.getElementById("token")?.value;
|
|
3727
3749
|
const secret = document.getElementById("secret")?.value;
|
|
3728
3750
|
const saveStatus = document.getElementById("saveStatus");
|
|
@@ -3744,14 +3766,19 @@ async function saveCredentials() {
|
|
|
3744
3766
|
if (typeof homebridge.getPluginConfig !== "function" || typeof homebridge.updatePluginConfig !== "function") {
|
|
3745
3767
|
throw new TypeError("Homebridge UI API not available");
|
|
3746
3768
|
}
|
|
3747
|
-
|
|
3748
|
-
if (!Array.isArray(configArr)
|
|
3749
|
-
|
|
3769
|
+
let configArr = await homebridge.getPluginConfig();
|
|
3770
|
+
if (!Array.isArray(configArr)) {
|
|
3771
|
+
configArr = [];
|
|
3750
3772
|
}
|
|
3751
|
-
|
|
3773
|
+
let idx = configArr.findIndex((c) => (c.platform || c.name || "").toLowerCase() === "switchbot");
|
|
3774
|
+
if (idx === -1) {
|
|
3775
|
+
configArr.push({ platform: "SwitchBot" });
|
|
3776
|
+
idx = configArr.length - 1;
|
|
3777
|
+
}
|
|
3778
|
+
const config = configArr[idx];
|
|
3752
3779
|
config.openApiToken = token;
|
|
3753
3780
|
config.openApiSecret = secret;
|
|
3754
|
-
await homebridge.updatePluginConfig(
|
|
3781
|
+
await homebridge.updatePluginConfig(configArr);
|
|
3755
3782
|
if (typeof homebridge.savePluginConfig === "function") {
|
|
3756
3783
|
await homebridge.savePluginConfig();
|
|
3757
3784
|
}
|
|
@@ -3781,10 +3808,42 @@ async function saveCredentials() {
|
|
|
3781
3808
|
// src/homebridge-ui/public/js/app.ts
|
|
3782
3809
|
init_devices();
|
|
3783
3810
|
init_discovery();
|
|
3811
|
+
async function ensureSwitchBotConfigBlock() {
|
|
3812
|
+
try {
|
|
3813
|
+
if (typeof homebridge.getPluginConfig !== "function" || typeof homebridge.updatePluginConfig !== "function") {
|
|
3814
|
+
return;
|
|
3815
|
+
}
|
|
3816
|
+
let configArr = await homebridge.getPluginConfig();
|
|
3817
|
+
if (!Array.isArray(configArr)) {
|
|
3818
|
+
configArr = [];
|
|
3819
|
+
}
|
|
3820
|
+
const idx = configArr.findIndex((c) => (c.platform || c.name || "").toLowerCase().includes("switchbot"));
|
|
3821
|
+
if (idx === -1) {
|
|
3822
|
+
configArr.push({ platform: "SwitchBot" });
|
|
3823
|
+
await homebridge.updatePluginConfig(configArr);
|
|
3824
|
+
if (typeof homebridge.savePluginConfig === "function") {
|
|
3825
|
+
await homebridge.savePluginConfig();
|
|
3826
|
+
}
|
|
3827
|
+
}
|
|
3828
|
+
} catch (_e) {
|
|
3829
|
+
}
|
|
3830
|
+
}
|
|
3784
3831
|
window.loadCredentialStatus = loadCredentialStatus;
|
|
3785
|
-
window.saveCredentials =
|
|
3832
|
+
window.saveCredentials = saveCredentials2;
|
|
3786
3833
|
window.discoverDevices = discoverDevices2;
|
|
3834
|
+
async function checkV4Config() {
|
|
3835
|
+
const banner = document.getElementById("v4ConfigWarning");
|
|
3836
|
+
if (!banner) {
|
|
3837
|
+
return;
|
|
3838
|
+
}
|
|
3839
|
+
const isV4 = await detectV4Config();
|
|
3840
|
+
if (isV4) {
|
|
3841
|
+
banner.style.display = "block";
|
|
3842
|
+
}
|
|
3843
|
+
}
|
|
3787
3844
|
async function init() {
|
|
3845
|
+
await ensureSwitchBotConfigBlock();
|
|
3846
|
+
await checkV4Config();
|
|
3788
3847
|
await loadCredentialStatus();
|
|
3789
3848
|
await initializeDiscoverySettings();
|
|
3790
3849
|
await loadConfiguredDevices();
|