ble-device-registry.js 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137
  1. const {
  2. DEFAULT_PACKET_SIZE,
  3. formatSignalText,
  4. hasTargetAdvertisedUuid,
  5. inferPacketSize,
  6. mergeAdvertisedServiceUUIDs,
  7. normalizeDevice
  8. } = require('./ble-utils.js')
  9. const DEFAULT_DEVICE_LIMIT = 30
  10. function createBleDeviceRegistry(options = {}) {
  11. const deviceLimit = Math.max(1, Number(options.deviceLimit) || DEFAULT_DEVICE_LIMIT)
  12. let deviceMap = {}
  13. let deviceSequence = 0
  14. function getDevice(deviceId) {
  15. return deviceMap[deviceId] || null
  16. }
  17. function getSortedDeviceList() {
  18. return Object.keys(deviceMap)
  19. .map((deviceId) => deviceMap[deviceId])
  20. .sort((left, right) => {
  21. const leftIndex = Number(left.seenIndex) || 0
  22. const rightIndex = Number(right.seenIndex) || 0
  23. return leftIndex - rightIndex
  24. })
  25. }
  26. function getDeviceList() {
  27. return getSortedDeviceList().slice(0, deviceLimit)
  28. }
  29. function mergeDevices(devices = []) {
  30. if (!Array.isArray(devices) || !devices.length) return false
  31. let changed = false
  32. devices.forEach((device) => {
  33. if (!device || !device.deviceId) return
  34. const previousDevice = deviceMap[device.deviceId] || {}
  35. const nextDevice = normalizeDevice(device)
  36. const advertisServiceUUIDs = mergeAdvertisedServiceUUIDs(
  37. previousDevice.advertisServiceUUIDs,
  38. nextDevice.advertisServiceUUIDs
  39. )
  40. const isTargetAdvertised = !!previousDevice.isTargetAdvertised || hasTargetAdvertisedUuid({
  41. advertisServiceUUIDs
  42. })
  43. const isTargetDevice = !!previousDevice.isTargetDevice
  44. const seenIndex = previousDevice.seenIndex || (deviceSequence += 1)
  45. deviceMap[device.deviceId] = {
  46. ...previousDevice,
  47. ...nextDevice,
  48. advertisServiceUUIDs,
  49. displayName: nextDevice.displayName === '未命名设备' && previousDevice.displayName
  50. ? previousDevice.displayName
  51. : nextDevice.displayName,
  52. isTargetAdvertised,
  53. isTargetDevice,
  54. packetSize: nextDevice.packetSize || previousDevice.packetSize || DEFAULT_PACKET_SIZE,
  55. seenIndex,
  56. serviceText: advertisServiceUUIDs.length ? advertisServiceUUIDs.join(', ') : '未广播服务',
  57. targetText: isTargetDevice ? '已发现目标特征' : (isTargetAdvertised ? '广播含目标 UUID' : '')
  58. }
  59. changed = true
  60. })
  61. return changed
  62. }
  63. function markConnectedDevice(deviceId, discovery = {}) {
  64. const device = getDevice(deviceId)
  65. if (!device) return null
  66. const isTargetDevice = !!discovery.isTargetDevice
  67. const connectedDevice = {
  68. ...device,
  69. isTargetDevice,
  70. packetSize: device.packetSize || inferPacketSize(device),
  71. targetText: isTargetDevice ? '已发现目标特征' : device.targetText
  72. }
  73. deviceMap[deviceId] = connectedDevice
  74. return connectedDevice
  75. }
  76. function applyRssiUpdate(deviceId, rssi, connectedDevice = null) {
  77. if (typeof rssi !== 'number') return null
  78. if (connectedDevice && connectedDevice.deviceId !== deviceId) return null
  79. const signalText = formatSignalText(rssi)
  80. const lastSeenAt = Date.now()
  81. const updatedDevice = connectedDevice
  82. ? {
  83. ...connectedDevice,
  84. RSSI: rssi,
  85. lastSeenAt,
  86. signalText
  87. }
  88. : null
  89. deviceMap[deviceId] = {
  90. ...(deviceMap[deviceId] || {}),
  91. RSSI: rssi,
  92. lastSeenAt,
  93. signalText
  94. }
  95. return {
  96. deviceList: getDeviceList(),
  97. updatedDevice
  98. }
  99. }
  100. function clear() {
  101. deviceMap = {}
  102. deviceSequence = 0
  103. }
  104. return {
  105. applyRssiUpdate,
  106. clear,
  107. getDevice,
  108. getDeviceList,
  109. getSortedDeviceList,
  110. markConnectedDevice,
  111. mergeDevices
  112. }
  113. }
  114. module.exports = {
  115. DEFAULT_DEVICE_LIMIT,
  116. createBleDeviceRegistry
  117. }