@switchbot/homebridge-switchbot 5.1.0-beta.0 → 5.1.0-beta.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.
Files changed (47) hide show
  1. package/dist/SwitchBotMatterPlatform.d.ts +1 -0
  2. package/dist/SwitchBotMatterPlatform.d.ts.map +1 -1
  3. package/dist/SwitchBotMatterPlatform.js +23 -0
  4. package/dist/SwitchBotMatterPlatform.js.map +1 -1
  5. package/dist/homebridge-ui/endpoints/config.d.ts.map +1 -1
  6. package/dist/homebridge-ui/endpoints/config.js +9 -2
  7. package/dist/homebridge-ui/endpoints/config.js.map +1 -1
  8. package/dist/homebridge-ui/homebridge-ui/endpoints/config.js +9 -2
  9. package/dist/homebridge-ui/homebridge-ui/endpoints/config.js.map +1 -1
  10. package/dist/homebridge-ui/homebridge-ui/utils/config-parser.js +8 -0
  11. package/dist/homebridge-ui/homebridge-ui/utils/config-parser.js.map +1 -1
  12. package/dist/homebridge-ui/homebridge-ui/utils/v4-detection.js +23 -0
  13. package/dist/homebridge-ui/homebridge-ui/utils/v4-detection.js.map +1 -0
  14. package/dist/homebridge-ui/public/css/styles.css +61 -1
  15. package/dist/homebridge-ui/public/index.html +25 -2
  16. package/dist/homebridge-ui/public/js/api.d.ts +10 -0
  17. package/dist/homebridge-ui/public/js/api.d.ts.map +1 -1
  18. package/dist/homebridge-ui/public/js/api.js +30 -0
  19. package/dist/homebridge-ui/public/js/api.js.map +1 -1
  20. package/dist/homebridge-ui/public/js/api.ts +30 -0
  21. package/dist/homebridge-ui/public/js/app.js +159 -109
  22. package/dist/homebridge-ui/public/js/app.js.map +4 -4
  23. package/dist/homebridge-ui/public/js/app.ts +22 -4
  24. package/dist/homebridge-ui/utils/config-parser.d.ts +8 -0
  25. package/dist/homebridge-ui/utils/config-parser.d.ts.map +1 -1
  26. package/dist/homebridge-ui/utils/config-parser.js +8 -0
  27. package/dist/homebridge-ui/utils/config-parser.js.map +1 -1
  28. package/dist/homebridge-ui/utils/v4-detection.d.ts +12 -0
  29. package/dist/homebridge-ui/utils/v4-detection.d.ts.map +1 -0
  30. package/dist/homebridge-ui/utils/v4-detection.js +23 -0
  31. package/dist/homebridge-ui/utils/v4-detection.js.map +1 -0
  32. package/docs/assets/icons.js +1 -1
  33. package/docs/assets/icons.svg +1 -1
  34. package/docs/assets/main.js +3 -3
  35. package/docs/variables/default.html +1 -1
  36. package/package.json +6 -6
  37. package/scripts/build-ui.js +30 -0
  38. package/src/SwitchBotMatterPlatform.ts +26 -0
  39. package/src/homebridge-ui/endpoints/config.ts +10 -2
  40. package/src/homebridge-ui/public/css/styles.css +61 -1
  41. package/src/homebridge-ui/public/index.html +23 -0
  42. package/src/homebridge-ui/public/js/api.ts +30 -0
  43. package/src/homebridge-ui/public/js/app.ts +22 -4
  44. package/src/homebridge-ui/utils/config-parser.ts +9 -0
  45. package/src/homebridge-ui/utils/v4-detection.ts +23 -0
  46. package/test/homebridge-ui/config-parser.spec.ts +61 -0
  47. package/test/platform/matter-integration.spec.ts +50 -0
@@ -1,5 +1,6 @@
1
1
  // Fetch the list of configured devices from the Homebridge UI API
2
2
  import { isValidDeviceType, normalizeDeviceType } from '../../../device-types.js'
3
+ import { isV4Config } from '../../utils/v4-detection.js'
3
4
  import './types.js'
4
5
  import { uiLog } from './logger.js'
5
6
  import { toastError } from './toast.js'
@@ -22,6 +23,35 @@ export async function fetchDevices(): Promise<any[]> {
22
23
  }
23
24
  }
24
25
 
26
+ /**
27
+ * Detect whether the current plugin config is in the legacy v4 format.
28
+ *
29
+ * v4 configs stored credentials under a `credentials` sub-object and devices
30
+ * under `options.devices`. v5+ flattened these to `openApiToken`,
31
+ * `openApiSecret`, and a root-level `devices` array.
32
+ *
33
+ * Returns true when a v4 config block is found, false otherwise.
34
+ */
35
+ export async function detectV4Config(): Promise<boolean> {
36
+ try {
37
+ if (typeof homebridge.getPluginConfig !== 'function') {
38
+ return false
39
+ }
40
+ const configArr = await homebridge.getPluginConfig()
41
+ if (!Array.isArray(configArr)) {
42
+ return false
43
+ }
44
+ const config = configArr.find(isSwitchBotPlatformConfig)
45
+ if (!config || typeof config !== 'object') {
46
+ return false
47
+ }
48
+ return isV4Config(config)
49
+ } catch (e) {
50
+ uiLog.warn('Error detecting v4 config:', e)
51
+ return false
52
+ }
53
+ }
54
+
25
55
  /**
26
56
  * Validate and auto-correct device types in the config array before saving.
27
57
  * Returns an array of errors for devices that cannot be fixed.
@@ -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,91 @@ 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
+ const fn = toast && typeof toast[method] === "function" ? toast[method] : void 0;
303
+ if (fn) {
304
+ try {
305
+ fn(message, title);
306
+ return;
307
+ } catch (err) {
308
+ uiLog.warn(`Toast ${method} threw:`, err);
309
+ }
310
+ }
311
+ uiLog.info(`[Toast:${method}] ${title} - ${message}`);
312
+ } catch (e) {
313
+ uiLog.warn(`Toast ${method} outer error:`, e);
314
+ uiLog.info(`[Toast:${method}] ${title} - ${message}`);
315
+ }
316
+ }
317
+ function toastSuccess(message, title) {
318
+ showToast("success", message, title);
319
+ }
320
+ function toastError(message, title) {
321
+ showToast("error", message, title);
322
+ }
323
+ function toastWarning(message, title) {
324
+ showToast("warning", message, title);
325
+ }
326
+ function toastInfo(message, title) {
327
+ showToast("info", message, title);
328
+ }
329
+ var init_toast = __esm({
330
+ "src/homebridge-ui/public/js/toast.ts"() {
331
+ "use strict";
332
+ init_types();
333
+ init_logger();
334
+ }
335
+ });
336
+
357
337
  // src/homebridge-ui/public/js/api.ts
358
338
  var api_exports = {};
359
339
  __export(api_exports, {
@@ -361,11 +341,12 @@ __export(api_exports, {
361
341
  addDevicesInBulk: () => addDevicesInBulk,
362
342
  deleteAllDevices: () => deleteAllDevices,
363
343
  deleteDevice: () => deleteDevice,
344
+ detectV4Config: () => detectV4Config,
364
345
  discoverDevices: () => discoverDevices,
365
346
  fetchBluetoothStatus: () => fetchBluetoothStatus,
366
347
  fetchCredentialStatus: () => fetchCredentialStatus,
367
348
  fetchDevices: () => fetchDevices,
368
- saveCredentials: () => saveCredentials2,
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 saveCredentials2(token, secret) {
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);
@@ -657,12 +657,48 @@ var init_api = __esm({
657
657
  "src/homebridge-ui/public/js/api.ts"() {
658
658
  "use strict";
659
659
  init_device_types();
660
+ init_v4_detection();
660
661
  init_types();
661
662
  init_logger();
662
663
  init_toast();
663
664
  }
664
665
  });
665
666
 
667
+ // src/homebridge-ui/public/js/modal.ts
668
+ function callUiMethod(name, ...args) {
669
+ try {
670
+ if (typeof homebridge?.[name] === "function") {
671
+ uiLog.info(`[callUiMethod] Invoking homebridge.${String(name)}()`);
672
+ const fn = homebridge?.[name];
673
+ if (typeof fn === "function") {
674
+ uiLog.info(`[callUiMethod] Invoking homebridge.${String(name)}()`);
675
+ fn.apply(homebridge, args);
676
+ } else {
677
+ uiLog.warn(`[callUiMethod] homebridge[${String(name)}] is not a function.`);
678
+ }
679
+ } else {
680
+ uiLog.warn(`[callUiMethod] homebridge[${String(name)}] is not a function.`);
681
+ }
682
+ } catch (e) {
683
+ uiLog.warn(`Homebridge UI method ${String(name)} failed:`, e);
684
+ }
685
+ }
686
+ function showBusyUi() {
687
+ callUiMethod("disableSaveButton");
688
+ callUiMethod("showSpinner");
689
+ }
690
+ function hideBusyUi() {
691
+ callUiMethod("hideSpinner");
692
+ callUiMethod("enableSaveButton");
693
+ }
694
+ var init_modal = __esm({
695
+ "src/homebridge-ui/public/js/modal.ts"() {
696
+ "use strict";
697
+ init_types();
698
+ init_logger();
699
+ }
700
+ });
701
+
666
702
  // src/homebridge-ui/public/js/discovery.ts
667
703
  var discovery_exports = {};
668
704
  __export(discovery_exports, {
@@ -3685,6 +3721,9 @@ var init_devices = __esm({
3685
3721
  }
3686
3722
  });
3687
3723
 
3724
+ // src/homebridge-ui/public/js/app.ts
3725
+ init_api();
3726
+
3688
3727
  // src/homebridge-ui/public/js/credentials.ts
3689
3728
  init_logger();
3690
3729
  init_modal();
@@ -3722,7 +3761,7 @@ async function loadCredentialStatus() {
3722
3761
  uiLog.error("Error loading credentials:", e);
3723
3762
  }
3724
3763
  }
3725
- async function saveCredentials() {
3764
+ async function saveCredentials2() {
3726
3765
  const token = document.getElementById("token")?.value;
3727
3766
  const secret = document.getElementById("secret")?.value;
3728
3767
  const saveStatus = document.getElementById("saveStatus");
@@ -3782,9 +3821,20 @@ async function saveCredentials() {
3782
3821
  init_devices();
3783
3822
  init_discovery();
3784
3823
  window.loadCredentialStatus = loadCredentialStatus;
3785
- window.saveCredentials = saveCredentials;
3824
+ window.saveCredentials = saveCredentials2;
3786
3825
  window.discoverDevices = discoverDevices2;
3826
+ async function checkV4Config() {
3827
+ const banner = document.getElementById("v4ConfigWarning");
3828
+ if (!banner) {
3829
+ return;
3830
+ }
3831
+ const isV4 = await detectV4Config();
3832
+ if (isV4) {
3833
+ banner.style.display = "block";
3834
+ }
3835
+ }
3787
3836
  async function init() {
3837
+ await checkV4Config();
3788
3838
  await loadCredentialStatus();
3789
3839
  await initializeDiscoverySettings();
3790
3840
  await loadConfiguredDevices();