homebridge-yoto 0.0.39 → 0.0.40

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/README.md CHANGED
@@ -25,6 +25,56 @@
25
25
 
26
26
  THIS PLUGIN IS A WIP. DO NOT USE YET.
27
27
 
28
+ Homebridge plugin that exposes Yoto players to HomeKit with optional playback controls, device status, and nightlight settings.
29
+
30
+ ## Settings
31
+
32
+ **Playback Controls** (`services.playbackAccessory`)
33
+ - **Bridged (Switch + Dimmer)**: Adds Playback and Volume services on the main accessory.
34
+ - **External Smart Speaker**: Publishes a separate Smart Speaker accessory for playback and volume. Requires pairing the extra accessory in the Home app.
35
+ - **None**: Disables playback and volume services entirely.
36
+
37
+ **Card Controls** (`services.cardControls`)
38
+ - Adds a per-device switch that plays the configured card ID.
39
+ - Optional "Play on All Yotos" accessory per card control.
40
+
41
+ **Service toggles**
42
+ - **Temperature Sensor**: Adds a temperature sensor when supported by the device.
43
+ - **Nightlight**: Adds day/night nightlight controls and status sensors.
44
+ - **Card Slot**: Adds a card insertion sensor.
45
+ - **Day Mode**: Adds a day/night mode sensor.
46
+ - **Sleep Timer**: Adds a sleep timer switch.
47
+ - **Bluetooth**: Adds a Bluetooth toggle switch.
48
+ - **Volume Limits**: Adds day/night max volume controls.
49
+
50
+ ## HomeKit Services
51
+
52
+ **Playback (bridged)**
53
+ - **Playback**: Switch; On resumes, Off pauses.
54
+ - **Volume**: Lightbulb; On unmutes, Off mutes, Brightness maps 0-100% to device volume steps.
55
+
56
+ **Smart Speaker (external)**
57
+ - **Smart Speaker**: Current/Target Media State, Volume, Mute, and StatusActive (online state).
58
+
59
+ **Card Controls**
60
+ - **Card Control**: Switch on each device that plays the configured card ID.
61
+ - **Card Control (All Yotos)**: Optional switch accessory that plays the card on every Yoto.
62
+
63
+ **Device status**
64
+ - **Online Status**: Contact sensor; Contact Not Detected = online.
65
+ - **Battery**: Battery level, charging state, and low battery.
66
+ - **Temperature**: Temperature sensor with fault status when offline/unavailable.
67
+
68
+ **Nightlight**
69
+ - **Day Nightlight / Night Nightlight**: Lightbulbs with On/Off, Brightness, Hue, and Saturation.
70
+ - **Nightlight Active / Day Nightlight Active / Night Nightlight Active**: Contact sensors for live nightlight state.
71
+
72
+ **Other controls**
73
+ - **Card Slot**: Contact sensor for card insertion.
74
+ - **Day Mode**: Contact sensor; Contact Not Detected = day mode.
75
+ - **Sleep Timer**: Switch to enable/disable sleep timer.
76
+ - **Bluetooth**: Switch to toggle Bluetooth.
77
+ - **Day/Night Max Volume**: Lightbulb brightness sets max volume limits.
28
78
 
29
79
  ## License
30
80
 
@@ -49,17 +49,17 @@
49
49
  "title": "Accessory Services",
50
50
  "type": "object",
51
51
  "properties": {
52
- "playback": {
53
- "title": "Playback",
54
- "type": "boolean",
55
- "default": true,
56
- "description": "Expose a playback switch."
57
- },
58
- "volume": {
59
- "title": "Volume",
60
- "type": "boolean",
61
- "default": true,
62
- "description": "Expose volume controls."
52
+ "playbackAccessory": {
53
+ "title": "Playback Controls",
54
+ "type": "string",
55
+ "default": "none",
56
+ "enum": ["bridged", "external", "none"],
57
+ "enumNames": [
58
+ "Bridged (Switch + Dimmer)",
59
+ "External Smart Speaker",
60
+ "None"
61
+ ],
62
+ "description": "Choose how playback and volume controls are exposed. External Smart Speaker requires additional pairing steps and appears as a separate accessory."
63
63
  },
64
64
  "temperature": {
65
65
  "title": "Temperature Sensor",
@@ -79,11 +79,40 @@
79
79
  "default": true,
80
80
  "description": "Expose card insertion status."
81
81
  },
82
- "nightMode": {
83
- "title": "Night Mode",
82
+ "cardControls": {
83
+ "title": "Card Controls",
84
+ "type": "array",
85
+ "description": "Add switches that play a specific card ID on each Yoto device. Optionally add an accessory that plays the card on all Yotos.",
86
+ "items": {
87
+ "title": "Card Control",
88
+ "type": "object",
89
+ "properties": {
90
+ "label": {
91
+ "title": "Label",
92
+ "type": "string",
93
+ "required": true,
94
+ "description": "Name shown in HomeKit for this card control."
95
+ },
96
+ "cardId": {
97
+ "title": "Card ID",
98
+ "type": "string",
99
+ "required": true,
100
+ "description": "The Yoto card ID to play."
101
+ },
102
+ "playOnAll": {
103
+ "title": "Play on All Yotos",
104
+ "type": "boolean",
105
+ "default": false,
106
+ "description": "Create a separate accessory that plays this card on every Yoto."
107
+ }
108
+ }
109
+ }
110
+ },
111
+ "dayMode": {
112
+ "title": "Day Mode",
84
113
  "type": "boolean",
85
114
  "default": true,
86
- "description": "Expose night mode status."
115
+ "description": "Expose day mode status."
87
116
  },
88
117
  "sleepTimer": {
89
118
  "title": "Sleep Timer",
@@ -133,12 +162,29 @@
133
162
  "type": "help",
134
163
  "helpvalue": "<p>Select which HomeKit services to expose for each Yoto device.</p>"
135
164
  },
136
- "services.playback",
137
- "services.volume",
165
+ {
166
+ "type": "help",
167
+ "helpvalue": "<p><strong>Playback Controls:</strong> External Smart Speaker requires additional pairing steps in the Home app and will appear as a separate accessory.</p>"
168
+ },
169
+ "services.playbackAccessory",
138
170
  "services.temperature",
139
171
  "services.nightlight",
140
172
  "services.cardSlot",
141
- "services.nightMode",
173
+ {
174
+ "type": "help",
175
+ "helpvalue": "<p><strong>Card Controls:</strong> Add switches that play a specific card ID on each Yoto. Enable \"Play on All Yotos\" to create a separate accessory.</p>"
176
+ },
177
+ {
178
+ "key": "services.cardControls",
179
+ "type": "array",
180
+ "buttonText": "Add Card Control",
181
+ "items": [
182
+ "services.cardControls[].label",
183
+ "services.cardControls[].cardId",
184
+ "services.cardControls[].playOnAll"
185
+ ]
186
+ },
187
+ "services.dayMode",
142
188
  "services.sleepTimer",
143
189
  "services.bluetooth",
144
190
  "services.volumeLimits"
package/lib/accessory.js CHANGED
@@ -8,6 +8,7 @@
8
8
  /** @import { YotoDevice } from 'yoto-nodejs-client/lib/api-endpoints/devices.js' */
9
9
  /** @import { YotoAccessoryContext } from './platform.js' */
10
10
  /** @import { ServiceSchemaKey } from '../config.schema.cjs' */
11
+ /** @import { CardControlConfig } from './card-controls.js' */
11
12
 
12
13
  /**
13
14
  * Device capabilities detected from metadata
@@ -25,7 +26,7 @@
25
26
  * @property {boolean} temperature
26
27
  * @property {boolean} nightlight
27
28
  * @property {boolean} cardSlot
28
- * @property {boolean} nightMode
29
+ * @property {boolean} dayMode
29
30
  * @property {boolean} sleepTimer
30
31
  * @property {boolean} bluetooth
31
32
  * @property {boolean} volumeLimits
@@ -41,6 +42,8 @@ import {
41
42
  import { sanitizeName } from './sanitize-name.js'
42
43
  import { syncServiceNames } from './sync-service-names.js'
43
44
  import { serviceSchema } from '../config.schema.cjs'
45
+ import { getPlaybackAccessoryConfig } from './service-config.js'
46
+ import { getCardControlConfigs } from './card-controls.js'
44
47
 
45
48
  // Use syncServiceNames for every visible service so HomeKit labels stay stable.
46
49
  // Exceptions: AccessoryInformation (named in platform) and Battery (set Characteristic.Name only).
@@ -60,7 +63,7 @@ function getBooleanSetting (value, fallback) {
60
63
  */
61
64
  function getServiceDefault (key) {
62
65
  const entry = serviceSchema[key]
63
- if (entry?.default !== undefined && typeof entry.default === 'boolean') {
66
+ if (entry && 'default' in entry && typeof entry.default === 'boolean') {
64
67
  return entry.default
65
68
  }
66
69
  return false
@@ -87,7 +90,7 @@ export class YotoPlayerAccessory {
87
90
  /** @type {Service | undefined} */ dayNightlightActiveService
88
91
  /** @type {Service | undefined} */ nightNightlightActiveService
89
92
  /** @type {Service | undefined} */ cardSlotService
90
- /** @type {Service | undefined} */ nightModeService
93
+ /** @type {Service | undefined} */ dayModeService
91
94
  /** @type {Service | undefined} */ sleepTimerService
92
95
  /** @type {Service | undefined} */ bluetoothService
93
96
  /** @type {Service | undefined} */ dayMaxVolumeService
@@ -127,14 +130,15 @@ export class YotoPlayerAccessory {
127
130
  const serviceConfig = typeof services === 'object' && services !== null
128
131
  ? /** @type {Record<string, unknown>} */ (services)
129
132
  : {}
133
+ const playbackConfig = getPlaybackAccessoryConfig(this.#platform.config)
130
134
 
131
135
  return {
132
- playback: getBooleanSetting(serviceConfig['playback'], getServiceDefault('playback')),
133
- volume: getBooleanSetting(serviceConfig['volume'], getServiceDefault('volume')),
136
+ playback: playbackConfig.playbackEnabled,
137
+ volume: playbackConfig.volumeEnabled,
134
138
  temperature: getBooleanSetting(serviceConfig['temperature'], getServiceDefault('temperature')),
135
139
  nightlight: getBooleanSetting(serviceConfig['nightlight'], getServiceDefault('nightlight')),
136
140
  cardSlot: getBooleanSetting(serviceConfig['cardSlot'], getServiceDefault('cardSlot')),
137
- nightMode: getBooleanSetting(serviceConfig['nightMode'], getServiceDefault('nightMode')),
141
+ dayMode: getBooleanSetting(serviceConfig['dayMode'], getServiceDefault('dayMode')),
138
142
  sleepTimer: getBooleanSetting(serviceConfig['sleepTimer'], getServiceDefault('sleepTimer')),
139
143
  bluetooth: getBooleanSetting(serviceConfig['bluetooth'], getServiceDefault('bluetooth')),
140
144
  volumeLimits: getBooleanSetting(serviceConfig['volumeLimits'], getServiceDefault('volumeLimits')),
@@ -188,8 +192,8 @@ export class YotoPlayerAccessory {
188
192
  if (serviceToggles.cardSlot) {
189
193
  this.setupCardSlotService()
190
194
  }
191
- if (serviceToggles.nightMode) {
192
- this.setupNightModeService()
195
+ if (serviceToggles.dayMode) {
196
+ this.setupDayModeService()
193
197
  }
194
198
  if (serviceToggles.sleepTimer) {
195
199
  this.setupSleepTimerService()
@@ -200,6 +204,7 @@ export class YotoPlayerAccessory {
200
204
  if (serviceToggles.volumeLimits) {
201
205
  this.setupVolumeLimitServices()
202
206
  }
207
+ this.setupCardControlServices()
203
208
 
204
209
  // Remove any services that aren't in our current set
205
210
  // (except AccessoryInformation which should always be preserved)
@@ -515,21 +520,21 @@ export class YotoPlayerAccessory {
515
520
  }
516
521
 
517
522
  /**
518
- * Setup night mode ContactSensor service
519
- * Shows if device is in night mode (vs day mode)
523
+ * Setup day mode ContactSensor service
524
+ * Shows if device is in day mode (vs night mode)
520
525
  */
521
- setupNightModeService () {
526
+ setupDayModeService () {
522
527
  const { Service, Characteristic } = this.#platform
523
- const serviceName = this.generateServiceName('Night Mode')
528
+ const serviceName = this.generateServiceName('Day Mode')
524
529
 
525
- const service = this.#accessory.getServiceById(Service.ContactSensor, 'NightModeStatus') ||
526
- this.#accessory.addService(Service.ContactSensor, serviceName, 'NightModeStatus')
530
+ const service = this.#accessory.getServiceById(Service.ContactSensor, 'DayModeStatus') ||
531
+ this.#accessory.addService(Service.ContactSensor, serviceName, 'DayModeStatus')
527
532
  syncServiceNames({ Characteristic, service, name: serviceName })
528
533
 
529
534
  service.getCharacteristic(Characteristic.ContactSensorState)
530
- .onGet(this.getNightModeStatus.bind(this))
535
+ .onGet(this.getDayModeStatus.bind(this))
531
536
 
532
- this.nightModeService = service
537
+ this.dayModeService = service
533
538
  this.#currentServices.add(service)
534
539
  }
535
540
 
@@ -632,6 +637,39 @@ export class YotoPlayerAccessory {
632
637
  this.#currentServices.add(nightService)
633
638
  }
634
639
 
640
+ /**
641
+ * Setup card control Switch services
642
+ */
643
+ setupCardControlServices () {
644
+ const cardControls = getCardControlConfigs(this.#platform.config)
645
+ if (cardControls.length === 0) {
646
+ return
647
+ }
648
+
649
+ const { Service, Characteristic } = this.#platform
650
+
651
+ for (const control of cardControls) {
652
+ const serviceName = this.generateServiceName(control.label)
653
+ const subtype = `CardControl:${control.id}`
654
+
655
+ const service = this.#accessory.getServiceById(Service.Switch, subtype) ||
656
+ this.#accessory.addService(Service.Switch, serviceName, subtype)
657
+
658
+ syncServiceNames({ Characteristic, service, name: serviceName })
659
+
660
+ service
661
+ .getCharacteristic(Characteristic.On)
662
+ .onGet(() => false)
663
+ .onSet(async (value) => {
664
+ await this.setCardControl(service, control, value)
665
+ })
666
+
667
+ service.updateCharacteristic(Characteristic.On, false)
668
+
669
+ this.#currentServices.add(service)
670
+ }
671
+ }
672
+
635
673
  /**
636
674
  * Setup event listeners for device model updates
637
675
  * Uses exhaustive switch pattern for type safety
@@ -677,8 +715,8 @@ export class YotoPlayerAccessory {
677
715
  break
678
716
 
679
717
  case 'dayMode':
680
- // Update night mode ContactSensor
681
- this.updateNightModeCharacteristic()
718
+ // Update day mode ContactSensor
719
+ this.updateDayModeCharacteristic()
682
720
  // Update nightlight status ContactSensors (depends on dayMode)
683
721
  if (this.#deviceModel.capabilities.hasColoredNightlight) {
684
722
  this.updateNightlightStatusCharacteristics()
@@ -927,7 +965,7 @@ export class YotoPlayerAccessory {
927
965
  const percent = Math.round((clampedSteps / 16) * 100)
928
966
  this.#log.debug(
929
967
  LOG_PREFIX.ACCESSORY,
930
- `[${this.#device.name}] Get volume rawSteps=${volumeSteps} steps=${clampedSteps} percent=${percent}`
968
+ `[${this.#device.name}] Get volume rawSteps=${volumeSteps} percent=${percent}`
931
969
  )
932
970
  return percent
933
971
  }
@@ -966,13 +1004,12 @@ export class YotoPlayerAccessory {
966
1004
  await deviceModel.setVolume(steps)
967
1005
  if (this.volumeService) {
968
1006
  const { Characteristic } = this.#platform
969
-
1007
+ const clampedPercent = Math.round((steps / 16) * 100)
970
1008
  this.volumeService
971
1009
  .getCharacteristic(Characteristic.On)
972
1010
  .updateValue(steps > 0)
973
1011
 
974
1012
  if (steps !== requestedSteps || normalizedPercent !== requestedPercent) {
975
- const clampedPercent = Math.round((steps / 16) * 100)
976
1013
  this.volumeService
977
1014
  .getCharacteristic(Characteristic.Brightness)
978
1015
  .updateValue(clampedPercent)
@@ -1489,17 +1526,17 @@ export class YotoPlayerAccessory {
1489
1526
  return hasCard ? Characteristic.ContactSensorState.CONTACT_NOT_DETECTED : Characteristic.ContactSensorState.CONTACT_DETECTED
1490
1527
  }
1491
1528
 
1492
- // ==================== Night Mode ContactSensor Getter ====================
1529
+ // ==================== Day Mode ContactSensor Getter ====================
1493
1530
 
1494
1531
  /**
1495
- * Get night mode status
1532
+ * Get day mode status
1496
1533
  * @returns {Promise<CharacteristicValue>}
1497
1534
  */
1498
- async getNightModeStatus () {
1535
+ async getDayModeStatus () {
1499
1536
  const { Characteristic } = this.#platform
1500
1537
  const status = this.#deviceModel.status
1501
- const isNightMode = status.dayMode === 'night'
1502
- return isNightMode
1538
+ const isDayMode = status.dayMode === 'day'
1539
+ return isDayMode
1503
1540
  ? Characteristic.ContactSensorState.CONTACT_NOT_DETECTED
1504
1541
  : Characteristic.ContactSensorState.CONTACT_DETECTED
1505
1542
  }
@@ -1560,6 +1597,54 @@ export class YotoPlayerAccessory {
1560
1597
  await this.#deviceModel.updateConfig({ bluetoothEnabled: enabled })
1561
1598
  }
1562
1599
 
1600
+ // ==================== Card Control Switch Setter ====================
1601
+
1602
+ /**
1603
+ * Trigger card playback for a configured card control.
1604
+ * @param {Service} service
1605
+ * @param {CardControlConfig} control
1606
+ * @param {CharacteristicValue} value
1607
+ * @returns {Promise<void>}
1608
+ */
1609
+ async setCardControl (service, control, value) {
1610
+ const { Characteristic } = this.#platform
1611
+ const isOn = Boolean(value)
1612
+
1613
+ if (!isOn) {
1614
+ service.getCharacteristic(Characteristic.On).updateValue(false)
1615
+ return
1616
+ }
1617
+
1618
+ if (!this.#deviceModel.status.isOnline) {
1619
+ this.#log.warn(LOG_PREFIX.ACCESSORY, `[${this.#device.name}] Card control skipped (offline): ${control.label}`)
1620
+ service.getCharacteristic(Characteristic.On).updateValue(false)
1621
+ throw new this.#platform.api.hap.HapStatusError(
1622
+ this.#platform.api.hap.HAPStatus.SERVICE_COMMUNICATION_FAILURE
1623
+ )
1624
+ }
1625
+
1626
+ this.#log.debug(
1627
+ LOG_PREFIX.ACCESSORY,
1628
+ `[${this.#device.name}] Play card control: ${control.label} (${control.cardId})`
1629
+ )
1630
+
1631
+ try {
1632
+ await this.#deviceModel.startCard({ cardId: control.cardId })
1633
+ } catch (error) {
1634
+ this.#log.error(
1635
+ LOG_PREFIX.ACCESSORY,
1636
+ `[${this.#device.name}] Failed to play card ${control.cardId}:`,
1637
+ error
1638
+ )
1639
+ service.getCharacteristic(Characteristic.On).updateValue(false)
1640
+ throw new this.#platform.api.hap.HapStatusError(
1641
+ this.#platform.api.hap.HAPStatus.SERVICE_COMMUNICATION_FAILURE
1642
+ )
1643
+ }
1644
+
1645
+ service.getCharacteristic(Characteristic.On).updateValue(false)
1646
+ }
1647
+
1563
1648
  // ==================== Volume Limit Lightbulb Getters/Setters ====================
1564
1649
 
1565
1650
  /**
@@ -1573,7 +1658,7 @@ export class YotoPlayerAccessory {
1573
1658
  const percent = Math.round((clampedSteps / 16) * 100)
1574
1659
  this.#log.debug(
1575
1660
  LOG_PREFIX.ACCESSORY,
1576
- `[${this.#device.name}] Get day max volume limit rawSteps=${limit} steps=${clampedSteps} percent=${percent}`
1661
+ `[${this.#device.name}] Get day max volume limit rawSteps=${limit} percent=${percent}`
1577
1662
  )
1578
1663
  return percent
1579
1664
  }
@@ -1612,7 +1697,7 @@ export class YotoPlayerAccessory {
1612
1697
  const percent = Math.round((clampedSteps / 16) * 100)
1613
1698
  this.#log.debug(
1614
1699
  LOG_PREFIX.ACCESSORY,
1615
- `[${this.#device.name}] Get night max volume limit rawSteps=${limit} steps=${clampedSteps} percent=${percent}`
1700
+ `[${this.#device.name}] Get night max volume limit rawSteps=${limit} percent=${percent}`
1616
1701
  )
1617
1702
  return percent
1618
1703
  }
@@ -1661,9 +1746,6 @@ export class YotoPlayerAccessory {
1661
1746
  * @param {number} volumeSteps - Volume level (0-16)
1662
1747
  */
1663
1748
  updateVolumeCharacteristic (volumeSteps) {
1664
- if (!this.volumeService) return
1665
-
1666
- const { Characteristic } = this.#platform
1667
1749
  if (volumeSteps > 0) {
1668
1750
  this.#lastNonZeroVolume = Math.round((volumeSteps / 16) * 100)
1669
1751
  }
@@ -1673,8 +1755,11 @@ export class YotoPlayerAccessory {
1673
1755
  const percent = Math.round((clampedVolume / 16) * 100)
1674
1756
  this.#log.debug(
1675
1757
  LOG_PREFIX.ACCESSORY,
1676
- `[${this.#device.name}] Update volume characteristic rawSteps=${volumeSteps} steps=${clampedVolume} percent=${percent}`
1758
+ `[${this.#device.name}] Update volume characteristic rawSteps=${volumeSteps} percent=${percent}`
1677
1759
  )
1760
+ if (!this.volumeService) return
1761
+
1762
+ const { Characteristic } = this.#platform
1678
1763
  this.volumeService
1679
1764
  .getCharacteristic(Characteristic.Brightness)
1680
1765
  .updateValue(percent)
@@ -1797,9 +1882,9 @@ export class YotoPlayerAccessory {
1797
1882
  .updateValue(isOnline)
1798
1883
  }
1799
1884
 
1800
- // Update night mode ContactSensor (device state)
1801
- if (this.nightModeService) {
1802
- this.nightModeService
1885
+ // Update day mode ContactSensor (device state)
1886
+ if (this.dayModeService) {
1887
+ this.dayModeService
1803
1888
  .getCharacteristic(Characteristic.StatusActive)
1804
1889
  .updateValue(isOnline)
1805
1890
  }
@@ -1883,20 +1968,20 @@ export class YotoPlayerAccessory {
1883
1968
  }
1884
1969
 
1885
1970
  /**
1886
- * Update night mode ContactSensor characteristic
1971
+ * Update day mode ContactSensor characteristic
1887
1972
  */
1888
- updateNightModeCharacteristic () {
1889
- if (!this.nightModeService) {
1973
+ updateDayModeCharacteristic () {
1974
+ if (!this.dayModeService) {
1890
1975
  return
1891
1976
  }
1892
1977
 
1893
1978
  const { Characteristic } = this.#platform
1894
1979
  const status = this.#deviceModel.status
1895
- const isNightMode = status.dayMode === 'night'
1980
+ const isDayMode = status.dayMode === 'day'
1896
1981
 
1897
- this.nightModeService
1982
+ this.dayModeService
1898
1983
  .getCharacteristic(Characteristic.ContactSensorState)
1899
- .updateValue(isNightMode ? Characteristic.ContactSensorState.CONTACT_NOT_DETECTED : Characteristic.ContactSensorState.CONTACT_DETECTED)
1984
+ .updateValue(isDayMode ? Characteristic.ContactSensorState.CONTACT_NOT_DETECTED : Characteristic.ContactSensorState.CONTACT_DETECTED)
1900
1985
  }
1901
1986
 
1902
1987
  /**
@@ -1944,7 +2029,7 @@ export class YotoPlayerAccessory {
1944
2029
  const percent = Math.round((clampedLimit / 16) * 100)
1945
2030
  this.#log.debug(
1946
2031
  LOG_PREFIX.ACCESSORY,
1947
- `[${this.#device.name}] Update day max volume characteristic rawSteps=${limit} steps=${clampedLimit} percent=${percent}`
2032
+ `[${this.#device.name}] Update day max volume characteristic rawSteps=${limit} percent=${percent}`
1948
2033
  )
1949
2034
  this.dayMaxVolumeService
1950
2035
  .getCharacteristic(Characteristic.Brightness)
@@ -1957,7 +2042,7 @@ export class YotoPlayerAccessory {
1957
2042
  const percent = Math.round((clampedLimit / 16) * 100)
1958
2043
  this.#log.debug(
1959
2044
  LOG_PREFIX.ACCESSORY,
1960
- `[${this.#device.name}] Update night max volume characteristic rawSteps=${limit} steps=${clampedLimit} percent=${percent}`
2045
+ `[${this.#device.name}] Update night max volume characteristic rawSteps=${limit} percent=${percent}`
1961
2046
  )
1962
2047
  this.nightMaxVolumeService
1963
2048
  .getCharacteristic(Characteristic.Brightness)