homebridge-bluos 1.1.3 → 1.1.5

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/CHANGELOG.md CHANGED
@@ -1,5 +1,19 @@
1
1
  # Changelog
2
2
 
3
+ ## [1.1.5](https://github.com/tbaur/homebridge-bluos/compare/v1.1.4...v1.1.5) (2026-08-31)
4
+
5
+
6
+ ### Bug Fixes
7
+
8
+ * keep discover progress in view and leave volume opt-in ([#33](https://github.com/tbaur/homebridge-bluos/issues/33)) ([1dec836](https://github.com/tbaur/homebridge-bluos/commit/1dec8361f2a82d2a1c355f74c4258078bcb945d2))
9
+
10
+ ## [1.1.4](https://github.com/tbaur/homebridge-bluos/compare/v1.1.3...v1.1.4) (2026-08-31)
11
+
12
+
13
+ ### Bug Fixes
14
+
15
+ * put the reboot switch on its own line ([#31](https://github.com/tbaur/homebridge-bluos/issues/31)) ([d721851](https://github.com/tbaur/homebridge-bluos/commit/d721851480d1d2e243b90ccfb1105087aed8aaa1))
16
+
3
17
  ## [1.1.3](https://github.com/tbaur/homebridge-bluos/compare/v1.1.2...v1.1.3) (2026-08-30)
4
18
 
5
19
 
package/README.md CHANGED
@@ -56,7 +56,7 @@ Nothing needs enabling on the player, because the BluOS LAN API is always on. A
56
56
 
57
57
  ### 3. Configure
58
58
 
59
- **Homebridge UI** (recommended): open the plugin settings and press **Discover Players**. Every zone that answers is listed with a suggested set of accessories. Tick what you want, then press the Homebridge Save button.
59
+ **Homebridge UI** (recommended): open the plugin settings and press **Discover Players**. Every zone that answers is listed. Tick the players and accessories you want, then press the Homebridge Save button.
60
60
 
61
61
  Or in `config.json`:
62
62
 
@@ -10,7 +10,39 @@
10
10
  -->
11
11
  <style>
12
12
  .bluos-intro { margin-bottom: 1rem; }
13
- .bluos-toolbar { display: flex; gap: .5rem; align-items: flex-end; flex-wrap: wrap; margin-bottom: 1rem; }
13
+ .bluos-toolbar {
14
+ display: flex;
15
+ gap: .5rem;
16
+ align-items: flex-end;
17
+ flex-wrap: wrap;
18
+ position: sticky;
19
+ top: 0;
20
+ z-index: 5;
21
+ margin: 0 0 1rem;
22
+ padding: .55rem 0;
23
+ /* Frosted so cards do not show through while this bar stays on screen. */
24
+ background: rgba(128, 128, 128, .12);
25
+ backdrop-filter: blur(10px);
26
+ }
27
+ .bluos-busy {
28
+ display: inline-flex;
29
+ align-items: center;
30
+ align-self: center;
31
+ gap: .4rem;
32
+ font-size: .85rem;
33
+ white-space: nowrap;
34
+ }
35
+ .bluos-busy[hidden] { display: none !important; }
36
+ .bluos-busy::before {
37
+ content: '';
38
+ width: .85rem;
39
+ height: .85rem;
40
+ border: 2px solid currentColor;
41
+ border-right-color: transparent;
42
+ border-radius: 50%;
43
+ animation: bluos-spin .7s linear infinite;
44
+ }
45
+ @keyframes bluos-spin { to { transform: rotate(360deg); } }
14
46
  .bluos-toolbar .form-group { margin-bottom: 0; }
15
47
  .bluos-card { border: 1px solid rgba(128, 128, 128, .3); border-radius: .5rem; padding: .85rem 1rem; margin-bottom: .75rem; }
16
48
  .bluos-card.is-selected { border-color: #007bff; box-shadow: 0 0 0 1px rgba(0, 123, 255, .35); }
@@ -20,6 +52,7 @@
20
52
  .bluos-badge { font-size: .7rem; text-transform: uppercase; letter-spacing: .03em; padding: .12rem .4rem; border-radius: .25rem; background: rgba(128, 128, 128, .2); }
21
53
  .bluos-badge.warn { background: rgba(255, 193, 7, .28); }
22
54
  .bluos-options { display: flex; gap: 1.1rem; flex-wrap: wrap; margin-top: .6rem; }
55
+ .bluos-options-reboot { flex-basis: 100%; }
23
56
  .bluos-check { display: inline-flex; align-items: center; gap: .4rem; margin: 0; }
24
57
  .bluos-check input { margin: 0; }
25
58
  .bluos-check label { margin: 0; }
@@ -45,6 +78,7 @@
45
78
 
46
79
  <div class="bluos-toolbar">
47
80
  <button class="btn btn-primary" id="discover">Discover Players</button>
81
+ <span id="discover-status" class="bluos-busy text-muted" hidden></span>
48
82
  <div class="form-group">
49
83
  <label for="timeout" class="mb-0" style="font-size: .8rem;">Listen for</label>
50
84
  <select class="form-control form-control-sm" id="timeout">
@@ -157,7 +157,10 @@
157
157
  derivedIdentity: player.derivedIdentity,
158
158
  online: true,
159
159
  selected: false,
160
- volumeSlider: player.suggested.volumeSlider,
160
+ // Discover listing a zone is not a request for a HomeKit accessory.
161
+ // Volume is a fan tile; leaving it ticked on every new player would
162
+ // mint one per zone the moment the user pressed Save.
163
+ volumeSlider: false,
161
164
  mute: player.suggested.mute,
162
165
  battery: player.suggested.battery,
163
166
  reboot: player.suggested.reboot,
@@ -396,12 +399,14 @@
396
399
  (value) => { player.battery = value },
397
400
  ))
398
401
  }
399
- options.append(checkbox(
400
- 'Reboot switch (reboots this player, and any zone sharing its box)',
402
+ const reboot = checkbox(
403
+ 'Reboot switch (reboots this player, and any zone on the same device)',
401
404
  player.reboot,
402
405
  false,
403
406
  (value) => { player.reboot = value },
404
- ))
407
+ )
408
+ reboot.className += ' bluos-options-reboot'
409
+ options.append(reboot)
405
410
  card.append(options)
406
411
 
407
412
  if (player.selected) {
@@ -452,9 +457,30 @@
452
457
 
453
458
  // --- Actions ------------------------------------------------------------
454
459
 
460
+ let requestInFlight = false
461
+
462
+ /**
463
+ * Show progress next to Discover, which is where the user just pressed.
464
+ *
465
+ * Homebridge's spinner is centred on the whole settings page. With a long
466
+ * list of players that centre sits below the fold, so a user who pressed
467
+ * Discover would see nothing happen for several seconds.
468
+ */
469
+ function setBusy(isBusy, message) {
470
+ requestInFlight = isBusy
471
+ byId('discover').disabled = isBusy
472
+ byId('manual-probe').disabled = isBusy
473
+ const status = byId('discover-status')
474
+ status.hidden = !isBusy
475
+ status.textContent = isBusy ? message : ''
476
+ }
477
+
455
478
  async function discover() {
479
+ if (requestInFlight) {
480
+ return
481
+ }
456
482
  const timeoutSec = Number(byId('timeout').value) || DEFAULT_TIMEOUT_SEC
457
- homebridge.showSpinner()
483
+ setBusy(true, 'Listening for players…')
458
484
  try {
459
485
  const response = await homebridge.request('/discover', { timeoutSec })
460
486
  const found = Array.isArray(response && response.players) ? response.players : []
@@ -479,11 +505,14 @@
479
505
  } catch (error) {
480
506
  homebridge.toast.error(describeError(error), 'Discovery failed')
481
507
  } finally {
482
- homebridge.hideSpinner()
508
+ setBusy(false)
483
509
  }
484
510
  }
485
511
 
486
512
  async function probe() {
513
+ if (requestInFlight) {
514
+ return
515
+ }
487
516
  const host = byId('manual-host').value.trim()
488
517
  const portValue = byId('manual-port').value.trim()
489
518
  if (host.length === 0) {
@@ -494,7 +523,7 @@
494
523
  if (portValue.length > 0) {
495
524
  payload.port = Number(portValue)
496
525
  }
497
- homebridge.showSpinner()
526
+ setBusy(true, 'Probing…')
498
527
  try {
499
528
  const response = await homebridge.request('/probe', payload)
500
529
  const found = Array.isArray(response && response.players) ? response.players : []
@@ -510,7 +539,7 @@
510
539
  } catch (error) {
511
540
  homebridge.toast.error(describeError(error), 'Probe failed')
512
541
  } finally {
513
- homebridge.hideSpinner()
542
+ setBusy(false)
514
543
  }
515
544
  }
516
545
 
@@ -155,11 +155,14 @@ class BluOSUiServer extends HomebridgePluginUiServer {
155
155
  }
156
156
 
157
157
  /**
158
- * Shape a discovered player for the page, including sensible defaults.
158
+ * Shape a discovered player for the page, including opt-in accessory defaults.
159
159
  *
160
- * A player that reports a fixed output level gets no slider suggested, because
161
- * writing a level to it does nothing. A player with no usable MAC is given a
162
- * generated identity here, once, so that it stays stable from then on.
160
+ * Volume, mute and reboot stay off until the user asks for them: Discover
161
+ * listing a zone is not a request for a HomeKit accessory. A player with a
162
+ * battery pack is offered that sensor, because it is a reading rather than a
163
+ * control. A player that reports a fixed output cannot take a slider at all,
164
+ * which the page learns from `fixedVolume`. A player with no usable MAC is
165
+ * given a generated identity here, once, so that it stays stable from then on.
163
166
  */
164
167
  describe(player) {
165
168
  const api = this.loadApi()
@@ -176,7 +179,7 @@ class BluOSUiServer extends HomebridgePluginUiServer {
176
179
  hasBattery: player.hasBattery === true,
177
180
  derivedIdentity: !(player.mac && player.mac.length > 0),
178
181
  suggested: {
179
- volumeSlider: player.fixedVolume !== true,
182
+ volumeSlider: false,
180
183
  mute: false,
181
184
  battery: player.hasBattery === true,
182
185
  // Never suggested. Restarting a player interrupts whatever it is doing,
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "homebridge-bluos",
3
3
  "displayName": "Homebridge BluOS",
4
- "version": "1.1.3",
4
+ "version": "1.1.5",
5
5
  "description": "Homebridge plugin for BluOS players — per-zone volume, mute, volume-preset and battery accessories over the LAN Custom Integration API. Verified on NAD and Bluesound hardware",
6
6
  "main": "dist/index.js",
7
7
  "types": "dist/index.d.ts",