@switchbot/homebridge-switchbot 3.8.3-beta.3 → 3.8.3-beta.30
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/.github/workflows/beta-release.yml +7 -4
- package/.github/workflows/release.yml +7 -6
- package/dist/device/blindtilt.d.ts +1 -4
- package/dist/device/blindtilt.d.ts.map +1 -1
- package/dist/device/blindtilt.js +18 -19
- package/dist/device/blindtilt.js.map +1 -1
- package/dist/device/bot.d.ts +1 -4
- package/dist/device/bot.d.ts.map +1 -1
- package/dist/device/bot.js +15 -16
- package/dist/device/bot.js.map +1 -1
- package/dist/device/ceilinglight.d.ts +1 -4
- package/dist/device/ceilinglight.d.ts.map +1 -1
- package/dist/device/ceilinglight.js +35 -39
- package/dist/device/ceilinglight.js.map +1 -1
- package/dist/device/colorbulb.d.ts +1 -4
- package/dist/device/colorbulb.d.ts.map +1 -1
- package/dist/device/colorbulb.js +35 -39
- package/dist/device/colorbulb.js.map +1 -1
- package/dist/device/contact.d.ts +1 -4
- package/dist/device/contact.d.ts.map +1 -1
- package/dist/device/contact.js +7 -7
- package/dist/device/contact.js.map +1 -1
- package/dist/device/curtain.d.ts +1 -4
- package/dist/device/curtain.d.ts.map +1 -1
- package/dist/device/curtain.js +16 -17
- package/dist/device/curtain.js.map +1 -1
- package/dist/device/device.d.ts +6 -6
- package/dist/device/device.d.ts.map +1 -1
- package/dist/device/device.js +30 -14
- package/dist/device/device.js.map +1 -1
- package/dist/device/fan.d.ts +1 -4
- package/dist/device/fan.d.ts.map +1 -1
- package/dist/device/fan.js +32 -34
- package/dist/device/fan.js.map +1 -1
- package/dist/device/hub.d.ts +1 -4
- package/dist/device/hub.d.ts.map +1 -1
- package/dist/device/hub.js +7 -7
- package/dist/device/hub.js.map +1 -1
- package/dist/device/humidifier.d.ts +1 -4
- package/dist/device/humidifier.d.ts.map +1 -1
- package/dist/device/humidifier.js +28 -31
- package/dist/device/humidifier.js.map +1 -1
- package/dist/device/iosensor.d.ts +1 -4
- package/dist/device/iosensor.d.ts.map +1 -1
- package/dist/device/iosensor.js +7 -7
- package/dist/device/iosensor.js.map +1 -1
- package/dist/device/lightstrip.d.ts +1 -4
- package/dist/device/lightstrip.d.ts.map +1 -1
- package/dist/device/lightstrip.js +28 -31
- package/dist/device/lightstrip.js.map +1 -1
- package/dist/device/lock.d.ts +1 -4
- package/dist/device/lock.d.ts.map +1 -1
- package/dist/device/lock.js +15 -16
- package/dist/device/lock.js.map +1 -1
- package/dist/device/meter.d.ts +1 -4
- package/dist/device/meter.d.ts.map +1 -1
- package/dist/device/meter.js +7 -7
- package/dist/device/meter.js.map +1 -1
- package/dist/device/meterplus.d.ts +1 -4
- package/dist/device/meterplus.d.ts.map +1 -1
- package/dist/device/meterplus.js +7 -7
- package/dist/device/meterplus.js.map +1 -1
- package/dist/device/motion.d.ts +1 -4
- package/dist/device/motion.d.ts.map +1 -1
- package/dist/device/motion.js +7 -7
- package/dist/device/motion.js.map +1 -1
- package/dist/device/plug.d.ts +1 -4
- package/dist/device/plug.d.ts.map +1 -1
- package/dist/device/plug.js +14 -15
- package/dist/device/plug.js.map +1 -1
- package/dist/device/robotvacuumcleaner.d.ts +1 -4
- package/dist/device/robotvacuumcleaner.d.ts.map +1 -1
- package/dist/device/robotvacuumcleaner.js +21 -23
- package/dist/device/robotvacuumcleaner.js.map +1 -1
- package/dist/device/waterdetector.d.ts +1 -4
- package/dist/device/waterdetector.d.ts.map +1 -1
- package/dist/device/waterdetector.js +7 -7
- package/dist/device/waterdetector.js.map +1 -1
- package/dist/irdevice/airconditioner.d.ts +1 -1
- package/dist/irdevice/airconditioner.d.ts.map +1 -1
- package/dist/irdevice/airconditioner.js +11 -12
- package/dist/irdevice/airconditioner.js.map +1 -1
- package/dist/irdevice/airpurifier.d.ts +1 -1
- package/dist/irdevice/airpurifier.d.ts.map +1 -1
- package/dist/irdevice/airpurifier.js +11 -12
- package/dist/irdevice/airpurifier.js.map +1 -1
- package/dist/irdevice/camera.d.ts +1 -1
- package/dist/irdevice/camera.d.ts.map +1 -1
- package/dist/irdevice/camera.js +9 -10
- package/dist/irdevice/camera.js.map +1 -1
- package/dist/irdevice/fan.d.ts +1 -1
- package/dist/irdevice/fan.d.ts.map +1 -1
- package/dist/irdevice/fan.js +15 -16
- package/dist/irdevice/fan.js.map +1 -1
- package/dist/irdevice/irdevice.d.ts +6 -6
- package/dist/irdevice/irdevice.d.ts.map +1 -1
- package/dist/irdevice/irdevice.js +7 -13
- package/dist/irdevice/irdevice.js.map +1 -1
- package/dist/irdevice/light.d.ts +1 -1
- package/dist/irdevice/light.d.ts.map +1 -1
- package/dist/irdevice/light.js +9 -10
- package/dist/irdevice/light.js.map +1 -1
- package/dist/irdevice/other.d.ts +1 -1
- package/dist/irdevice/other.d.ts.map +1 -1
- package/dist/irdevice/other.js +9 -10
- package/dist/irdevice/other.js.map +1 -1
- package/dist/irdevice/tv.d.ts +1 -1
- package/dist/irdevice/tv.d.ts.map +1 -1
- package/dist/irdevice/tv.js +27 -28
- package/dist/irdevice/tv.js.map +1 -1
- package/dist/irdevice/vacuumcleaner.d.ts +1 -1
- package/dist/irdevice/vacuumcleaner.d.ts.map +1 -1
- package/dist/irdevice/vacuumcleaner.js +9 -10
- package/dist/irdevice/vacuumcleaner.js.map +1 -1
- package/dist/irdevice/waterheater.d.ts +1 -1
- package/dist/irdevice/waterheater.d.ts.map +1 -1
- package/dist/irdevice/waterheater.js +9 -10
- package/dist/irdevice/waterheater.js.map +1 -1
- package/dist/platform.d.ts +6 -14
- package/dist/platform.d.ts.map +1 -1
- package/dist/platform.js +105 -170
- package/dist/platform.js.map +1 -1
- package/dist/settings.d.ts +1 -3
- package/dist/settings.d.ts.map +1 -1
- package/dist/settings.js.map +1 -1
- package/dist/utils.d.ts +1 -1
- package/dist/utils.d.ts.map +1 -1
- package/dist/utils.js.map +1 -1
- package/docs/assets/highlight.css +42 -0
- package/docs/assets/main.js +1 -1
- package/docs/functions/default.html +1 -1
- package/docs/index.html +61 -50
- package/docs/media/security-privacy-bluetooth.png +0 -0
- package/package.json +13 -14
- package/src/device/blindtilt.ts +20 -24
- package/src/device/bot.ts +16 -20
- package/src/device/ceilinglight.ts +36 -43
- package/src/device/colorbulb.ts +36 -43
- package/src/device/contact.ts +8 -11
- package/src/device/curtain.ts +18 -22
- package/src/device/device.ts +29 -18
- package/src/device/fan.ts +33 -38
- package/src/device/hub.ts +8 -11
- package/src/device/humidifier.ts +29 -35
- package/src/device/iosensor.ts +8 -11
- package/src/device/lightstrip.ts +29 -35
- package/src/device/lock.ts +16 -20
- package/src/device/meter.ts +8 -11
- package/src/device/meterplus.ts +8 -11
- package/src/device/motion.ts +8 -11
- package/src/device/plug.ts +15 -19
- package/src/device/robotvacuumcleaner.ts +22 -31
- package/src/device/waterdetector.ts +8 -11
- package/src/irdevice/airconditioner.ts +12 -14
- package/src/irdevice/airpurifier.ts +12 -13
- package/src/irdevice/camera.ts +10 -11
- package/src/irdevice/fan.ts +16 -17
- package/src/irdevice/irdevice.ts +9 -17
- package/src/irdevice/light.ts +10 -11
- package/src/irdevice/other.ts +10 -11
- package/src/irdevice/tv.ts +28 -29
- package/src/irdevice/vacuumcleaner.ts +10 -11
- package/src/irdevice/waterheater.ts +10 -11
- package/src/platform.ts +110 -171
- package/src/settings.ts +5 -4
- package/src/utils.ts +2 -1
- package/dist/types/bledevicestatus.d.ts +0 -281
- package/dist/types/bledevicestatus.d.ts.map +0 -1
- package/dist/types/bledevicestatus.js +0 -2
- package/dist/types/bledevicestatus.js.map +0 -1
- package/dist/types/devicelist.d.ts +0 -89
- package/dist/types/devicelist.d.ts.map +0 -1
- package/dist/types/devicelist.js +0 -6
- package/dist/types/devicelist.js.map +0 -1
- package/dist/types/deviceresponse.d.ts +0 -13
- package/dist/types/deviceresponse.d.ts.map +0 -1
- package/dist/types/deviceresponse.js +0 -2
- package/dist/types/deviceresponse.js.map +0 -1
- package/dist/types/devicestatus.d.ts +0 -149
- package/dist/types/devicestatus.d.ts.map +0 -1
- package/dist/types/devicestatus.js +0 -3
- package/dist/types/devicestatus.js.map +0 -1
- package/dist/types/devicewebhookstatus.d.ts +0 -156
- package/dist/types/devicewebhookstatus.d.ts.map +0 -1
- package/dist/types/devicewebhookstatus.js +0 -2
- package/dist/types/devicewebhookstatus.js.map +0 -1
- package/dist/types/irdevicelist.d.ts +0 -10
- package/dist/types/irdevicelist.d.ts.map +0 -1
- package/dist/types/irdevicelist.js +0 -2
- package/dist/types/irdevicelist.js.map +0 -1
- package/dist/types/pushbody.d.ts +0 -6
- package/dist/types/pushbody.d.ts.map +0 -1
- package/dist/types/pushbody.js +0 -2
- package/dist/types/pushbody.js.map +0 -1
- package/src/types/bledevicestatus.ts +0 -303
- package/src/types/devicelist.ts +0 -124
- package/src/types/deviceresponse.ts +0 -14
- package/src/types/devicestatus.ts +0 -178
- package/src/types/devicewebhookstatus.ts +0 -191
- package/src/types/irdevicelist.ts +0 -15
- 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 {
|
|
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 {
|
|
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 {
|
|
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 {
|
|
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
|
|
@@ -132,6 +131,37 @@ export class SwitchBotPlatform implements DynamicPlatformPlugin {
|
|
|
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
|
+
this.switchBotAPI.on('log', (log) => {
|
|
138
|
+
switch (log.level) {
|
|
139
|
+
case LogLevel.SUCCESS:
|
|
140
|
+
this.successLog(log.message)
|
|
141
|
+
break
|
|
142
|
+
case LogLevel.DEBUGSUCCESS:
|
|
143
|
+
this.debugSuccessLog(log.message)
|
|
144
|
+
break
|
|
145
|
+
case LogLevel.WARN:
|
|
146
|
+
this.warnLog(log.message)
|
|
147
|
+
break
|
|
148
|
+
case LogLevel.DEBUGWARN:
|
|
149
|
+
this.debugWarnLog(log.message)
|
|
150
|
+
break
|
|
151
|
+
case LogLevel.ERROR:
|
|
152
|
+
this.errorLog(log.message)
|
|
153
|
+
break
|
|
154
|
+
case LogLevel.DEBUGERROR:
|
|
155
|
+
this.debugErrorLog(log.message)
|
|
156
|
+
break
|
|
157
|
+
case LogLevel.DEBUG:
|
|
158
|
+
this.debugLog(log.message)
|
|
159
|
+
break
|
|
160
|
+
case LogLevel.INFO:
|
|
161
|
+
default:
|
|
162
|
+
this.infoLog(log.message)
|
|
163
|
+
}
|
|
164
|
+
})
|
|
135
165
|
// import fakegato-history module and EVE characteristics
|
|
136
166
|
this.fakegatoAPI = fakegato(api)
|
|
137
167
|
this.eve = new EveHomeKitTypes(api)
|
|
@@ -208,121 +238,24 @@ export class SwitchBotPlatform implements DynamicPlatformPlugin {
|
|
|
208
238
|
// webhook configuration
|
|
209
239
|
if (this.config.options?.webhookURL) {
|
|
210
240
|
const url = this.config.options?.webhookURL
|
|
211
|
-
|
|
212
241
|
try {
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
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}`)
|
|
242
|
+
this.switchBotAPI.setupWebhook(url)
|
|
243
|
+
// Listen for webhook events
|
|
244
|
+
this.switchBotAPI.on('webhookEvent', (body) => {
|
|
245
|
+
if (this.config.options?.mqttURL) {
|
|
246
|
+
const mac = body.context.deviceMac?.toLowerCase().match(/[\s\S]{1,2}/g)?.join(':')
|
|
247
|
+
const options = this.config.options?.mqttPubOptions || {}
|
|
248
|
+
this.mqttClient?.publish(`homebridge-switchbot/webhook/${mac}`, `${JSON.stringify(body.context)}`, options)
|
|
242
249
|
}
|
|
243
|
-
|
|
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
|
-
}),
|
|
258
|
-
})
|
|
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
|
-
} 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
|
-
}),
|
|
250
|
+
this.webhookEventHandler[body.context.deviceMac]?.(body.context)
|
|
296
251
|
})
|
|
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
252
|
} catch (e: any) {
|
|
306
|
-
await this.errorLog(`Failed to
|
|
253
|
+
await this.errorLog(`Failed to setup webhook. Error:${e.message}`)
|
|
307
254
|
}
|
|
308
255
|
|
|
309
256
|
this.api.on('shutdown', async () => {
|
|
310
257
|
try {
|
|
311
|
-
|
|
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
|
-
}
|
|
258
|
+
this.switchBotAPI.deleteWebhook(url)
|
|
326
259
|
} catch (e: any) {
|
|
327
260
|
await this.errorLog(`Failed to delete webhook. Error:${e.message}`)
|
|
328
261
|
}
|
|
@@ -331,19 +264,52 @@ export class SwitchBotPlatform implements DynamicPlatformPlugin {
|
|
|
331
264
|
}
|
|
332
265
|
|
|
333
266
|
async setupBlE() {
|
|
267
|
+
this.switchBotBLE = new SwitchBotBLE()
|
|
268
|
+
// Listen for log events
|
|
269
|
+
this.switchBotBLE.on('log', (log) => {
|
|
270
|
+
switch (log.level) {
|
|
271
|
+
case LogLevel.SUCCESS:
|
|
272
|
+
this.successLog(log.message)
|
|
273
|
+
break
|
|
274
|
+
case LogLevel.DEBUGSUCCESS:
|
|
275
|
+
this.debugSuccessLog(log.message)
|
|
276
|
+
break
|
|
277
|
+
case LogLevel.WARN:
|
|
278
|
+
this.warnLog(log.message)
|
|
279
|
+
break
|
|
280
|
+
case LogLevel.DEBUGWARN:
|
|
281
|
+
this.debugWarnLog(log.message)
|
|
282
|
+
break
|
|
283
|
+
case LogLevel.ERROR:
|
|
284
|
+
this.errorLog(log.message)
|
|
285
|
+
break
|
|
286
|
+
case LogLevel.DEBUGERROR:
|
|
287
|
+
this.debugErrorLog(log.message)
|
|
288
|
+
break
|
|
289
|
+
case LogLevel.DEBUG:
|
|
290
|
+
this.debugLog(log.message)
|
|
291
|
+
break
|
|
292
|
+
case LogLevel.INFO:
|
|
293
|
+
default:
|
|
294
|
+
this.infoLog(log.message)
|
|
295
|
+
}
|
|
296
|
+
})
|
|
334
297
|
if (this.config.options?.BLE) {
|
|
335
298
|
await this.debugLog('setupBLE')
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
await this.errorLog(`wasn't able to establish BLE Connection, node-switchbot: ${switchbot}`)
|
|
299
|
+
if (this.switchBotBLE === undefined) {
|
|
300
|
+
await this.errorLog(`wasn't able to establish BLE Connection, node-switchbot: ${this.switchBotBLE}`)
|
|
339
301
|
} else {
|
|
340
302
|
// Start to monitor advertisement packets
|
|
341
303
|
(async () => {
|
|
342
304
|
// Start to monitor advertisement packets
|
|
343
305
|
await this.debugLog('Scanning for BLE SwitchBot devices...')
|
|
344
|
-
|
|
306
|
+
try {
|
|
307
|
+
await this.switchBotBLE.startScan()
|
|
308
|
+
} catch (e: any) {
|
|
309
|
+
await this.errorLog(`Failed to start BLE scanning. Error:${e}`)
|
|
310
|
+
}
|
|
345
311
|
// Set an event handler to monitor advertisement packets
|
|
346
|
-
|
|
312
|
+
this.switchBotBLE.onadvertisement = async (ad: any) => {
|
|
347
313
|
try {
|
|
348
314
|
this.bleEventHandler[ad.address]?.(ad.serviceData)
|
|
349
315
|
} catch (e: any) {
|
|
@@ -354,7 +320,7 @@ export class SwitchBotPlatform implements DynamicPlatformPlugin {
|
|
|
354
320
|
|
|
355
321
|
this.api.on('shutdown', async () => {
|
|
356
322
|
try {
|
|
357
|
-
|
|
323
|
+
this.switchBotBLE.stopScan()
|
|
358
324
|
await this.infoLog('Stopped BLE scanning to close listening.')
|
|
359
325
|
} catch (e: any) {
|
|
360
326
|
await this.errorLog(`Failed to stop Platform BLE scanning. Error:${e.message}`)
|
|
@@ -531,25 +497,6 @@ export class SwitchBotPlatform implements DynamicPlatformPlugin {
|
|
|
531
497
|
}
|
|
532
498
|
}
|
|
533
499
|
|
|
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',
|
|
550
|
-
}
|
|
551
|
-
}
|
|
552
|
-
|
|
553
500
|
async discoverDevices() {
|
|
554
501
|
if (!this.config.credentials?.token) {
|
|
555
502
|
return this.handleManualConfig()
|
|
@@ -565,17 +512,14 @@ export class SwitchBotPlatform implements DynamicPlatformPlugin {
|
|
|
565
512
|
|
|
566
513
|
while (retryCount < maxRetries) {
|
|
567
514
|
try {
|
|
568
|
-
const {
|
|
569
|
-
await this.
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
if (this.isSuccessfulResponse(statusCode, devicesAPI.statusCode)) {
|
|
574
|
-
await this.handleDevices(devicesAPI.body.deviceList)
|
|
575
|
-
await this.handleIRDevices(devicesAPI.body.infraredRemoteList)
|
|
515
|
+
const { response, statusCode } = await this.switchBotAPI.getDevices()
|
|
516
|
+
await this.debugLog(`response: ${JSON.stringify(response)}`)
|
|
517
|
+
if (this.isSuccessfulResponse(statusCode)) {
|
|
518
|
+
await this.handleDevices(Array.isArray(response.body.deviceList) ? response.body.deviceList : [])
|
|
519
|
+
await this.handleIRDevices(Array.isArray(response.body.infraredRemoteList) ? response.body.infraredRemoteList : [])
|
|
576
520
|
break
|
|
577
521
|
} else {
|
|
578
|
-
await this.handleErrorResponse(statusCode,
|
|
522
|
+
await this.handleErrorResponse(statusCode, retryCount, maxRetries, delayBetweenRetries)
|
|
579
523
|
retryCount++
|
|
580
524
|
}
|
|
581
525
|
} catch (e: any) {
|
|
@@ -608,8 +552,8 @@ export class SwitchBotPlatform implements DynamicPlatformPlugin {
|
|
|
608
552
|
}
|
|
609
553
|
}
|
|
610
554
|
|
|
611
|
-
private isSuccessfulResponse(
|
|
612
|
-
return (
|
|
555
|
+
private isSuccessfulResponse(apiStatusCode: number): boolean {
|
|
556
|
+
return (apiStatusCode === 200 || apiStatusCode === 100)
|
|
613
557
|
}
|
|
614
558
|
|
|
615
559
|
private async handleDevices(deviceLists: any[]) {
|
|
@@ -674,11 +618,10 @@ export class SwitchBotPlatform implements DynamicPlatformPlugin {
|
|
|
674
618
|
})
|
|
675
619
|
}
|
|
676
620
|
|
|
677
|
-
private async handleErrorResponse(
|
|
678
|
-
await this.statusCode(statusCode)
|
|
621
|
+
private async handleErrorResponse(apiStatusCode: number, retryCount: number, maxRetries: number, delayBetweenRetries: number) {
|
|
679
622
|
await this.statusCode(apiStatusCode)
|
|
680
|
-
if (
|
|
681
|
-
this.infoLog(`statusCode: ${
|
|
623
|
+
if (apiStatusCode === 500) {
|
|
624
|
+
this.infoLog(`statusCode: ${apiStatusCode} Attempt ${retryCount + 1} of ${maxRetries}`)
|
|
682
625
|
await sleep(delayBetweenRetries)
|
|
683
626
|
}
|
|
684
627
|
}
|
|
@@ -2639,18 +2582,15 @@ export class SwitchBotPlatform implements DynamicPlatformPlugin {
|
|
|
2639
2582
|
}
|
|
2640
2583
|
}
|
|
2641
2584
|
|
|
2642
|
-
async retryRequest(
|
|
2585
|
+
async retryRequest(deviceId: string, deviceMaxRetries: number, deviceDelayBetweenRetries: number): Promise<{ response: any, statusCode: number }> {
|
|
2643
2586
|
let retryCount = 0
|
|
2644
2587
|
const maxRetries = deviceMaxRetries
|
|
2645
2588
|
const delayBetweenRetries = deviceDelayBetweenRetries
|
|
2646
2589
|
while (retryCount < maxRetries) {
|
|
2647
2590
|
try {
|
|
2648
|
-
const {
|
|
2649
|
-
|
|
2650
|
-
|
|
2651
|
-
} else {
|
|
2652
|
-
await this.debugLog(`Received status code: ${statusCode}`)
|
|
2653
|
-
}
|
|
2591
|
+
const { response, statusCode } = await this.switchBotAPI.getDeviceStatus(deviceId)
|
|
2592
|
+
await this.debugLog(`response: ${JSON.stringify(response)}`)
|
|
2593
|
+
return { response, statusCode }
|
|
2654
2594
|
} catch (error: any) {
|
|
2655
2595
|
await this.errorLog(`Error making request: ${error.message}`)
|
|
2656
2596
|
}
|
|
@@ -2658,16 +2598,15 @@ export class SwitchBotPlatform implements DynamicPlatformPlugin {
|
|
|
2658
2598
|
await this.debugLog(`Retry attempt ${retryCount} of ${maxRetries}`)
|
|
2659
2599
|
await sleep(delayBetweenRetries)
|
|
2660
2600
|
}
|
|
2661
|
-
return {
|
|
2601
|
+
return { response: null, statusCode: 500 }
|
|
2662
2602
|
}
|
|
2663
2603
|
|
|
2664
2604
|
// BLE Connection
|
|
2665
2605
|
async connectBLE(accessory: PlatformAccessory, device: device & devicesConfig): Promise<any> {
|
|
2666
2606
|
try {
|
|
2667
|
-
|
|
2668
|
-
|
|
2669
|
-
|
|
2670
|
-
return switchbot
|
|
2607
|
+
queueScheduler.schedule(async () => this.switchBotBLE)
|
|
2608
|
+
await this.debugLog(`${device.deviceType}: ${accessory.displayName} 'node-switchbot' found: ${this.switchBotBLE}`)
|
|
2609
|
+
return this.switchBotBLE
|
|
2671
2610
|
} catch (e: any) {
|
|
2672
2611
|
await this.errorLog(`${device.deviceType}: ${accessory.displayName} 'node-switchbot' not found, Error: ${e}`)
|
|
2673
2612
|
return false
|
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
|
-
|
|
8
|
-
|
|
9
|
-
import type { device } from '
|
|
10
|
-
|
|
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
|
*/
|
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',
|