@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.
- package/.github/workflows/beta-release.yml +7 -4
- package/.github/workflows/release.yml +7 -6
- package/CHANGELOG.md +2 -1
- package/config.schema.json +24 -0
- package/dist/device/blindtilt.d.ts +1 -4
- package/dist/device/blindtilt.d.ts.map +1 -1
- package/dist/device/blindtilt.js +33 -34
- 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 +30 -31
- 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 +50 -54
- 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 +62 -66
- 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 +18 -18
- 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 +31 -32
- 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 +33 -17
- 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 +47 -49
- 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 +18 -18
- 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 +43 -46
- 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 +18 -18
- 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 +51 -54
- 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 +31 -32
- 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 +18 -18
- 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 +18 -18
- 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 +18 -18
- 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 +29 -30
- 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 +36 -38
- 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 +18 -18
- 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 +127 -188
- package/dist/platform.js.map +1 -1
- package/dist/settings.d.ts +4 -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 +14 -15
- package/src/device/blindtilt.ts +35 -39
- package/src/device/bot.ts +31 -35
- package/src/device/ceilinglight.ts +51 -58
- package/src/device/colorbulb.ts +63 -70
- package/src/device/contact.ts +19 -22
- package/src/device/curtain.ts +33 -37
- package/src/device/device.ts +32 -21
- package/src/device/fan.ts +48 -53
- package/src/device/hub.ts +19 -22
- package/src/device/humidifier.ts +44 -50
- package/src/device/iosensor.ts +19 -22
- package/src/device/lightstrip.ts +52 -58
- package/src/device/lock.ts +32 -36
- package/src/device/meter.ts +19 -22
- package/src/device/meterplus.ts +19 -22
- package/src/device/motion.ts +19 -22
- package/src/device/plug.ts +30 -34
- package/src/device/robotvacuumcleaner.ts +37 -46
- package/src/device/waterdetector.ts +19 -22
- 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 +131 -188
- package/src/settings.ts +8 -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
|
|
@@ -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
|
-
|
|
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}`)
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
337
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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 {
|
|
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)
|
|
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,
|
|
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(
|
|
612
|
-
return (
|
|
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(
|
|
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 (
|
|
681
|
-
this.infoLog(`statusCode: ${
|
|
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(
|
|
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 {
|
|
2649
|
-
|
|
2650
|
-
|
|
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 {
|
|
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
|
-
|
|
2668
|
-
|
|
2669
|
-
|
|
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
|
-
|
|
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
|
*/
|
|
@@ -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',
|