homebridge-unifi-access 1.4.0 → 1.6.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.
@@ -50,16 +50,8 @@ export class FeatureOptions {
50
50
  * @returns Returns true or false, depending on the option default.
51
51
  */
52
52
  defaultValue(option) {
53
- // Value-centric feature options don't have default values.
54
- if (this.isValue(option)) {
55
- return this.defaultReturnValue;
56
- }
57
- const value = this.defaults[option.toLowerCase()];
58
- // If it's unknown to us, assume it's true.
59
- if (value === undefined) {
60
- return this.defaultReturnValue;
61
- }
62
- return value;
53
+ // If it's unknown to us, return the default return value.
54
+ return this.defaults[option.toLowerCase()] ?? this.defaultReturnValue;
63
55
  }
64
56
  /**
65
57
  * Return whether the option explicitly exists in the list of configured options.
@@ -96,7 +88,7 @@ export class FeatureOptions {
96
88
  * @param device - Optional device scope identifier.
97
89
  * @param controller - Optional controller scope identifier.
98
90
  *
99
- * @returns Returns the value of a value-centric option as a floating point number or `undefined` if it doesn't exist or couldn't be parsed.
91
+ * @returns Returns the value of a value-centric option as a floating point number, `undefined` if it doesn't exist or couldn't be parsed, and `null` if disabled.
100
92
  */
101
93
  getFloat(option, device, controller) {
102
94
  // Parse the number and return the value.
@@ -109,7 +101,7 @@ export class FeatureOptions {
109
101
  * @param device - Optional device scope identifier.
110
102
  * @param controller - Optional controller scope identifier.
111
103
  *
112
- * @returns Returns the value of a value-centric option as an integer or `undefined` if it doesn't exist or couldn't be parsed.
104
+ * @returns Returns the value of a value-centric option as an integer, `undefined` if it doesn't exist or couldn't be parsed, and `null` if disabled.
113
105
  */
114
106
  getInteger(option, device, controller) {
115
107
  // Parse the number and return the value.
@@ -147,7 +139,10 @@ export class FeatureOptions {
147
139
  * @returns Returns true if it is a value-centric option and false otherwise.
148
140
  */
149
141
  isValue(option) {
150
- return this.valueOptions[option?.toLowerCase()] === true;
142
+ if (!option) {
143
+ return false;
144
+ }
145
+ return option.toLowerCase() in this.valueOptions;
151
146
  }
152
147
  /**
153
148
  * Return the scope hierarchy location of an option.
@@ -180,20 +175,24 @@ export class FeatureOptions {
180
175
  * @param device - Optional device scope identifier.
181
176
  * @param controller - Optional controller scope identifier.
182
177
  *
183
- * @returns Returns the current value associated with `option` or `undefined` if none.
178
+ * @returns Returns the current value associated with `option` if the feature option is enabled, `null` if disabled (or not a value-centric feature option), or
179
+ * `undefined` if it's not specified.
184
180
  */
185
181
  value(option, device, controller) {
186
182
  // If this isn't a value-centric feature option, we're done.
187
183
  if (!this.isValue(option)) {
188
- return undefined;
184
+ return null;
189
185
  }
186
+ // Normalize the option.
187
+ option = option.toLowerCase();
190
188
  const getValue = (checkOption, checkId) => {
191
189
  const regex = this.valueRegex(checkOption, checkId);
192
190
  // Get the option value, if we have one.
193
191
  for (const entry of this.configuredOptions) {
194
192
  const regexMatch = regex.exec(entry);
195
193
  if (regexMatch) {
196
- return regexMatch[1];
194
+ // If the option is enabled, return the value. Otherwise, we have nothing.
195
+ return (regexMatch[1].toLowerCase() === "enable") ? regexMatch[2] : null;
197
196
  }
198
197
  }
199
198
  return undefined;
@@ -201,6 +200,10 @@ export class FeatureOptions {
201
200
  // Check to see if we have a device-level value first.
202
201
  if (device) {
203
202
  const value = getValue(option, device);
203
+ // The option must been explicitly disabled.
204
+ if (value === null) {
205
+ return undefined;
206
+ }
204
207
  if (value) {
205
208
  return value;
206
209
  }
@@ -208,12 +211,25 @@ export class FeatureOptions {
208
211
  // Now check to see if we have an controller-level value.
209
212
  if (controller) {
210
213
  const value = getValue(option, controller);
214
+ // The option's been explicitly disabled.
215
+ if (value === null) {
216
+ return undefined;
217
+ }
211
218
  if (value) {
212
219
  return value;
213
220
  }
214
221
  }
215
222
  // Finally, we check for a global-level value.
216
- return getValue(option);
223
+ const value = getValue(option);
224
+ if (value) {
225
+ return value;
226
+ }
227
+ // The option's been explicitly disabled or is disabled by default.
228
+ if ((value === null) || !this.defaultValue(option)) {
229
+ return null;
230
+ }
231
+ // Return the enabled value, or the default value if we've got nothing explicitly configured.
232
+ return value ?? ((this.valueOptions[option] === undefined) ? undefined : this.valueOptions[option]?.toString());
217
233
  }
218
234
  /**
219
235
  * Return the list of available feature option categories.
@@ -279,6 +295,10 @@ export class FeatureOptions {
279
295
  this._groups = {};
280
296
  this.valueOptions = {};
281
297
  for (const category of this.categories) {
298
+ // If the category doesn't exist, let's skip it.
299
+ if (!this.options[category.name]) {
300
+ continue;
301
+ }
282
302
  // Now enumerate all the feature options for a given device and add then to the full list.
283
303
  for (const option of this.options[category.name]) {
284
304
  // Expand the entry.
@@ -286,7 +306,9 @@ export class FeatureOptions {
286
306
  // Index the default value.
287
307
  this.defaults[entry.toLowerCase()] = option.default;
288
308
  // Track value-centric options.
289
- this.valueOptions[entry.toLowerCase()] = "defaultValue" in option;
309
+ if ("defaultValue" in option) {
310
+ this.valueOptions[entry.toLowerCase()] = option.defaultValue;
311
+ }
290
312
  // Cross reference the feature option group it belongs to, if any.
291
313
  if (option.group !== undefined) {
292
314
  const expandedGroup = category.name + (option.group.length ? ("." + option.group) : "");
@@ -332,11 +354,7 @@ export class FeatureOptions {
332
354
  // Utility to test whether an option is set in a given scope.
333
355
  // We return true if an option is enabled, false for disabled, undefined otherwise. For value-centric options, we return true if a value exists.
334
356
  isOptionEnabled(option, id) {
335
- // Deal with value-centric options uniquely.
336
- if (this.isValue(option)) {
337
- return this.exists(option, id);
338
- }
339
- const regex = this.optionRegex(option, id);
357
+ const regex = this.isValue(option) ? this.valueRegex(option, id) : this.optionRegex(option, id);
340
358
  // Get the option value, if we have one.
341
359
  for (const entry of this.configuredOptions) {
342
360
  const regexMatch = regex.exec(entry);
@@ -354,14 +372,14 @@ export class FeatureOptions {
354
372
  }
355
373
  // Utility function to parse and return a numeric configuration parameter.
356
374
  parseOptionNumeric(option, convert) {
357
- // We don't have the option configured -- we're done.
358
- if (option === undefined) {
359
- return undefined;
375
+ // If the option is disabled or we don't have it configured -- we're done.
376
+ if (!option) {
377
+ return (option === null) ? null : undefined;
360
378
  }
361
379
  // Convert it to a number, if needed.
362
380
  const convertedValue = convert(option);
363
381
  // Let's validate to make sure it's really a number.
364
- if (isNaN(convertedValue) || (convertedValue < 0)) {
382
+ if (isNaN(convertedValue)) {
365
383
  return undefined;
366
384
  }
367
385
  // Return the value.
@@ -369,8 +387,11 @@ export class FeatureOptions {
369
387
  }
370
388
  // Regular expression test for value-centric feature options.
371
389
  valueRegex(option, id) {
372
- // This regular expression is a bit more intricate than you might think it should be due to the need to ensure we capture values at the very end of the option.
373
- return new RegExp("^Enable\\." + option.replace(/[.*+?^${}()|[\]\\]/g, "\\$&") + (!id ? "" : "\\." + id) + "\\.([^\\.]+)$", "gi");
390
+ // Escape out our option to ensure we have no inadvertent issues in matching the regular expression.
391
+ option = option.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
392
+ // This regular expression is a bit more intricate than you might think it should be due to the need to ensure we capture values at the very end of the option when
393
+ // the option is enabled, and that we ignore the values at the end when the option is disabled in order to correctly traverse the hierarchy.
394
+ return new RegExp("^(Disable|Enable)\\." + option + (!id ? "" : "\\." + id) + "(?:(?<=^Enable\\." + option + (!id ? "" : "\\." + id) + ")\\.([^\\.]*))?$", "gi");
374
395
  }
375
396
  }
376
397
  //# sourceMappingURL=featureoptions.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"featureoptions.js","sourceRoot":"","sources":["../src/featureoptions.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"featureoptions.js","sourceRoot":"","sources":["../src/featureoptions.ts"],"names":[],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- /* Copyright(C) 2017-2024, HJD (https://github.com/hjdhjd). All rights reserved.
1
+ /* Copyright(C) 2017-2025, HJD (https://github.com/hjdhjd). All rights reserved.
2
2
  *
3
3
  * webUi-featureoptions.mjs: Device feature option webUI.
4
4
  */
@@ -150,14 +150,17 @@ export class webUiFeatureOptions {
150
150
  this.#configTable.innerHTML = "";
151
151
  this.webUiDeviceList = [];
152
152
 
153
- // Create our hover style for our sidebar.
154
- const sidebarHoverStyle = document.createElement("style");
153
+ // Create our override styles for things like hover for our sidebar and workarounds for Homebridge UI quirks.
154
+ const overrideStyles = document.createElement("style");
155
+
156
+ // We want to override the default colors that Homebridge UI might apply for table cells.
157
+ overrideStyles.innerHTML = "td { color: unset !important }";
155
158
 
156
159
  // We emulate the styles that Bootstrap uses when hovering over a table, accounting for both light and dark modes.
157
- sidebarHoverStyle.innerHTML = "@media (prefers-color-scheme: dark) { .hbup-hover td:hover { background-color: #212121; color: #FFA000 } }" +
160
+ overrideStyles.innerHTML += "@media (prefers-color-scheme: dark) { .hbup-hover td:hover { background-color: #212121; color: #FFA000 !important } }" +
158
161
  "@media (prefers-color-scheme: light) { .hbup-hover td:hover { background-color: #ECECEC; } }";
159
162
 
160
- document.head.appendChild(sidebarHoverStyle);
163
+ document.head.appendChild(overrideStyles);
161
164
 
162
165
  // Add our hover styles to the controllers and devices tables.
163
166
  controllersTable.classList.add("hbup-hover");
@@ -179,6 +182,7 @@ export class webUiFeatureOptions {
179
182
  }
180
183
 
181
184
  // Initialize our informational header.
185
+ document.getElementById("headerInfo").style.fontWeight = "bold";
182
186
  document.getElementById("headerInfo").innerHTML = "Feature options are applied in prioritized order, from global to device-specific options:" +
183
187
  "<br><i class=\"text-warning\">Global options</i> (lowest priority) &rarr; " +
184
188
  (this.#hasControllers ? "<i class=\"text-success\">Controller options</i> &rarr; " : "") +
@@ -312,7 +316,7 @@ export class webUiFeatureOptions {
312
316
  }
313
317
 
314
318
  // The first entry returned by getDevices() must always be the controller.
315
- this.#controller = this.#devices[0]?.serial ?? null;
319
+ this.#controller = this.#devices[0]?.serialNumber ?? null;
316
320
  }
317
321
 
318
322
  // Make the UI visible.
@@ -329,7 +333,7 @@ export class webUiFeatureOptions {
329
333
  this.#sidebar.showDevices(controller, this.#devices);
330
334
 
331
335
  // Display the feature options to the user.
332
- this.showDeviceOptions(controller ? this.#devices[0].serial : "Global Options");
336
+ this.showDeviceOptions(controller ? this.#devices[0].serialNumber : "Global Options");
333
337
 
334
338
  // All done. Let the user interact with us.
335
339
  homebridge.hideSpinner();
@@ -345,7 +349,7 @@ export class webUiFeatureOptions {
345
349
  webUiEntry.parentElement.classList.add("bg-info", "text-white") : webUiEntry.parentElement.classList.remove("bg-info", "text-white"));
346
350
 
347
351
  // Populate the device information info pane.
348
- const currentDevice = this.#devices.find(device => device.serial === deviceId);
352
+ const currentDevice = this.#devices.find(device => device.serialNumber === deviceId);
349
353
 
350
354
  // Populate the details view. If there's no device specified, the context is considered global and we hide the device details view.
351
355
  if(!currentDevice) {
@@ -382,7 +386,7 @@ export class webUiFeatureOptions {
382
386
  th.classList.add("p-0");
383
387
  th.style.fontWeight = "bold";
384
388
  th.colSpan = 3;
385
- tbody.classList.add("table-bordered");
389
+ tbody.classList.add("border");
386
390
 
387
391
  // Add the feature option category description.
388
392
  th.appendChild(document.createTextNode(category.description + (!currentDevice ? " (Global)" :
@@ -428,13 +432,13 @@ export class webUiFeatureOptions {
428
432
  checkbox.readOnly = false;
429
433
  checkbox.id = featureOption;
430
434
  checkbox.name = featureOption;
431
- checkbox.value = featureOption + (!currentDevice ? "" : ("." + currentDevice.serial));
435
+ checkbox.value = featureOption + (!currentDevice ? "" : ("." + currentDevice.serialNumber));
432
436
 
433
437
  let initialValue = undefined;
434
438
  let initialScope;
435
439
 
436
440
  // Determine our initial option scope to show the user what's been set.
437
- switch(initialScope = this.#featureOptions.scope(featureOption, currentDevice?.serial, this.#controller)) {
441
+ switch(initialScope = this.#featureOptions.scope(featureOption, currentDevice?.serialNumber, this.#controller)) {
438
442
 
439
443
  case "global":
440
444
  case "controller":
@@ -442,13 +446,11 @@ export class webUiFeatureOptions {
442
446
  // If we're looking at the global scope, show the option value. Otherwise, we show that we're inheriting a value from the scope above.
443
447
  if(!currentDevice) {
444
448
 
449
+ checkbox.checked = this.#featureOptions.test(featureOption);
450
+
445
451
  if(this.#featureOptions.isValue(featureOption)) {
446
452
 
447
- checkbox.checked = this.#featureOptions.exists(featureOption);
448
453
  initialValue = this.#featureOptions.value(checkbox.id);
449
- } else {
450
-
451
- checkbox.checked = this.#featureOptions.test(featureOption);
452
454
  }
453
455
 
454
456
  if(checkbox.checked) {
@@ -472,13 +474,11 @@ export class webUiFeatureOptions {
472
474
  case "none":
473
475
  default:
474
476
 
475
- if(this.#featureOptions.isValue(featureOption)) {
477
+ checkbox.checked = this.#featureOptions.test(featureOption, currentDevice?.serialNumber);
476
478
 
477
- checkbox.checked = this.#featureOptions.exists(featureOption, currentDevice?.serial);
478
- initialValue = this.#featureOptions.value(checkbox.id, currentDevice?.serial);
479
- } else {
479
+ if(this.#featureOptions.isValue(featureOption)) {
480
480
 
481
- checkbox.checked = this.#featureOptions.test(featureOption, currentDevice?.serial);
481
+ initialValue = this.#featureOptions.value(checkbox.id, currentDevice?.serialNumber);
482
482
  }
483
483
 
484
484
  break;
@@ -512,35 +512,10 @@ export class webUiFeatureOptions {
512
512
  inputValue.type = "text";
513
513
  inputValue.value = initialValue ?? option.defaultValue;
514
514
  inputValue.size = 5;
515
- inputValue.readOnly = !checkbox.checked;
515
+ inputValue.readOnly = checkbox.readOnly;
516
516
 
517
517
  // Add or remove the setting from our configuration when we've changed our state.
518
- inputValue.addEventListener("change", async () => {
519
-
520
- // Find the option in our list and delete it if it exists.
521
- const optionRegex = new RegExp("^(?:Enable|Disable)\\." + checkbox.id + (!currentDevice ? "" : ("\\." + currentDevice.serial)) + "\\.[^\\.]+$", "gi");
522
- const newOptions = this.#featureOptions.configuredOptions.filter(entry => !optionRegex.test(entry));
523
-
524
- if(checkbox.checked) {
525
-
526
- newOptions.push("Enable." + checkbox.value + "." + inputValue.value);
527
- } else if(checkbox.indeterminate) {
528
-
529
- // If we're in an indeterminate state, we need to traverse the tree to get the upstream value we're inheriting.
530
- inputValue.value = (currentDevice?.serial !== this.#controller) ?
531
- (this.#featureOptions.value(checkbox.id, this.#controller) ?? this.#featureOptions.value(checkbox.id)) :
532
- (this.#featureOptions.value(checkbox.id) ?? option.defaultValue);
533
- } else {
534
-
535
- inputValue.value = option.defaultValue;
536
- }
537
-
538
- // Update our configuration in Homebridge.
539
- this.currentConfig[0].options = newOptions;
540
- this.#featureOptions.configuredOptions = newOptions;
541
- await homebridge.updatePluginConfig(this.currentConfig);
542
- });
543
-
518
+ inputValue.addEventListener("change", () => checkbox.dispatchEvent(new Event("change")));
544
519
  tdInput.appendChild(inputValue);
545
520
  trX.appendChild(tdInput);
546
521
  }
@@ -553,7 +528,7 @@ export class webUiFeatureOptions {
553
528
  labelDescription.classList.add("user-select-none", "my-0", "py-0");
554
529
 
555
530
  // Highlight options for the user that are different than our defaults.
556
- const scopeColor = this.#featureOptions.color(featureOption, currentDevice?.serial, this.#controller);
531
+ const scopeColor = this.#featureOptions.color(featureOption, currentDevice?.serialNumber, this.#controller);
557
532
 
558
533
  if(scopeColor) {
559
534
 
@@ -564,19 +539,21 @@ export class webUiFeatureOptions {
564
539
  checkbox.addEventListener("change", async () => {
565
540
 
566
541
  // Find the option in our list and delete it if it exists.
567
- const optionRegex = new RegExp("^(?:Enable|Disable)\\." + checkbox.id + (!currentDevice ? "" : ("\\." + currentDevice.serial)) + "$", "gi");
542
+ const optionRegex = new RegExp("^(?:Enable|Disable)\\." + checkbox.id + (!currentDevice ? "" : ("\\." + currentDevice.serialNumber)) +
543
+ "(?:\\.([^\\.]*))?$", "gi");
544
+
568
545
  const newOptions = this.#featureOptions.configuredOptions.filter(entry => !optionRegex.test(entry));
569
546
 
570
547
  // Figure out if we've got the option set upstream.
571
548
  let upstreamOption = false;
572
549
 
573
550
  // We explicitly want to check for the scope of the feature option above where we are now, so we can appropriately determine what we should show.
574
- switch(this.#featureOptions.scope(checkbox.id, (currentDevice && (currentDevice.serial !== this.#controller)) ? this.#controller : undefined)) {
551
+ switch(this.#featureOptions.scope(checkbox.id, (currentDevice && (currentDevice.serialNumber !== this.#controller)) ? this.#controller : undefined)) {
575
552
 
576
553
  case "device":
577
554
  case "controller":
578
555
 
579
- if(currentDevice.serial !== this.#controller) {
556
+ if(currentDevice.serialNumber !== this.#controller) {
580
557
 
581
558
  upstreamOption = true;
582
559
  }
@@ -597,15 +574,24 @@ export class webUiFeatureOptions {
597
574
  break;
598
575
  }
599
576
 
600
- // For value-centric feature options, if there's an upstream value assigned above us, we don't allow for an unchecked state as it doesn't make sense in this
601
- // context.
602
- if(checkbox.readOnly && (!this.#featureOptions.isValue(featureOption) || (this.#featureOptions.isValue(featureOption) && inputValue && !upstreamOption))) {
577
+ // We're currently in an indetermindate state and transitioning to an unchecked state.
578
+ if(checkbox.readOnly) {
603
579
 
604
- // We're truly unchecked. We need this because a checkbox can be in both an unchecked and indeterminate simultaneously,
605
- // so we use the readOnly property to let us know that we've just cycled from an indeterminate state.
580
+ // The user wants to change the state to unchecked. We need this because a checkbox can be in both an unchecked and indeterminate simultaneously, so we use
581
+ // the readOnly property to let us know that we've just cycled from an indeterminate state.
606
582
  checkbox.checked = checkbox.readOnly = false;
583
+
584
+ // If we have a value-centric feature option, we show the default value when we're in an indeterminate state.
585
+ if(this.#featureOptions.isValue(featureOption)) {
586
+
587
+ // If we're unchecked, clear out the value and make it read only. We show the system default for reference.
588
+ inputValue.value = option.defaultValue;
589
+ inputValue.readOnly = true;
590
+ }
607
591
  } else if(!checkbox.checked) {
608
592
 
593
+ // We're currently in a checked state and transitioning to an unchecked or an indeterminate state.
594
+
609
595
  // If we have an upstream option configured, we reveal a third state to show inheritance of that option and allow the user to select it.
610
596
  if(upstreamOption) {
611
597
 
@@ -614,51 +600,64 @@ export class webUiFeatureOptions {
614
600
  checkbox.readOnly = checkbox.indeterminate = true;
615
601
  }
616
602
 
617
- if(this.#featureOptions.isValue(featureOption) && inputValue) {
603
+ // If we're in an indeterminate state, we need to traverse the tree to get the upstream value we're inheriting.
604
+ if(this.#featureOptions.isValue(featureOption)) {
605
+
606
+ let newInputValue;
607
+
608
+ // If our scope is global, let's fallback on the default value.
609
+ // eslint-disable-next-line eqeqeq
610
+ if((currentDevice?.serialNumber == null) && (this.#controller == null)) {
618
611
 
612
+ newInputValue = option.defaultValue;
613
+ } else if(currentDevice?.serialNumber !== this.#controller) {
614
+
615
+ // We're at the device level - get the controller level value if it exists and fallback to the global value otherwise.
616
+ newInputValue = this.#featureOptions.value(checkbox.id, this.#controller) ?? this.#featureOptions.value(checkbox.id);
617
+ } else {
618
+
619
+ // We're at the controller level - get the global value.
620
+ newInputValue = this.#featureOptions.value(checkbox.id);
621
+ }
622
+
623
+ // Our fallback if there's no value defined within the scope hierarchy is the default value.
624
+ inputValue.value = newInputValue ?? option.defaultValue;
619
625
  inputValue.readOnly = true;
620
626
  }
621
627
  } else if(checkbox.checked) {
622
628
 
623
- // We've explicitly checked this option.
629
+ // We're currently in an unchecked state and transitioning to a checked state.
624
630
  checkbox.readOnly = checkbox.indeterminate = false;
625
631
 
626
- if(this.#featureOptions.isValue(featureOption) && inputValue) {
632
+ if(this.#featureOptions.isValue(featureOption)) {
627
633
 
628
634
  inputValue.readOnly = false;
629
635
  }
630
636
  }
631
637
 
632
- // The setting is different from the default, highlight it for the user, accounting for upstream scope, and add it to our configuration.
633
- if(!checkbox.indeterminate && ((checkbox.checked !== option.default) || upstreamOption)) {
638
+ // The feature option is different from the default - highlight it for the user, accounting for the scope hierarchy, and add it to our configuration. We
639
+ // provide a visual queue to the user, highlighting to indicate that a non-default option has been set.
640
+ if(!checkbox.indeterminate && ((checkbox.checked !== option.default) ||
641
+ (this.#featureOptions.isValue(featureOption) && (inputValue.value.toString() !== option.defaultValue.toString())) || upstreamOption)) {
634
642
 
635
643
  labelDescription.classList.add("text-info");
636
- newOptions.push((checkbox.checked ? "Enable." : "Disable.") + checkbox.value);
644
+ newOptions.push((checkbox.checked ? "Enable." : "Disable.") + checkbox.value +
645
+ (this.#featureOptions.isValue(featureOption) && checkbox.checked ? ("." + inputValue.value) : ""));
637
646
  } else {
638
647
 
639
648
  // We've reset to the defaults, remove our highlighting.
640
649
  labelDescription.classList.remove("text-info");
641
650
  }
642
651
 
643
- // Update our Homebridge configuration.
644
- if(this.#featureOptions.isValue(featureOption) && inputValue) {
645
-
646
- // Inform our value-centric feature option to update Homebridge.
647
- const changeEvent = new Event("change");
648
-
649
- inputValue.dispatchEvent(changeEvent);
650
- } else {
651
-
652
- // Update our configuration in Homebridge.
653
- this.currentConfig[0].options = newOptions;
654
- this.#featureOptions.configuredOptions = newOptions;
655
- await homebridge.updatePluginConfig(this.currentConfig);
656
- }
652
+ // Update our configuration in Homebridge.
653
+ this.currentConfig[0].options = newOptions;
654
+ this.#featureOptions.configuredOptions = newOptions;
655
+ await homebridge.updatePluginConfig(this.currentConfig);
657
656
 
658
657
  // If we've reset to defaults, make sure our color coding for scope is reflected.
659
658
  if((checkbox.checked === option.default) || checkbox.indeterminate) {
660
659
 
661
- const scopeColor = this.#featureOptions.color(featureOption, currentDevice?.serial, this.#controller);
660
+ const scopeColor = this.#featureOptions.color(featureOption, currentDevice?.serialNumber, this.#controller);
662
661
 
663
662
  if(scopeColor) {
664
663
 
@@ -669,7 +668,7 @@ export class webUiFeatureOptions {
669
668
  // Adjust visibility of other feature options that depend on us.
670
669
  if(this.#featureOptions.groups[checkbox.id]) {
671
670
 
672
- const entryVisibility = this.#featureOptions.test(featureOption, currentDevice?.serial) ? "" : "none";
671
+ const entryVisibility = this.#featureOptions.test(featureOption, currentDevice?.serialNumber) ? "" : "none";
673
672
 
674
673
  // Lookup each feature option setting and set the visibility accordingly.
675
674
  for(const entry of this.#featureOptions.groups[checkbox.id]) {
@@ -692,7 +691,7 @@ export class webUiFeatureOptions {
692
691
  trX.appendChild(tdLabel);
693
692
 
694
693
  // Adjust the visibility of the feature option, if it's logically grouped.
695
- if((option.group !== undefined) && !this.#featureOptions.test(category.name + (option.group.length ? ("." + option.group) : ""), currentDevice?.serial)) {
694
+ if((option.group !== undefined) && !this.#featureOptions.test(category.name + (option.group.length ? ("." + option.group) : ""), currentDevice?.serialNumber)) {
696
695
 
697
696
  trX.style.display = "none";
698
697
  } else {
@@ -738,7 +737,7 @@ export class webUiFeatureOptions {
738
737
 
739
738
  // Display our device details.
740
739
  deviceFirmware.innerHTML = device.firmwareVersion;
741
- deviceSerial.innerHTML = device.serial;
740
+ deviceSerial.innerHTML = device.serialNumber;
742
741
  }
743
742
 
744
743
  // Default method for enumerating the device list in the sidebar.
@@ -785,12 +784,12 @@ export class webUiFeatureOptions {
785
784
 
786
785
  const label = document.createElement("label");
787
786
 
788
- label.name = device.serial;
787
+ label.name = device.serialNumber;
789
788
  label.appendChild(document.createTextNode(device.name ?? "Unknown"));
790
789
  label.style.cursor = "pointer";
791
790
  label.classList.add("mx-2", "my-0", "p-0", "w-100");
792
791
 
793
- label.addEventListener("click", () => this.showDeviceOptions(device.serial));
792
+ label.addEventListener("click", () => this.showDeviceOptions(device.serialNumber));
794
793
 
795
794
  // Add the device label to our cell.
796
795
  tdDevice.appendChild(label);
@@ -814,10 +813,14 @@ export class webUiFeatureOptions {
814
813
  // Filter out only the components we're interested in.
815
814
  devices = devices.map(device => ({
816
815
 
817
- firmwareVersion: (device.services.find(service => service.constructorName ===
816
+ firmwareRevision: (device.services.find(service => service.constructorName ===
818
817
  "AccessoryInformation")?.characteristics.find(characteristic => characteristic.constructorName === "FirmwareRevision")?.value ?? ""),
818
+ manufacturer: (device.services.find(service => service.constructorName ===
819
+ "AccessoryInformation")?.characteristics.find(characteristic => characteristic.constructorName === "Manufacturer")?.value ?? ""),
820
+ model: (device.services.find(service => service.constructorName ===
821
+ "AccessoryInformation")?.characteristics.find(characteristic => characteristic.constructorName === "Model")?.value ?? ""),
819
822
  name: device.displayName,
820
- serial: (device.services.find(service => service.constructorName ===
823
+ serialNumber: (device.services.find(service => service.constructorName ===
821
824
  "AccessoryInformation")?.characteristics.find(characteristic => characteristic.constructorName === "SerialNumber")?.value ?? "")
822
825
  }));
823
826
 
@@ -1,4 +1,4 @@
1
- /* Copyright(C) 2017-2024, HJD (https://github.com/hjdhjd). All rights reserved.
1
+ /* Copyright(C) 2017-2025, HJD (https://github.com/hjdhjd). All rights reserved.
2
2
  *
3
3
  * webUi.mjs: Plugin webUI.
4
4
  */
@@ -142,11 +142,8 @@ export class webUi {
142
142
  document.getElementById("menuFeatureOptions").addEventListener("click", () => this.featureOptions.show());
143
143
  document.getElementById("menuSettings").addEventListener("click", () => this.#showSettings());
144
144
 
145
- // Get the list of devices the plugin knows about.
146
- const devices = await homebridge.getCachedAccessories();
147
-
148
145
  // If we've got devices detected, we launch our feature option UI. Otherwise, we launch our first run UI.
149
- if(this.featureOptions.currentConfig.length && devices?.length && !(await this.#processHandler(this.#firstRun.isRequired))) {
146
+ if(this.featureOptions.currentConfig.length && !(await this.#processHandler(this.#firstRun.isRequired))) {
150
147
 
151
148
  document.getElementById("menuWrapper").style.display = "inline-flex";
152
149
  this.featureOptions.show();