@switchbot/homebridge-switchbot 5.0.0-beta.146 → 5.0.0-beta.148

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 (74) hide show
  1. package/.github/workflows/ci.yml +1 -1
  2. package/.github/workflows/manual-e2e.yml +3 -3
  3. package/config.schema.json +6 -0
  4. package/dist/deviceCommandMapper.d.ts +10 -0
  5. package/dist/deviceCommandMapper.d.ts.map +1 -0
  6. package/dist/deviceCommandMapper.js +319 -0
  7. package/dist/deviceCommandMapper.js.map +1 -0
  8. package/dist/deviceFactory.d.ts +2 -3
  9. package/dist/deviceFactory.d.ts.map +1 -1
  10. package/dist/deviceFactory.js +12 -3
  11. package/dist/deviceFactory.js.map +1 -1
  12. package/dist/homebridge-ui/endpoints/config.d.ts.map +1 -1
  13. package/dist/homebridge-ui/endpoints/config.js +1 -18
  14. package/dist/homebridge-ui/endpoints/config.js.map +1 -1
  15. package/dist/homebridge-ui/endpoints/devices.d.ts.map +1 -1
  16. package/dist/homebridge-ui/endpoints/devices.js +1 -350
  17. package/dist/homebridge-ui/endpoints/devices.js.map +1 -1
  18. package/dist/homebridge-ui/public/index.html +6 -0
  19. package/dist/homebridge-ui/public/js/advanced-settings.d.ts.map +1 -1
  20. package/dist/homebridge-ui/public/js/advanced-settings.js +22 -12
  21. package/dist/homebridge-ui/public/js/advanced-settings.js.map +1 -1
  22. package/dist/homebridge-ui/public/js/advanced-settings.ts +36 -25
  23. package/dist/homebridge-ui/public/js/api.d.ts +1 -1
  24. package/dist/homebridge-ui/public/js/api.d.ts.map +1 -1
  25. package/dist/homebridge-ui/public/js/api.js +111 -52
  26. package/dist/homebridge-ui/public/js/api.js.map +1 -1
  27. package/dist/homebridge-ui/public/js/api.ts +112 -53
  28. package/dist/homebridge-ui/public/js/app.js +234 -177
  29. package/dist/homebridge-ui/public/js/app.js.map +4 -4
  30. package/dist/homebridge-ui/public/js/credentials.d.ts.map +1 -1
  31. package/dist/homebridge-ui/public/js/credentials.js +26 -23
  32. package/dist/homebridge-ui/public/js/credentials.js.map +1 -1
  33. package/dist/homebridge-ui/public/js/credentials.ts +26 -25
  34. package/dist/homebridge-ui/public/js/devices-delete.d.ts.map +1 -1
  35. package/dist/homebridge-ui/public/js/devices-delete.js +3 -10
  36. package/dist/homebridge-ui/public/js/devices-delete.js.map +1 -1
  37. package/dist/homebridge-ui/public/js/devices-delete.ts +3 -12
  38. package/dist/homebridge-ui/public/js/devices.d.ts.map +1 -1
  39. package/dist/homebridge-ui/public/js/devices.js +0 -3
  40. package/dist/homebridge-ui/public/js/devices.js.map +1 -1
  41. package/dist/homebridge-ui/public/js/devices.ts +5 -9
  42. package/dist/homebridge-ui/server.js +0 -2
  43. package/dist/homebridge-ui/server.js.map +1 -1
  44. package/dist/platform.d.ts.map +1 -1
  45. package/dist/platform.js +3 -2
  46. package/dist/platform.js.map +1 -1
  47. package/dist/settings.d.ts +1 -0
  48. package/dist/settings.d.ts.map +1 -1
  49. package/dist/settings.js +1 -0
  50. package/dist/settings.js.map +1 -1
  51. package/dist/switchbotClient.d.ts.map +1 -1
  52. package/dist/switchbotClient.js +42 -55
  53. package/dist/switchbotClient.js.map +1 -1
  54. package/docs/variables/default.html +1 -1
  55. package/package.json +1 -1
  56. package/src/deviceCommandMapper.ts +333 -0
  57. package/src/deviceFactory.ts +14 -6
  58. package/src/homebridge-ui/endpoints/config.ts +2 -18
  59. package/src/homebridge-ui/endpoints/devices.ts +1 -392
  60. package/src/homebridge-ui/public/index.html +6 -0
  61. package/src/homebridge-ui/public/js/advanced-settings.ts +36 -25
  62. package/src/homebridge-ui/public/js/api.ts +112 -53
  63. package/src/homebridge-ui/public/js/credentials.ts +26 -25
  64. package/src/homebridge-ui/public/js/devices-delete.ts +3 -12
  65. package/src/homebridge-ui/public/js/devices.ts +5 -9
  66. package/src/homebridge-ui/server.ts +0 -2
  67. package/src/platform.ts +3 -2
  68. package/src/settings.ts +2 -0
  69. package/src/switchbotClient.ts +43 -54
  70. package/dist/homebridge-ui/endpoints/credentials.d.ts +0 -6
  71. package/dist/homebridge-ui/endpoints/credentials.d.ts.map +0 -1
  72. package/dist/homebridge-ui/endpoints/credentials.js +0 -65
  73. package/dist/homebridge-ui/endpoints/credentials.js.map +0 -1
  74. package/src/homebridge-ui/endpoints/credentials.ts +0 -74
@@ -8,6 +8,98 @@ 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) {
43
+ try {
44
+ const value = homebridge?.[name];
45
+ if (typeof value === "function") {
46
+ const fn = value;
47
+ fn();
48
+ }
49
+ } catch (e) {
50
+ uiLog.warn(`Homebridge UI method ${String(name)} failed:`, e);
51
+ }
52
+ }
53
+ function showBusyUi() {
54
+ callUiMethod("disableSaveButton");
55
+ callUiMethod("showSpinner");
56
+ }
57
+ function hideBusyUi() {
58
+ callUiMethod("hideSpinner");
59
+ callUiMethod("enableSaveButton");
60
+ }
61
+ var init_modal = __esm({
62
+ "src/homebridge-ui/public/js/modal.ts"() {
63
+ "use strict";
64
+ init_types();
65
+ init_logger();
66
+ }
67
+ });
68
+
69
+ // src/homebridge-ui/public/js/toast.ts
70
+ function showToast(method, message, title = "SwitchBot") {
71
+ try {
72
+ const toast = homebridge?.toast;
73
+ const fn = toast?.[method];
74
+ if (typeof fn === "function") {
75
+ fn(message, title);
76
+ return;
77
+ }
78
+ uiLog.info(`[Toast:${method}] ${title} - ${message}`);
79
+ } catch (e) {
80
+ uiLog.warn(`Toast ${method} failed:`, e);
81
+ }
82
+ }
83
+ function toastSuccess(message, title) {
84
+ showToast("success", message, title);
85
+ }
86
+ function toastError(message, title) {
87
+ showToast("error", message, title);
88
+ }
89
+ function toastWarning(message, title) {
90
+ showToast("warning", message, title);
91
+ }
92
+ function toastInfo(message, title) {
93
+ showToast("info", message, title);
94
+ }
95
+ var init_toast = __esm({
96
+ "src/homebridge-ui/public/js/toast.ts"() {
97
+ "use strict";
98
+ init_types();
99
+ init_logger();
100
+ }
101
+ });
102
+
11
103
  // src/device-types.ts
12
104
  function getValidDeviceTypes() {
13
105
  const validTypes = /* @__PURE__ */ new Set();
@@ -253,36 +345,6 @@ var init_device_types = __esm({
253
345
  }
254
346
  });
255
347
 
256
- // src/homebridge-ui/public/js/types.ts
257
- var init_types = __esm({
258
- "src/homebridge-ui/public/js/types.ts"() {
259
- "use strict";
260
- }
261
- });
262
-
263
- // src/homebridge-ui/public/js/logger.ts
264
- var PREFIX, uiLog;
265
- var init_logger = __esm({
266
- "src/homebridge-ui/public/js/logger.ts"() {
267
- "use strict";
268
- PREFIX = "[SwitchBot UI/html]";
269
- uiLog = {
270
- info: (message, ...parameters) => {
271
- console.log(PREFIX, message, ...parameters);
272
- },
273
- warn: (message, ...parameters) => {
274
- console.warn(PREFIX, message, ...parameters);
275
- },
276
- error: (message, ...parameters) => {
277
- console.error(PREFIX, message, ...parameters);
278
- },
279
- debug: (message, ...parameters) => {
280
- console.debug(PREFIX, message, ...parameters);
281
- }
282
- };
283
- }
284
- });
285
-
286
348
  // src/homebridge-ui/public/js/api.ts
287
349
  var api_exports = {};
288
350
  __export(api_exports, {
@@ -294,12 +356,29 @@ __export(api_exports, {
294
356
  fetchBluetoothStatus: () => fetchBluetoothStatus,
295
357
  fetchCredentialStatus: () => fetchCredentialStatus,
296
358
  fetchDevices: () => fetchDevices,
297
- saveCredentials: () => saveCredentials,
359
+ saveCredentials: () => saveCredentials2,
298
360
  syncParentPluginConfigFromDisk: () => syncParentPluginConfigFromDisk,
299
361
  testDeviceConnection: () => testDeviceConnection,
300
362
  updateDevice: () => updateDevice,
301
363
  validateAndFixDeviceTypes: () => validateAndFixDeviceTypes
302
364
  });
365
+ async function fetchDevices() {
366
+ try {
367
+ if (typeof homebridge.getPluginConfig !== "function") {
368
+ throw new TypeError("Homebridge UI API not available");
369
+ }
370
+ const configArr = await homebridge.getPluginConfig();
371
+ const config = Array.isArray(configArr) && configArr.length > 0 ? configArr.find(isSwitchBotPlatformConfig) : null;
372
+ if (!config || !Array.isArray(config.devices)) {
373
+ return [];
374
+ }
375
+ return config.devices;
376
+ } catch (e) {
377
+ const msg = e instanceof Error ? e.message : String(e);
378
+ uiLog.error("Error fetching devices:", msg);
379
+ return [];
380
+ }
381
+ }
303
382
  function validateAndFixDeviceTypes(devices) {
304
383
  const errors = [];
305
384
  for (const d of devices) {
@@ -375,7 +454,7 @@ async function fetchCredentialStatus() {
375
454
  return null;
376
455
  }
377
456
  }
378
- async function saveCredentials(token, secret) {
457
+ async function saveCredentials2(token, secret) {
379
458
  uiLog.info("Saving credentials...");
380
459
  const resp = await homebridge.request("/credentials", { token, secret });
381
460
  uiLog.info("Save response:", resp);
@@ -384,20 +463,6 @@ async function saveCredentials(token, secret) {
384
463
  }
385
464
  return resp.data || resp;
386
465
  }
387
- async function fetchDevices() {
388
- try {
389
- const resp = await homebridge.request("/devices", {});
390
- if (!resp || resp.success === false) {
391
- const backendMsg = resp?.data?.message || resp?.message;
392
- throw new Error(backendMsg || "request failed");
393
- }
394
- return resp.data || [];
395
- } catch (e) {
396
- const msg = e instanceof Error ? e.message : String(e);
397
- uiLog.error("Error fetching devices:", msg);
398
- return [];
399
- }
400
- }
401
466
  async function discoverDevices(mode = "all", options) {
402
467
  const resp = await homebridge.request("/discover", { mode, ...options });
403
468
  uiLog.info("Discover response:", resp);
@@ -431,29 +496,45 @@ async function testDeviceConnection(payload) {
431
496
  };
432
497
  }
433
498
  async function addDevice(deviceId, name, type, options) {
434
- const payload = { deviceId, name, type };
499
+ if (typeof homebridge.getPluginConfig !== "function" || typeof homebridge.updatePluginConfig !== "function") {
500
+ throw new TypeError("Homebridge UI API not available");
501
+ }
502
+ const configArr = await homebridge.getPluginConfig();
503
+ const idx = Array.isArray(configArr) ? configArr.findIndex(isSwitchBotPlatformConfig) : -1;
504
+ if (idx === -1) {
505
+ throw new Error("SwitchBot config not found");
506
+ }
507
+ const config = configArr[idx];
508
+ if (!Array.isArray(config.devices)) {
509
+ config.devices = [];
510
+ }
511
+ const normalizedDeviceId = String(deviceId).trim().toLowerCase();
512
+ const exists = config.devices.some((d) => String(d.deviceId ?? d.id ?? "").trim().toLowerCase() === normalizedDeviceId);
513
+ if (exists) {
514
+ return { alreadyExists: true, message: "Device already in config" };
515
+ }
516
+ const newDevice = { deviceId, configDeviceName: name, configDeviceType: type };
435
517
  if (options?.address) {
436
- payload.address = options.address;
518
+ newDevice.address = options.address;
437
519
  }
438
520
  if (options?.model) {
439
- payload.model = options.model;
521
+ newDevice.model = options.model;
440
522
  }
441
523
  if (options?.rssi !== void 0 && options?.rssi !== null && options?.rssi !== 0) {
442
- payload.rssi = options.rssi;
524
+ newDevice.rssi = options.rssi;
443
525
  }
444
526
  if (options?.encryptionKey) {
445
- payload.encryptionKey = options.encryptionKey;
527
+ newDevice.encryptionKey = options.encryptionKey;
446
528
  }
447
529
  if (options?.keyId) {
448
- payload.keyId = options.keyId;
530
+ newDevice.keyId = options.keyId;
449
531
  }
450
- uiLog.info("Adding device to config:", payload);
451
- const resp = await homebridge.request("/add-device", payload);
452
- uiLog.info("Add device response:", resp);
453
- if (!resp || resp.success === false) {
454
- throw new Error(resp?.data?.message || "Failed to add device");
532
+ config.devices.push(newDevice);
533
+ await homebridge.updatePluginConfig(configArr);
534
+ if (typeof homebridge.savePluginConfig === "function") {
535
+ await homebridge.savePluginConfig();
455
536
  }
456
- return resp.data || resp;
537
+ return { added: true, message: `Device "${name}" added successfully` };
457
538
  }
458
539
  async function addDevicesInBulk(devices) {
459
540
  const resp = await homebridge.request("/add-devices", { devices });
@@ -464,108 +545,88 @@ async function addDevicesInBulk(devices) {
464
545
  return resp.data || resp;
465
546
  }
466
547
  async function updateDevice(deviceId, configDeviceName, configDeviceType, options) {
467
- const params = { deviceId };
548
+ if (typeof homebridge.getPluginConfig !== "function" || typeof homebridge.updatePluginConfig !== "function") {
549
+ throw new TypeError("Homebridge UI API not available");
550
+ }
551
+ const configArr = await homebridge.getPluginConfig();
552
+ const idx = Array.isArray(configArr) ? configArr.findIndex(isSwitchBotPlatformConfig) : -1;
553
+ if (idx === -1) {
554
+ throw new Error("SwitchBot config not found");
555
+ }
556
+ const config = configArr[idx];
557
+ if (!Array.isArray(config.devices)) {
558
+ throw new TypeError("No devices array in config");
559
+ }
560
+ const normalizedDeviceId = String(deviceId).trim().toLowerCase();
561
+ const device = config.devices.find((d) => String(d.deviceId ?? d.id ?? "").trim().toLowerCase() === normalizedDeviceId);
562
+ if (!device) {
563
+ throw new Error("Device not found in config");
564
+ }
468
565
  if (configDeviceName) {
469
- params.configDeviceName = configDeviceName;
566
+ device.configDeviceName = configDeviceName;
470
567
  }
471
568
  if (configDeviceType) {
472
- params.configDeviceType = configDeviceType;
569
+ device.configDeviceType = configDeviceType;
473
570
  }
474
571
  if (options) {
475
- Object.assign(params, options);
572
+ Object.assign(device, options);
476
573
  }
477
- uiLog.info("[Update Device] Sending update request with params:", params);
478
- const resp = await homebridge.request("/update-device", params);
479
- uiLog.info("[Update Device] Update response:", resp);
480
- if (!resp || resp.success === false) {
481
- throw new Error(resp?.data?.message || "Failed to update device");
574
+ await homebridge.updatePluginConfig(configArr);
575
+ if (typeof homebridge.savePluginConfig === "function") {
576
+ await homebridge.savePluginConfig();
482
577
  }
483
- return resp.data || resp;
578
+ return { updated: true, message: `Device updated successfully` };
484
579
  }
485
580
  async function deleteDevice(deviceId) {
486
- uiLog.info("Sending delete request for deviceId:", deviceId);
487
- const resp = await homebridge.request("/delete-device", { deviceId });
488
- uiLog.info("Delete response:", resp);
489
- if (!resp || resp.success === false) {
490
- throw new Error(resp?.data?.message || "Failed to delete device");
581
+ if (typeof homebridge.getPluginConfig !== "function" || typeof homebridge.updatePluginConfig !== "function") {
582
+ throw new TypeError("Homebridge UI API not available");
491
583
  }
492
- return resp.data || resp;
493
- }
494
- async function deleteAllDevices() {
495
- uiLog.info("Sending delete all devices request");
496
- const resp = await homebridge.request("/delete-all-devices", {});
497
- uiLog.info("Delete all response:", resp);
498
- if (!resp || resp.success === false) {
499
- throw new Error(resp?.data?.message || "Failed to delete all devices");
584
+ const configArr = await homebridge.getPluginConfig();
585
+ const idx = Array.isArray(configArr) ? configArr.findIndex(isSwitchBotPlatformConfig) : -1;
586
+ if (idx === -1) {
587
+ throw new Error("SwitchBot config not found");
500
588
  }
501
- return resp.data || resp;
502
- }
503
- var init_api = __esm({
504
- "src/homebridge-ui/public/js/api.ts"() {
505
- "use strict";
506
- init_device_types();
507
- init_types();
508
- init_logger();
589
+ const config = configArr[idx];
590
+ if (!Array.isArray(config.devices)) {
591
+ throw new TypeError("No devices array in config");
509
592
  }
510
- });
511
-
512
- // src/homebridge-ui/public/js/modal.ts
513
- function callUiMethod(name) {
514
- try {
515
- const value = homebridge?.[name];
516
- if (typeof value === "function") {
517
- const fn = value;
518
- fn();
519
- }
520
- } catch (e) {
521
- uiLog.warn(`Homebridge UI method ${String(name)} failed:`, e);
593
+ const normalizedDeviceId = String(deviceId).trim().toLowerCase();
594
+ const before = config.devices.length;
595
+ config.devices = config.devices.filter((d) => String(d.deviceId ?? d.id ?? "").trim().toLowerCase() !== normalizedDeviceId);
596
+ if (config.devices.length === before) {
597
+ throw new Error("Device not found in config");
522
598
  }
599
+ await homebridge.updatePluginConfig(configArr);
600
+ if (typeof homebridge.savePluginConfig === "function") {
601
+ await homebridge.savePluginConfig();
602
+ }
603
+ return { deleted: true, message: `Device removed from config` };
523
604
  }
524
- function showBusyUi() {
525
- callUiMethod("disableSaveButton");
526
- callUiMethod("showSpinner");
527
- }
528
- function hideBusyUi() {
529
- callUiMethod("hideSpinner");
530
- callUiMethod("enableSaveButton");
531
- }
532
- var init_modal = __esm({
533
- "src/homebridge-ui/public/js/modal.ts"() {
534
- "use strict";
535
- init_types();
536
- init_logger();
605
+ async function deleteAllDevices() {
606
+ if (typeof homebridge.getPluginConfig !== "function" || typeof homebridge.updatePluginConfig !== "function") {
607
+ throw new TypeError("Homebridge UI API not available");
537
608
  }
538
- });
539
-
540
- // src/homebridge-ui/public/js/toast.ts
541
- function showToast(method, message, title = "SwitchBot") {
542
- try {
543
- const toast = homebridge?.toast;
544
- const fn = toast?.[method];
545
- if (typeof fn === "function") {
546
- fn(message, title);
547
- return;
548
- }
549
- uiLog.info(`[Toast:${method}] ${title} - ${message}`);
550
- } catch (e) {
551
- uiLog.warn(`Toast ${method} failed:`, e);
609
+ const configArr = await homebridge.getPluginConfig();
610
+ const idx = Array.isArray(configArr) ? configArr.findIndex(isSwitchBotPlatformConfig) : -1;
611
+ if (idx === -1) {
612
+ throw new Error("SwitchBot config not found");
552
613
  }
614
+ const config = configArr[idx];
615
+ if (!Array.isArray(config.devices)) {
616
+ throw new TypeError("No devices array in config");
617
+ }
618
+ const deletedCount = config.devices.length;
619
+ config.devices = [];
620
+ await homebridge.updatePluginConfig(configArr);
621
+ if (typeof homebridge.savePluginConfig === "function") {
622
+ await homebridge.savePluginConfig();
623
+ }
624
+ return { deleted: true, deletedCount, message: `Removed ${deletedCount} device(s) from config` };
553
625
  }
554
- function toastSuccess(message, title) {
555
- showToast("success", message, title);
556
- }
557
- function toastError(message, title) {
558
- showToast("error", message, title);
559
- }
560
- function toastWarning(message, title) {
561
- showToast("warning", message, title);
562
- }
563
- function toastInfo(message, title) {
564
- showToast("info", message, title);
565
- }
566
- var init_toast = __esm({
567
- "src/homebridge-ui/public/js/toast.ts"() {
626
+ var init_api = __esm({
627
+ "src/homebridge-ui/public/js/api.ts"() {
568
628
  "use strict";
629
+ init_device_types();
569
630
  init_types();
570
631
  init_logger();
571
632
  }
@@ -2569,12 +2630,9 @@ async function deleteDeviceFromConfig(deviceId, deviceName) {
2569
2630
  }
2570
2631
  try {
2571
2632
  showBusyUi();
2572
- uiLog.info("Sending delete request for deviceId:", deviceId);
2633
+ uiLog.info("Deleting device from config:", deviceId);
2573
2634
  const resp = await deleteDevice(deviceId);
2574
2635
  uiLog.info("Delete response:", resp);
2575
- if (!resp || resp.success === false) {
2576
- throw new Error(resp?.data?.message || "Failed to delete device");
2577
- }
2578
2636
  uiLog.info("Syncing parent config from disk...");
2579
2637
  const synced = await syncParentPluginConfigFromDisk(true);
2580
2638
  if (!synced) {
@@ -2672,12 +2730,9 @@ async function deleteAllDevicesFromConfig() {
2672
2730
  return;
2673
2731
  }
2674
2732
  showBusyUi();
2675
- uiLog.info("Sending delete all devices request");
2733
+ uiLog.info("Deleting all devices from config");
2676
2734
  const resp = await deleteAllDevices();
2677
2735
  uiLog.info("Delete all response:", resp);
2678
- if (!resp || resp.success === false) {
2679
- throw new Error(resp?.data?.message || "Failed to delete all devices");
2680
- }
2681
2736
  uiLog.info("Syncing parent config from disk...");
2682
2737
  const synced = await syncParentPluginConfigFromDisk(true);
2683
2738
  if (!synced) {
@@ -2687,7 +2742,7 @@ async function deleteAllDevicesFromConfig() {
2687
2742
  const updatedList = await fetchDevices();
2688
2743
  uiLog.info("Rendering devices:", updatedList.length);
2689
2744
  renderDeviceList(updatedList);
2690
- const deletedCount = resp?.deletedCount || list.length;
2745
+ const deletedCount = resp?.deletedCount || 0;
2691
2746
  uiLog.info(`\u2713 Removed ${deletedCount} device(s) successfully`);
2692
2747
  toastSuccess(`Removed ${deletedCount} device(s) successfully`);
2693
2748
  } catch (e) {
@@ -3611,9 +3666,6 @@ async function addDeviceToConfig2(device, options = {}) {
3611
3666
  keyId: importValues.keyId
3612
3667
  });
3613
3668
  uiLog.info("Add device response:", resp);
3614
- if (!resp || resp.success === false) {
3615
- throw new Error(resp?.data?.message || "Failed to add device");
3616
- }
3617
3669
  const alreadyExists = !!resp?.alreadyExists;
3618
3670
  const message = resp?.message || (alreadyExists ? `Device "${importValues.configDeviceName}" already in config` : `Device "${importValues.configDeviceName}" added successfully!`);
3619
3671
  if (alreadyExists) {
@@ -3682,31 +3734,33 @@ var init_devices = __esm({
3682
3734
  });
3683
3735
 
3684
3736
  // src/homebridge-ui/public/js/credentials.ts
3685
- init_api();
3686
3737
  init_logger();
3687
3738
  init_modal();
3688
3739
  init_toast();
3689
3740
  async function loadCredentialStatus() {
3690
3741
  try {
3691
- const creds = await fetchCredentialStatus();
3692
- if (!creds) {
3693
- uiLog.error("Failed to load credentials");
3742
+ if (typeof homebridge.getPluginConfig !== "function") {
3743
+ uiLog.error("Homebridge UI API not available");
3694
3744
  return;
3695
3745
  }
3746
+ const configArr = await homebridge.getPluginConfig();
3747
+ const config = Array.isArray(configArr) && configArr.length > 0 ? configArr[0] : {};
3748
+ const token = config.openApiToken || "";
3749
+ const secret = config.openApiSecret || "";
3696
3750
  const tokenStatus = document.getElementById("tokenStatus");
3697
3751
  const secretStatus = document.getElementById("secretStatus");
3698
3752
  if (!tokenStatus || !secretStatus) {
3699
3753
  return;
3700
3754
  }
3701
- if (creds.hasToken) {
3702
- tokenStatus.textContent = `\u2713 Configured (${creds.tokenLength} characters)`;
3755
+ if (token) {
3756
+ tokenStatus.textContent = `\u2713 Configured (${token.length} characters)`;
3703
3757
  tokenStatus.classList.add("ok");
3704
3758
  } else {
3705
3759
  tokenStatus.textContent = "Not configured";
3706
3760
  tokenStatus.classList.remove("ok");
3707
3761
  }
3708
- if (creds.hasSecret) {
3709
- secretStatus.textContent = `\u2713 Configured (${creds.secretLength} characters)`;
3762
+ if (secret) {
3763
+ secretStatus.textContent = `\u2713 Configured (${secret.length} characters)`;
3710
3764
  secretStatus.classList.add("ok");
3711
3765
  } else {
3712
3766
  secretStatus.textContent = "Not configured";
@@ -3716,7 +3770,7 @@ async function loadCredentialStatus() {
3716
3770
  uiLog.error("Error loading credentials:", e);
3717
3771
  }
3718
3772
  }
3719
- async function saveCredentials2() {
3773
+ async function saveCredentials() {
3720
3774
  const token = document.getElementById("token")?.value;
3721
3775
  const secret = document.getElementById("secret")?.value;
3722
3776
  const saveStatus = document.getElementById("saveStatus");
@@ -3735,21 +3789,24 @@ async function saveCredentials2() {
3735
3789
  saveBtn.disabled = true;
3736
3790
  saveBtn.textContent = "Saving...";
3737
3791
  uiLog.info("Saving credentials...");
3738
- const result = await saveCredentials(token, secret);
3739
- uiLog.info("Save response:", result);
3740
- const message = result?.message || "Credentials saved successfully";
3741
- saveStatus.textContent = `\u2713 ${message}`;
3792
+ if (typeof homebridge.getPluginConfig !== "function" || typeof homebridge.updatePluginConfig !== "function") {
3793
+ throw new TypeError("Homebridge UI API not available");
3794
+ }
3795
+ const configArr = await homebridge.getPluginConfig();
3796
+ if (!Array.isArray(configArr) || configArr.length === 0) {
3797
+ throw new Error("No plugin config found");
3798
+ }
3799
+ const config = configArr[0];
3800
+ config.openApiToken = token;
3801
+ config.openApiSecret = secret;
3802
+ await homebridge.updatePluginConfig([config]);
3803
+ if (typeof homebridge.savePluginConfig === "function") {
3804
+ await homebridge.savePluginConfig();
3805
+ }
3806
+ saveStatus.textContent = `\u2713 Credentials saved successfully`;
3742
3807
  saveStatus.classList.remove("error");
3743
3808
  saveStatus.classList.add("success-msg");
3744
- toastSuccess(message);
3745
- const synced = await syncParentPluginConfigFromDisk(true);
3746
- if (synced) {
3747
- saveStatus.textContent += " - Config saved automatically.";
3748
- toastSuccess("Configuration synced and saved automatically");
3749
- } else {
3750
- toastWarning("Credentials saved, but configuration sync failed");
3751
- }
3752
- ;
3809
+ toastSuccess("Credentials saved successfully");
3753
3810
  document.getElementById("token").value = "";
3754
3811
  document.getElementById("secret").value = "";
3755
3812
  setTimeout(loadCredentialStatus, 500);
@@ -3773,7 +3830,7 @@ async function saveCredentials2() {
3773
3830
  init_devices();
3774
3831
  init_discovery();
3775
3832
  window.loadCredentialStatus = loadCredentialStatus;
3776
- window.saveCredentials = saveCredentials2;
3833
+ window.saveCredentials = saveCredentials;
3777
3834
  window.discoverDevices = discoverDevices2;
3778
3835
  async function init() {
3779
3836
  await loadCredentialStatus();