@switchbot/homebridge-switchbot 3.8.3 → 4.0.0-beta.1
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/npm-version-script.cjs +81 -0
- package/.github/workflows/beta-release.yml +12 -4
- package/CHANGELOG.md +15 -1
- package/config.schema.json +583 -937
- package/dist/device/blindtilt.d.ts +1 -4
- package/dist/device/blindtilt.d.ts.map +1 -1
- package/dist/device/blindtilt.js +68 -66
- 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 +63 -59
- 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 +56 -65
- 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 +73 -80
- 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 +38 -38
- 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 +60 -60
- 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 +86 -20
- 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 +50 -51
- 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 +48 -48
- 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 +53 -55
- 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 +35 -35
- 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 +57 -65
- 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 +38 -39
- 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 +35 -35
- 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 +35 -35
- 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 +27 -27
- 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 +32 -32
- 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 +39 -40
- 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 +28 -28
- 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 +31 -32
- 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 +22 -23
- 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 +28 -14
- 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 +12 -13
- 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 +12 -15
- 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 +9 -22
- package/dist/platform.d.ts.map +1 -1
- package/dist/platform.js +154 -260
- package/dist/platform.js.map +1 -1
- package/dist/settings.d.ts +64 -82
- package/dist/settings.d.ts.map +1 -1
- package/dist/settings.js +0 -20
- package/dist/settings.js.map +1 -1
- package/dist/utils.d.ts +1 -102
- package/dist/utils.d.ts.map +1 -1
- package/dist/utils.js +0 -105
- 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 +5 -7
- package/src/device/blindtilt.ts +74 -74
- package/src/device/bot.ts +68 -67
- package/src/device/ceilinglight.ts +59 -70
- package/src/device/colorbulb.ts +79 -88
- package/src/device/contact.ts +40 -43
- package/src/device/curtain.ts +66 -68
- package/src/device/device.ts +86 -40
- package/src/device/fan.ts +52 -56
- package/src/device/hub.ts +50 -53
- package/src/device/humidifier.ts +56 -61
- package/src/device/iosensor.ts +37 -40
- package/src/device/lightstrip.ts +62 -72
- package/src/device/lock.ts +41 -45
- package/src/device/meter.ts +37 -40
- package/src/device/meterplus.ts +37 -40
- package/src/device/motion.ts +29 -32
- package/src/device/plug.ts +34 -37
- package/src/device/robotvacuumcleaner.ts +41 -49
- package/src/device/waterdetector.ts +30 -33
- package/src/irdevice/airconditioner.ts +33 -35
- package/src/irdevice/airpurifier.ts +12 -13
- package/src/irdevice/camera.ts +10 -11
- package/src/irdevice/fan.ts +24 -25
- package/src/irdevice/irdevice.ts +31 -27
- package/src/irdevice/light.ts +14 -15
- package/src/irdevice/other.ts +14 -17
- 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 +178 -287
- package/src/settings.ts +67 -88
- package/src/utils.ts +2 -106
- 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
|
-
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'
|
|
10
|
+
import type { blindTiltConfig, curtainConfig, devicesConfig, irDevicesConfig, options, SwitchBotPlatformConfig } from './settings.js'
|
|
15
11
|
|
|
16
|
-
import {
|
|
17
|
-
import crypto, { randomUUID } from 'node:crypto'
|
|
18
|
-
import { readFileSync, writeFileSync } from 'node:fs'
|
|
19
|
-
import { createServer } from 'node:http'
|
|
12
|
+
import { readFileSync } from 'node:fs'
|
|
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
|
|
@@ -103,6 +102,7 @@ export class SwitchBotPlatform implements DynamicPlatformPlugin {
|
|
|
103
102
|
|
|
104
103
|
// only load if configured
|
|
105
104
|
if (!config) {
|
|
105
|
+
this.log.error('No configuration found for the plugin, please check your config.')
|
|
106
106
|
return
|
|
107
107
|
}
|
|
108
108
|
|
|
@@ -112,6 +112,8 @@ export class SwitchBotPlatform implements DynamicPlatformPlugin {
|
|
|
112
112
|
name: config.name,
|
|
113
113
|
credentials: config.credentials as object,
|
|
114
114
|
options: config.options as object,
|
|
115
|
+
devices: config.devices as { deviceId: string }[],
|
|
116
|
+
deviceConfig: config.deviceConfig as { [deviceType: string]: devicesConfig },
|
|
115
117
|
}
|
|
116
118
|
|
|
117
119
|
// Plugin Configuration
|
|
@@ -127,11 +129,51 @@ export class SwitchBotPlatform implements DynamicPlatformPlugin {
|
|
|
127
129
|
this.verifyConfig()
|
|
128
130
|
this.debugLog('Config OK')
|
|
129
131
|
} 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}`)
|
|
132
|
+
this.errorLog(`Verify Config, Error Message: ${e.message ?? e}, Submit Bugs Here: ` + 'https://tinyurl.com/SwitchBotBug')
|
|
133
|
+
this.debugErrorLog(`Verify Config, Error: ${e.message ?? e}`)
|
|
132
134
|
return
|
|
133
135
|
}
|
|
134
136
|
|
|
137
|
+
// SwitchBot OpenAPI
|
|
138
|
+
if (this.config.credentials?.token && this.config.credentials?.secret) {
|
|
139
|
+
this.switchBotAPI = new SwitchBotOpenAPI(this.config.credentials.token, this.config.credentials.secret)
|
|
140
|
+
} else {
|
|
141
|
+
this.debugErrorLog('Missing SwitchBot API credentials (token or secret).')
|
|
142
|
+
}
|
|
143
|
+
// Listen for log events
|
|
144
|
+
if (!this.config.options?.disableLogsforOpenAPI && this.switchBotAPI) {
|
|
145
|
+
this.switchBotAPI.on('log', (log) => {
|
|
146
|
+
switch (log.level) {
|
|
147
|
+
case LogLevel.SUCCESS:
|
|
148
|
+
this.successLog(log.message)
|
|
149
|
+
break
|
|
150
|
+
case LogLevel.DEBUGSUCCESS:
|
|
151
|
+
this.debugSuccessLog(log.message)
|
|
152
|
+
break
|
|
153
|
+
case LogLevel.WARN:
|
|
154
|
+
this.warnLog(log.message)
|
|
155
|
+
break
|
|
156
|
+
case LogLevel.DEBUGWARN:
|
|
157
|
+
this.debugWarnLog(log.message)
|
|
158
|
+
break
|
|
159
|
+
case LogLevel.ERROR:
|
|
160
|
+
this.errorLog(log.message)
|
|
161
|
+
break
|
|
162
|
+
case LogLevel.DEBUGERROR:
|
|
163
|
+
this.debugErrorLog(log.message)
|
|
164
|
+
break
|
|
165
|
+
case LogLevel.DEBUG:
|
|
166
|
+
this.debugLog(log.message)
|
|
167
|
+
break
|
|
168
|
+
case LogLevel.INFO:
|
|
169
|
+
default:
|
|
170
|
+
this.infoLog(log.message)
|
|
171
|
+
}
|
|
172
|
+
})
|
|
173
|
+
} else {
|
|
174
|
+
this.debugErrorLog(`SwitchBot OpenAPI logs are disabled, enable it by setting disableLogsforOpenAPI to false.`)
|
|
175
|
+
this.debugLog(`SwitchBot OpenAPI: ${JSON.stringify(this.switchBotAPI)}, disableLogsforOpenAPI: ${this.config.options?.disableLogsforOpenAPI}`)
|
|
176
|
+
}
|
|
135
177
|
// import fakegato-history module and EVE characteristics
|
|
136
178
|
this.fakegatoAPI = fakegato(api)
|
|
137
179
|
this.eve = new EveHomeKitTypes(api)
|
|
@@ -144,33 +186,27 @@ export class SwitchBotPlatform implements DynamicPlatformPlugin {
|
|
|
144
186
|
await this.debugLog('Executed didFinishLaunching callback')
|
|
145
187
|
// run the method to discover / register your devices as accessories
|
|
146
188
|
try {
|
|
147
|
-
|
|
148
|
-
await this.updateToken()
|
|
149
|
-
} else if (this.config.credentials?.token && !this.config.credentials?.secret) {
|
|
150
|
-
await this.errorLog('"secret" config is not populated, you must populate then please restart Homebridge.')
|
|
151
|
-
} else {
|
|
152
|
-
await this.discoverDevices()
|
|
153
|
-
}
|
|
189
|
+
await this.discoverDevices()
|
|
154
190
|
} 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}`)
|
|
191
|
+
await this.errorLog(`Failed to Discover, Error Message: ${e.message ?? e}, Submit Bugs Here: ` + 'https://tinyurl.com/SwitchBotBug')
|
|
192
|
+
await this.debugErrorLog(`Failed to Discover, Error: ${e.message ?? e}`)
|
|
157
193
|
}
|
|
158
194
|
})
|
|
159
195
|
|
|
160
196
|
try {
|
|
161
197
|
this.setupMqtt()
|
|
162
198
|
} catch (e: any) {
|
|
163
|
-
this.errorLog(`Setup MQTT, Error Message: ${e.message}, Submit Bugs Here: ` + 'https://tinyurl.com/SwitchBotBug')
|
|
199
|
+
this.errorLog(`Setup MQTT, Error Message: ${e.message ?? e}, Submit Bugs Here: ` + 'https://tinyurl.com/SwitchBotBug')
|
|
164
200
|
}
|
|
165
201
|
try {
|
|
166
202
|
this.setupwebhook()
|
|
167
203
|
} catch (e: any) {
|
|
168
|
-
this.errorLog(`Setup Webhook, Error Message: ${e.message}, Submit Bugs Here: ` + 'https://tinyurl.com/SwitchBotBug')
|
|
204
|
+
this.errorLog(`Setup Webhook, Error Message: ${e.message ?? e}, Submit Bugs Here: ` + 'https://tinyurl.com/SwitchBotBug')
|
|
169
205
|
}
|
|
170
206
|
try {
|
|
171
207
|
this.setupBlE()
|
|
172
208
|
} catch (e: any) {
|
|
173
|
-
this.errorLog(`Setup Platform BLE, Error Message: ${e.message}, Submit Bugs Here: ` + 'https://tinyurl.com/SwitchBotBug')
|
|
209
|
+
this.errorLog(`Setup Platform BLE, Error Message: ${e.message ?? e}, Submit Bugs Here: ` + 'https://tinyurl.com/SwitchBotBug')
|
|
174
210
|
}
|
|
175
211
|
}
|
|
176
212
|
|
|
@@ -181,7 +217,7 @@ export class SwitchBotPlatform implements DynamicPlatformPlugin {
|
|
|
181
217
|
this.mqttClient = await connectAsync(this.config.options?.mqttURL, this.config.options.mqttOptions || {})
|
|
182
218
|
await this.debugLog('MQTT connection has been established successfully.')
|
|
183
219
|
this.mqttClient.on('error', async (e: Error) => {
|
|
184
|
-
await this.errorLog(`Failed to publish MQTT messages. ${e}`)
|
|
220
|
+
await this.errorLog(`Failed to publish MQTT messages. ${e.message ?? e}`)
|
|
185
221
|
})
|
|
186
222
|
if (!this.config.options?.webhookURL) {
|
|
187
223
|
// receive webhook events via MQTT
|
|
@@ -193,13 +229,13 @@ export class SwitchBotPlatform implements DynamicPlatformPlugin {
|
|
|
193
229
|
const context = JSON.parse(message.toString())
|
|
194
230
|
this.webhookEventHandler[context.deviceMac]?.(context)
|
|
195
231
|
} catch (e: any) {
|
|
196
|
-
await this.errorLog(`Failed to handle webhook event. Error:${e}`)
|
|
232
|
+
await this.errorLog(`Failed to handle webhook event. Error:${e.message ?? e}`)
|
|
197
233
|
}
|
|
198
234
|
})
|
|
199
235
|
}
|
|
200
|
-
} catch (e) {
|
|
236
|
+
} catch (e: any) {
|
|
201
237
|
this.mqttClient = null
|
|
202
|
-
await this.errorLog(`Failed to establish MQTT connection. ${e}`)
|
|
238
|
+
await this.errorLog(`Failed to establish MQTT connection. ${e.message ?? e}`)
|
|
203
239
|
}
|
|
204
240
|
}
|
|
205
241
|
}
|
|
@@ -208,156 +244,94 @@ export class SwitchBotPlatform implements DynamicPlatformPlugin {
|
|
|
208
244
|
// webhook configuration
|
|
209
245
|
if (this.config.options?.webhookURL) {
|
|
210
246
|
const url = this.config.options?.webhookURL
|
|
211
|
-
|
|
212
247
|
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}`)
|
|
248
|
+
this.switchBotAPI.setupWebhook(url)
|
|
249
|
+
// Listen for webhook events
|
|
250
|
+
this.switchBotAPI.on('webhookEvent', (body) => {
|
|
251
|
+
if (this.config.options?.mqttURL) {
|
|
252
|
+
const mac = body.context.deviceMac?.toLowerCase().match(/[\s\S]{1,2}/g)?.join(':')
|
|
253
|
+
const options = this.config.options?.mqttPubOptions || {}
|
|
254
|
+
this.mqttClient?.publish(`homebridge-switchbot/webhook/${mac}`, `${JSON.stringify(body.context)}`, options)
|
|
242
255
|
}
|
|
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
|
-
}),
|
|
256
|
+
this.webhookEventHandler[body.context.deviceMac]?.(body.context)
|
|
258
257
|
})
|
|
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
258
|
} 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}`)
|
|
259
|
+
await this.errorLog(`Failed to setup webhook. Error:${e.message ?? e}`)
|
|
307
260
|
}
|
|
308
261
|
|
|
309
262
|
this.api.on('shutdown', async () => {
|
|
310
263
|
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
|
-
}
|
|
264
|
+
this.switchBotAPI.deleteWebhook(url)
|
|
326
265
|
} catch (e: any) {
|
|
327
|
-
await this.errorLog(`Failed to delete webhook. Error:${e.message}`)
|
|
266
|
+
await this.errorLog(`Failed to delete webhook. Error:${e.message ?? e}`)
|
|
328
267
|
}
|
|
329
268
|
})
|
|
330
269
|
}
|
|
331
270
|
}
|
|
332
271
|
|
|
333
272
|
async setupBlE() {
|
|
273
|
+
this.switchBotBLE = new SwitchBotBLE()
|
|
274
|
+
// Listen for log events
|
|
275
|
+
if (!this.config.options?.disableLogsforBLE) {
|
|
276
|
+
this.switchBotBLE.on('log', (log) => {
|
|
277
|
+
switch (log.level) {
|
|
278
|
+
case LogLevel.SUCCESS:
|
|
279
|
+
this.successLog(log.message)
|
|
280
|
+
break
|
|
281
|
+
case LogLevel.DEBUGSUCCESS:
|
|
282
|
+
this.debugSuccessLog(log.message)
|
|
283
|
+
break
|
|
284
|
+
case LogLevel.WARN:
|
|
285
|
+
this.warnLog(log.message)
|
|
286
|
+
break
|
|
287
|
+
case LogLevel.DEBUGWARN:
|
|
288
|
+
this.debugWarnLog(log.message)
|
|
289
|
+
break
|
|
290
|
+
case LogLevel.ERROR:
|
|
291
|
+
this.errorLog(log.message)
|
|
292
|
+
break
|
|
293
|
+
case LogLevel.DEBUGERROR:
|
|
294
|
+
this.debugErrorLog(log.message)
|
|
295
|
+
break
|
|
296
|
+
case LogLevel.DEBUG:
|
|
297
|
+
this.debugLog(log.message)
|
|
298
|
+
break
|
|
299
|
+
case LogLevel.INFO:
|
|
300
|
+
default:
|
|
301
|
+
this.infoLog(log.message)
|
|
302
|
+
}
|
|
303
|
+
})
|
|
304
|
+
}
|
|
334
305
|
if (this.config.options?.BLE) {
|
|
335
306
|
await this.debugLog('setupBLE')
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
await this.errorLog(`wasn't able to establish BLE Connection, node-switchbot: ${switchbot}`)
|
|
307
|
+
if (this.switchBotBLE === undefined) {
|
|
308
|
+
await this.errorLog(`wasn't able to establish BLE Connection, node-switchbot: ${JSON.stringify(this.switchBotBLE)}`)
|
|
339
309
|
} else {
|
|
340
310
|
// Start to monitor advertisement packets
|
|
341
311
|
(async () => {
|
|
342
312
|
// Start to monitor advertisement packets
|
|
343
313
|
await this.debugLog('Scanning for BLE SwitchBot devices...')
|
|
344
|
-
|
|
314
|
+
try {
|
|
315
|
+
await this.switchBotBLE.startScan()
|
|
316
|
+
} catch (e: any) {
|
|
317
|
+
await this.errorLog(`Failed to start BLE scanning. Error:${e.message ?? e}`)
|
|
318
|
+
}
|
|
345
319
|
// Set an event handler to monitor advertisement packets
|
|
346
|
-
|
|
320
|
+
this.switchBotBLE.onadvertisement = async (ad: any) => {
|
|
347
321
|
try {
|
|
348
322
|
this.bleEventHandler[ad.address]?.(ad.serviceData)
|
|
349
323
|
} catch (e: any) {
|
|
350
|
-
await this.errorLog(`Failed to handle BLE event. Error:${e}`)
|
|
324
|
+
await this.errorLog(`Failed to handle BLE event. Error:${e.message ?? e}`)
|
|
351
325
|
}
|
|
352
326
|
}
|
|
353
327
|
})()
|
|
354
328
|
|
|
355
329
|
this.api.on('shutdown', async () => {
|
|
356
330
|
try {
|
|
357
|
-
|
|
331
|
+
// this.switchBotBLE.stopScan()
|
|
358
332
|
await this.infoLog('Stopped BLE scanning to close listening.')
|
|
359
333
|
} catch (e: any) {
|
|
360
|
-
await this.errorLog(`Failed to stop Platform BLE scanning. Error:${e.message}`)
|
|
334
|
+
await this.errorLog(`Failed to stop Platform BLE scanning. Error:${e.message ?? e}`)
|
|
361
335
|
}
|
|
362
336
|
})
|
|
363
337
|
}
|
|
@@ -408,7 +382,7 @@ export class SwitchBotPlatform implements DynamicPlatformPlugin {
|
|
|
408
382
|
if (!deviceConfig.deviceId) {
|
|
409
383
|
throw new Error('The devices config section is missing the *Device ID* in the config. Please check your config.')
|
|
410
384
|
}
|
|
411
|
-
if (!deviceConfig.configDeviceType && deviceConfig.connectionType) {
|
|
385
|
+
if (!deviceConfig.configDeviceType && (deviceConfig as devicesConfig).connectionType) {
|
|
412
386
|
throw new Error('The devices config section is missing the *Device Type* in the config. Please check your config.')
|
|
413
387
|
}
|
|
414
388
|
}
|
|
@@ -477,79 +451,6 @@ export class SwitchBotPlatform implements DynamicPlatformPlugin {
|
|
|
477
451
|
}
|
|
478
452
|
}
|
|
479
453
|
|
|
480
|
-
/**
|
|
481
|
-
* The openToken was old config.
|
|
482
|
-
* This method saves the openToken as the token in the config.json file
|
|
483
|
-
*/
|
|
484
|
-
async updateToken() {
|
|
485
|
-
try {
|
|
486
|
-
// check the new token was provided
|
|
487
|
-
if (!this.config.credentials?.openToken) {
|
|
488
|
-
throw new Error('New token not provided')
|
|
489
|
-
}
|
|
490
|
-
|
|
491
|
-
// load in the current config
|
|
492
|
-
const currentConfig = JSON.parse(readFileSync(this.api.user.configPath(), 'utf8'))
|
|
493
|
-
|
|
494
|
-
// check the platforms section is an array before we do array things on it
|
|
495
|
-
if (!Array.isArray(currentConfig.platforms)) {
|
|
496
|
-
throw new TypeError('Cannot find platforms array in config')
|
|
497
|
-
}
|
|
498
|
-
|
|
499
|
-
// find this plugins current config
|
|
500
|
-
const pluginConfig = currentConfig.platforms.find((x: { platform: string }) => x.platform === PLATFORM_NAME)
|
|
501
|
-
|
|
502
|
-
if (!pluginConfig) {
|
|
503
|
-
throw new Error(`Cannot find config for ${PLATFORM_NAME} in platforms array`)
|
|
504
|
-
}
|
|
505
|
-
|
|
506
|
-
// check the .credentials is an object before doing object things with it
|
|
507
|
-
if (typeof pluginConfig.credentials !== 'object') {
|
|
508
|
-
throw new TypeError('pluginConfig.credentials is not an object')
|
|
509
|
-
}
|
|
510
|
-
// Move openToken to token
|
|
511
|
-
if (!this.config.credentials.secret) {
|
|
512
|
-
await this.warnLog('This plugin has been updated to use OpenAPI v1.1, config is set with openToken, "openToken" cconfig has been moved to the "token" config')
|
|
513
|
-
this.errorLog('"secret" config is not populated, you must populate then please restart Homebridge.')
|
|
514
|
-
} else {
|
|
515
|
-
await this.warnLog('This plugin has been updated to use OpenAPI v1.1, config is set with openToken, "openToken" config has been moved to the "token" config, please restart Homebridge.')
|
|
516
|
-
}
|
|
517
|
-
|
|
518
|
-
// set the refresh token
|
|
519
|
-
pluginConfig.credentials.token = this.config.credentials?.openToken
|
|
520
|
-
if (pluginConfig.credentials.token) {
|
|
521
|
-
pluginConfig.credentials.openToken = undefined
|
|
522
|
-
}
|
|
523
|
-
|
|
524
|
-
await this.debugWarnLog(`token: ${pluginConfig.credentials.token}`)
|
|
525
|
-
|
|
526
|
-
// save the config, ensuring we maintain pretty json
|
|
527
|
-
writeFileSync(this.api.user.configPath(), JSON.stringify(currentConfig, null, 4))
|
|
528
|
-
await this.verifyConfig()
|
|
529
|
-
} 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',
|
|
550
|
-
}
|
|
551
|
-
}
|
|
552
|
-
|
|
553
454
|
async discoverDevices() {
|
|
554
455
|
if (!this.config.credentials?.token) {
|
|
555
456
|
return this.handleManualConfig()
|
|
@@ -565,23 +466,20 @@ export class SwitchBotPlatform implements DynamicPlatformPlugin {
|
|
|
565
466
|
|
|
566
467
|
while (retryCount < maxRetries) {
|
|
567
468
|
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)
|
|
469
|
+
const { response, statusCode } = await this.switchBotAPI.getDevices()
|
|
470
|
+
await this.debugLog(`response: ${JSON.stringify(response)}`)
|
|
471
|
+
if (this.isSuccessfulResponse(statusCode)) {
|
|
472
|
+
await this.handleDevices(Array.isArray(response.body.deviceList) ? response.body.deviceList : [])
|
|
473
|
+
await this.handleIRDevices(Array.isArray(response.body.infraredRemoteList) ? response.body.infraredRemoteList : [])
|
|
576
474
|
break
|
|
577
475
|
} else {
|
|
578
|
-
await this.handleErrorResponse(statusCode,
|
|
476
|
+
await this.handleErrorResponse(statusCode, retryCount, maxRetries, delayBetweenRetries)
|
|
579
477
|
retryCount++
|
|
580
478
|
}
|
|
581
479
|
} catch (e: any) {
|
|
582
480
|
retryCount++
|
|
583
481
|
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}`)
|
|
482
|
+
await this.debugErrorLog(`Failed to Discover Devices, Error: ${e.message ?? e}`)
|
|
585
483
|
}
|
|
586
484
|
}
|
|
587
485
|
}
|
|
@@ -608,8 +506,8 @@ export class SwitchBotPlatform implements DynamicPlatformPlugin {
|
|
|
608
506
|
}
|
|
609
507
|
}
|
|
610
508
|
|
|
611
|
-
private isSuccessfulResponse(
|
|
612
|
-
return (
|
|
509
|
+
private isSuccessfulResponse(apiStatusCode: number): boolean {
|
|
510
|
+
return (apiStatusCode === 200 || apiStatusCode === 100)
|
|
613
511
|
}
|
|
614
512
|
|
|
615
513
|
private async handleDevices(deviceLists: any[]) {
|
|
@@ -674,11 +572,10 @@ export class SwitchBotPlatform implements DynamicPlatformPlugin {
|
|
|
674
572
|
})
|
|
675
573
|
}
|
|
676
574
|
|
|
677
|
-
private async handleErrorResponse(
|
|
678
|
-
await this.statusCode(statusCode)
|
|
575
|
+
private async handleErrorResponse(apiStatusCode: number, retryCount: number, maxRetries: number, delayBetweenRetries: number) {
|
|
679
576
|
await this.statusCode(apiStatusCode)
|
|
680
|
-
if (
|
|
681
|
-
this.infoLog(`statusCode: ${
|
|
577
|
+
if (apiStatusCode === 500) {
|
|
578
|
+
this.infoLog(`statusCode: ${apiStatusCode} Attempt ${retryCount + 1} of ${maxRetries}`)
|
|
682
579
|
await sleep(delayBetweenRetries)
|
|
683
580
|
}
|
|
684
581
|
}
|
|
@@ -728,9 +625,9 @@ export class SwitchBotPlatform implements DynamicPlatformPlugin {
|
|
|
728
625
|
}
|
|
729
626
|
}
|
|
730
627
|
|
|
731
|
-
private async createIRDevice(device: irdevice &
|
|
628
|
+
private async createIRDevice(device: irdevice & irDevicesConfig) {
|
|
732
629
|
device.connectionType = device.connectionType ?? 'OpenAPI'
|
|
733
|
-
const deviceTypeHandlers: { [key: string]: (device: irdevice &
|
|
630
|
+
const deviceTypeHandlers: { [key: string]: (device: irdevice & irDevicesConfig) => Promise<void> } = {
|
|
734
631
|
'TV': this.createTV.bind(this),
|
|
735
632
|
'DIY TV': this.createTV.bind(this),
|
|
736
633
|
'Projector': this.createTV.bind(this),
|
|
@@ -1355,14 +1252,14 @@ export class SwitchBotPlatform implements DynamicPlatformPlugin {
|
|
|
1355
1252
|
this.api.updatePlatformAccessories([existingAccessory])
|
|
1356
1253
|
// create the accessory handler for the restored accessory
|
|
1357
1254
|
// this is imported from `platformAccessory.ts`
|
|
1358
|
-
new BlindTilt(this, existingAccessory, device)
|
|
1255
|
+
new BlindTilt(this, existingAccessory, device as blindTiltConfig)
|
|
1359
1256
|
await this.debugLog(`${device.deviceType} uuid: ${device.deviceId}-${device.deviceType}, (${existingAccessory.UUID})`)
|
|
1360
1257
|
} else {
|
|
1361
1258
|
this.unregisterPlatformAccessories(existingAccessory)
|
|
1362
1259
|
}
|
|
1363
1260
|
} else if (await this.registerDevice(device)) {
|
|
1364
1261
|
if (isBlindTiltDevice(device)) {
|
|
1365
|
-
if (device.group && !device.
|
|
1262
|
+
if (device.group && !(device as blindTiltConfig | curtainConfig).disable_group) {
|
|
1366
1263
|
this.debugLog(
|
|
1367
1264
|
'Your Curtains are grouped, '
|
|
1368
1265
|
+ `, Secondary curtain automatically hidden. Main Curtain: ${device.deviceName}, deviceId: ${device.deviceId}`,
|
|
@@ -1397,7 +1294,7 @@ export class SwitchBotPlatform implements DynamicPlatformPlugin {
|
|
|
1397
1294
|
await this.infoLog(`${newOrExternal} accessory: ${accessory.displayName} deviceId: ${device.deviceId}`)
|
|
1398
1295
|
// create the accessory handler for the newly create accessory
|
|
1399
1296
|
// this is imported from `platformAccessory.ts`
|
|
1400
|
-
new BlindTilt(this, accessory, device)
|
|
1297
|
+
new BlindTilt(this, accessory, device as blindTiltConfig)
|
|
1401
1298
|
await this.debugLog(`${device.deviceType} uuid: ${device.deviceId}-${device.deviceType}, (${accessory.UUID})`)
|
|
1402
1299
|
|
|
1403
1300
|
// publish device externally or link the accessory to your platform
|
|
@@ -1432,14 +1329,14 @@ export class SwitchBotPlatform implements DynamicPlatformPlugin {
|
|
|
1432
1329
|
this.api.updatePlatformAccessories([existingAccessory])
|
|
1433
1330
|
// create the accessory handler for the restored accessory
|
|
1434
1331
|
// this is imported from `platformAccessory.ts`
|
|
1435
|
-
new Curtain(this, existingAccessory, device)
|
|
1332
|
+
new Curtain(this, existingAccessory, device as curtainConfig)
|
|
1436
1333
|
await this.debugLog(`${device.deviceType} uuid: ${device.deviceId}-${device.deviceType}, (${existingAccessory.UUID})`)
|
|
1437
1334
|
} else {
|
|
1438
1335
|
this.unregisterPlatformAccessories(existingAccessory)
|
|
1439
1336
|
}
|
|
1440
1337
|
} else if (await this.registerDevice(device)) {
|
|
1441
1338
|
if (isCurtainDevice(device)) {
|
|
1442
|
-
if (device.group && !device.
|
|
1339
|
+
if (device.group && !(device as blindTiltConfig | curtainConfig).disable_group) {
|
|
1443
1340
|
this.debugLog(
|
|
1444
1341
|
'Your Curtains are grouped, '
|
|
1445
1342
|
+ `, Secondary curtain automatically hidden. Main Curtain: ${device.deviceName}, deviceId: ${device.deviceId}`,
|
|
@@ -1474,7 +1371,7 @@ export class SwitchBotPlatform implements DynamicPlatformPlugin {
|
|
|
1474
1371
|
await this.infoLog(`${newOrExternal} accessory: ${accessory.displayName} deviceId: ${device.deviceId}`)
|
|
1475
1372
|
// create the accessory handler for the newly create accessory
|
|
1476
1373
|
// this is imported from `platformAccessory.ts`
|
|
1477
|
-
new Curtain(this, accessory, device)
|
|
1374
|
+
new Curtain(this, accessory, device as curtainConfig)
|
|
1478
1375
|
await this.debugLog(`${device.deviceType} uuid: ${device.deviceId}-${device.deviceType}, (${accessory.UUID})`)
|
|
1479
1376
|
|
|
1480
1377
|
// publish device externally or link the accessory to your platform
|
|
@@ -1947,7 +1844,7 @@ export class SwitchBotPlatform implements DynamicPlatformPlugin {
|
|
|
1947
1844
|
}
|
|
1948
1845
|
}
|
|
1949
1846
|
|
|
1950
|
-
private async createTV(device: irdevice &
|
|
1847
|
+
private async createTV(device: irdevice & irDevicesConfig) {
|
|
1951
1848
|
const uuid = this.api.hap.uuid.generate(`${device.deviceId}-${device.remoteType}`)
|
|
1952
1849
|
|
|
1953
1850
|
// see if an accessory with the same uuid has already been registered and restored from
|
|
@@ -1986,7 +1883,7 @@ export class SwitchBotPlatform implements DynamicPlatformPlugin {
|
|
|
1986
1883
|
? await this.validateAndCleanDisplayName(device.configDeviceName, 'configDeviceName', device.configDeviceName)
|
|
1987
1884
|
: await this.validateAndCleanDisplayName(device.deviceName, 'deviceName', device.deviceName)
|
|
1988
1885
|
accessory.context.connectionType = await this.connectionType(device)
|
|
1989
|
-
accessory.context.version = device.firmware ??
|
|
1886
|
+
accessory.context.version = device.firmware ?? this.version ?? '0.0.0'
|
|
1990
1887
|
const newOrExternal = !device.external ? 'Adding new' : 'Loading external'
|
|
1991
1888
|
await this.infoLog(`${newOrExternal} accessory: ${accessory.displayName} deviceId: ${device.deviceId}`)
|
|
1992
1889
|
// create the accessory handler for the newly create accessory
|
|
@@ -2001,7 +1898,7 @@ export class SwitchBotPlatform implements DynamicPlatformPlugin {
|
|
|
2001
1898
|
}
|
|
2002
1899
|
}
|
|
2003
1900
|
|
|
2004
|
-
private async createIRFan(device: irdevice &
|
|
1901
|
+
private async createIRFan(device: irdevice & irDevicesConfig) {
|
|
2005
1902
|
const uuid = this.api.hap.uuid.generate(`${device.deviceId}-${device.remoteType}`)
|
|
2006
1903
|
|
|
2007
1904
|
// see if an accessory with the same uuid has already been registered and restored from
|
|
@@ -2045,7 +1942,7 @@ export class SwitchBotPlatform implements DynamicPlatformPlugin {
|
|
|
2045
1942
|
? await this.validateAndCleanDisplayName(device.configDeviceName, 'configDeviceName', device.configDeviceName)
|
|
2046
1943
|
: await this.validateAndCleanDisplayName(device.deviceName, 'deviceName', device.deviceName)
|
|
2047
1944
|
accessory.context.connectionType = await this.connectionType(device)
|
|
2048
|
-
accessory.context.version = device.firmware ??
|
|
1945
|
+
accessory.context.version = device.firmware ?? this.version ?? '0.0.0'
|
|
2049
1946
|
const newOrExternal = !device.external ? 'Adding new' : 'Loading external'
|
|
2050
1947
|
await this.infoLog(`${newOrExternal} accessory: ${accessory.displayName} deviceId: ${device.deviceId}`)
|
|
2051
1948
|
// create the accessory handler for the newly create accessory
|
|
@@ -2061,7 +1958,7 @@ export class SwitchBotPlatform implements DynamicPlatformPlugin {
|
|
|
2061
1958
|
}
|
|
2062
1959
|
}
|
|
2063
1960
|
|
|
2064
|
-
private async createLight(device: irdevice &
|
|
1961
|
+
private async createLight(device: irdevice & irDevicesConfig) {
|
|
2065
1962
|
const uuid = this.api.hap.uuid.generate(`${device.deviceId}-${device.remoteType}`)
|
|
2066
1963
|
|
|
2067
1964
|
// see if an accessory with the same uuid has already been registered and restored from
|
|
@@ -2105,7 +2002,7 @@ export class SwitchBotPlatform implements DynamicPlatformPlugin {
|
|
|
2105
2002
|
? await this.validateAndCleanDisplayName(device.configDeviceName, 'configDeviceName', device.configDeviceName)
|
|
2106
2003
|
: await this.validateAndCleanDisplayName(device.deviceName, 'deviceName', device.deviceName)
|
|
2107
2004
|
accessory.context.connectionType = await this.connectionType(device)
|
|
2108
|
-
accessory.context.version = device.firmware ??
|
|
2005
|
+
accessory.context.version = device.firmware ?? this.version ?? '0.0.0'
|
|
2109
2006
|
const newOrExternal = !device.external ? 'Adding new' : 'Loading external'
|
|
2110
2007
|
await this.infoLog(`${newOrExternal} accessory: ${accessory.displayName} deviceId: ${device.deviceId}`)
|
|
2111
2008
|
// create the accessory handler for the newly create accessory
|
|
@@ -2121,7 +2018,7 @@ export class SwitchBotPlatform implements DynamicPlatformPlugin {
|
|
|
2121
2018
|
}
|
|
2122
2019
|
}
|
|
2123
2020
|
|
|
2124
|
-
private async createAirConditioner(device: irdevice &
|
|
2021
|
+
private async createAirConditioner(device: irdevice & irDevicesConfig) {
|
|
2125
2022
|
const uuid = this.api.hap.uuid.generate(`${device.deviceId}-${device.remoteType}`)
|
|
2126
2023
|
|
|
2127
2024
|
// see if an accessory with the same uuid has already been registered and restored from
|
|
@@ -2165,7 +2062,7 @@ export class SwitchBotPlatform implements DynamicPlatformPlugin {
|
|
|
2165
2062
|
? await this.validateAndCleanDisplayName(device.configDeviceName, 'configDeviceName', device.configDeviceName)
|
|
2166
2063
|
: await this.validateAndCleanDisplayName(device.deviceName, 'deviceName', device.deviceName)
|
|
2167
2064
|
accessory.context.connectionType = await this.connectionType(device)
|
|
2168
|
-
accessory.context.version = device.firmware ??
|
|
2065
|
+
accessory.context.version = device.firmware ?? this.version ?? '0.0.0'
|
|
2169
2066
|
const newOrExternal = !device.external ? 'Adding new' : 'Loading external'
|
|
2170
2067
|
await this.infoLog(`${newOrExternal} accessory: ${accessory.displayName} deviceId: ${device.deviceId}`)
|
|
2171
2068
|
// create the accessory handler for the newly create accessory
|
|
@@ -2181,7 +2078,7 @@ export class SwitchBotPlatform implements DynamicPlatformPlugin {
|
|
|
2181
2078
|
}
|
|
2182
2079
|
}
|
|
2183
2080
|
|
|
2184
|
-
private async createAirPurifier(device: irdevice &
|
|
2081
|
+
private async createAirPurifier(device: irdevice & irDevicesConfig) {
|
|
2185
2082
|
const uuid = this.api.hap.uuid.generate(`${device.deviceId}-${device.remoteType}`)
|
|
2186
2083
|
|
|
2187
2084
|
// see if an accessory with the same uuid has already been registered and restored from
|
|
@@ -2225,7 +2122,7 @@ export class SwitchBotPlatform implements DynamicPlatformPlugin {
|
|
|
2225
2122
|
? await this.validateAndCleanDisplayName(device.configDeviceName, 'configDeviceName', device.configDeviceName)
|
|
2226
2123
|
: await this.validateAndCleanDisplayName(device.deviceName, 'deviceName', device.deviceName)
|
|
2227
2124
|
accessory.context.connectionType = await this.connectionType(device)
|
|
2228
|
-
accessory.context.version = device.firmware ??
|
|
2125
|
+
accessory.context.version = device.firmware ?? this.version ?? '0.0.0'
|
|
2229
2126
|
const newOrExternal = !device.external ? 'Adding new' : 'Loading external'
|
|
2230
2127
|
await this.infoLog(`${newOrExternal} accessory: ${accessory.displayName} deviceId: ${device.deviceId}`)
|
|
2231
2128
|
// create the accessory handler for the newly create accessory
|
|
@@ -2241,7 +2138,7 @@ export class SwitchBotPlatform implements DynamicPlatformPlugin {
|
|
|
2241
2138
|
}
|
|
2242
2139
|
}
|
|
2243
2140
|
|
|
2244
|
-
private async createWaterHeater(device: irdevice &
|
|
2141
|
+
private async createWaterHeater(device: irdevice & irDevicesConfig) {
|
|
2245
2142
|
const uuid = this.api.hap.uuid.generate(`${device.deviceId}-${device.remoteType}`)
|
|
2246
2143
|
|
|
2247
2144
|
// see if an accessory with the same uuid has already been registered and restored from
|
|
@@ -2285,7 +2182,7 @@ export class SwitchBotPlatform implements DynamicPlatformPlugin {
|
|
|
2285
2182
|
? await this.validateAndCleanDisplayName(device.configDeviceName, 'configDeviceName', device.configDeviceName)
|
|
2286
2183
|
: await this.validateAndCleanDisplayName(device.deviceName, 'deviceName', device.deviceName)
|
|
2287
2184
|
accessory.context.connectionType = await this.connectionType(device)
|
|
2288
|
-
accessory.context.version = device.firmware ??
|
|
2185
|
+
accessory.context.version = device.firmware ?? this.version ?? '0.0.0'
|
|
2289
2186
|
const newOrExternal = !device.external ? 'Adding new' : 'Loading external'
|
|
2290
2187
|
await this.infoLog(`${newOrExternal} accessory: ${accessory.displayName} deviceId: ${device.deviceId}`)
|
|
2291
2188
|
// create the accessory handler for the newly create accessory
|
|
@@ -2301,7 +2198,7 @@ export class SwitchBotPlatform implements DynamicPlatformPlugin {
|
|
|
2301
2198
|
}
|
|
2302
2199
|
}
|
|
2303
2200
|
|
|
2304
|
-
private async createVacuumCleaner(device: irdevice &
|
|
2201
|
+
private async createVacuumCleaner(device: irdevice & irDevicesConfig) {
|
|
2305
2202
|
const uuid = this.api.hap.uuid.generate(`${device.deviceId}-${device.remoteType}`)
|
|
2306
2203
|
|
|
2307
2204
|
// see if an accessory with the same uuid has already been registered and restored from
|
|
@@ -2345,7 +2242,7 @@ export class SwitchBotPlatform implements DynamicPlatformPlugin {
|
|
|
2345
2242
|
? await this.validateAndCleanDisplayName(device.configDeviceName, 'configDeviceName', device.configDeviceName)
|
|
2346
2243
|
: await this.validateAndCleanDisplayName(device.deviceName, 'deviceName', device.deviceName)
|
|
2347
2244
|
accessory.context.connectionType = await this.connectionType(device)
|
|
2348
|
-
accessory.context.version = device.firmware ??
|
|
2245
|
+
accessory.context.version = device.firmware ?? this.version ?? '0.0.0'
|
|
2349
2246
|
const newOrExternal = !device.external ? 'Adding new' : 'Loading external'
|
|
2350
2247
|
await this.infoLog(`${newOrExternal} accessory: ${accessory.displayName} deviceId: ${device.deviceId}`)
|
|
2351
2248
|
// create the accessory handler for the newly create accessory
|
|
@@ -2361,7 +2258,7 @@ export class SwitchBotPlatform implements DynamicPlatformPlugin {
|
|
|
2361
2258
|
}
|
|
2362
2259
|
}
|
|
2363
2260
|
|
|
2364
|
-
private async createCamera(device: irdevice &
|
|
2261
|
+
private async createCamera(device: irdevice & irDevicesConfig) {
|
|
2365
2262
|
const uuid = this.api.hap.uuid.generate(`${device.deviceId}-${device.remoteType}`)
|
|
2366
2263
|
|
|
2367
2264
|
// see if an accessory with the same uuid has already been registered and restored from
|
|
@@ -2405,7 +2302,7 @@ export class SwitchBotPlatform implements DynamicPlatformPlugin {
|
|
|
2405
2302
|
? await this.validateAndCleanDisplayName(device.configDeviceName, 'configDeviceName', device.configDeviceName)
|
|
2406
2303
|
: await this.validateAndCleanDisplayName(device.deviceName, 'deviceName', device.deviceName)
|
|
2407
2304
|
accessory.context.connectionType = await this.connectionType(device)
|
|
2408
|
-
accessory.context.version = device.firmware ??
|
|
2305
|
+
accessory.context.version = device.firmware ?? this.version ?? '0.0.0'
|
|
2409
2306
|
const newOrExternal = !device.external ? 'Adding new' : 'Loading external'
|
|
2410
2307
|
await this.infoLog(`${newOrExternal} accessory: ${accessory.displayName} deviceId: ${device.deviceId}`)
|
|
2411
2308
|
// create the accessory handler for the newly create accessory
|
|
@@ -2421,7 +2318,7 @@ export class SwitchBotPlatform implements DynamicPlatformPlugin {
|
|
|
2421
2318
|
}
|
|
2422
2319
|
}
|
|
2423
2320
|
|
|
2424
|
-
private async createOthers(device: irdevice &
|
|
2321
|
+
private async createOthers(device: irdevice & irDevicesConfig) {
|
|
2425
2322
|
const uuid = this.api.hap.uuid.generate(`${device.deviceId}-${device.remoteType}`)
|
|
2426
2323
|
|
|
2427
2324
|
// see if an accessory with the same uuid has already been registered and restored from
|
|
@@ -2465,7 +2362,7 @@ export class SwitchBotPlatform implements DynamicPlatformPlugin {
|
|
|
2465
2362
|
? await this.validateAndCleanDisplayName(device.configDeviceName, 'configDeviceName', device.configDeviceName)
|
|
2466
2363
|
: await this.validateAndCleanDisplayName(device.deviceName, 'deviceName', device.deviceName)
|
|
2467
2364
|
accessory.context.connectionType = await this.connectionType(device)
|
|
2468
|
-
accessory.context.version = device.firmware ??
|
|
2365
|
+
accessory.context.version = device.firmware ?? this.version ?? '0.0.0'
|
|
2469
2366
|
const newOrExternal = !device.external ? 'Adding new' : 'Loading external'
|
|
2470
2367
|
await this.infoLog(`${newOrExternal} accessory: ${accessory.displayName} deviceId: ${device.deviceId}`)
|
|
2471
2368
|
// create the accessory handler for the newly create accessory
|
|
@@ -2484,10 +2381,10 @@ export class SwitchBotPlatform implements DynamicPlatformPlugin {
|
|
|
2484
2381
|
async registerCurtains(device: device & devicesConfig): Promise<boolean> {
|
|
2485
2382
|
let registerWindowCovering: boolean
|
|
2486
2383
|
if (isCurtainDevice(device)) {
|
|
2487
|
-
await this.debugWarnLog(`deviceName: ${device.deviceName} deviceId: ${device.deviceId}, curtainDevicesIds: ${device.curtainDevicesIds},x master: ${device.master}, group: ${device.group}, disable_group: ${device.
|
|
2384
|
+
await this.debugWarnLog(`deviceName: ${device.deviceName} deviceId: ${device.deviceId}, curtainDevicesIds: ${device.curtainDevicesIds},x master: ${device.master}, group: ${device.group}, disable_group: ${(device as blindTiltConfig | curtainConfig).disable_group}, connectionType: ${device.connectionType}`)
|
|
2488
2385
|
registerWindowCovering = await this.registerWindowCovering(device)
|
|
2489
2386
|
} else if (isBlindTiltDevice(device)) {
|
|
2490
|
-
await this.debugWarnLog(`deviceName: ${device.deviceName} deviceId: ${device.deviceId}, blindTiltDevicesIds: ${device.blindTiltDevicesIds}, master: ${device.master}, group: ${device.group}, disable_group: ${device.
|
|
2387
|
+
await this.debugWarnLog(`deviceName: ${device.deviceName} deviceId: ${device.deviceId}, blindTiltDevicesIds: ${device.blindTiltDevicesIds}, master: ${device.master}, group: ${device.group}, disable_group: ${(device as blindTiltConfig | curtainConfig).disable_group}, connectionType: ${device.connectionType}`)
|
|
2491
2388
|
registerWindowCovering = await this.registerWindowCovering(device)
|
|
2492
2389
|
} else {
|
|
2493
2390
|
registerWindowCovering = false
|
|
@@ -2495,7 +2392,7 @@ export class SwitchBotPlatform implements DynamicPlatformPlugin {
|
|
|
2495
2392
|
return registerWindowCovering
|
|
2496
2393
|
}
|
|
2497
2394
|
|
|
2498
|
-
async registerWindowCovering(device: (
|
|
2395
|
+
async registerWindowCovering(device: (curtain | curtain3 | blindTilt) & devicesConfig) {
|
|
2499
2396
|
await this.debugLog(`master: ${device.master}`)
|
|
2500
2397
|
let registerCurtain: boolean
|
|
2501
2398
|
if (device.master && device.group) {
|
|
@@ -2503,11 +2400,9 @@ export class SwitchBotPlatform implements DynamicPlatformPlugin {
|
|
|
2503
2400
|
registerCurtain = true
|
|
2504
2401
|
await this.debugLog(`deviceName: ${device.deviceName} [${device.deviceType} Config] device.master: ${device.master}, device.group: ${device.group} connectionType; ${device.connectionType}`)
|
|
2505
2402
|
await this.debugWarnLog(`Device: ${device.deviceName} registerCurtains: ${registerCurtain}`)
|
|
2506
|
-
} else if (!device.master && device.
|
|
2507
|
-
// !device.group && device.connectionType === 'BLE'
|
|
2508
|
-
// OpenAPI: Non-Master Curtains/Blind Tilts that has Disable Grouping Checked
|
|
2403
|
+
} else if (!device.master && (device as blindTiltConfig | curtainConfig).disable_group) {
|
|
2509
2404
|
registerCurtain = true
|
|
2510
|
-
await this.debugLog(`deviceName: ${device.deviceName} [${device.deviceType} Config] device.master: ${device.master}, disable_group: ${device.
|
|
2405
|
+
await this.debugLog(`deviceName: ${device.deviceName} [${device.deviceType} Config] device.master: ${device.master}, disable_group: ${(device as blindTiltConfig | curtainConfig).disable_group}, connectionType; ${device.connectionType}`)
|
|
2511
2406
|
await this.debugWarnLog(`Device: ${device.deviceName} registerCurtains: ${registerCurtain}`)
|
|
2512
2407
|
} else if (device.master && !device.group) {
|
|
2513
2408
|
// OpenAPI: Master Curtains/Blind Tilts not in Group
|
|
@@ -2521,13 +2416,13 @@ export class SwitchBotPlatform implements DynamicPlatformPlugin {
|
|
|
2521
2416
|
await this.debugWarnLog(`Device: ${device.deviceName} registerCurtains: ${registerCurtain}`)
|
|
2522
2417
|
} else {
|
|
2523
2418
|
registerCurtain = false
|
|
2524
|
-
await this.debugErrorLog(`deviceName: ${device.deviceName} [${device.deviceType} Config] disable_group: ${device.
|
|
2419
|
+
await this.debugErrorLog(`deviceName: ${device.deviceName} [${device.deviceType} Config] disable_group: ${(device as blindTiltConfig | curtainConfig).disable_group}, device.master: ${device.master}, device.group: ${device.group}`)
|
|
2525
2420
|
await this.debugWarnLog(`Device: ${device.deviceName} registerCurtains: ${registerCurtain}, device.connectionType: ${device.connectionType}`)
|
|
2526
2421
|
}
|
|
2527
2422
|
return registerCurtain
|
|
2528
2423
|
}
|
|
2529
2424
|
|
|
2530
|
-
async connectionType(device: device & devicesConfig): Promise<any> {
|
|
2425
|
+
async connectionType(device: (device & devicesConfig) | (irdevice & irDevicesConfig)): Promise<any> {
|
|
2531
2426
|
let connectionType: string
|
|
2532
2427
|
if (!device.connectionType && this.config.credentials?.token && this.config.credentials.secret) {
|
|
2533
2428
|
connectionType = 'OpenAPI'
|
|
@@ -2577,7 +2472,7 @@ export class SwitchBotPlatform implements DynamicPlatformPlugin {
|
|
|
2577
2472
|
return registerDevice
|
|
2578
2473
|
}
|
|
2579
2474
|
|
|
2580
|
-
public async externalOrPlatform(device: device &
|
|
2475
|
+
public async externalOrPlatform(device: (device & devicesConfig) | (irdevice & irDevicesConfig), accessory: PlatformAccessory) {
|
|
2581
2476
|
const { displayName } = accessory
|
|
2582
2477
|
const isExternal = device.external ?? false
|
|
2583
2478
|
|
|
@@ -2639,18 +2534,15 @@ export class SwitchBotPlatform implements DynamicPlatformPlugin {
|
|
|
2639
2534
|
}
|
|
2640
2535
|
}
|
|
2641
2536
|
|
|
2642
|
-
async retryRequest(
|
|
2537
|
+
async retryRequest(deviceId: string, deviceMaxRetries: number, deviceDelayBetweenRetries: number): Promise<{ response: any, statusCode: number }> {
|
|
2643
2538
|
let retryCount = 0
|
|
2644
2539
|
const maxRetries = deviceMaxRetries
|
|
2645
2540
|
const delayBetweenRetries = deviceDelayBetweenRetries
|
|
2646
2541
|
while (retryCount < maxRetries) {
|
|
2647
2542
|
try {
|
|
2648
|
-
const {
|
|
2649
|
-
|
|
2650
|
-
|
|
2651
|
-
} else {
|
|
2652
|
-
await this.debugLog(`Received status code: ${statusCode}`)
|
|
2653
|
-
}
|
|
2543
|
+
const { response, statusCode } = await this.switchBotAPI.getDeviceStatus(deviceId)
|
|
2544
|
+
await this.debugLog(`response: ${JSON.stringify(response)}`)
|
|
2545
|
+
return { response, statusCode }
|
|
2654
2546
|
} catch (error: any) {
|
|
2655
2547
|
await this.errorLog(`Error making request: ${error.message}`)
|
|
2656
2548
|
}
|
|
@@ -2658,18 +2550,17 @@ export class SwitchBotPlatform implements DynamicPlatformPlugin {
|
|
|
2658
2550
|
await this.debugLog(`Retry attempt ${retryCount} of ${maxRetries}`)
|
|
2659
2551
|
await sleep(delayBetweenRetries)
|
|
2660
2552
|
}
|
|
2661
|
-
return {
|
|
2553
|
+
return { response: null, statusCode: 500 }
|
|
2662
2554
|
}
|
|
2663
2555
|
|
|
2664
2556
|
// BLE Connection
|
|
2665
2557
|
async connectBLE(accessory: PlatformAccessory, device: device & devicesConfig): Promise<any> {
|
|
2666
2558
|
try {
|
|
2667
|
-
|
|
2668
|
-
|
|
2669
|
-
|
|
2670
|
-
return switchbot
|
|
2559
|
+
queueScheduler.schedule(async () => this.switchBotBLE)
|
|
2560
|
+
await this.debugLog(`${device.deviceType}: ${accessory.displayName} 'node-switchbot' found: ${this.switchBotBLE}`)
|
|
2561
|
+
return this.switchBotBLE
|
|
2671
2562
|
} catch (e: any) {
|
|
2672
|
-
await this.errorLog(`${device.deviceType}: ${accessory.displayName} 'node-switchbot' not found, Error: ${e}`)
|
|
2563
|
+
await this.errorLog(`${device.deviceType}: ${accessory.displayName} 'node-switchbot' not found, Error: ${e.message ?? e}`)
|
|
2673
2564
|
return false
|
|
2674
2565
|
}
|
|
2675
2566
|
}
|