homebridge-yoto 0.0.37 → 0.0.39

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/lib/accessory.js CHANGED
@@ -92,8 +92,8 @@ export class YotoPlayerAccessory {
92
92
  /** @type {Service | undefined} */ bluetoothService
93
93
  /** @type {Service | undefined} */ dayMaxVolumeService
94
94
  /** @type {Service | undefined} */ nightMaxVolumeService
95
- // Volume state for mute/unmute (0-16 steps)
96
- /** @type {number} */ #lastNonZeroVolume = 8
95
+ // Volume state for mute/unmute (0-100 percent)
96
+ /** @type {number} */ #lastNonZeroVolume = 50
97
97
  // Nightlight color state for restore-on-ON
98
98
  /** @type {string} */ #lastDayColor = '0xffffff'
99
99
  /** @type {string} */ #lastNightColor = '0xffffff'
@@ -325,7 +325,7 @@ export class YotoPlayerAccessory {
325
325
  .getCharacteristic(Characteristic.Brightness)
326
326
  .setProps({
327
327
  minValue: 0,
328
- maxValue: 16,
328
+ maxValue: 100,
329
329
  minStep: 1,
330
330
  })
331
331
  .onGet(this.getVolume.bind(this))
@@ -598,7 +598,7 @@ export class YotoPlayerAccessory {
598
598
 
599
599
  dayService
600
600
  .getCharacteristic(Characteristic.Brightness)
601
- .setProps({ minValue: 0, maxValue: 16, minStep: 1 })
601
+ .setProps({ minValue: 0, maxValue: 100, minStep: 1 })
602
602
  .onGet(this.getDayMaxVolume.bind(this))
603
603
  .onSet(this.setDayMaxVolume.bind(this))
604
604
 
@@ -622,7 +622,7 @@ export class YotoPlayerAccessory {
622
622
 
623
623
  nightService
624
624
  .getCharacteristic(Characteristic.Brightness)
625
- .setProps({ minValue: 0, maxValue: 16, minStep: 1 })
625
+ .setProps({ minValue: 0, maxValue: 100, minStep: 1 })
626
626
  .onGet(this.getNightMaxVolume.bind(this))
627
627
  .onSet(this.setNightMaxVolume.bind(this))
628
628
 
@@ -917,16 +917,23 @@ export class YotoPlayerAccessory {
917
917
  }
918
918
 
919
919
  /**
920
- * Get volume level (0-16 steps) from live status
920
+ * Get volume level as percentage (mapped from 0-16 steps)
921
921
  * @returns {Promise<CharacteristicValue>}
922
922
  */
923
923
  async getVolume () {
924
- this.#log.debug(LOG_PREFIX.ACCESSORY, `[${this.#device.name}] Get volume`)
925
- return this.#deviceModel.status.volume
924
+ const volumeSteps = this.#deviceModel.status.volume
925
+ const normalizedSteps = Number.isFinite(volumeSteps) ? volumeSteps : 0
926
+ const clampedSteps = Math.max(0, Math.min(normalizedSteps, 16))
927
+ const percent = Math.round((clampedSteps / 16) * 100)
928
+ this.#log.debug(
929
+ LOG_PREFIX.ACCESSORY,
930
+ `[${this.#device.name}] Get volume rawSteps=${volumeSteps} steps=${clampedSteps} percent=${percent}`
931
+ )
932
+ return percent
926
933
  }
927
934
 
928
935
  /**
929
- * Set volume level (0-16 steps)
936
+ * Set volume level as percentage (mapped to 0-16 steps)
930
937
  * @param {CharacteristicValue} value
931
938
  * @returns {Promise<void>}
932
939
  */
@@ -934,25 +941,25 @@ export class YotoPlayerAccessory {
934
941
  const deviceModel = this.#deviceModel
935
942
  this.#log.debug(LOG_PREFIX.ACCESSORY, `[${this.#device.name}] Set volume:`, value)
936
943
 
937
- const requestedSteps = typeof value === 'number' ? value : Number(value)
938
- if (!Number.isFinite(requestedSteps)) {
944
+ const requestedPercent = typeof value === 'number' ? value : Number(value)
945
+ if (!Number.isFinite(requestedPercent)) {
939
946
  throw new this.#platform.api.hap.HapStatusError(
940
947
  this.#platform.api.hap.HAPStatus.INVALID_VALUE_IN_REQUEST
941
948
  )
942
949
  }
943
950
 
944
- const maxVolumeSteps = Number.isFinite(deviceModel.status.maxVolume)
945
- ? deviceModel.status.maxVolume
946
- : 16
947
- const steps = Math.max(0, Math.min(Math.round(requestedSteps), maxVolumeSteps))
951
+ const normalizedPercent = Math.max(0, Math.min(Math.round(requestedPercent), 100))
952
+ const requestedSteps = Math.round((normalizedPercent / 100) * 16)
953
+ const steps = Math.max(0, Math.min(Math.round(requestedSteps), 16))
954
+ const resultPercent = Math.round((steps / 16) * 100)
948
955
  this.#log.debug(
949
956
  LOG_PREFIX.ACCESSORY,
950
- `[${this.#device.name}] Set volume raw=${value} steps=${requestedSteps} -> ${steps} (max ${maxVolumeSteps}/16)`
957
+ `[${this.#device.name}] Set volume raw=${value} normalizedPercent=${normalizedPercent} requestedSteps=${requestedSteps} -> steps=${steps} percent=${resultPercent}`
951
958
  )
952
959
 
953
960
  // Track last non-zero volume for unmute
954
961
  if (steps > 0) {
955
- this.#lastNonZeroVolume = steps
962
+ this.#lastNonZeroVolume = Math.round((steps / 16) * 100)
956
963
  }
957
964
 
958
965
  try {
@@ -964,10 +971,11 @@ export class YotoPlayerAccessory {
964
971
  .getCharacteristic(Characteristic.On)
965
972
  .updateValue(steps > 0)
966
973
 
967
- if (steps !== requestedSteps) {
974
+ if (steps !== requestedSteps || normalizedPercent !== requestedPercent) {
975
+ const clampedPercent = Math.round((steps / 16) * 100)
968
976
  this.volumeService
969
977
  .getCharacteristic(Characteristic.Brightness)
970
- .updateValue(steps)
978
+ .updateValue(clampedPercent)
971
979
  }
972
980
  }
973
981
  } catch (error) {
@@ -1024,8 +1032,8 @@ export class YotoPlayerAccessory {
1024
1032
  async getOnlineStatus () {
1025
1033
  const { Characteristic } = this.#platform
1026
1034
  return this.#deviceModel.status.isOnline
1027
- ? Characteristic.ContactSensorState.CONTACT_DETECTED
1028
- : Characteristic.ContactSensorState.CONTACT_NOT_DETECTED
1035
+ ? Characteristic.ContactSensorState.CONTACT_NOT_DETECTED
1036
+ : Characteristic.ContactSensorState.CONTACT_DETECTED
1029
1037
  }
1030
1038
 
1031
1039
  // ==================== Battery Characteristic Handlers ====================
@@ -1439,7 +1447,7 @@ export class YotoPlayerAccessory {
1439
1447
  const { Characteristic } = this.#platform
1440
1448
  const status = this.#deviceModel.status
1441
1449
  const isActive = status.nightlightMode !== 'off'
1442
- return isActive ? Characteristic.ContactSensorState.CONTACT_DETECTED : Characteristic.ContactSensorState.CONTACT_NOT_DETECTED
1450
+ return isActive ? Characteristic.ContactSensorState.CONTACT_NOT_DETECTED : Characteristic.ContactSensorState.CONTACT_DETECTED
1443
1451
  }
1444
1452
 
1445
1453
  /**
@@ -1452,7 +1460,7 @@ export class YotoPlayerAccessory {
1452
1460
  const isDay = status.dayMode === 'day'
1453
1461
  const isActive = status.nightlightMode !== 'off'
1454
1462
  const isShowing = isDay && isActive
1455
- return isShowing ? Characteristic.ContactSensorState.CONTACT_DETECTED : Characteristic.ContactSensorState.CONTACT_NOT_DETECTED
1463
+ return isShowing ? Characteristic.ContactSensorState.CONTACT_NOT_DETECTED : Characteristic.ContactSensorState.CONTACT_DETECTED
1456
1464
  }
1457
1465
 
1458
1466
  /**
@@ -1465,7 +1473,7 @@ export class YotoPlayerAccessory {
1465
1473
  const isNight = status.dayMode === 'night'
1466
1474
  const isActive = status.nightlightMode !== 'off'
1467
1475
  const isShowing = isNight && isActive
1468
- return isShowing ? Characteristic.ContactSensorState.CONTACT_DETECTED : Characteristic.ContactSensorState.CONTACT_NOT_DETECTED
1476
+ return isShowing ? Characteristic.ContactSensorState.CONTACT_NOT_DETECTED : Characteristic.ContactSensorState.CONTACT_DETECTED
1469
1477
  }
1470
1478
 
1471
1479
  // ==================== Card Slot ContactSensor Getter ====================
@@ -1478,7 +1486,7 @@ export class YotoPlayerAccessory {
1478
1486
  const { Characteristic } = this.#platform
1479
1487
  const status = this.#deviceModel.status
1480
1488
  const hasCard = status.cardInsertionState !== 'none'
1481
- return hasCard ? Characteristic.ContactSensorState.CONTACT_DETECTED : Characteristic.ContactSensorState.CONTACT_NOT_DETECTED
1489
+ return hasCard ? Characteristic.ContactSensorState.CONTACT_NOT_DETECTED : Characteristic.ContactSensorState.CONTACT_DETECTED
1482
1490
  }
1483
1491
 
1484
1492
  // ==================== Night Mode ContactSensor Getter ====================
@@ -1492,8 +1500,8 @@ export class YotoPlayerAccessory {
1492
1500
  const status = this.#deviceModel.status
1493
1501
  const isNightMode = status.dayMode === 'night'
1494
1502
  return isNightMode
1495
- ? Characteristic.ContactSensorState.CONTACT_DETECTED
1496
- : Characteristic.ContactSensorState.CONTACT_NOT_DETECTED
1503
+ ? Characteristic.ContactSensorState.CONTACT_NOT_DETECTED
1504
+ : Characteristic.ContactSensorState.CONTACT_DETECTED
1497
1505
  }
1498
1506
 
1499
1507
  // ==================== Sleep Timer Switch Getter/Setter ====================
@@ -1555,67 +1563,79 @@ export class YotoPlayerAccessory {
1555
1563
  // ==================== Volume Limit Lightbulb Getters/Setters ====================
1556
1564
 
1557
1565
  /**
1558
- * Get day max volume limit
1566
+ * Get day max volume limit as percentage (mapped from 0-16 steps)
1559
1567
  * @returns {Promise<CharacteristicValue>}
1560
1568
  */
1561
1569
  async getDayMaxVolume () {
1562
1570
  const limit = this.#deviceModel.config.maxVolumeLimit
1571
+ const steps = Number.isFinite(limit) ? limit : 16
1572
+ const clampedSteps = Math.max(0, Math.min(steps, 16))
1573
+ const percent = Math.round((clampedSteps / 16) * 100)
1563
1574
  this.#log.debug(
1564
1575
  LOG_PREFIX.ACCESSORY,
1565
- `[${this.#device.name}] Get day max volume limit: ${limit}`
1576
+ `[${this.#device.name}] Get day max volume limit rawSteps=${limit} steps=${clampedSteps} percent=${percent}`
1566
1577
  )
1567
- return Number.isFinite(limit) ? limit : 16
1578
+ return percent
1568
1579
  }
1569
1580
 
1570
1581
  /**
1571
- * Set day max volume limit
1582
+ * Set day max volume limit as percentage (mapped to 0-16 steps)
1572
1583
  * @param {CharacteristicValue} value
1573
1584
  */
1574
1585
  async setDayMaxVolume (value) {
1575
- const requested = typeof value === 'number' ? value : Number(value)
1576
- if (!Number.isFinite(requested)) {
1586
+ const requestedPercent = typeof value === 'number' ? value : Number(value)
1587
+ if (!Number.isFinite(requestedPercent)) {
1577
1588
  throw new this.#platform.api.hap.HapStatusError(
1578
1589
  this.#platform.api.hap.HAPStatus.INVALID_VALUE_IN_REQUEST
1579
1590
  )
1580
1591
  }
1581
1592
 
1582
- const limit = Math.max(0, Math.min(Math.round(requested), 16))
1593
+ const normalizedPercent = Math.max(0, Math.min(Math.round(requestedPercent), 100))
1594
+ const requestedSteps = Math.round((normalizedPercent / 100) * 16)
1595
+ const limit = Math.max(0, Math.min(Math.round(requestedSteps), 16))
1596
+ const limitPercent = Math.round((limit / 16) * 100)
1583
1597
  this.#log.debug(
1584
1598
  LOG_PREFIX.ACCESSORY,
1585
- `[${this.#device.name}] Set day max volume limit raw=${value} requested=${requested} -> ${limit}/16`
1599
+ `[${this.#device.name}] Set day max volume limit raw=${value} normalizedPercent=${normalizedPercent} requestedSteps=${requestedSteps} -> steps=${limit} percent=${limitPercent}`
1586
1600
  )
1587
1601
  await this.#deviceModel.updateConfig({ maxVolumeLimit: limit })
1588
1602
  }
1589
1603
 
1590
1604
  /**
1591
- * Get night max volume limit
1605
+ * Get night max volume limit as percentage (mapped from 0-16 steps)
1592
1606
  * @returns {Promise<CharacteristicValue>}
1593
1607
  */
1594
1608
  async getNightMaxVolume () {
1595
1609
  const limit = this.#deviceModel.config.nightMaxVolumeLimit
1610
+ const steps = Number.isFinite(limit) ? limit : 10
1611
+ const clampedSteps = Math.max(0, Math.min(steps, 16))
1612
+ const percent = Math.round((clampedSteps / 16) * 100)
1596
1613
  this.#log.debug(
1597
1614
  LOG_PREFIX.ACCESSORY,
1598
- `[${this.#device.name}] Get night max volume limit: ${limit}`
1615
+ `[${this.#device.name}] Get night max volume limit rawSteps=${limit} steps=${clampedSteps} percent=${percent}`
1599
1616
  )
1600
- return Number.isFinite(limit) ? limit : 10
1617
+ return percent
1601
1618
  }
1602
1619
 
1603
1620
  /**
1604
- * Set night max volume limit
1621
+ * Set night max volume limit as percentage (mapped to 0-16 steps)
1605
1622
  * @param {CharacteristicValue} value
1606
1623
  */
1607
1624
  async setNightMaxVolume (value) {
1608
- const requested = typeof value === 'number' ? value : Number(value)
1609
- if (!Number.isFinite(requested)) {
1625
+ const requestedPercent = typeof value === 'number' ? value : Number(value)
1626
+ if (!Number.isFinite(requestedPercent)) {
1610
1627
  throw new this.#platform.api.hap.HapStatusError(
1611
1628
  this.#platform.api.hap.HAPStatus.INVALID_VALUE_IN_REQUEST
1612
1629
  )
1613
1630
  }
1614
1631
 
1615
- const limit = Math.max(0, Math.min(Math.round(requested), 16))
1632
+ const normalizedPercent = Math.max(0, Math.min(Math.round(requestedPercent), 100))
1633
+ const requestedSteps = Math.round((normalizedPercent / 100) * 16)
1634
+ const limit = Math.max(0, Math.min(Math.round(requestedSteps), 16))
1635
+ const limitPercent = Math.round((limit / 16) * 100)
1616
1636
  this.#log.debug(
1617
1637
  LOG_PREFIX.ACCESSORY,
1618
- `[${this.#device.name}] Set night max volume limit raw=${value} requested=${requested} -> ${limit}/16`
1638
+ `[${this.#device.name}] Set night max volume limit raw=${value} normalizedPercent=${normalizedPercent} requestedSteps=${requestedSteps} -> steps=${limit} percent=${limitPercent}`
1619
1639
  )
1620
1640
  await this.#deviceModel.updateConfig({ nightMaxVolumeLimit: limit })
1621
1641
  }
@@ -1645,18 +1665,19 @@ export class YotoPlayerAccessory {
1645
1665
 
1646
1666
  const { Characteristic } = this.#platform
1647
1667
  if (volumeSteps > 0) {
1648
- this.#lastNonZeroVolume = volumeSteps
1668
+ this.#lastNonZeroVolume = Math.round((volumeSteps / 16) * 100)
1649
1669
  }
1650
1670
 
1651
1671
  const normalizedVolume = Number.isFinite(volumeSteps) ? volumeSteps : 0
1652
1672
  const clampedVolume = Math.max(0, Math.min(normalizedVolume, 16))
1673
+ const percent = Math.round((clampedVolume / 16) * 100)
1653
1674
  this.#log.debug(
1654
1675
  LOG_PREFIX.ACCESSORY,
1655
- `[${this.#device.name}] Update volume characteristic raw=${volumeSteps} -> ${clampedVolume}`
1676
+ `[${this.#device.name}] Update volume characteristic rawSteps=${volumeSteps} steps=${clampedVolume} percent=${percent}`
1656
1677
  )
1657
1678
  this.volumeService
1658
1679
  .getCharacteristic(Characteristic.Brightness)
1659
- .updateValue(clampedVolume)
1680
+ .updateValue(percent)
1660
1681
  }
1661
1682
 
1662
1683
  /**
@@ -1741,8 +1762,8 @@ export class YotoPlayerAccessory {
1741
1762
  this.onlineStatusService
1742
1763
  .getCharacteristic(Characteristic.ContactSensorState)
1743
1764
  .updateValue(isOnline
1744
- ? Characteristic.ContactSensorState.CONTACT_DETECTED
1745
- : Characteristic.ContactSensorState.CONTACT_NOT_DETECTED)
1765
+ ? Characteristic.ContactSensorState.CONTACT_NOT_DETECTED
1766
+ : Characteristic.ContactSensorState.CONTACT_DETECTED)
1746
1767
  }
1747
1768
 
1748
1769
  // Update TemperatureSensor (temperature reading)
@@ -1822,7 +1843,7 @@ export class YotoPlayerAccessory {
1822
1843
  const isActive = status.nightlightMode !== 'off'
1823
1844
  this.nightlightActiveService
1824
1845
  .getCharacteristic(Characteristic.ContactSensorState)
1825
- .updateValue(isActive ? Characteristic.ContactSensorState.CONTACT_DETECTED : Characteristic.ContactSensorState.CONTACT_NOT_DETECTED)
1846
+ .updateValue(isActive ? Characteristic.ContactSensorState.CONTACT_NOT_DETECTED : Characteristic.ContactSensorState.CONTACT_DETECTED)
1826
1847
  }
1827
1848
 
1828
1849
  if (this.dayNightlightActiveService) {
@@ -1831,7 +1852,7 @@ export class YotoPlayerAccessory {
1831
1852
  const isShowing = isDay && isActive
1832
1853
  this.dayNightlightActiveService
1833
1854
  .getCharacteristic(Characteristic.ContactSensorState)
1834
- .updateValue(isShowing ? Characteristic.ContactSensorState.CONTACT_DETECTED : Characteristic.ContactSensorState.CONTACT_NOT_DETECTED)
1855
+ .updateValue(isShowing ? Characteristic.ContactSensorState.CONTACT_NOT_DETECTED : Characteristic.ContactSensorState.CONTACT_DETECTED)
1835
1856
  }
1836
1857
 
1837
1858
  if (this.nightNightlightActiveService) {
@@ -1840,7 +1861,7 @@ export class YotoPlayerAccessory {
1840
1861
  const isShowing = isNight && isActive
1841
1862
  this.nightNightlightActiveService
1842
1863
  .getCharacteristic(Characteristic.ContactSensorState)
1843
- .updateValue(isShowing ? Characteristic.ContactSensorState.CONTACT_DETECTED : Characteristic.ContactSensorState.CONTACT_NOT_DETECTED)
1864
+ .updateValue(isShowing ? Characteristic.ContactSensorState.CONTACT_NOT_DETECTED : Characteristic.ContactSensorState.CONTACT_DETECTED)
1844
1865
  }
1845
1866
  }
1846
1867
 
@@ -1858,7 +1879,7 @@ export class YotoPlayerAccessory {
1858
1879
 
1859
1880
  this.cardSlotService
1860
1881
  .getCharacteristic(Characteristic.ContactSensorState)
1861
- .updateValue(hasCard ? Characteristic.ContactSensorState.CONTACT_DETECTED : Characteristic.ContactSensorState.CONTACT_NOT_DETECTED)
1882
+ .updateValue(hasCard ? Characteristic.ContactSensorState.CONTACT_NOT_DETECTED : Characteristic.ContactSensorState.CONTACT_DETECTED)
1862
1883
  }
1863
1884
 
1864
1885
  /**
@@ -1875,7 +1896,7 @@ export class YotoPlayerAccessory {
1875
1896
 
1876
1897
  this.nightModeService
1877
1898
  .getCharacteristic(Characteristic.ContactSensorState)
1878
- .updateValue(isNightMode ? Characteristic.ContactSensorState.CONTACT_DETECTED : Characteristic.ContactSensorState.CONTACT_NOT_DETECTED)
1899
+ .updateValue(isNightMode ? Characteristic.ContactSensorState.CONTACT_NOT_DETECTED : Characteristic.ContactSensorState.CONTACT_DETECTED)
1879
1900
  }
1880
1901
 
1881
1902
  /**
@@ -1920,25 +1941,27 @@ export class YotoPlayerAccessory {
1920
1941
  if (this.dayMaxVolumeService) {
1921
1942
  const limit = Number.isFinite(config.maxVolumeLimit) ? config.maxVolumeLimit : 16
1922
1943
  const clampedLimit = Math.max(0, Math.min(limit, 16))
1944
+ const percent = Math.round((clampedLimit / 16) * 100)
1923
1945
  this.#log.debug(
1924
1946
  LOG_PREFIX.ACCESSORY,
1925
- `[${this.#device.name}] Update day max volume characteristic raw=${limit} -> ${clampedLimit}`
1947
+ `[${this.#device.name}] Update day max volume characteristic rawSteps=${limit} steps=${clampedLimit} percent=${percent}`
1926
1948
  )
1927
1949
  this.dayMaxVolumeService
1928
1950
  .getCharacteristic(Characteristic.Brightness)
1929
- .updateValue(clampedLimit)
1951
+ .updateValue(percent)
1930
1952
  }
1931
1953
 
1932
1954
  if (this.nightMaxVolumeService) {
1933
1955
  const limit = Number.isFinite(config.nightMaxVolumeLimit) ? config.nightMaxVolumeLimit : 10
1934
1956
  const clampedLimit = Math.max(0, Math.min(limit, 16))
1957
+ const percent = Math.round((clampedLimit / 16) * 100)
1935
1958
  this.#log.debug(
1936
1959
  LOG_PREFIX.ACCESSORY,
1937
- `[${this.#device.name}] Update night max volume characteristic raw=${limit} -> ${clampedLimit}`
1960
+ `[${this.#device.name}] Update night max volume characteristic rawSteps=${limit} steps=${clampedLimit} percent=${percent}`
1938
1961
  )
1939
1962
  this.nightMaxVolumeService
1940
1963
  .getCharacteristic(Characteristic.Brightness)
1941
- .updateValue(clampedLimit)
1964
+ .updateValue(percent)
1942
1965
  }
1943
1966
  }
1944
1967
 
package/lib/platform.js CHANGED
@@ -188,68 +188,104 @@ export class YotoPlatform {
188
188
  this.log.info(`Device offline: ${deviceId}${reason}`)
189
189
  })
190
190
 
191
+ /**
192
+ * @param {string} deviceId
193
+ * @returns {string}
194
+ */
195
+ const getDeviceLabel = (deviceId) => {
196
+ const deviceName = this.yotoAccount?.getDevice(deviceId)?.device?.name
197
+ return deviceName || deviceId
198
+ }
199
+
200
+ /**
201
+ * @param {{ status?: Record<string, unknown> } | null | undefined} message
202
+ * @returns {string}
203
+ */
204
+ const formatLegacyStatusFields = (message) => {
205
+ const status = message?.status
206
+ if (!status || typeof status !== 'object') return ''
207
+ const fields = Object.keys(status)
208
+ if (!fields.length) return ''
209
+ const preview = fields.slice(0, 8).join(', ')
210
+ const suffix = fields.length > 8 ? `, +${fields.length - 8} more` : ''
211
+ return ` fields: ${preview}${suffix}`
212
+ }
213
+
191
214
  this.yotoAccount.on('statusUpdate', ({ deviceId, source, changedFields }) => {
215
+ const label = getDeviceLabel(deviceId)
192
216
  const fields = Array.from(changedFields).join(', ')
193
- this.log.debug(`Status update [${deviceId} ${source}]: ${fields}`)
217
+ this.log.debug(`Status update [${label} ${source}]: ${fields}`)
194
218
  })
195
219
 
196
220
  this.yotoAccount.on('configUpdate', ({ deviceId, changedFields }) => {
221
+ const label = getDeviceLabel(deviceId)
197
222
  const fields = Array.from(changedFields).join(', ')
198
- this.log.debug(`Config update [${deviceId}]: ${fields}`)
223
+ this.log.debug(`Config update [${label}]: ${fields}`)
199
224
  })
200
225
 
201
226
  this.yotoAccount.on('playbackUpdate', ({ deviceId, changedFields }) => {
227
+ const label = getDeviceLabel(deviceId)
202
228
  const fields = Array.from(changedFields).join(', ')
203
- this.log.debug(`Playback update [${deviceId}]: ${fields}`)
229
+ this.log.debug(`Playback update [${label}]: ${fields}`)
204
230
  })
205
231
 
206
232
  this.yotoAccount.on('mqttConnect', ({ deviceId }) => {
207
- const deviceName = this.yotoAccount?.getDevice(deviceId)?.device?.name
208
- const label = deviceName ? `${deviceName} (${deviceId})` : deviceId
233
+ const label = getDeviceLabel(deviceId)
209
234
  this.log.debug(`MQTT connected: ${label}`)
210
235
  })
211
236
 
212
237
  this.yotoAccount.on('mqttDisconnect', ({ deviceId, metadata }) => {
238
+ const label = getDeviceLabel(deviceId)
213
239
  const reasonCode = metadata?.packet?.reasonCode
214
240
  const reason = typeof reasonCode === 'number' ? ` (code ${reasonCode})` : ''
215
- this.log.warn(`MQTT disconnected: ${deviceId}${reason}`)
241
+ this.log.warn(`MQTT disconnected: ${label}${reason}`)
216
242
  })
217
243
 
218
244
  this.yotoAccount.on('mqttClose', ({ deviceId, metadata }) => {
245
+ const label = getDeviceLabel(deviceId)
219
246
  const reason = metadata?.reason ? ` (${metadata.reason})` : ''
220
- this.log.debug(`MQTT closed: ${deviceId}${reason}`)
247
+ this.log.debug(`MQTT closed: ${label}${reason}`)
221
248
  })
222
249
 
223
250
  this.yotoAccount.on('mqttReconnect', ({ deviceId }) => {
224
- this.log.debug(`MQTT reconnecting: ${deviceId}`)
251
+ const label = getDeviceLabel(deviceId)
252
+ this.log.debug(`MQTT reconnecting: ${label}`)
225
253
  })
226
254
 
227
255
  this.yotoAccount.on('mqttOffline', ({ deviceId }) => {
228
- this.log.debug(`MQTT offline: ${deviceId}`)
256
+ const label = getDeviceLabel(deviceId)
257
+ this.log.debug(`MQTT offline: ${label}`)
229
258
  })
230
259
 
231
260
  this.yotoAccount.on('mqttEnd', ({ deviceId }) => {
232
- this.log.debug(`MQTT ended: ${deviceId}`)
261
+ const label = getDeviceLabel(deviceId)
262
+ this.log.debug(`MQTT ended: ${label}`)
233
263
  })
234
264
 
235
265
  this.yotoAccount.on('mqttStatus', ({ deviceId, topic }) => {
236
- this.log.debug(`MQTT status [${deviceId}]: ${topic}`)
266
+ const label = getDeviceLabel(deviceId)
267
+ this.log.debug(`MQTT status [${label}]: ${topic}`)
237
268
  })
238
269
 
239
270
  this.yotoAccount.on('mqttEvents', ({ deviceId, topic }) => {
240
- this.log.debug(`MQTT events [${deviceId}]: ${topic}`)
271
+ const label = getDeviceLabel(deviceId)
272
+ this.log.debug(`MQTT events [${label}]: ${topic}`)
241
273
  })
242
274
 
243
- this.yotoAccount.on('mqttStatusLegacy', ({ deviceId, topic }) => {
244
- this.log.debug(`MQTT legacy status [${deviceId}]: ${topic}`)
275
+ this.yotoAccount.on('mqttStatusLegacy', ({ deviceId, topic, message }) => {
276
+ const label = getDeviceLabel(deviceId)
277
+ const fields = formatLegacyStatusFields(message)
278
+ this.log.debug(`MQTT legacy status [${label}]: ${topic}${fields}`)
245
279
  })
246
280
 
247
281
  this.yotoAccount.on('mqttResponse', ({ deviceId, topic }) => {
248
- this.log.debug(`MQTT response [${deviceId}]: ${topic}`)
282
+ const label = getDeviceLabel(deviceId)
283
+ this.log.debug(`MQTT response [${label}]: ${topic}`)
249
284
  })
250
285
 
251
286
  this.yotoAccount.on('mqttUnknown', ({ deviceId, topic }) => {
252
- this.log.debug(`MQTT unknown [${deviceId}]: ${topic}`)
287
+ const label = getDeviceLabel(deviceId)
288
+ this.log.debug(`MQTT unknown [${label}]: ${topic}`)
253
289
  })
254
290
 
255
291
  // Start the account (discovers devices, creates device models, starts MQTT)
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "homebridge-yoto",
3
3
  "description": "Control your Yoto players through Apple HomeKit with real-time MQTT updates",
4
- "version": "0.0.37",
4
+ "version": "0.0.39",
5
5
  "author": "Bret Comnes <bcomnes@gmail.com> (https://bret.io)",
6
6
  "bugs": {
7
7
  "url": "https://github.com/bcomnes/homebridge-yoto/issues"