@switchbot/homebridge-switchbot 4.3.2-beta.9 → 4.3.2

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.
Files changed (222) hide show
  1. package/.github/copilot-instructions.md +328 -0
  2. package/.github/scripts/npm-version-script-esm-auto.js +207 -0
  3. package/.github/workflows/beta-release.yml +8 -12
  4. package/.github/workflows/release.yml +54 -22
  5. package/CHANGELOG.md +1 -1
  6. package/README.md +13 -10
  7. package/config.schema.json +2 -2
  8. package/coverage/base.css +224 -0
  9. package/coverage/block-navigation.js +87 -0
  10. package/coverage/clover.xml +15847 -0
  11. package/coverage/coverage-final.json +42 -0
  12. package/coverage/docs/assets/dmt/dmt-component-data.js.html +85 -0
  13. package/coverage/docs/assets/dmt/dmt-components.js.html +286 -0
  14. package/coverage/docs/assets/dmt/index.html +131 -0
  15. package/coverage/docs/assets/hierarchy.js.html +85 -0
  16. package/coverage/docs/assets/icons.js.html +136 -0
  17. package/coverage/docs/assets/index.html +146 -0
  18. package/coverage/docs/assets/main.js.html +265 -0
  19. package/coverage/favicon.png +0 -0
  20. package/coverage/index.html +191 -0
  21. package/coverage/prettify.css +1 -0
  22. package/coverage/prettify.js +2 -0
  23. package/coverage/sort-arrow-sprite.png +0 -0
  24. package/coverage/sorter.js +196 -0
  25. package/coverage/src/device/blindtilt.ts.html +3238 -0
  26. package/coverage/src/device/bot.ts.html +2803 -0
  27. package/coverage/src/device/ceilinglight.ts.html +2338 -0
  28. package/coverage/src/device/colorbulb.ts.html +2824 -0
  29. package/coverage/src/device/contact.ts.html +1465 -0
  30. package/coverage/src/device/curtain.ts.html +2869 -0
  31. package/coverage/src/device/device.ts.html +2500 -0
  32. package/coverage/src/device/fan.ts.html +2242 -0
  33. package/coverage/src/device/hub.ts.html +1408 -0
  34. package/coverage/src/device/humidifier.ts.html +2116 -0
  35. package/coverage/src/device/index.html +416 -0
  36. package/coverage/src/device/iosensor.ts.html +1375 -0
  37. package/coverage/src/device/lightstrip.ts.html +2617 -0
  38. package/coverage/src/device/lock.ts.html +1963 -0
  39. package/coverage/src/device/meter.ts.html +1372 -0
  40. package/coverage/src/device/meterplus.ts.html +1384 -0
  41. package/coverage/src/device/meterpro.ts.html +1618 -0
  42. package/coverage/src/device/motion.ts.html +1264 -0
  43. package/coverage/src/device/plug.ts.html +1372 -0
  44. package/coverage/src/device/relayswitch.ts.html +2284 -0
  45. package/coverage/src/device/robotvacuumcleaner.ts.html +1810 -0
  46. package/coverage/src/device/waterdetector.ts.html +1294 -0
  47. package/coverage/src/homebridge-ui/index.html +116 -0
  48. package/coverage/src/homebridge-ui/server.ts.html +229 -0
  49. package/coverage/src/index.html +161 -0
  50. package/coverage/src/index.ts.html +124 -0
  51. package/coverage/src/irdevice/airconditioner.ts.html +1687 -0
  52. package/coverage/src/irdevice/airpurifier.ts.html +844 -0
  53. package/coverage/src/irdevice/camera.ts.html +475 -0
  54. package/coverage/src/irdevice/fan.ts.html +766 -0
  55. package/coverage/src/irdevice/index.html +251 -0
  56. package/coverage/src/irdevice/irdevice.ts.html +1117 -0
  57. package/coverage/src/irdevice/light.ts.html +826 -0
  58. package/coverage/src/irdevice/other.ts.html +2458 -0
  59. package/coverage/src/irdevice/tv.ts.html +1222 -0
  60. package/coverage/src/irdevice/vacuumcleaner.ts.html +466 -0
  61. package/coverage/src/irdevice/waterheater.ts.html +469 -0
  62. package/coverage/src/platform.ts.html +8776 -0
  63. package/coverage/src/settings.ts.html +934 -0
  64. package/coverage/src/utils.ts.html +2092 -0
  65. package/dist/device/blindtilt.d.ts.map +1 -1
  66. package/dist/device/blindtilt.js +12 -4
  67. package/dist/device/blindtilt.js.map +1 -1
  68. package/dist/device/bot.d.ts.map +1 -1
  69. package/dist/device/bot.js +12 -4
  70. package/dist/device/bot.js.map +1 -1
  71. package/dist/device/ceilinglight.d.ts.map +1 -1
  72. package/dist/device/ceilinglight.js +18 -7
  73. package/dist/device/ceilinglight.js.map +1 -1
  74. package/dist/device/colorbulb.d.ts.map +1 -1
  75. package/dist/device/colorbulb.js +18 -7
  76. package/dist/device/colorbulb.js.map +1 -1
  77. package/dist/device/contact.d.ts.map +1 -1
  78. package/dist/device/contact.js +6 -2
  79. package/dist/device/contact.js.map +1 -1
  80. package/dist/device/curtain.d.ts.map +1 -1
  81. package/dist/device/curtain.js +12 -4
  82. package/dist/device/curtain.js.map +1 -1
  83. package/dist/device/device.d.ts +5 -7
  84. package/dist/device/device.d.ts.map +1 -1
  85. package/dist/device/device.js +11 -5
  86. package/dist/device/device.js.map +1 -1
  87. package/dist/device/fan.d.ts.map +1 -1
  88. package/dist/device/fan.js +16 -6
  89. package/dist/device/fan.js.map +1 -1
  90. package/dist/device/hub.d.ts +2 -2
  91. package/dist/device/hub.d.ts.map +1 -1
  92. package/dist/device/hub.js +8 -3
  93. package/dist/device/hub.js.map +1 -1
  94. package/dist/device/humidifier.d.ts.map +1 -1
  95. package/dist/device/humidifier.js +16 -6
  96. package/dist/device/humidifier.js.map +1 -1
  97. package/dist/device/iosensor.d.ts.map +1 -1
  98. package/dist/device/iosensor.js +6 -2
  99. package/dist/device/iosensor.js.map +1 -1
  100. package/dist/device/lightstrip.d.ts.map +1 -1
  101. package/dist/device/lightstrip.js +16 -6
  102. package/dist/device/lightstrip.js.map +1 -1
  103. package/dist/device/lock.d.ts.map +1 -1
  104. package/dist/device/lock.js +12 -4
  105. package/dist/device/lock.js.map +1 -1
  106. package/dist/device/meter.d.ts.map +1 -1
  107. package/dist/device/meter.js +6 -2
  108. package/dist/device/meter.js.map +1 -1
  109. package/dist/device/meterplus.d.ts.map +1 -1
  110. package/dist/device/meterplus.js +6 -2
  111. package/dist/device/meterplus.js.map +1 -1
  112. package/dist/device/meterpro.d.ts.map +1 -1
  113. package/dist/device/meterpro.js +7 -4
  114. package/dist/device/meterpro.js.map +1 -1
  115. package/dist/device/motion.d.ts.map +1 -1
  116. package/dist/device/motion.js +6 -2
  117. package/dist/device/motion.js.map +1 -1
  118. package/dist/device/occupancy.d.ts +42 -0
  119. package/dist/device/occupancy.d.ts.map +1 -0
  120. package/dist/device/occupancy.js +349 -0
  121. package/dist/device/occupancy.js.map +1 -0
  122. package/dist/device/plug.d.ts.map +1 -1
  123. package/dist/device/plug.js +12 -4
  124. package/dist/device/plug.js.map +1 -1
  125. package/dist/device/relayswitch.d.ts.map +1 -1
  126. package/dist/device/relayswitch.js +12 -4
  127. package/dist/device/relayswitch.js.map +1 -1
  128. package/dist/device/robotvacuumcleaner.d.ts.map +1 -1
  129. package/dist/device/robotvacuumcleaner.js +14 -5
  130. package/dist/device/robotvacuumcleaner.js.map +1 -1
  131. package/dist/device/waterdetector.d.ts.map +1 -1
  132. package/dist/device/waterdetector.js +6 -2
  133. package/dist/device/waterdetector.js.map +1 -1
  134. package/dist/homebridge-ui/public/index.html +1 -1
  135. package/dist/irdevice/airconditioner.d.ts.map +1 -1
  136. package/dist/irdevice/airconditioner.js +2 -1
  137. package/dist/irdevice/airconditioner.js.map +1 -1
  138. package/dist/irdevice/airpurifier.d.ts +1 -1
  139. package/dist/irdevice/airpurifier.d.ts.map +1 -1
  140. package/dist/irdevice/airpurifier.js +6 -5
  141. package/dist/irdevice/airpurifier.js.map +1 -1
  142. package/dist/irdevice/camera.d.ts.map +1 -1
  143. package/dist/irdevice/camera.js +2 -1
  144. package/dist/irdevice/camera.js.map +1 -1
  145. package/dist/irdevice/fan.d.ts.map +1 -1
  146. package/dist/irdevice/fan.js +2 -1
  147. package/dist/irdevice/fan.js.map +1 -1
  148. package/dist/irdevice/irdevice.d.ts +2 -6
  149. package/dist/irdevice/irdevice.d.ts.map +1 -1
  150. package/dist/irdevice/irdevice.js.map +1 -1
  151. package/dist/irdevice/light.d.ts.map +1 -1
  152. package/dist/irdevice/light.js +2 -1
  153. package/dist/irdevice/light.js.map +1 -1
  154. package/dist/irdevice/other.d.ts.map +1 -1
  155. package/dist/irdevice/other.js +2 -1
  156. package/dist/irdevice/other.js.map +1 -1
  157. package/dist/irdevice/tv.d.ts.map +1 -1
  158. package/dist/irdevice/tv.js +2 -1
  159. package/dist/irdevice/tv.js.map +1 -1
  160. package/dist/irdevice/vacuumcleaner.d.ts.map +1 -1
  161. package/dist/irdevice/vacuumcleaner.js +2 -1
  162. package/dist/irdevice/vacuumcleaner.js.map +1 -1
  163. package/dist/irdevice/waterheater.d.ts.map +1 -1
  164. package/dist/irdevice/waterheater.js +2 -1
  165. package/dist/irdevice/waterheater.js.map +1 -1
  166. package/dist/platform.d.ts +2 -2
  167. package/dist/platform.d.ts.map +1 -1
  168. package/dist/platform.js +77 -78
  169. package/dist/platform.js.map +1 -1
  170. package/dist/settings.d.ts +6 -0
  171. package/dist/settings.d.ts.map +1 -1
  172. package/dist/settings.js +1 -0
  173. package/dist/settings.js.map +1 -1
  174. package/docs/index.html +20 -11
  175. package/docs/variables/default.html +1 -1
  176. package/eslint.config.js +0 -1
  177. package/package.json +9 -10
  178. package/src/device/blindtilt.ts +10 -4
  179. package/src/device/bot.ts +10 -4
  180. package/src/device/ceilinglight.ts +16 -7
  181. package/src/device/colorbulb.ts +16 -7
  182. package/src/device/contact.ts +5 -2
  183. package/src/device/curtain.ts +12 -6
  184. package/src/device/device.ts +14 -8
  185. package/src/device/fan.ts +14 -6
  186. package/src/device/hub.ts +10 -6
  187. package/src/device/humidifier.ts +14 -6
  188. package/src/device/iosensor.ts +5 -2
  189. package/src/device/lightstrip.ts +14 -6
  190. package/src/device/lock.ts +10 -4
  191. package/src/device/meter.ts +6 -3
  192. package/src/device/meterplus.ts +5 -2
  193. package/src/device/meterpro.ts +7 -5
  194. package/src/device/motion.ts +5 -2
  195. package/src/device/occupancy.ts +393 -0
  196. package/src/device/plug.ts +10 -4
  197. package/src/device/relayswitch.ts +10 -4
  198. package/src/device/robotvacuumcleaner.ts +12 -5
  199. package/src/device/waterdetector.ts +5 -2
  200. package/src/homebridge-ui/public/index.html +1 -1
  201. package/src/irdevice/airconditioner.ts +2 -1
  202. package/src/irdevice/airpurifier.ts +6 -5
  203. package/src/irdevice/camera.ts +2 -1
  204. package/src/irdevice/fan.ts +2 -1
  205. package/src/irdevice/irdevice.ts +2 -2
  206. package/src/irdevice/light.ts +2 -1
  207. package/src/irdevice/other.ts +2 -1
  208. package/src/irdevice/tv.ts +2 -1
  209. package/src/irdevice/vacuumcleaner.ts +2 -1
  210. package/src/irdevice/waterheater.ts +2 -1
  211. package/src/platform.ts +80 -88
  212. package/src/settings.ts +7 -0
  213. package/.github/npm-version-script-esm.js +0 -97
  214. package/.github/workflows/build.yml +0 -18
  215. package/.github/workflows/changerelease.yml +0 -11
  216. package/.github/workflows/labeler.yml +0 -16
  217. package/.github/workflows/release-drafter.yml +0 -14
  218. package/dist/device/airpurifier.d.ts +0 -54
  219. package/dist/device/airpurifier.d.ts.map +0 -1
  220. package/dist/device/airpurifier.js +0 -527
  221. package/dist/device/airpurifier.js.map +0 -1
  222. package/src/device/airpurifier.ts +0 -563
@@ -346,7 +346,8 @@ export class TV extends irdeviceBase {
346
346
  if (this.device.connectionType === 'OpenAPI') {
347
347
  this.infoLog(`Sending request to SwitchBot API, body: ${JSON.stringify(bodyChange)}`)
348
348
  try {
349
- const deviceStatus = await this.pushChangeRequest(bodyChange)
349
+ const response = await this.pushChangeRequest(bodyChange)
350
+ const deviceStatus: any = response.body
350
351
  await this.pushStatusCodes(deviceStatus)
351
352
  if (await this.successfulStatusCodes(deviceStatus)) {
352
353
  await this.successfulPushChange(deviceStatus, bodyChange)
@@ -97,7 +97,8 @@ export class VacuumCleaner extends irdeviceBase {
97
97
  if (this.device.connectionType === 'OpenAPI') {
98
98
  this.infoLog(`Sending request to SwitchBot API, body: ${JSON.stringify(bodyChange)}`)
99
99
  try {
100
- const deviceStatus = await this.pushChangeRequest(bodyChange)
100
+ const response = await this.pushChangeRequest(bodyChange)
101
+ const deviceStatus: any = response.body
101
102
  await this.pushStatusCodes(deviceStatus)
102
103
  if (await this.successfulStatusCodes(deviceStatus)) {
103
104
  await this.successfulPushChange(deviceStatus, bodyChange)
@@ -98,7 +98,8 @@ export class WaterHeater extends irdeviceBase {
98
98
  if (this.device.connectionType === 'OpenAPI') {
99
99
  this.infoLog(`Sending request to SwitchBot API, body: ${JSON.stringify(bodyChange)}`)
100
100
  try {
101
- const deviceStatus = await this.pushChangeRequest(bodyChange)
101
+ const response = await this.pushChangeRequest(bodyChange)
102
+ const deviceStatus: any = response.body
102
103
  await this.pushStatusCodes(deviceStatus)
103
104
  if (await this.successfulStatusCodes(deviceStatus)) {
104
105
  await this.successfulPushChange(deviceStatus, bodyChange)
package/src/platform.ts CHANGED
@@ -24,7 +24,6 @@ import { EveHomeKitTypes } from 'homebridge-lib/EveHomeKitTypes'
24
24
  import { LogLevel, SwitchBotBLE, SwitchBotModel, SwitchBotOpenAPI } from 'node-switchbot'
25
25
  import { queueScheduler } from 'rxjs'
26
26
 
27
- import { AirPurifier } from './device/airpurifier.js'
28
27
  import { BlindTilt } from './device/blindtilt.js'
29
28
  import { Bot } from './device/bot.js'
30
29
  import { CeilingLight } from './device/ceilinglight.js'
@@ -41,12 +40,13 @@ import { Meter } from './device/meter.js'
41
40
  import { MeterPlus } from './device/meterplus.js'
42
41
  import { MeterPro } from './device/meterpro.js'
43
42
  import { Motion } from './device/motion.js'
43
+ import { Occupancy } from './device/occupancy.js'
44
44
  import { Plug } from './device/plug.js'
45
45
  import { RelaySwitch } from './device/relayswitch.js'
46
46
  import { RobotVacuumCleaner } from './device/robotvacuumcleaner.js'
47
47
  import { WaterDetector } from './device/waterdetector.js'
48
48
  import { AirConditioner } from './irdevice/airconditioner.js'
49
- import { AirPurifierIR } from './irdevice/airpurifier.js'
49
+ import { AirPurifier } from './irdevice/airpurifier.js'
50
50
  import { Camera } from './irdevice/camera.js'
51
51
  import { IRFan } from './irdevice/fan.js'
52
52
  import { Light } from './irdevice/light.js'
@@ -233,7 +233,7 @@ export class SwitchBotPlatform implements DynamicPlatformPlugin {
233
233
  const context = JSON.parse(message.toString())
234
234
  this.webhookEventHandler[context.deviceMac]?.(context)
235
235
  } catch (e: any) {
236
- this.errorLog(`Failed to handle webhook event. Error:${e.message ?? e}`)
236
+ this.errorLog(`Failed to handle webhook event. Error: ${e.message ?? e}`)
237
237
  }
238
238
  })
239
239
  }
@@ -260,14 +260,14 @@ export class SwitchBotPlatform implements DynamicPlatformPlugin {
260
260
  this.webhookEventHandler[body.context.deviceMac]?.(body.context)
261
261
  })
262
262
  } catch (e: any) {
263
- this.errorLog(`Failed to setup webhook. Error:${e.message ?? e}`)
263
+ this.errorLog(`Failed to setup webhook. Error: ${e.message ?? e}`)
264
264
  }
265
265
 
266
266
  this.api.on('shutdown', async () => {
267
267
  try {
268
268
  this.switchBotAPI.deleteWebhook(url)
269
269
  } catch (e: any) {
270
- this.errorLog(`Failed to delete webhook. Error:${e.message ?? e}`)
270
+ this.errorLog(`Failed to delete webhook. Error: ${e.message ?? e}`)
271
271
  }
272
272
  })
273
273
  }
@@ -318,14 +318,14 @@ export class SwitchBotPlatform implements DynamicPlatformPlugin {
318
318
  try {
319
319
  await this.switchBotBLE.startScan()
320
320
  } catch (e: any) {
321
- this.errorLog(`Failed to start BLE scanning. Error:${e.message ?? e}`)
321
+ this.errorLog(`Failed to start BLE scanning. Error: ${e.message ?? e}`)
322
322
  }
323
323
  // Set an event handler to monitor advertisement packets
324
324
  this.switchBotBLE.onadvertisement = async (ad: any) => {
325
325
  try {
326
326
  this.bleEventHandler[ad.address]?.(ad.serviceData)
327
327
  } catch (e: any) {
328
- this.errorLog(`Failed to handle BLE event. Error:${e.message ?? e}`)
328
+ this.errorLog(`Failed to handle BLE event. Error: ${e.message ?? e}`)
329
329
  }
330
330
  }
331
331
  })()
@@ -335,7 +335,7 @@ export class SwitchBotPlatform implements DynamicPlatformPlugin {
335
335
  // this.switchBotBLE.stopScan()
336
336
  this.infoLog('Stopped BLE scanning to close listening.')
337
337
  } catch (e: any) {
338
- this.errorLog(`Failed to stop Platform BLE scanning. Error:${e.message ?? e}`)
338
+ this.errorLog(`Failed to stop Platform BLE scanning. Error: ${e.message ?? e}`)
339
339
  }
340
340
  })
341
341
  }
@@ -583,17 +583,19 @@ export class SwitchBotPlatform implements DynamicPlatformPlugin {
583
583
  'Humidifier': this.createHumidifier.bind(this),
584
584
  'Humidifier2': this.createHumidifier.bind(this),
585
585
  'Hub 2': this.createHub2.bind(this),
586
+ 'Hub 3': this.createHub2.bind(this),
586
587
  'Bot': this.createBot.bind(this),
587
588
  'Relay Switch 1': this.createRelaySwitch.bind(this),
588
589
  'Relay Switch 1PM': this.createRelaySwitch.bind(this),
589
590
  'Meter': this.createMeter.bind(this),
590
591
  'MeterPlus': this.createMeterPlus.bind(this),
591
592
  'Meter Plus (JP)': this.createMeterPlus.bind(this),
592
- 'MeterPro': this.createMeterPro.bind(this),
593
+ 'Meter Pro': this.createMeterPro.bind(this),
593
594
  'MeterPro(CO2)': this.createMeterPro.bind(this),
594
595
  'WoIOSensor': this.createIOSensor.bind(this),
595
596
  'Water Detector': this.createWaterDetector.bind(this),
596
597
  'Motion Sensor': this.createMotion.bind(this),
598
+ 'Presence Sensor': this.createOccupancy.bind(this),
597
599
  'Contact Sensor': this.createContact.bind(this),
598
600
  'Curtain': this.createCurtain.bind(this),
599
601
  'Curtain3': this.createCurtain.bind(this),
@@ -617,10 +619,6 @@ export class SwitchBotPlatform implements DynamicPlatformPlugin {
617
619
  'Ceiling Light Pro': this.createCeilingLight.bind(this),
618
620
  'Strip Light': this.createStripLight.bind(this),
619
621
  'Battery Circulator Fan': this.createFan.bind(this),
620
- 'Air Purifier PM2.5': this.createAirPurifier.bind(this),
621
- 'Air Purifier Table PM2.5': this.createAirPurifier.bind(this),
622
- 'Air Purifier VOC': this.createAirPurifier.bind(this),
623
- 'Air Purifier Table VOC': this.createAirPurifier.bind(this),
624
622
  }
625
623
 
626
624
  if (deviceTypeHandlers[device.deviceType!]) {
@@ -654,8 +652,8 @@ export class SwitchBotPlatform implements DynamicPlatformPlugin {
654
652
  'DIY Air Conditioner': this.createAirConditioner.bind(this),
655
653
  'Light': this.createLight.bind(this),
656
654
  'DIY Light': this.createLight.bind(this),
657
- 'Air Purifier': this.createAirPurifierIR.bind(this),
658
- 'DIY Air Purifier': this.createAirPurifierIR.bind(this),
655
+ 'Air Purifier': this.createAirPurifier.bind(this),
656
+ 'DIY Air Purifier': this.createAirPurifier.bind(this),
659
657
  'Water Heater': this.createWaterHeater.bind(this),
660
658
  'DIY Water Heater': this.createWaterHeater.bind(this),
661
659
  'Vacuum Cleaner': this.createVacuumCleaner.bind(this),
@@ -1300,6 +1298,68 @@ export class SwitchBotPlatform implements DynamicPlatformPlugin {
1300
1298
  }
1301
1299
  }
1302
1300
 
1301
+ private async createOccupancy(device: device & devicesConfig) {
1302
+ const uuid = this.api.hap.uuid.generate(`${device.deviceId}-${device.deviceType}`)
1303
+
1304
+ // see if an accessory with the same uuid has already been registered and restored from
1305
+ // the cached devices we stored in the `configureAccessory` method above
1306
+ const existingAccessory = this.accessories.find(accessory => accessory.UUID === uuid)
1307
+
1308
+ if (existingAccessory) {
1309
+ // the accessory already exists
1310
+ if (await this.registerDevice(device)) {
1311
+ // if you need to update the accessory.context then you should run `api.updatePlatformAccessories`. eg.:
1312
+ existingAccessory.context.device = device
1313
+ existingAccessory.context.deviceId = device.deviceId
1314
+ existingAccessory.context.deviceType = device.deviceType
1315
+ existingAccessory.context.model = SwitchBotModel.PresenceSensor
1316
+ existingAccessory.displayName = device.configDeviceName
1317
+ ? await this.validateAndCleanDisplayName(device.configDeviceName, 'configDeviceName', device.configDeviceName)
1318
+ : await this.validateAndCleanDisplayName(device.deviceName, 'deviceName', device.deviceName)
1319
+ existingAccessory.context.connectionType = await this.connectionType(device)
1320
+ existingAccessory.context.version = device.firmware ?? device.version ?? this.version ?? '0.0.0'
1321
+ this.infoLog(`Restoring existing accessory from cache: ${existingAccessory.displayName} deviceId: ${device.deviceId}`)
1322
+ this.api.updatePlatformAccessories([existingAccessory])
1323
+ // create the accessory handler for the restored accessory
1324
+ // this is imported from `platformAccessory.ts`
1325
+ new Occupancy(this, existingAccessory, device)
1326
+ this.debugLog(`${device.deviceType} uuid: ${device.deviceId}-${device.deviceType}, (${existingAccessory.UUID})`)
1327
+ } else {
1328
+ this.unregisterPlatformAccessories(existingAccessory)
1329
+ }
1330
+ } else if (await this.registerDevice(device)) {
1331
+ // create a new accessory
1332
+ const accessory = new this.api.platformAccessory(device.configDeviceName
1333
+ ? await this.validateAndCleanDisplayName(device.configDeviceName, 'configDeviceName', device.configDeviceName)
1334
+ : await this.validateAndCleanDisplayName(device.deviceName, 'deviceName', device.deviceName), uuid)
1335
+
1336
+ // store a copy of the device object in the `accessory.context`
1337
+ // the `context` property can be used to store any data about the accessory you may need
1338
+ accessory.context.device = device
1339
+ accessory.context.deviceId = device.deviceId
1340
+ accessory.context.deviceType = device.deviceType
1341
+ accessory.context.model = SwitchBotModel.PresenceSensor
1342
+ accessory.displayName = device.configDeviceName
1343
+ ? await this.validateAndCleanDisplayName(device.configDeviceName, 'configDeviceName', device.configDeviceName)
1344
+ : await this.validateAndCleanDisplayName(device.deviceName, 'deviceName', device.deviceName)
1345
+ accessory.context.connectionType = await this.connectionType(device)
1346
+ accessory.context.connectionType = await this.connectionType(device)
1347
+ accessory.context.version = device.firmware ?? device.version ?? this.version ?? '0.0.0'
1348
+ const newOrExternal = !device.external ? 'Adding new' : 'Loading external'
1349
+ this.infoLog(`${newOrExternal} accessory: ${accessory.displayName} deviceId: ${device.deviceId}`)
1350
+ // create the accessory handler for the newly create accessory
1351
+ // this is imported from `platformAccessory.ts`
1352
+ new Occupancy(this, accessory, device)
1353
+ this.debugLog(`${device.deviceType} uuid: ${device.deviceId}-${device.deviceType}, (${accessory.UUID})`)
1354
+
1355
+ // publish device externally or link the accessory to your platform
1356
+ this.externalOrPlatform(device, accessory)
1357
+ this.accessories.push(accessory)
1358
+ } else {
1359
+ this.debugLog(`Device not registered: ${device.deviceName} ${device.deviceType} deviceId: ${device.deviceId}`)
1360
+ }
1361
+ }
1362
+
1303
1363
  private async createContact(device: device & devicesConfig) {
1304
1364
  const uuid = this.api.hap.uuid.generate(`${device.deviceId}-${device.deviceType}`)
1305
1365
 
@@ -1896,68 +1956,6 @@ export class SwitchBotPlatform implements DynamicPlatformPlugin {
1896
1956
  }
1897
1957
  }
1898
1958
 
1899
- private async createAirPurifier(device: device & devicesConfig) {
1900
- const uuid = this.api.hap.uuid.generate(`${device.deviceId}-${device.deviceType}`)
1901
-
1902
- // see if an accessory with the same uuid has already been registered and restored from
1903
- // the cached devices we stored in the `configureAccessory` method above
1904
- const existingAccessory = this.accessories.find(accessory => accessory.UUID === uuid)
1905
-
1906
- if (existingAccessory) {
1907
- // the accessory already exists
1908
- if (await this.registerDevice(device)) {
1909
- // if you need to update the accessory.context then you should run `api.updatePlatformAccessories`. eg.:
1910
- existingAccessory.context.device = device
1911
- existingAccessory.context.deviceId = device.deviceId
1912
- existingAccessory.context.deviceType = device.deviceType
1913
- existingAccessory.context.model = SwitchBotModel.BatteryCirculatorFan
1914
- existingAccessory.displayName = device.configDeviceName
1915
- ? await this.validateAndCleanDisplayName(device.configDeviceName, 'configDeviceName', device.configDeviceName)
1916
- : await this.validateAndCleanDisplayName(device.deviceName, 'deviceName', device.deviceName)
1917
- existingAccessory.context.connectionType = await this.connectionType(device)
1918
- existingAccessory.context.version = device.firmware ?? device.version ?? this.version ?? '0.0.0'
1919
- this.infoLog(`Restoring existing accessory from cache: ${existingAccessory.displayName} deviceId: ${device.deviceId}`)
1920
- this.api.updatePlatformAccessories([existingAccessory])
1921
- // create the accessory handler for the restored accessory
1922
- // this is imported from `platformAccessory.ts`
1923
- new AirPurifier(this, existingAccessory, device)
1924
- this.debugLog(`${device.deviceType} uuid: ${device.deviceId}-${device.deviceType}, (${existingAccessory.UUID})`)
1925
- } else {
1926
- this.unregisterPlatformAccessories(existingAccessory)
1927
- }
1928
- } else if (await this.registerDevice(device)) {
1929
- // create a new accessory
1930
- const accessory = new this.api.platformAccessory(device.configDeviceName
1931
- ? await this.validateAndCleanDisplayName(device.configDeviceName, 'configDeviceName', device.configDeviceName)
1932
- : await this.validateAndCleanDisplayName(device.deviceName, 'deviceName', device.deviceName), uuid)
1933
-
1934
- // store a copy of the device object in the `accessory.context`
1935
- // the `context` property can be used to store any data about the accessory you may need
1936
- accessory.context.device = device
1937
- accessory.context.deviceId = device.deviceId
1938
- accessory.context.deviceType = device.deviceType
1939
- accessory.context.model = SwitchBotModel.BatteryCirculatorFan
1940
- accessory.displayName = device.configDeviceName
1941
- ? await this.validateAndCleanDisplayName(device.configDeviceName, 'configDeviceName', device.configDeviceName)
1942
- : await this.validateAndCleanDisplayName(device.deviceName, 'deviceName', device.deviceName)
1943
- accessory.context.connectionType = await this.connectionType(device)
1944
- accessory.context.connectionType = await this.connectionType(device)
1945
- accessory.context.version = device.firmware ?? device.version ?? this.version ?? '0.0.0'
1946
- const newOrExternal = !device.external ? 'Adding new' : 'Loading external'
1947
- this.infoLog(`${newOrExternal} accessory: ${accessory.displayName} deviceId: ${device.deviceId}`)
1948
- // create the accessory handler for the newly create accessory
1949
- // this is imported from `platformAccessory.ts`
1950
- new AirPurifier(this, accessory, device)
1951
- this.debugLog(`${device.deviceType} uuid: ${device.deviceId}-${device.deviceType}, (${accessory.UUID})`)
1952
-
1953
- // publish device externally or link the accessory to your platform
1954
- this.externalOrPlatform(device, accessory)
1955
- this.accessories.push(accessory)
1956
- } else {
1957
- this.debugLog(`Device not registered: ${device.deviceName} ${device.deviceType} deviceId: ${device.deviceId}`)
1958
- }
1959
- }
1960
-
1961
1959
  private async createRobotVacuumCleaner(device: device & devicesConfig) {
1962
1960
  const uuid = this.api.hap.uuid.generate(`${device.deviceId}-${device.deviceType}`)
1963
1961
 
@@ -2274,7 +2272,7 @@ export class SwitchBotPlatform implements DynamicPlatformPlugin {
2274
2272
  }
2275
2273
  }
2276
2274
 
2277
- private async createAirPurifierIR(device: irdevice & irDevicesConfig) {
2275
+ private async createAirPurifier(device: irdevice & irDevicesConfig) {
2278
2276
  const uuid = this.api.hap.uuid.generate(`${device.deviceId}-${device.remoteType}`)
2279
2277
 
2280
2278
  // see if an accessory with the same uuid has already been registered and restored from
@@ -2297,7 +2295,7 @@ export class SwitchBotPlatform implements DynamicPlatformPlugin {
2297
2295
  this.api.updatePlatformAccessories([existingAccessory])
2298
2296
  // create the accessory handler for the restored accessory
2299
2297
  // this is imported from `platformAccessory.ts`
2300
- new AirPurifierIR(this, existingAccessory, device)
2298
+ new AirPurifier(this, existingAccessory, device)
2301
2299
  this.debugLog(`${device.remoteType} uuid: ${device.deviceId}-${device.remoteType}, (${existingAccessory.UUID})`)
2302
2300
  } else {
2303
2301
  this.unregisterPlatformAccessories(existingAccessory)
@@ -2323,7 +2321,7 @@ export class SwitchBotPlatform implements DynamicPlatformPlugin {
2323
2321
  this.infoLog(`${newOrExternal} accessory: ${accessory.displayName} deviceId: ${device.deviceId}`)
2324
2322
  // create the accessory handler for the newly create accessory
2325
2323
  // this is imported from `platformAccessory.ts`
2326
- new AirPurifierIR(this, accessory, device)
2324
+ new AirPurifier(this, accessory, device)
2327
2325
  this.debugLog(`${device.remoteType} uuid: ${device.deviceId}-${device.remoteType}, (${accessory.UUID})`)
2328
2326
 
2329
2327
  // publish device externally or link the accessory to your platform
@@ -2752,6 +2750,7 @@ export class SwitchBotPlatform implements DynamicPlatformPlugin {
2752
2750
  hubDeviceId: '',
2753
2751
  version: 0,
2754
2752
  deviceName: '',
2753
+ enableCloudService: false,
2755
2754
  }, statusCode: 500 }
2756
2755
  }
2757
2756
 
@@ -2761,14 +2760,7 @@ export class SwitchBotPlatform implements DynamicPlatformPlugin {
2761
2760
  const delayBetweenRetries = deviceDelayBetweenRetries ?? 1000
2762
2761
  while (retryCount < maxRetries) {
2763
2762
  try {
2764
- const { response, statusCode } = await this.switchBotAPI.controlDevice(
2765
- device.deviceId,
2766
- bodyChange.command,
2767
- bodyChange.parameter,
2768
- bodyChange.commandType as import('node-switchbot').commandType,
2769
- this.config.credentials?.token,
2770
- this.config.credentials?.secret,
2771
- )
2763
+ const { response, statusCode } = await this.switchBotAPI.controlDevice(device.deviceId, bodyChange.command, bodyChange.parameter, bodyChange.commandType as any, this.config.credentials?.token, this.config.credentials?.secret)
2772
2764
  this.debugLog(`response: ${JSON.stringify(response)}`)
2773
2765
  return { response, statusCode }
2774
2766
  } catch (error: any) {
package/src/settings.ts CHANGED
@@ -182,6 +182,13 @@ export interface motionConfig extends BaseDeviceConfig {
182
182
  set_maxLux?: number
183
183
  };
184
184
 
185
+ export interface occupancyConfig extends BaseDeviceConfig {
186
+ configDeviceType: 'Occupancy Sensor'
187
+ hide_lightsensor?: boolean
188
+ set_minLux?: number
189
+ set_maxLux?: number
190
+ };
191
+
185
192
  export interface waterDetectorConfig extends BaseDeviceConfig {
186
193
  configDeviceType: 'Water Detector'
187
194
  hide_leak?: boolean
@@ -1,97 +0,0 @@
1
- #!/bin/env node
2
-
3
- /**
4
- * This scripts queries the npm registry to pull out the latest version for a given tag.
5
- */
6
-
7
- import assert from 'node:assert'
8
- import child_process from 'node:child_process'
9
- import fs from 'node:fs'
10
- import process from 'node:process'
11
-
12
- const BRANCH_VERSION_PATTERN = /^([A-Z]+)-(\d+\.\d+\.\d+)$/i
13
-
14
- // Load the contents of the package.json file
15
- const packageJSON = JSON.parse(fs.readFileSync('package.json', 'utf8'))
16
-
17
- const refArgument = process.argv[2]
18
- const tagArgument = process.argv[3] || 'latest'
19
-
20
- if (!refArgument) {
21
- console.error('ref argument is missing')
22
- console.error('Usage: npm-version-script-esm.js <ref> [tag]')
23
- process.exit(1)
24
- }
25
-
26
- /**
27
- * Queries the NPM registry for the latest version for the provided base version and tag.
28
- * If the tag is latest, then the base version is returned if it exists. For other tags, the latest
29
- * version found for that base version and tag is returned.
30
- * @param baseVersion The base version to query for, e.g. 2.0.0
31
- * @param tag The tag to query for, e.g. beta or latest
32
- * @returns {string} Returns the version, or '' if not found
33
- */
34
- function getTagVersionFromNpm(baseVersion, tag) {
35
- try {
36
- return JSON.parse(child_process.execSync(`npm info ${packageJSON.name} versions --json`).toString('utf8').trim())
37
- .filter(v => tag === 'latest' ? v === baseVersion : v.startsWith(`${baseVersion}-${tag}.`)) // find all published versions for this base version and tag
38
- .reduce((_, current) => current, '') // choose the last as they're sorted in ascending order, or '' if there are none
39
- } catch (e) {
40
- console.error(`Failed to query the npm registry for the latest version for tag: ${tag}`, e)
41
- // throw e;
42
- return ''
43
- }
44
- }
45
-
46
- function desiredTargetVersion(ref) {
47
- // ref is a GitHub action ref string
48
- if (ref.startsWith('refs/pull/')) {
49
- throw new Error('The version script was executed inside a PR!')
50
- }
51
-
52
- assert(ref.startsWith('refs/heads/'))
53
- const branchName = ref.slice('refs/heads/'.length)
54
-
55
- const results = branchName.match(BRANCH_VERSION_PATTERN)
56
- if (results !== null) {
57
- if (results[1] !== tagArgument) {
58
- console.warn(`The base branch name (${results[1]}) differs from the tag name ${tagArgument}`)
59
- }
60
-
61
- return results[2]
62
- }
63
-
64
- throw new Error(`Malformed branch name for ref: ${ref}. Can't derive the base version. Use a branch name like: beta-x.x.x or alpha-x.x.x`)
65
- }
66
-
67
- // derive the base version from the branch ref
68
- const baseVersion = desiredTargetVersion(refArgument)
69
-
70
- // query the npm registry for the latest version of the provided tag name
71
- const latestReleasedVersion = getTagVersionFromNpm(baseVersion, tagArgument) // e.g. 0.7.0-beta.12
72
-
73
- let publishTag
74
-
75
- if (latestReleasedVersion) {
76
- console.warn(`Latest published version for ${baseVersion} with tag ${tagArgument} is ${latestReleasedVersion}`)
77
- publishTag = latestReleasedVersion // set this released beta or alpha to be incremented
78
- } else {
79
- console.warn(`No published versions for ${baseVersion} with tag ${tagArgument}`)
80
- publishTag = baseVersion // start off with a new beta or alpha version
81
- }
82
-
83
- if (packageJSON.version !== publishTag) {
84
- // report the change for CI
85
- console.warn(`Changing version in package.json from ${packageJSON.version} to ${publishTag}`)
86
-
87
- // save the package.json
88
- packageJSON.version = publishTag
89
- fs.writeFileSync('package.json', JSON.stringify(packageJSON, null, 2))
90
-
91
- // perform the same change to the package-lock.json
92
- const packageLockJSON = JSON.parse(fs.readFileSync('package-lock.json', 'utf8'))
93
- packageLockJSON.version = publishTag
94
- fs.writeFileSync('package-lock.json', JSON.stringify(packageLockJSON, null, 2))
95
- } else {
96
- console.warn(`Leaving version in package.json at ${packageJSON.version}`)
97
- }
@@ -1,18 +0,0 @@
1
- name: Node Build
2
-
3
- on:
4
- push:
5
- branches: [latest]
6
- pull_request:
7
- workflow_dispatch:
8
-
9
- jobs:
10
- build_and_test:
11
- uses: OpenWonderLabs/.github/.github/workflows/nodejs-build-and-test.yml@latest
12
- with:
13
- enable_coverage: false
14
- secrets:
15
- token: ${{ secrets.GITHUB_TOKEN }}
16
- lint:
17
- needs: build_and_test
18
- uses: OpenWonderLabs/.github/.github/workflows/eslint.yml@latest
@@ -1,11 +0,0 @@
1
- name: Changelog to Release
2
-
3
- on:
4
- release:
5
- types: [published]
6
-
7
- jobs:
8
- changerelease:
9
- uses: OpenWonderLabs/.github/.github/workflows/changerelease.yml@latest
10
- secrets:
11
- token: ${{ secrets.GITHUB_TOKEN }}
@@ -1,16 +0,0 @@
1
- # This workflow will triage pull requests and apply a label based on the
2
- # paths that are modified in the pull request.
3
- #
4
- # To use this workflow, you will need to set up a .github/labeler.yml
5
- # file with configuration. For more information, see:
6
- # https://github.com/actions/labeler/blob/main/README.md
7
-
8
- name: Labeler
9
-
10
- on: pull_request_target
11
-
12
- jobs:
13
- labeler:
14
- uses: OpenWonderLabs/.github/.github/workflows/labeler.yml@latest
15
- secrets:
16
- token: ${{ secrets.GITHUB_TOKEN }}
@@ -1,14 +0,0 @@
1
- name: Release Drafter
2
-
3
- on:
4
- push:
5
- branches: [latest]
6
- pull_request: # required for autolabeler
7
- types: [opened, reopened, synchronize]
8
- workflow_dispatch:
9
-
10
- jobs:
11
- release-drafter:
12
- uses: OpenWonderLabs/.github/.github/workflows/release-drafter.yml@latest
13
- secrets:
14
- token: ${{ secrets.GITHUB_TOKEN }}
@@ -1,54 +0,0 @@
1
- import type { CharacteristicValue, PlatformAccessory } from 'homebridge';
2
- import type { airPurifierServiceData, airPurifierStatus, airPurifierTableServiceData, airPurifierTableStatus, airPurifierTableWebhookContext, airPurifierWebhookContext, device, SwitchBotBLE } from 'node-switchbot';
3
- import type { SwitchBotPlatform } from '../platform.js';
4
- import type { devicesConfig } from '../settings.js';
5
- import { Subject } from 'rxjs';
6
- import { deviceBase } from './device.js';
7
- export declare class AirPurifier extends deviceBase {
8
- readonly platform: SwitchBotPlatform;
9
- private AirPurifier;
10
- deviceStatus: airPurifierStatus | airPurifierTableStatus;
11
- webhookContext: airPurifierWebhookContext | airPurifierTableWebhookContext;
12
- serviceData: airPurifierServiceData | airPurifierTableServiceData;
13
- airPurifierUpdateInProgress: boolean;
14
- doAirPurifierUpdate: Subject<void>;
15
- constructor(platform: SwitchBotPlatform, accessory: PlatformAccessory, device: device & devicesConfig);
16
- BLEparseStatus(): Promise<void>;
17
- openAPIparseStatus(): Promise<void>;
18
- parseStatusWebhook(): Promise<void>;
19
- /**
20
- * Asks the SwitchBot API for the latest device information
21
- */
22
- refreshStatus(): Promise<void>;
23
- BLERefreshStatus(): Promise<void>;
24
- registerPlatformBLE(): Promise<void>;
25
- openAPIRefreshStatus(): Promise<void>;
26
- registerWebhook(): Promise<void>;
27
- /**
28
- * Pushes the requested changes to the SwitchBot API
29
- * commandType command parameter Description
30
- * "command" "turnOff" "default" = set to OFF state
31
- * "command" "turnOn" "default" = set to ON state
32
- * "command" "setNightLightMode" "off, 1, or 2" = off, turn off nightlight, (1, bright) (2, dim)
33
- * "command" "setWindMode" "direct, natural, sleep, or baby" = Set fan mode
34
- * "command" "setWindSpeed" "{1-100} e.g. 10" = Set fan speed 1~100
35
- */
36
- pushChanges(): Promise<void>;
37
- BLEpushChanges(): Promise<void>;
38
- openAPIpushChanges(): Promise<void>;
39
- pushRotationSpeedChanges(): Promise<void>;
40
- /**
41
- * Handle requests to set the value of the "On" characteristic
42
- */
43
- ActiveSet(value: CharacteristicValue): Promise<void>;
44
- /**
45
- * Handle requests to set the value of the "On" characteristic
46
- */
47
- RotationSpeedSet(value: CharacteristicValue): Promise<void>;
48
- updateHomeKitCharacteristics(): Promise<void>;
49
- BLEPushConnection(): Promise<void>;
50
- BLERefreshConnection(switchbot: SwitchBotBLE): Promise<void>;
51
- offlineOff(): Promise<void>;
52
- apiError(e: any): Promise<void>;
53
- }
54
- //# sourceMappingURL=airpurifier.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"airpurifier.d.ts","sourceRoot":"","sources":["../../src/device/airpurifier.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,mBAAmB,EAAE,iBAAiB,EAAW,MAAM,YAAY,CAAA;AACjF,OAAO,KAAK,EAAE,sBAAsB,EAAE,iBAAiB,EAAE,2BAA2B,EAAE,sBAAsB,EAAE,8BAA8B,EAAE,yBAAyB,EAAc,MAAM,EAAE,YAAY,EAAmB,MAAM,gBAAgB,CAAA;AAElP,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAA;AACvD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAA;AAOnD,OAAO,EAAqC,OAAO,EAAa,MAAM,MAAM,CAAA;AAG5E,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAA;AAExC,qBAAa,WAAY,SAAQ,UAAU;IA0BvC,QAAQ,CAAC,QAAQ,EAAE,iBAAiB;IAxBtC,OAAO,CAAC,WAAW,CAQlB;IAGD,YAAY,EAAG,iBAAiB,GAAG,sBAAsB,CAAA;IAGzD,cAAc,EAAG,yBAAyB,GAAG,8BAA8B,CAAA;IAG3E,WAAW,EAAG,sBAAsB,GAAG,2BAA2B,CAAA;IAGlE,2BAA2B,EAAG,OAAO,CAAA;IACrC,mBAAmB,EAAG,OAAO,CAAC,IAAI,CAAC,CAAA;gBAGxB,QAAQ,EAAE,iBAAiB,EACpC,SAAS,EAAE,iBAAiB,EAC5B,MAAM,EAAE,MAAM,GAAG,aAAa;IAoF1B,cAAc,IAAI,OAAO,CAAC,IAAI,CAAC;IAa/B,kBAAkB;IAmDlB,kBAAkB,IAAI,OAAO,CAAC,IAAI,CAAC;IA2CzC;;OAEG;IACG,aAAa,IAAI,OAAO,CAAC,IAAI,CAAC;IAW9B,gBAAgB,IAAI,OAAO,CAAC,IAAI,CAAC;IA4BjC,mBAAmB,IAAI,OAAO,CAAC,IAAI,CAAC;IA+BpC,oBAAoB,IAAI,OAAO,CAAC,IAAI,CAAC;IAmBrC,eAAe;IAsBrB;;;;;;;;OAQG;IAEG,WAAW,IAAI,OAAO,CAAC,IAAI,CAAC;IA0B5B,cAAc,IAAI,OAAO,CAAC,IAAI,CAAC;IA6C/B,kBAAkB;IA4BlB,wBAAwB,IAAI,OAAO,CAAC,IAAI,CAAC;IA2B/C;;OAEG;IACG,SAAS,CAAC,KAAK,EAAE,mBAAmB,GAAG,OAAO,CAAC,IAAI,CAAC;IAW1D;;OAEG;IACG,gBAAgB,CAAC,KAAK,EAAE,mBAAmB,GAAG,OAAO,CAAC,IAAI,CAAC;IAW3D,4BAA4B,IAAI,OAAO,CAAC,IAAI,CAAC;IAa7C,iBAAiB;IAOjB,oBAAoB,CAAC,SAAS,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC;IAQ5D,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAU3B,QAAQ,CAAC,CAAC,EAAE,GAAG,GAAG,OAAO,CAAC,IAAI,CAAC;CAOtC"}