@switchbot/homebridge-switchbot 3.8.3-beta.3 → 3.8.3-beta.31

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 (203) hide show
  1. package/.github/workflows/beta-release.yml +7 -4
  2. package/.github/workflows/release.yml +7 -6
  3. package/CHANGELOG.md +2 -1
  4. package/config.schema.json +24 -0
  5. package/dist/device/blindtilt.d.ts +1 -4
  6. package/dist/device/blindtilt.d.ts.map +1 -1
  7. package/dist/device/blindtilt.js +33 -34
  8. package/dist/device/blindtilt.js.map +1 -1
  9. package/dist/device/bot.d.ts +1 -4
  10. package/dist/device/bot.d.ts.map +1 -1
  11. package/dist/device/bot.js +30 -31
  12. package/dist/device/bot.js.map +1 -1
  13. package/dist/device/ceilinglight.d.ts +1 -4
  14. package/dist/device/ceilinglight.d.ts.map +1 -1
  15. package/dist/device/ceilinglight.js +50 -54
  16. package/dist/device/ceilinglight.js.map +1 -1
  17. package/dist/device/colorbulb.d.ts +1 -4
  18. package/dist/device/colorbulb.d.ts.map +1 -1
  19. package/dist/device/colorbulb.js +62 -66
  20. package/dist/device/colorbulb.js.map +1 -1
  21. package/dist/device/contact.d.ts +1 -4
  22. package/dist/device/contact.d.ts.map +1 -1
  23. package/dist/device/contact.js +18 -18
  24. package/dist/device/contact.js.map +1 -1
  25. package/dist/device/curtain.d.ts +1 -4
  26. package/dist/device/curtain.d.ts.map +1 -1
  27. package/dist/device/curtain.js +31 -32
  28. package/dist/device/curtain.js.map +1 -1
  29. package/dist/device/device.d.ts +6 -6
  30. package/dist/device/device.d.ts.map +1 -1
  31. package/dist/device/device.js +33 -17
  32. package/dist/device/device.js.map +1 -1
  33. package/dist/device/fan.d.ts +1 -4
  34. package/dist/device/fan.d.ts.map +1 -1
  35. package/dist/device/fan.js +47 -49
  36. package/dist/device/fan.js.map +1 -1
  37. package/dist/device/hub.d.ts +1 -4
  38. package/dist/device/hub.d.ts.map +1 -1
  39. package/dist/device/hub.js +18 -18
  40. package/dist/device/hub.js.map +1 -1
  41. package/dist/device/humidifier.d.ts +1 -4
  42. package/dist/device/humidifier.d.ts.map +1 -1
  43. package/dist/device/humidifier.js +43 -46
  44. package/dist/device/humidifier.js.map +1 -1
  45. package/dist/device/iosensor.d.ts +1 -4
  46. package/dist/device/iosensor.d.ts.map +1 -1
  47. package/dist/device/iosensor.js +18 -18
  48. package/dist/device/iosensor.js.map +1 -1
  49. package/dist/device/lightstrip.d.ts +1 -4
  50. package/dist/device/lightstrip.d.ts.map +1 -1
  51. package/dist/device/lightstrip.js +51 -54
  52. package/dist/device/lightstrip.js.map +1 -1
  53. package/dist/device/lock.d.ts +1 -4
  54. package/dist/device/lock.d.ts.map +1 -1
  55. package/dist/device/lock.js +31 -32
  56. package/dist/device/lock.js.map +1 -1
  57. package/dist/device/meter.d.ts +1 -4
  58. package/dist/device/meter.d.ts.map +1 -1
  59. package/dist/device/meter.js +18 -18
  60. package/dist/device/meter.js.map +1 -1
  61. package/dist/device/meterplus.d.ts +1 -4
  62. package/dist/device/meterplus.d.ts.map +1 -1
  63. package/dist/device/meterplus.js +18 -18
  64. package/dist/device/meterplus.js.map +1 -1
  65. package/dist/device/motion.d.ts +1 -4
  66. package/dist/device/motion.d.ts.map +1 -1
  67. package/dist/device/motion.js +18 -18
  68. package/dist/device/motion.js.map +1 -1
  69. package/dist/device/plug.d.ts +1 -4
  70. package/dist/device/plug.d.ts.map +1 -1
  71. package/dist/device/plug.js +29 -30
  72. package/dist/device/plug.js.map +1 -1
  73. package/dist/device/robotvacuumcleaner.d.ts +1 -4
  74. package/dist/device/robotvacuumcleaner.d.ts.map +1 -1
  75. package/dist/device/robotvacuumcleaner.js +36 -38
  76. package/dist/device/robotvacuumcleaner.js.map +1 -1
  77. package/dist/device/waterdetector.d.ts +1 -4
  78. package/dist/device/waterdetector.d.ts.map +1 -1
  79. package/dist/device/waterdetector.js +18 -18
  80. package/dist/device/waterdetector.js.map +1 -1
  81. package/dist/irdevice/airconditioner.d.ts +1 -1
  82. package/dist/irdevice/airconditioner.d.ts.map +1 -1
  83. package/dist/irdevice/airconditioner.js +11 -12
  84. package/dist/irdevice/airconditioner.js.map +1 -1
  85. package/dist/irdevice/airpurifier.d.ts +1 -1
  86. package/dist/irdevice/airpurifier.d.ts.map +1 -1
  87. package/dist/irdevice/airpurifier.js +11 -12
  88. package/dist/irdevice/airpurifier.js.map +1 -1
  89. package/dist/irdevice/camera.d.ts +1 -1
  90. package/dist/irdevice/camera.d.ts.map +1 -1
  91. package/dist/irdevice/camera.js +9 -10
  92. package/dist/irdevice/camera.js.map +1 -1
  93. package/dist/irdevice/fan.d.ts +1 -1
  94. package/dist/irdevice/fan.d.ts.map +1 -1
  95. package/dist/irdevice/fan.js +15 -16
  96. package/dist/irdevice/fan.js.map +1 -1
  97. package/dist/irdevice/irdevice.d.ts +6 -6
  98. package/dist/irdevice/irdevice.d.ts.map +1 -1
  99. package/dist/irdevice/irdevice.js +7 -13
  100. package/dist/irdevice/irdevice.js.map +1 -1
  101. package/dist/irdevice/light.d.ts +1 -1
  102. package/dist/irdevice/light.d.ts.map +1 -1
  103. package/dist/irdevice/light.js +9 -10
  104. package/dist/irdevice/light.js.map +1 -1
  105. package/dist/irdevice/other.d.ts +1 -1
  106. package/dist/irdevice/other.d.ts.map +1 -1
  107. package/dist/irdevice/other.js +9 -10
  108. package/dist/irdevice/other.js.map +1 -1
  109. package/dist/irdevice/tv.d.ts +1 -1
  110. package/dist/irdevice/tv.d.ts.map +1 -1
  111. package/dist/irdevice/tv.js +27 -28
  112. package/dist/irdevice/tv.js.map +1 -1
  113. package/dist/irdevice/vacuumcleaner.d.ts +1 -1
  114. package/dist/irdevice/vacuumcleaner.d.ts.map +1 -1
  115. package/dist/irdevice/vacuumcleaner.js +9 -10
  116. package/dist/irdevice/vacuumcleaner.js.map +1 -1
  117. package/dist/irdevice/waterheater.d.ts +1 -1
  118. package/dist/irdevice/waterheater.d.ts.map +1 -1
  119. package/dist/irdevice/waterheater.js +9 -10
  120. package/dist/irdevice/waterheater.js.map +1 -1
  121. package/dist/platform.d.ts +6 -14
  122. package/dist/platform.d.ts.map +1 -1
  123. package/dist/platform.js +127 -188
  124. package/dist/platform.js.map +1 -1
  125. package/dist/settings.d.ts +4 -3
  126. package/dist/settings.d.ts.map +1 -1
  127. package/dist/settings.js.map +1 -1
  128. package/dist/utils.d.ts +1 -1
  129. package/dist/utils.d.ts.map +1 -1
  130. package/dist/utils.js.map +1 -1
  131. package/docs/assets/highlight.css +42 -0
  132. package/docs/assets/main.js +1 -1
  133. package/docs/functions/default.html +1 -1
  134. package/docs/index.html +61 -50
  135. package/docs/media/security-privacy-bluetooth.png +0 -0
  136. package/package.json +14 -15
  137. package/src/device/blindtilt.ts +35 -39
  138. package/src/device/bot.ts +31 -35
  139. package/src/device/ceilinglight.ts +51 -58
  140. package/src/device/colorbulb.ts +63 -70
  141. package/src/device/contact.ts +19 -22
  142. package/src/device/curtain.ts +33 -37
  143. package/src/device/device.ts +32 -21
  144. package/src/device/fan.ts +48 -53
  145. package/src/device/hub.ts +19 -22
  146. package/src/device/humidifier.ts +44 -50
  147. package/src/device/iosensor.ts +19 -22
  148. package/src/device/lightstrip.ts +52 -58
  149. package/src/device/lock.ts +32 -36
  150. package/src/device/meter.ts +19 -22
  151. package/src/device/meterplus.ts +19 -22
  152. package/src/device/motion.ts +19 -22
  153. package/src/device/plug.ts +30 -34
  154. package/src/device/robotvacuumcleaner.ts +37 -46
  155. package/src/device/waterdetector.ts +19 -22
  156. package/src/irdevice/airconditioner.ts +12 -14
  157. package/src/irdevice/airpurifier.ts +12 -13
  158. package/src/irdevice/camera.ts +10 -11
  159. package/src/irdevice/fan.ts +16 -17
  160. package/src/irdevice/irdevice.ts +9 -17
  161. package/src/irdevice/light.ts +10 -11
  162. package/src/irdevice/other.ts +10 -11
  163. package/src/irdevice/tv.ts +28 -29
  164. package/src/irdevice/vacuumcleaner.ts +10 -11
  165. package/src/irdevice/waterheater.ts +10 -11
  166. package/src/platform.ts +131 -188
  167. package/src/settings.ts +8 -4
  168. package/src/utils.ts +2 -1
  169. package/dist/types/bledevicestatus.d.ts +0 -281
  170. package/dist/types/bledevicestatus.d.ts.map +0 -1
  171. package/dist/types/bledevicestatus.js +0 -2
  172. package/dist/types/bledevicestatus.js.map +0 -1
  173. package/dist/types/devicelist.d.ts +0 -89
  174. package/dist/types/devicelist.d.ts.map +0 -1
  175. package/dist/types/devicelist.js +0 -6
  176. package/dist/types/devicelist.js.map +0 -1
  177. package/dist/types/deviceresponse.d.ts +0 -13
  178. package/dist/types/deviceresponse.d.ts.map +0 -1
  179. package/dist/types/deviceresponse.js +0 -2
  180. package/dist/types/deviceresponse.js.map +0 -1
  181. package/dist/types/devicestatus.d.ts +0 -149
  182. package/dist/types/devicestatus.d.ts.map +0 -1
  183. package/dist/types/devicestatus.js +0 -3
  184. package/dist/types/devicestatus.js.map +0 -1
  185. package/dist/types/devicewebhookstatus.d.ts +0 -156
  186. package/dist/types/devicewebhookstatus.d.ts.map +0 -1
  187. package/dist/types/devicewebhookstatus.js +0 -2
  188. package/dist/types/devicewebhookstatus.js.map +0 -1
  189. package/dist/types/irdevicelist.d.ts +0 -10
  190. package/dist/types/irdevicelist.d.ts.map +0 -1
  191. package/dist/types/irdevicelist.js +0 -2
  192. package/dist/types/irdevicelist.js.map +0 -1
  193. package/dist/types/pushbody.d.ts +0 -6
  194. package/dist/types/pushbody.d.ts.map +0 -1
  195. package/dist/types/pushbody.js +0 -2
  196. package/dist/types/pushbody.js.map +0 -1
  197. package/src/types/bledevicestatus.ts +0 -303
  198. package/src/types/devicelist.ts +0 -124
  199. package/src/types/deviceresponse.ts +0 -14
  200. package/src/types/devicestatus.ts +0 -178
  201. package/src/types/devicewebhookstatus.ts +0 -191
  202. package/src/types/irdevicelist.ts +0 -15
  203. package/src/types/pushbody.ts +0 -9
package/src/platform.ts CHANGED
@@ -2,21 +2,14 @@
2
2
  *
3
3
  * platform.ts: @switchbot/homebridge-switchbot platform class.
4
4
  */
5
- import type { IncomingMessage, Server, ServerResponse } from 'node:http'
6
- import type { UrlObject } from 'node:url'
5
+ import type { Server } from 'node:http'
7
6
 
8
7
  import type { API, DynamicPlatformPlugin, Logging, PlatformAccessory } from 'homebridge'
9
8
  import type { MqttClient } from 'mqtt'
10
- import type { Dispatcher } from 'undici'
11
9
 
12
10
  import type { devicesConfig, irDevicesConfig, options, SwitchBotPlatformConfig } from './settings.js'
13
- import type { blindTilt, curtain, curtain3, device } from './types/devicelist.js'
14
- import type { irdevice } from './types/irdevicelist.js'
15
11
 
16
- import { Buffer } from 'node:buffer'
17
- import crypto, { randomUUID } from 'node:crypto'
18
12
  import { readFileSync, writeFileSync } from 'node:fs'
19
- import { createServer } from 'node:http'
20
13
  import process from 'node:process'
21
14
 
22
15
  import asyncmqtt from 'async-mqtt'
@@ -24,11 +17,13 @@ import fakegato from 'fakegato-history'
24
17
  import { EveHomeKitTypes } from 'homebridge-lib/EveHomeKitTypes'
25
18
  /*
26
19
  * For Testing Locally:
27
- * import { SwitchBotModel } from '/Users/Shared/GitHub/OpenWonderLabs/node-switchbot/dist/index.js';
20
+ * import type { blindTilt, curtain, curtain3, device, irdevice } from '/Users/Shared/GitHub/OpenWonderLabs/node-switchbot/dist/index.js';
21
+ * import { LogLevel, SwitchBotBLE, SwitchBotModel, SwitchBotOpenAPI } from '/Users/Shared/GitHub/OpenWonderLabs/node-switchbot/dist/index.js';
28
22
  */
29
- import { SwitchBot, SwitchBotModel } from 'node-switchbot'
23
+ import type { blindTilt, curtain, curtain3, device, irdevice } from 'node-switchbot'
24
+
25
+ import { LogLevel, SwitchBotBLE, SwitchBotModel, SwitchBotOpenAPI } from 'node-switchbot'
30
26
  import { queueScheduler } from 'rxjs'
31
- import { request } from 'undici'
32
27
 
33
28
  import { BlindTilt } from './device/blindtilt.js'
34
29
  import { Bot } from './device/bot.js'
@@ -57,7 +52,7 @@ import { Others } from './irdevice/other.js'
57
52
  import { TV } from './irdevice/tv.js'
58
53
  import { VacuumCleaner } from './irdevice/vacuumcleaner.js'
59
54
  import { WaterHeater } from './irdevice/waterheater.js'
60
- import { deleteWebhook, Devices, PLATFORM_NAME, PLUGIN_NAME, queryWebhook, setupWebhook, updateWebhook } from './settings.js'
55
+ import { PLATFORM_NAME, PLUGIN_NAME } from './settings.js'
61
56
  import { formatDeviceIdAsMac, isBlindTiltDevice, isCurtainDevice, sleep } from './utils.js'
62
57
 
63
58
  /**
@@ -85,6 +80,10 @@ export class SwitchBotPlatform implements DynamicPlatformPlugin {
85
80
  mqttClient: MqttClient | null = null
86
81
  webhookEventListener: Server | null = null
87
82
 
83
+ // SwitchBot APIs
84
+ switchBotAPI!: SwitchBotOpenAPI
85
+ switchBotBLE!: SwitchBotBLE
86
+
88
87
  // External APIs
89
88
  public readonly eve: any
90
89
  public readonly fakegatoAPI: any
@@ -127,11 +126,44 @@ export class SwitchBotPlatform implements DynamicPlatformPlugin {
127
126
  this.verifyConfig()
128
127
  this.debugLog('Config OK')
129
128
  } catch (e: any) {
130
- this.errorLog(`Verify Config, Error Message: ${e.message}, Submit Bugs Here: ` + 'https://tinyurl.com/SwitchBotBug')
131
- this.debugErrorLog(`Verify Config, Error: ${e}`)
129
+ this.errorLog(`Verify Config, Error Message: ${e.message ?? e}, Submit Bugs Here: ` + 'https://tinyurl.com/SwitchBotBug')
130
+ this.debugErrorLog(`Verify Config, Error: ${e.message ?? e}`)
132
131
  return
133
132
  }
134
133
 
134
+ // SwitchBot OpenAPI
135
+ this.switchBotAPI = new SwitchBotOpenAPI(this.config.credentials?.token, this.config.credentials?.secret)
136
+ // Listen for log events
137
+ if (!this.config.options?.disableLogsforOpenAPI) {
138
+ this.switchBotAPI.on('log', (log) => {
139
+ switch (log.level) {
140
+ case LogLevel.SUCCESS:
141
+ this.successLog(log.message)
142
+ break
143
+ case LogLevel.DEBUGSUCCESS:
144
+ this.debugSuccessLog(log.message)
145
+ break
146
+ case LogLevel.WARN:
147
+ this.warnLog(log.message)
148
+ break
149
+ case LogLevel.DEBUGWARN:
150
+ this.debugWarnLog(log.message)
151
+ break
152
+ case LogLevel.ERROR:
153
+ this.errorLog(log.message)
154
+ break
155
+ case LogLevel.DEBUGERROR:
156
+ this.debugErrorLog(log.message)
157
+ break
158
+ case LogLevel.DEBUG:
159
+ this.debugLog(log.message)
160
+ break
161
+ case LogLevel.INFO:
162
+ default:
163
+ this.infoLog(log.message)
164
+ }
165
+ })
166
+ }
135
167
  // import fakegato-history module and EVE characteristics
136
168
  this.fakegatoAPI = fakegato(api)
137
169
  this.eve = new EveHomeKitTypes(api)
@@ -152,25 +184,25 @@ export class SwitchBotPlatform implements DynamicPlatformPlugin {
152
184
  await this.discoverDevices()
153
185
  }
154
186
  } catch (e: any) {
155
- await this.errorLog(`Failed to Discover, Error Message: ${e.message}, Submit Bugs Here: ` + 'https://tinyurl.com/SwitchBotBug')
156
- await this.debugErrorLog(`Failed to Discover, Error: ${e}`)
187
+ await this.errorLog(`Failed to Discover, Error Message: ${e.message ?? e}, Submit Bugs Here: ` + 'https://tinyurl.com/SwitchBotBug')
188
+ await this.debugErrorLog(`Failed to Discover, Error: ${e.message ?? e}`)
157
189
  }
158
190
  })
159
191
 
160
192
  try {
161
193
  this.setupMqtt()
162
194
  } catch (e: any) {
163
- this.errorLog(`Setup MQTT, Error Message: ${e.message}, Submit Bugs Here: ` + 'https://tinyurl.com/SwitchBotBug')
195
+ this.errorLog(`Setup MQTT, Error Message: ${e.message ?? e}, Submit Bugs Here: ` + 'https://tinyurl.com/SwitchBotBug')
164
196
  }
165
197
  try {
166
198
  this.setupwebhook()
167
199
  } catch (e: any) {
168
- this.errorLog(`Setup Webhook, Error Message: ${e.message}, Submit Bugs Here: ` + 'https://tinyurl.com/SwitchBotBug')
200
+ this.errorLog(`Setup Webhook, Error Message: ${e.message ?? e}, Submit Bugs Here: ` + 'https://tinyurl.com/SwitchBotBug')
169
201
  }
170
202
  try {
171
203
  this.setupBlE()
172
204
  } catch (e: any) {
173
- this.errorLog(`Setup Platform BLE, Error Message: ${e.message}, Submit Bugs Here: ` + 'https://tinyurl.com/SwitchBotBug')
205
+ this.errorLog(`Setup Platform BLE, Error Message: ${e.message ?? e}, Submit Bugs Here: ` + 'https://tinyurl.com/SwitchBotBug')
174
206
  }
175
207
  }
176
208
 
@@ -181,7 +213,7 @@ export class SwitchBotPlatform implements DynamicPlatformPlugin {
181
213
  this.mqttClient = await connectAsync(this.config.options?.mqttURL, this.config.options.mqttOptions || {})
182
214
  await this.debugLog('MQTT connection has been established successfully.')
183
215
  this.mqttClient.on('error', async (e: Error) => {
184
- await this.errorLog(`Failed to publish MQTT messages. ${e}`)
216
+ await this.errorLog(`Failed to publish MQTT messages. ${e.message ?? e}`)
185
217
  })
186
218
  if (!this.config.options?.webhookURL) {
187
219
  // receive webhook events via MQTT
@@ -193,13 +225,13 @@ export class SwitchBotPlatform implements DynamicPlatformPlugin {
193
225
  const context = JSON.parse(message.toString())
194
226
  this.webhookEventHandler[context.deviceMac]?.(context)
195
227
  } catch (e: any) {
196
- await this.errorLog(`Failed to handle webhook event. Error:${e}`)
228
+ await this.errorLog(`Failed to handle webhook event. Error:${e.message ?? e}`)
197
229
  }
198
230
  })
199
231
  }
200
- } catch (e) {
232
+ } catch (e: any) {
201
233
  this.mqttClient = null
202
- await this.errorLog(`Failed to establish MQTT connection. ${e}`)
234
+ await this.errorLog(`Failed to establish MQTT connection. ${e.message ?? e}`)
203
235
  }
204
236
  }
205
237
  }
@@ -208,156 +240,94 @@ export class SwitchBotPlatform implements DynamicPlatformPlugin {
208
240
  // webhook configuration
209
241
  if (this.config.options?.webhookURL) {
210
242
  const url = this.config.options?.webhookURL
211
-
212
243
  try {
213
- const xurl = new URL(url)
214
- const port = Number(xurl.port)
215
- const path = xurl.pathname
216
- this.webhookEventListener = createServer((request: IncomingMessage, response: ServerResponse) => {
217
- try {
218
- if (request.url === path && request.method === 'POST') {
219
- request.on('data', async (data) => {
220
- try {
221
- const body = JSON.parse(data)
222
- await this.debugLog(`Received Webhook: ${JSON.stringify(body)}`)
223
- if (this.config.options?.mqttURL) {
224
- const mac = body.context.deviceMac?.toLowerCase().match(/[\s\S]{1,2}/g)?.join(':')
225
- const options = this.config.options?.mqttPubOptions || {}
226
- this.mqttClient?.publish(`homebridge-switchbot/webhook/${mac}`, `${JSON.stringify(body.context)}`, options)
227
- }
228
- this.webhookEventHandler[body.context.deviceMac]?.(body.context)
229
- } catch (e: any) {
230
- await this.errorLog(`Failed to handle webhook event. Error:${e}`)
231
- }
232
- })
233
- response.writeHead(200, { 'Content-Type': 'text/plain' })
234
- response.end('OK')
235
- }
236
- // else {
237
- // response.writeHead(403, {'Content-Type': 'text/plain'});
238
- // response.end(`NG`);
239
- // }
240
- } catch (e: any) {
241
- this.errorLog(`Failed to handle webhook event. Error:${e}`)
244
+ this.switchBotAPI.setupWebhook(url)
245
+ // Listen for webhook events
246
+ this.switchBotAPI.on('webhookEvent', (body) => {
247
+ if (this.config.options?.mqttURL) {
248
+ const mac = body.context.deviceMac?.toLowerCase().match(/[\s\S]{1,2}/g)?.join(':')
249
+ const options = this.config.options?.mqttPubOptions || {}
250
+ this.mqttClient?.publish(`homebridge-switchbot/webhook/${mac}`, `${JSON.stringify(body.context)}`, options)
242
251
  }
243
- }).listen(port || 80)
244
- } catch (e: any) {
245
- await this.errorLog(`Failed to create webhook listener. Error:${e.message}`)
246
- return
247
- }
248
-
249
- try {
250
- const { body, statusCode } = await request(setupWebhook, {
251
- method: 'POST',
252
- headers: this.generateHeaders(),
253
- body: JSON.stringify({
254
- action: 'setupWebhook',
255
- url,
256
- deviceList: 'ALL',
257
- }),
252
+ this.webhookEventHandler[body.context.deviceMac]?.(body.context)
258
253
  })
259
- const response: any = await body.json()
260
- await this.debugLog(`setupWebhook: url:${url}, body:${JSON.stringify(response)}, statusCode:${statusCode}`)
261
- if (statusCode !== 200 || response?.statusCode !== 100) {
262
- await this.errorLog(`Failed to configure webhook. Existing webhook well be overridden. HTTP:${statusCode} API:${response?.statusCode} message:${response?.message}`)
263
- }
264
254
  } catch (e: any) {
265
- await this.errorLog(`Failed to configure webhook. Error: ${e.message}`)
266
- }
267
-
268
- try {
269
- const { body, statusCode } = await request(updateWebhook, {
270
- method: 'POST',
271
- headers: this.generateHeaders(),
272
- body: JSON.stringify({
273
- action: 'updateWebhook',
274
- config: {
275
- url,
276
- enable: true,
277
- },
278
- }),
279
- })
280
- const response: any = await body.json()
281
- await this.debugLog(`updateWebhook: url:${url}, body:${JSON.stringify(response)}, statusCode:${statusCode}`)
282
- if (statusCode !== 200 || response?.statusCode !== 100) {
283
- await this.errorLog(`Failed to update webhook. HTTP:${statusCode} API:${response?.statusCode} message:${response?.message}`)
284
- }
285
- } catch (e: any) {
286
- await this.errorLog(`Failed to update webhook. Error:${e.message}`)
287
- }
288
-
289
- try {
290
- const { body, statusCode } = await request(queryWebhook, {
291
- method: 'POST',
292
- headers: this.generateHeaders(),
293
- body: JSON.stringify({
294
- action: 'queryUrl',
295
- }),
296
- })
297
- const response: any = await body.json()
298
- await this.debugLog(`queryWebhook: body:${JSON.stringify(response)}`)
299
- await this.debugLog(`queryWebhook: statusCode:${statusCode}`)
300
- if (statusCode !== 200 || response?.statusCode !== 100) {
301
- await this.errorLog(`Failed to query webhook. HTTP:${statusCode} API:${response?.statusCode} message:${response?.message}`)
302
- } else {
303
- await this.infoLog(`Listening webhook on ${response?.body?.urls[0]}`)
304
- }
305
- } catch (e: any) {
306
- await this.errorLog(`Failed to query webhook. Error:${e}`)
255
+ await this.errorLog(`Failed to setup webhook. Error:${e.message ?? e}`)
307
256
  }
308
257
 
309
258
  this.api.on('shutdown', async () => {
310
259
  try {
311
- const { body, statusCode } = await request(deleteWebhook, {
312
- method: 'POST',
313
- headers: this.generateHeaders(),
314
- body: JSON.stringify({
315
- action: 'deleteWebhook',
316
- url,
317
- }),
318
- })
319
- const response: any = await body.json()
320
- await this.debugLog(`deleteWebhook: url:${url}, body:${JSON.stringify(response)}, statusCode:${statusCode}`)
321
- if (statusCode !== 200 || response?.statusCode !== 100) {
322
- await this.errorLog(`Failed to delete webhook. HTTP:${statusCode} API:${response?.statusCode} message:${response?.message}`)
323
- } else {
324
- await this.infoLog('Unregistered webhook to close listening.')
325
- }
260
+ this.switchBotAPI.deleteWebhook(url)
326
261
  } catch (e: any) {
327
- await this.errorLog(`Failed to delete webhook. Error:${e.message}`)
262
+ await this.errorLog(`Failed to delete webhook. Error:${e.message ?? e}`)
328
263
  }
329
264
  })
330
265
  }
331
266
  }
332
267
 
333
268
  async setupBlE() {
269
+ this.switchBotBLE = new SwitchBotBLE()
270
+ // Listen for log events
271
+ if (!this.config.options?.disableLogsforBLE) {
272
+ this.switchBotBLE.on('log', (log) => {
273
+ switch (log.level) {
274
+ case LogLevel.SUCCESS:
275
+ this.successLog(log.message)
276
+ break
277
+ case LogLevel.DEBUGSUCCESS:
278
+ this.debugSuccessLog(log.message)
279
+ break
280
+ case LogLevel.WARN:
281
+ this.warnLog(log.message)
282
+ break
283
+ case LogLevel.DEBUGWARN:
284
+ this.debugWarnLog(log.message)
285
+ break
286
+ case LogLevel.ERROR:
287
+ this.errorLog(log.message)
288
+ break
289
+ case LogLevel.DEBUGERROR:
290
+ this.debugErrorLog(log.message)
291
+ break
292
+ case LogLevel.DEBUG:
293
+ this.debugLog(log.message)
294
+ break
295
+ case LogLevel.INFO:
296
+ default:
297
+ this.infoLog(log.message)
298
+ }
299
+ })
300
+ }
334
301
  if (this.config.options?.BLE) {
335
302
  await this.debugLog('setupBLE')
336
- const switchbot = new SwitchBot()
337
- if (switchbot === undefined) {
338
- await this.errorLog(`wasn't able to establish BLE Connection, node-switchbot: ${switchbot}`)
303
+ if (this.switchBotBLE === undefined) {
304
+ await this.errorLog(`wasn't able to establish BLE Connection, node-switchbot: ${JSON.stringify(this.switchBotBLE)}`)
339
305
  } else {
340
306
  // Start to monitor advertisement packets
341
307
  (async () => {
342
308
  // Start to monitor advertisement packets
343
309
  await this.debugLog('Scanning for BLE SwitchBot devices...')
344
- await switchbot.startScan()
310
+ try {
311
+ await this.switchBotBLE.startScan()
312
+ } catch (e: any) {
313
+ await this.errorLog(`Failed to start BLE scanning. Error:${e.message ?? e}`)
314
+ }
345
315
  // Set an event handler to monitor advertisement packets
346
- switchbot.onadvertisement = async (ad: any) => {
316
+ this.switchBotBLE.onadvertisement = async (ad: any) => {
347
317
  try {
348
318
  this.bleEventHandler[ad.address]?.(ad.serviceData)
349
319
  } catch (e: any) {
350
- await this.errorLog(`Failed to handle BLE event. Error:${e}`)
320
+ await this.errorLog(`Failed to handle BLE event. Error:${e.message ?? e}`)
351
321
  }
352
322
  }
353
323
  })()
354
324
 
355
325
  this.api.on('shutdown', async () => {
356
326
  try {
357
- switchbot.stopScan()
327
+ // this.switchBotBLE.stopScan()
358
328
  await this.infoLog('Stopped BLE scanning to close listening.')
359
329
  } catch (e: any) {
360
- await this.errorLog(`Failed to stop Platform BLE scanning. Error:${e.message}`)
330
+ await this.errorLog(`Failed to stop Platform BLE scanning. Error:${e.message ?? e}`)
361
331
  }
362
332
  })
363
333
  }
@@ -527,26 +497,7 @@ export class SwitchBotPlatform implements DynamicPlatformPlugin {
527
497
  writeFileSync(this.api.user.configPath(), JSON.stringify(currentConfig, null, 4))
528
498
  await this.verifyConfig()
529
499
  } catch (e: any) {
530
- await this.errorLog(`Update Token: ${e}`)
531
- }
532
- }
533
-
534
- generateHeaders = () => {
535
- const t = `${Date.now()}`
536
- const nonce = randomUUID()
537
- const data = this.config.credentials?.token + t + nonce
538
- const signTerm = crypto
539
- .createHmac('sha256', this.config.credentials?.secret)
540
- .update(Buffer.from(data, 'utf-8'))
541
- .digest()
542
- const sign = signTerm.toString('base64')
543
-
544
- return {
545
- 'Authorization': this.config.credentials?.token,
546
- 'sign': sign,
547
- 'nonce': nonce,
548
- 't': t,
549
- 'Content-Type': 'application/json',
500
+ await this.errorLog(`Update Token: ${e.message ?? e}`)
550
501
  }
551
502
  }
552
503
 
@@ -565,23 +516,20 @@ export class SwitchBotPlatform implements DynamicPlatformPlugin {
565
516
 
566
517
  while (retryCount < maxRetries) {
567
518
  try {
568
- const { body, statusCode } = await request(Devices, { headers: this.generateHeaders() })
569
- await this.debugWarnLog(`statusCode: ${statusCode}`)
570
- const devicesAPI: any = await body.json()
571
- await this.debugWarnLog(`devicesAPI: ${JSON.stringify(devicesAPI)}`)
572
-
573
- if (this.isSuccessfulResponse(statusCode, devicesAPI.statusCode)) {
574
- await this.handleDevices(devicesAPI.body.deviceList)
575
- await this.handleIRDevices(devicesAPI.body.infraredRemoteList)
519
+ const { response, statusCode } = await this.switchBotAPI.getDevices()
520
+ await this.debugLog(`response: ${JSON.stringify(response)}`)
521
+ if (this.isSuccessfulResponse(statusCode)) {
522
+ await this.handleDevices(Array.isArray(response.body.deviceList) ? response.body.deviceList : [])
523
+ await this.handleIRDevices(Array.isArray(response.body.infraredRemoteList) ? response.body.infraredRemoteList : [])
576
524
  break
577
525
  } else {
578
- await this.handleErrorResponse(statusCode, devicesAPI.statusCode, retryCount, maxRetries, delayBetweenRetries)
526
+ await this.handleErrorResponse(statusCode, retryCount, maxRetries, delayBetweenRetries)
579
527
  retryCount++
580
528
  }
581
529
  } catch (e: any) {
582
530
  retryCount++
583
531
  await this.debugErrorLog(`Failed to Discover Devices, Error Message: ${JSON.stringify(e.message)}, Submit Bugs Here: https://tinyurl.com/SwitchBotBug`)
584
- await this.debugErrorLog(`Failed to Discover Devices, Error: ${e}`)
532
+ await this.debugErrorLog(`Failed to Discover Devices, Error: ${e.message ?? e}`)
585
533
  }
586
534
  }
587
535
  }
@@ -608,8 +556,8 @@ export class SwitchBotPlatform implements DynamicPlatformPlugin {
608
556
  }
609
557
  }
610
558
 
611
- private isSuccessfulResponse(statusCode: number, apiStatusCode: number): boolean {
612
- return (statusCode === 200 || statusCode === 100) && (apiStatusCode === 200 || apiStatusCode === 100)
559
+ private isSuccessfulResponse(apiStatusCode: number): boolean {
560
+ return (apiStatusCode === 200 || apiStatusCode === 100)
613
561
  }
614
562
 
615
563
  private async handleDevices(deviceLists: any[]) {
@@ -674,11 +622,10 @@ export class SwitchBotPlatform implements DynamicPlatformPlugin {
674
622
  })
675
623
  }
676
624
 
677
- private async handleErrorResponse(statusCode: number, apiStatusCode: number, retryCount: number, maxRetries: number, delayBetweenRetries: number) {
678
- await this.statusCode(statusCode)
625
+ private async handleErrorResponse(apiStatusCode: number, retryCount: number, maxRetries: number, delayBetweenRetries: number) {
679
626
  await this.statusCode(apiStatusCode)
680
- if (statusCode === 500) {
681
- this.infoLog(`statusCode: ${statusCode} Attempt ${retryCount + 1} of ${maxRetries}`)
627
+ if (apiStatusCode === 500) {
628
+ this.infoLog(`statusCode: ${apiStatusCode} Attempt ${retryCount + 1} of ${maxRetries}`)
682
629
  await sleep(delayBetweenRetries)
683
630
  }
684
631
  }
@@ -2639,18 +2586,15 @@ export class SwitchBotPlatform implements DynamicPlatformPlugin {
2639
2586
  }
2640
2587
  }
2641
2588
 
2642
- async retryRequest(deviceMaxRetries: number, deviceDelayBetweenRetries: number, url: string | URL | UrlObject, options?: { dispatcher?: Dispatcher } & Omit<Dispatcher.RequestOptions, 'origin' | 'path' | 'method'> & Partial<Pick<Dispatcher.RequestOptions, 'method'>>): Promise<{ body: any, statusCode: number }> {
2589
+ async retryRequest(deviceId: string, deviceMaxRetries: number, deviceDelayBetweenRetries: number): Promise<{ response: any, statusCode: number }> {
2643
2590
  let retryCount = 0
2644
2591
  const maxRetries = deviceMaxRetries
2645
2592
  const delayBetweenRetries = deviceDelayBetweenRetries
2646
2593
  while (retryCount < maxRetries) {
2647
2594
  try {
2648
- const { body, statusCode } = await request(url, options)
2649
- if (statusCode === 200 || statusCode === 100) {
2650
- return { body, statusCode }
2651
- } else {
2652
- await this.debugLog(`Received status code: ${statusCode}`)
2653
- }
2595
+ const { response, statusCode } = await this.switchBotAPI.getDeviceStatus(deviceId)
2596
+ await this.debugLog(`response: ${JSON.stringify(response)}`)
2597
+ return { response, statusCode }
2654
2598
  } catch (error: any) {
2655
2599
  await this.errorLog(`Error making request: ${error.message}`)
2656
2600
  }
@@ -2658,18 +2602,17 @@ export class SwitchBotPlatform implements DynamicPlatformPlugin {
2658
2602
  await this.debugLog(`Retry attempt ${retryCount} of ${maxRetries}`)
2659
2603
  await sleep(delayBetweenRetries)
2660
2604
  }
2661
- return { body: null, statusCode: -1 }
2605
+ return { response: null, statusCode: 500 }
2662
2606
  }
2663
2607
 
2664
2608
  // BLE Connection
2665
2609
  async connectBLE(accessory: PlatformAccessory, device: device & devicesConfig): Promise<any> {
2666
2610
  try {
2667
- const switchbot = new SwitchBot()
2668
- queueScheduler.schedule(async () => switchbot)
2669
- await this.debugLog(`${device.deviceType}: ${accessory.displayName} 'node-switchbot' found: ${switchbot}`)
2670
- return switchbot
2611
+ queueScheduler.schedule(async () => this.switchBotBLE)
2612
+ await this.debugLog(`${device.deviceType}: ${accessory.displayName} 'node-switchbot' found: ${this.switchBotBLE}`)
2613
+ return this.switchBotBLE
2671
2614
  } catch (e: any) {
2672
- await this.errorLog(`${device.deviceType}: ${accessory.displayName} 'node-switchbot' not found, Error: ${e}`)
2615
+ await this.errorLog(`${device.deviceType}: ${accessory.displayName} 'node-switchbot' not found, Error: ${e.message ?? e}`)
2673
2616
  return false
2674
2617
  }
2675
2618
  }
package/src/settings.ts CHANGED
@@ -4,10 +4,11 @@
4
4
  */
5
5
  import type { IClientOptions } from 'async-mqtt'
6
6
  import type { PlatformConfig } from 'homebridge'
7
- import type { SwitchBotBLEModel, SwitchBotBLEModelFriendlyName, SwitchBotBLEModelName } from 'node-switchbot'
8
-
9
- import type { device } from './types/devicelist'
10
- import type { irdevice } from './types/irdevicelist'
7
+ /*
8
+ * For Testing Locally:
9
+ * import type { device, irdevice, SwitchBotBLEModel, SwitchBotBLEModelFriendlyName, SwitchBotBLEModelName } from '/Users/Shared/GitHub/OpenWonderLabs/node-switchbot/dist/index.js';
10
+ */
11
+ import type { device, irdevice, SwitchBotBLEModel, SwitchBotBLEModelFriendlyName, SwitchBotBLEModelName } from 'node-switchbot'
11
12
  /**
12
13
  * This is the name of the platform that users will use to register the plugin in the Homebridge config.json
13
14
  */
@@ -63,6 +64,9 @@ export interface options {
63
64
  mqttOptions?: IClientOptions
64
65
  mqttPubOptions?: IClientOptions
65
66
  BLE?: boolean
67
+ discoverBLE?: boolean
68
+ disableLogsforBLE?: boolean
69
+ disableLogsforOpenAPI?: boolean
66
70
  webhookURL?: string
67
71
  maxRetries?: number
68
72
  delayBetweenRetries?: number
package/src/utils.ts CHANGED
@@ -2,8 +2,9 @@
2
2
  *
3
3
  * util.ts: @switchbot/homebridge-switchbot platform class.
4
4
  */
5
+ import type { blindTilt, curtain, curtain3, device } from 'node-switchbot'
6
+
5
7
  import type { devicesConfig } from './settings.js'
6
- import type { blindTilt, curtain, curtain3, device } from './types/devicelist.js'
7
8
 
8
9
  export enum SwitchBotModel {
9
10
  HubMini = 'W0202200',