@switchbot/homebridge-switchbot 3.7.1-beta.2 → 3.7.1-beta.20

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (199) hide show
  1. package/CHANGELOG.md +10 -0
  2. package/README.md +14 -0
  3. package/assets/security-privacy-bluetooth.png +0 -0
  4. package/config.schema.json +74 -2
  5. package/dist/device/blindtilt.d.ts +21 -9
  6. package/dist/device/blindtilt.d.ts.map +1 -1
  7. package/dist/device/blindtilt.js +167 -96
  8. package/dist/device/blindtilt.js.map +1 -1
  9. package/dist/device/bot-old.d.ts +132 -0
  10. package/dist/device/bot-old.d.ts.map +1 -0
  11. package/dist/device/bot-old.js +1514 -0
  12. package/dist/device/bot-old.js.map +1 -0
  13. package/dist/device/bot.d.ts +10 -9
  14. package/dist/device/bot.d.ts.map +1 -1
  15. package/dist/device/bot.js +186 -187
  16. package/dist/device/bot.js.map +1 -1
  17. package/dist/device/ceilinglight.d.ts +14 -13
  18. package/dist/device/ceilinglight.d.ts.map +1 -1
  19. package/dist/device/ceilinglight.js +87 -97
  20. package/dist/device/ceilinglight.js.map +1 -1
  21. package/dist/device/colorbulb.d.ts +13 -12
  22. package/dist/device/colorbulb.d.ts.map +1 -1
  23. package/dist/device/colorbulb.js +92 -105
  24. package/dist/device/colorbulb.js.map +1 -1
  25. package/dist/device/contact.d.ts +6 -5
  26. package/dist/device/contact.d.ts.map +1 -1
  27. package/dist/device/contact.js +71 -68
  28. package/dist/device/contact.js.map +1 -1
  29. package/dist/device/curtain.d.ts +17 -5
  30. package/dist/device/curtain.d.ts.map +1 -1
  31. package/dist/device/curtain.js +184 -118
  32. package/dist/device/curtain.js.map +1 -1
  33. package/dist/device/device.d.ts +18 -18
  34. package/dist/device/device.d.ts.map +1 -1
  35. package/dist/device/device.js +33 -36
  36. package/dist/device/device.js.map +1 -1
  37. package/dist/device/fan.d.ts +9 -8
  38. package/dist/device/fan.d.ts.map +1 -1
  39. package/dist/device/fan.js +94 -101
  40. package/dist/device/fan.js.map +1 -1
  41. package/dist/device/hub.d.ts +6 -5
  42. package/dist/device/hub.d.ts.map +1 -1
  43. package/dist/device/hub.js +69 -65
  44. package/dist/device/hub.js.map +1 -1
  45. package/dist/device/humidifier.d.ts +6 -5
  46. package/dist/device/humidifier.d.ts.map +1 -1
  47. package/dist/device/humidifier.js +89 -104
  48. package/dist/device/humidifier.js.map +1 -1
  49. package/dist/device/iosensor.d.ts +6 -5
  50. package/dist/device/iosensor.d.ts.map +1 -1
  51. package/dist/device/iosensor.js +72 -66
  52. package/dist/device/iosensor.js.map +1 -1
  53. package/dist/device/lightstrip.d.ts +7 -6
  54. package/dist/device/lightstrip.d.ts.map +1 -1
  55. package/dist/device/lightstrip.js +85 -99
  56. package/dist/device/lightstrip.js.map +1 -1
  57. package/dist/device/lock.d.ts +10 -9
  58. package/dist/device/lock.d.ts.map +1 -1
  59. package/dist/device/lock.js +89 -79
  60. package/dist/device/lock.js.map +1 -1
  61. package/dist/device/meter.d.ts +6 -5
  62. package/dist/device/meter.d.ts.map +1 -1
  63. package/dist/device/meter.js +72 -65
  64. package/dist/device/meter.js.map +1 -1
  65. package/dist/device/meterplus.d.ts +6 -5
  66. package/dist/device/meterplus.d.ts.map +1 -1
  67. package/dist/device/meterplus.js +72 -64
  68. package/dist/device/meterplus.js.map +1 -1
  69. package/dist/device/motion.d.ts +6 -5
  70. package/dist/device/motion.d.ts.map +1 -1
  71. package/dist/device/motion.js +65 -58
  72. package/dist/device/motion.js.map +1 -1
  73. package/dist/device/plug.d.ts +13 -12
  74. package/dist/device/plug.d.ts.map +1 -1
  75. package/dist/device/plug.js +68 -52
  76. package/dist/device/plug.js.map +1 -1
  77. package/dist/device/robotvacuumcleaner.d.ts +12 -11
  78. package/dist/device/robotvacuumcleaner.d.ts.map +1 -1
  79. package/dist/device/robotvacuumcleaner.js +93 -82
  80. package/dist/device/robotvacuumcleaner.js.map +1 -1
  81. package/dist/device/waterdetector.d.ts +6 -5
  82. package/dist/device/waterdetector.d.ts.map +1 -1
  83. package/dist/device/waterdetector.js +73 -63
  84. package/dist/device/waterdetector.js.map +1 -1
  85. package/dist/homebridge-ui/server.js +2 -2
  86. package/dist/homebridge-ui/server.js.map +1 -1
  87. package/dist/index.d.ts.map +1 -1
  88. package/dist/index.js +0 -4
  89. package/dist/index.js.map +1 -1
  90. package/dist/irdevice/airconditioner.d.ts +8 -8
  91. package/dist/irdevice/airconditioner.d.ts.map +1 -1
  92. package/dist/irdevice/airconditioner.js +64 -105
  93. package/dist/irdevice/airconditioner.js.map +1 -1
  94. package/dist/irdevice/airpurifier.d.ts +10 -10
  95. package/dist/irdevice/airpurifier.d.ts.map +1 -1
  96. package/dist/irdevice/airpurifier.js +22 -42
  97. package/dist/irdevice/airpurifier.js.map +1 -1
  98. package/dist/irdevice/camera.d.ts +9 -9
  99. package/dist/irdevice/camera.d.ts.map +1 -1
  100. package/dist/irdevice/camera.js +15 -25
  101. package/dist/irdevice/camera.js.map +1 -1
  102. package/dist/irdevice/fan.d.ts +8 -8
  103. package/dist/irdevice/fan.d.ts.map +1 -1
  104. package/dist/irdevice/fan.js +21 -40
  105. package/dist/irdevice/fan.js.map +1 -1
  106. package/dist/irdevice/irdevice.d.ts +11 -11
  107. package/dist/irdevice/irdevice.d.ts.map +1 -1
  108. package/dist/irdevice/irdevice.js +14 -22
  109. package/dist/irdevice/irdevice.js.map +1 -1
  110. package/dist/irdevice/light.d.ts +9 -9
  111. package/dist/irdevice/light.d.ts.map +1 -1
  112. package/dist/irdevice/light.js +24 -47
  113. package/dist/irdevice/light.js.map +1 -1
  114. package/dist/irdevice/other.d.ts +9 -9
  115. package/dist/irdevice/other.d.ts.map +1 -1
  116. package/dist/irdevice/other.js +40 -83
  117. package/dist/irdevice/other.js.map +1 -1
  118. package/dist/irdevice/tv.d.ts +9 -9
  119. package/dist/irdevice/tv.d.ts.map +1 -1
  120. package/dist/irdevice/tv.js +29 -54
  121. package/dist/irdevice/tv.js.map +1 -1
  122. package/dist/irdevice/vacuumcleaner.d.ts +5 -5
  123. package/dist/irdevice/vacuumcleaner.d.ts.map +1 -1
  124. package/dist/irdevice/vacuumcleaner.js +11 -21
  125. package/dist/irdevice/vacuumcleaner.js.map +1 -1
  126. package/dist/irdevice/waterheater.d.ts +5 -5
  127. package/dist/irdevice/waterheater.d.ts.map +1 -1
  128. package/dist/irdevice/waterheater.js +11 -22
  129. package/dist/irdevice/waterheater.js.map +1 -1
  130. package/dist/platform.d.ts +24 -23
  131. package/dist/platform.d.ts.map +1 -1
  132. package/dist/platform.js +510 -722
  133. package/dist/platform.js.map +1 -1
  134. package/dist/settings.d.ts +5 -2
  135. package/dist/settings.d.ts.map +1 -1
  136. package/dist/settings.js.map +1 -1
  137. package/dist/types/bledevicestatus.d.ts +9 -9
  138. package/dist/types/bledevicestatus.d.ts.map +1 -1
  139. package/dist/types/devicelist.d.ts +6 -6
  140. package/dist/types/devicelist.d.ts.map +1 -1
  141. package/dist/types/deviceresponse.d.ts +4 -4
  142. package/dist/types/deviceresponse.d.ts.map +1 -1
  143. package/dist/types/devicestatus.d.ts +2 -2
  144. package/dist/types/devicestatus.d.ts.map +1 -1
  145. package/dist/types/devicewebhookstatus.d.ts +5 -5
  146. package/dist/types/devicewebhookstatus.d.ts.map +1 -1
  147. package/dist/types/irdevicelist.d.ts +4 -4
  148. package/dist/types/irdevicelist.d.ts.map +1 -1
  149. package/dist/types/pushbody.d.ts +2 -2
  150. package/dist/types/pushbody.d.ts.map +1 -1
  151. package/dist/utils.d.ts +4 -4
  152. package/dist/utils.d.ts.map +1 -1
  153. package/dist/utils.js +9 -13
  154. package/dist/utils.js.map +1 -1
  155. package/eslint.config.js +48 -93
  156. package/package.json +62 -53
  157. package/src/device/blindtilt.ts +537 -456
  158. package/src/device/bot-old.ts +1578 -0
  159. package/src/device/bot.ts +732 -725
  160. package/src/device/ceilinglight.ts +359 -368
  161. package/src/device/colorbulb.ts +441 -453
  162. package/src/device/contact.ts +229 -226
  163. package/src/device/curtain.ts +526 -444
  164. package/src/device/device.ts +206 -208
  165. package/src/device/fan.ts +336 -345
  166. package/src/device/hub.ts +213 -214
  167. package/src/device/humidifier.ts +326 -347
  168. package/src/device/iosensor.ts +211 -209
  169. package/src/device/lightstrip.ts +391 -404
  170. package/src/device/lock.ts +292 -282
  171. package/src/device/meter.ts +212 -210
  172. package/src/device/meterplus.ts +212 -209
  173. package/src/device/motion.ts +198 -190
  174. package/src/device/plug.ts +203 -182
  175. package/src/device/robotvacuumcleaner.ts +280 -269
  176. package/src/device/waterdetector.ts +198 -189
  177. package/src/homebridge-ui/server.ts +16 -15
  178. package/src/index.ts +5 -6
  179. package/src/irdevice/airconditioner.ts +280 -326
  180. package/src/irdevice/airpurifier.ts +124 -143
  181. package/src/irdevice/camera.ts +58 -64
  182. package/src/irdevice/fan.ts +106 -123
  183. package/src/irdevice/irdevice.ts +116 -119
  184. package/src/irdevice/light.ts +119 -143
  185. package/src/irdevice/other.ts +417 -461
  186. package/src/irdevice/tv.ts +155 -177
  187. package/src/irdevice/vacuumcleaner.ts +54 -60
  188. package/src/irdevice/waterheater.ts +56 -63
  189. package/src/platform.ts +1493 -1681
  190. package/src/settings.ts +172 -169
  191. package/src/types/bledevicestatus.ts +255 -255
  192. package/src/types/devicelist.ts +79 -79
  193. package/src/types/deviceresponse.ts +12 -13
  194. package/src/types/devicestatus.ts +124 -124
  195. package/src/types/devicewebhookstatus.ts +126 -127
  196. package/src/types/irdevicelist.ts +10 -10
  197. package/src/types/pushbody.ts +5 -5
  198. package/src/utils.ts +64 -65
  199. package/tsconfig.json +10 -9
package/dist/platform.js CHANGED
@@ -1,55 +1,58 @@
1
- /* Copyright(C) 2017-2024, donavanbecker (https://github.com/donavanbecker). All rights reserved.
2
- *
3
- * platform.ts: @switchbot/homebridge-switchbot platform class.
4
- */
5
- import { Hub } from './device/hub.js';
6
- import { Bot } from './device/bot.js';
7
- import { Plug } from './device/plug.js';
8
- import { Lock } from './device/lock.js';
9
- import { Meter } from './device/meter.js';
10
- import { Motion } from './device/motion.js';
1
+ import { Buffer } from 'node:buffer';
2
+ import crypto, { randomUUID } from 'node:crypto';
3
+ import { readFileSync, writeFileSync } from 'node:fs';
4
+ import { createServer } from 'node:http';
5
+ import process from 'node:process';
6
+ import asyncmqtt from 'async-mqtt';
7
+ import fakegato from 'fakegato-history';
8
+ import { EveHomeKitTypes } from 'homebridge-lib/EveHomeKitTypes';
9
+ /*
10
+ * For Testing Locally:
11
+ * import { SwitchBotModel } from '/Users/Shared/GitHub/OpenWonderLabs/node-switchbot/dist/index.js';
12
+ */
13
+ import { SwitchBotModel } from 'node-switchbot';
14
+ import { queueScheduler } from 'rxjs';
15
+ import { request } from 'undici';
16
+ import { BlindTilt } from './device/blindtilt.js';
17
+ import { Bot } from './device/bot-old.js';
18
+ import { CeilingLight } from './device/ceilinglight.js';
19
+ import { ColorBulb } from './device/colorbulb.js';
11
20
  import { Contact } from './device/contact.js';
12
21
  import { Curtain } from './device/curtain.js';
22
+ import { Fan } from './device/fan.js';
23
+ import { Hub } from './device/hub.js';
24
+ import { Humidifier } from './device/humidifier.js';
13
25
  import { IOSensor } from './device/iosensor.js';
14
- import { MeterPlus } from './device/meterplus.js';
15
- import { ColorBulb } from './device/colorbulb.js';
16
26
  import { StripLight } from './device/lightstrip.js';
17
- import { Humidifier } from './device/humidifier.js';
18
- import { CeilingLight } from './device/ceilinglight.js';
19
- import { WaterDetector } from './device/waterdetector.js';
27
+ import { Lock } from './device/lock.js';
28
+ import { Meter } from './device/meter.js';
29
+ import { MeterPlus } from './device/meterplus.js';
30
+ import { Motion } from './device/motion.js';
31
+ import { Plug } from './device/plug.js';
20
32
  import { RobotVacuumCleaner } from './device/robotvacuumcleaner.js';
21
- import { Fan } from './device/fan.js';
22
- import { TV } from './irdevice/tv.js';
33
+ import { WaterDetector } from './device/waterdetector.js';
34
+ import { AirConditioner } from './irdevice/airconditioner.js';
35
+ import { AirPurifier } from './irdevice/airpurifier.js';
36
+ import { Camera } from './irdevice/camera.js';
23
37
  import { IRFan } from './irdevice/fan.js';
24
38
  import { Light } from './irdevice/light.js';
25
39
  import { Others } from './irdevice/other.js';
26
- import { Camera } from './irdevice/camera.js';
27
- import { BlindTilt } from './device/blindtilt.js';
28
- import { AirPurifier } from './irdevice/airpurifier.js';
29
- import { WaterHeater } from './irdevice/waterheater.js';
40
+ import { TV } from './irdevice/tv.js';
30
41
  import { VacuumCleaner } from './irdevice/vacuumcleaner.js';
31
- import { AirConditioner } from './irdevice/airconditioner.js';
32
- import { Buffer } from 'buffer';
33
- import { request } from 'undici';
34
- import asyncmqtt from 'async-mqtt';
35
- import { createServer } from 'http';
36
- import { queueScheduler } from 'rxjs';
37
- import fakegato from 'fakegato-history';
38
- import crypto, { randomUUID } from 'crypto';
39
- import { readFileSync, writeFileSync } from 'fs';
40
- import { EveHomeKitTypes } from 'homebridge-lib/EveHomeKitTypes';
41
- import { PLATFORM_NAME, PLUGIN_NAME, Devices, deleteWebhook, queryWebhook, setupWebhook, updateWebhook } from './settings.js';
42
+ import { WaterHeater } from './irdevice/waterheater.js';
43
+ import { deleteWebhook, Devices, PLATFORM_NAME, PLUGIN_NAME, queryWebhook, setupWebhook, updateWebhook } from './settings.js';
42
44
  import { isBlindTiltDevice, isCurtainDevice, sleep } from './utils.js';
43
- import { SwitchBotModel } from 'node-switchbot';
44
45
  /**
45
46
  * HomebridgePlatform
46
47
  * This class is the main constructor for your plugin, this is where you should
47
48
  * parse the user config and discover/register accessories with Homebridge.
48
49
  */
49
50
  export class SwitchBotPlatform {
50
- accessories;
51
+ // Platform properties
52
+ accessories = [];
51
53
  api;
52
54
  log;
55
+ // Configuration properties
53
56
  version;
54
57
  Logging;
55
58
  debugMode;
@@ -58,15 +61,16 @@ export class SwitchBotPlatform {
58
61
  platformConfig;
59
62
  platformLogging;
60
63
  config;
64
+ // MQTT and Webhook properties
61
65
  mqttClient = null;
62
66
  webhookEventListener = null;
67
+ // External APIs
63
68
  eve;
64
69
  fakegatoAPI;
70
+ // Event Handlers
65
71
  webhookEventHandler = {};
66
72
  bleEventHandler = {};
67
73
  constructor(log, config, api) {
68
- // initialize
69
- this.accessories = [];
70
74
  this.api = api;
71
75
  this.log = log;
72
76
  // only load if configured
@@ -104,27 +108,42 @@ export class SwitchBotPlatform {
104
108
  // in order to ensure they weren't added to homebridge already. This event can also be used
105
109
  // to start discovery of new accessories.
106
110
  this.api.on('didFinishLaunching', async () => {
107
- this.debugLog('Executed didFinishLaunching callback');
111
+ await this.debugLog('Executed didFinishLaunching callback');
108
112
  // run the method to discover / register your devices as accessories
109
113
  try {
110
114
  if (this.config.credentials?.openToken && !this.config.credentials.token) {
111
115
  await this.updateToken();
112
116
  }
113
117
  else if (this.config.credentials?.token && !this.config.credentials?.secret) {
114
- this.errorLog('"secret" config is not populated, you must populate then please restart Homebridge.');
118
+ await this.errorLog('"secret" config is not populated, you must populate then please restart Homebridge.');
115
119
  }
116
120
  else {
117
- this.discoverDevices();
121
+ await this.discoverDevices();
118
122
  }
119
123
  }
120
124
  catch (e) {
121
- this.errorLog(`Failed to Discover, Error Message: ${e.message}, Submit Bugs Here: ` + 'https://tinyurl.com/SwitchBotBug');
125
+ await this.errorLog(`Failed to Discover, Error Message: ${e.message}, Submit Bugs Here: ` + 'https://tinyurl.com/SwitchBotBug');
122
126
  await this.debugErrorLog(`Failed to Discover, Error: ${e}`);
123
127
  }
124
128
  });
125
- this.setupMqtt();
126
- this.setupwebhook();
127
- this.setupBlE();
129
+ try {
130
+ this.setupMqtt();
131
+ }
132
+ catch (e) {
133
+ this.errorLog(`Setup MQTT, Error Message: ${e.message}, Submit Bugs Here: ` + 'https://tinyurl.com/SwitchBotBug');
134
+ }
135
+ try {
136
+ this.setupwebhook();
137
+ }
138
+ catch (e) {
139
+ this.errorLog(`Setup Webhook, Error Message: ${e.message}, Submit Bugs Here: ` + 'https://tinyurl.com/SwitchBotBug');
140
+ }
141
+ try {
142
+ this.setupBlE();
143
+ }
144
+ catch (e) {
145
+ this.errorLog(`Setup Platform BLE, Error Message: ${e.message}, Submit Bugs Here: ` + 'https://tinyurl.com/SwitchBotBug');
146
+ }
128
147
  }
129
148
  async setupMqtt() {
130
149
  if (this.config.options?.mqttURL) {
@@ -141,7 +160,7 @@ export class SwitchBotPlatform {
141
160
  this.mqttClient.subscribe('homebridge-switchbot/webhook/+');
142
161
  this.mqttClient.on('message', async (topic, message) => {
143
162
  try {
144
- await await this.debugLog(`Received Webhook via MQTT: ${topic}=${message}`);
163
+ await this.debugLog(`Received Webhook via MQTT: ${topic}=${message}`);
145
164
  const context = JSON.parse(message.toString());
146
165
  this.webhookEventHandler[context.deviceMac]?.(context);
147
166
  }
@@ -158,7 +177,7 @@ export class SwitchBotPlatform {
158
177
  }
159
178
  }
160
179
  async setupwebhook() {
161
- //webhook configuration
180
+ // webhook configuration
162
181
  if (this.config.options?.webhookURL) {
163
182
  const url = this.config.options?.webhookURL;
164
183
  try {
@@ -173,17 +192,14 @@ export class SwitchBotPlatform {
173
192
  const body = JSON.parse(data);
174
193
  await this.debugLog(`Received Webhook: ${JSON.stringify(body)}`);
175
194
  if (this.config.options?.mqttURL) {
176
- const mac = body.context.deviceMac
177
- ?.toLowerCase()
178
- .match(/[\s\S]{1,2}/g)
179
- ?.join(':');
195
+ const mac = body.context.deviceMac?.toLowerCase().match(/[\s\S]{1,2}/g)?.join(':');
180
196
  const options = this.config.options?.mqttPubOptions || {};
181
197
  this.mqttClient?.publish(`homebridge-switchbot/webhook/${mac}`, `${JSON.stringify(body.context)}`, options);
182
198
  }
183
199
  this.webhookEventHandler[body.context.deviceMac]?.(body.context);
184
200
  }
185
201
  catch (e) {
186
- this.errorLog(`Failed to handle webhook event. Error:${e}`);
202
+ await this.errorLog(`Failed to handle webhook event. Error:${e}`);
187
203
  }
188
204
  });
189
205
  response.writeHead(200, { 'Content-Type': 'text/plain' });
@@ -197,10 +213,10 @@ export class SwitchBotPlatform {
197
213
  catch (e) {
198
214
  this.errorLog(`Failed to handle webhook event. Error:${e}`);
199
215
  }
200
- }).listen(port ? port : 80);
216
+ }).listen(port || 80);
201
217
  }
202
218
  catch (e) {
203
- this.errorLog(`Failed to create webhook listener. Error:${e.message}`);
219
+ await this.errorLog(`Failed to create webhook listener. Error:${e.message}`);
204
220
  return;
205
221
  }
206
222
  try {
@@ -208,64 +224,61 @@ export class SwitchBotPlatform {
208
224
  method: 'POST',
209
225
  headers: this.generateHeaders(),
210
226
  body: JSON.stringify({
211
- 'action': 'setupWebhook',
212
- 'url': url,
213
- 'deviceList': 'ALL',
227
+ action: 'setupWebhook',
228
+ url,
229
+ deviceList: 'ALL',
214
230
  }),
215
231
  });
216
232
  const response = await body.json();
217
- await this.debugLog(`setupWebhook: url:${url}`);
218
- await this.debugLog(`setupWebhook: body:${JSON.stringify(response)}`);
219
- await this.debugLog(`setupWebhook: statusCode:${statusCode}`);
233
+ await this.debugLog(`setupWebhook: url:${url}, body:${JSON.stringify(response)}, statusCode:${statusCode}`);
220
234
  if (statusCode !== 200 || response?.statusCode !== 100) {
221
- this.errorLog(`Failed to configure webhook. Existing webhook well be overridden. HTTP:${statusCode} API:${response?.statusCode} `
222
- + `message:${response?.message}`);
235
+ await this.errorLog(`Failed to configure webhook. Existing webhook well be overridden. HTTP:${statusCode} API:${response?.statusCode} message:${response?.message}`);
223
236
  }
224
237
  }
225
238
  catch (e) {
226
- this.errorLog(`Failed to configure webhook. Error: ${e.message}`);
239
+ await this.errorLog(`Failed to configure webhook. Error: ${e.message}`);
227
240
  }
228
241
  try {
229
242
  const { body, statusCode } = await request(updateWebhook, {
230
- method: 'POST', headers: this.generateHeaders(), body: JSON.stringify({
231
- 'action': 'updateWebhook',
232
- 'config': {
233
- 'url': url,
234
- 'enable': true,
243
+ method: 'POST',
244
+ headers: this.generateHeaders(),
245
+ body: JSON.stringify({
246
+ action: 'updateWebhook',
247
+ config: {
248
+ url,
249
+ enable: true,
235
250
  },
236
251
  }),
237
252
  });
238
253
  const response = await body.json();
239
- await this.debugLog(`updateWebhook: url:${url}`);
240
- await this.debugLog(`updateWebhook: body:${JSON.stringify(response)}`);
241
- await this.debugLog(`updateWebhook: statusCode:${statusCode}`);
254
+ await this.debugLog(`updateWebhook: url:${url}, body:${JSON.stringify(response)}, statusCode:${statusCode}`);
242
255
  if (statusCode !== 200 || response?.statusCode !== 100) {
243
- this.errorLog(`Failed to update webhook. HTTP:${statusCode} API:${response?.statusCode} message:${response?.message}`);
256
+ await this.errorLog(`Failed to update webhook. HTTP:${statusCode} API:${response?.statusCode} message:${response?.message}`);
244
257
  }
245
258
  }
246
259
  catch (e) {
247
- this.errorLog(`Failed to update webhook. Error:${e.message}`);
260
+ await this.errorLog(`Failed to update webhook. Error:${e.message}`);
248
261
  }
249
262
  try {
250
263
  const { body, statusCode } = await request(queryWebhook, {
251
264
  method: 'POST',
252
265
  headers: this.generateHeaders(),
253
266
  body: JSON.stringify({
254
- 'action': 'queryUrl',
267
+ action: 'queryUrl',
255
268
  }),
256
269
  });
257
270
  const response = await body.json();
258
271
  await this.debugLog(`queryWebhook: body:${JSON.stringify(response)}`);
259
272
  await this.debugLog(`queryWebhook: statusCode:${statusCode}`);
260
273
  if (statusCode !== 200 || response?.statusCode !== 100) {
261
- this.errorLog(`Failed to query webhook. HTTP:${statusCode} API:${response?.statusCode} message:${response?.message}`);
274
+ await this.errorLog(`Failed to query webhook. HTTP:${statusCode} API:${response?.statusCode} message:${response?.message}`);
262
275
  }
263
276
  else {
264
- this.infoLog(`Listening webhook on ${response?.body?.urls[0]}`);
277
+ await this.infoLog(`Listening webhook on ${response?.body?.urls[0]}`);
265
278
  }
266
279
  }
267
280
  catch (e) {
268
- this.errorLog(`Failed to query webhook. Error:${e}`);
281
+ await this.errorLog(`Failed to query webhook. Error:${e}`);
269
282
  }
270
283
  this.api.on('shutdown', async () => {
271
284
  try {
@@ -273,21 +286,21 @@ export class SwitchBotPlatform {
273
286
  method: 'POST',
274
287
  headers: this.generateHeaders(),
275
288
  body: JSON.stringify({
276
- 'action': 'deleteWebhook',
277
- 'url': url,
289
+ action: 'deleteWebhook',
290
+ url,
278
291
  }),
279
292
  });
280
293
  const response = await body.json();
281
294
  await this.debugLog(`deleteWebhook: url:${url}, body:${JSON.stringify(response)}, statusCode:${statusCode}`);
282
295
  if (statusCode !== 200 || response?.statusCode !== 100) {
283
- this.errorLog(`Failed to delete webhook. HTTP:${statusCode} API:${response?.statusCode} message:${response?.message}`);
296
+ await this.errorLog(`Failed to delete webhook. HTTP:${statusCode} API:${response?.statusCode} message:${response?.message}`);
284
297
  }
285
298
  else {
286
- this.infoLog('Unregistered webhook to close listening.');
299
+ await this.infoLog('Unregistered webhook to close listening.');
287
300
  }
288
301
  }
289
302
  catch (e) {
290
- this.errorLog(`Failed to delete webhook. Error:${e.message}`);
303
+ await this.errorLog(`Failed to delete webhook. Error:${e.message}`);
291
304
  }
292
305
  });
293
306
  }
@@ -319,10 +332,10 @@ export class SwitchBotPlatform {
319
332
  this.api.on('shutdown', async () => {
320
333
  try {
321
334
  switchbot.stopScan();
322
- this.infoLog('Stopped BLE scanning to close listening.');
335
+ await this.infoLog('Stopped BLE scanning to close listening.');
323
336
  }
324
337
  catch (e) {
325
- this.errorLog(`Failed to stop Platform BLE scanning. Error:${e.message}`);
338
+ await this.errorLog(`Failed to stop Platform BLE scanning. Error:${e.message}`);
326
339
  }
327
340
  });
328
341
  }
@@ -336,7 +349,8 @@ export class SwitchBotPlatform {
336
349
  * It should be used to setup event handlers for characteristics and update respective values.
337
350
  */
338
351
  async configureAccessory(accessory) {
339
- await this.debugLog(`Loading accessory from cache: ${accessory.displayName}`);
352
+ const { displayName } = accessory;
353
+ await this.debugLog(`Loading accessory from cache: ${displayName}`);
340
354
  // add the restored accessory to the accessories cache so we can track if it has already been registered
341
355
  this.accessories.push(accessory);
342
356
  }
@@ -344,18 +358,18 @@ export class SwitchBotPlatform {
344
358
  * Verify the config passed to the plugin is valid
345
359
  */
346
360
  async verifyConfig() {
347
- this.debugLog('Verifying Config');
361
+ await this.debugLog('Verifying Config');
348
362
  this.config = this.config || {};
349
363
  this.config.options = this.config.options || {};
350
364
  const platformConfig = {};
351
365
  if (this.config.options.logging) {
352
- platformConfig['logging'] = this.config.options.logging;
366
+ platformConfig.logging = this.config.options.logging;
353
367
  }
354
368
  if (this.config.options.logging && this.config.options.refreshRate) {
355
- platformConfig['refreshRate'] = this.config.options.refreshRate;
369
+ platformConfig.refreshRate = this.config.options.refreshRate;
356
370
  }
357
371
  if (this.config.options.logging && this.config.options.pushRate) {
358
- platformConfig['pushRate'] = this.config.options.pushRate;
372
+ platformConfig.pushRate = this.config.options.pushRate;
359
373
  }
360
374
  if (Object.entries(platformConfig).length !== 0) {
361
375
  await this.debugWarnLog(`Platform Config: ${JSON.stringify(platformConfig)}`);
@@ -379,10 +393,10 @@ export class SwitchBotPlatform {
379
393
  for (const irDeviceConfig of this.config.options.irdevices) {
380
394
  if (!irDeviceConfig.hide_device) {
381
395
  if (!irDeviceConfig.deviceId) {
382
- this.errorLog('The devices config section is missing the *Device ID* in the config. Please check your config.');
396
+ await this.errorLog('The devices config section is missing the *Device ID* in the config. Please check your config.');
383
397
  }
384
398
  if (!irDeviceConfig.deviceId && !irDeviceConfig.configRemoteType) {
385
- this.errorLog('The devices config section is missing the *Device Type* in the config. Please check your config.');
399
+ await this.errorLog('The devices config section is missing the *Device Type* in the config. Please check your config.');
386
400
  }
387
401
  }
388
402
  }
@@ -394,16 +408,16 @@ export class SwitchBotPlatform {
394
408
  if (!this.config.options.refreshRate) {
395
409
  // default 120 seconds (2 minutes)
396
410
  this.config.options.refreshRate = 120;
397
- this.debugWarnLog('Using Default Refresh Rate (2 minutes).');
411
+ await this.debugWarnLog('Using Default Refresh Rate (2 minutes).');
398
412
  }
399
413
  if (!this.config.options.pushRate) {
400
414
  // default 100 milliseconds
401
415
  this.config.options.pushRate = 0.1;
402
- this.debugWarnLog('Using Default Push Rate.');
416
+ await this.debugWarnLog('Using Default Push Rate.');
403
417
  }
404
418
  if (!this.config.options.maxRetries) {
405
419
  this.config.options.maxRetries = 5;
406
- this.debugWarnLog('Using Default Max Retries.');
420
+ await this.debugWarnLog('Using Default Max Retries.');
407
421
  }
408
422
  else {
409
423
  this.maxRetries = this.config.options.maxRetries;
@@ -411,23 +425,23 @@ export class SwitchBotPlatform {
411
425
  if (!this.config.options.delayBetweenRetries) {
412
426
  // default 3 seconds
413
427
  this.config.options.delayBetweenRetries = 3000;
414
- this.debugWarnLog('Using Default Delay Between Retries.');
428
+ await this.debugWarnLog('Using Default Delay Between Retries.');
415
429
  }
416
430
  else {
417
431
  this.delayBetweenRetries = this.config.options.delayBetweenRetries * 1000;
418
432
  }
419
433
  if (!this.config.credentials && !this.config.options) {
420
- this.debugWarnLog('Missing Credentials');
434
+ await this.debugWarnLog('Missing Credentials');
421
435
  }
422
436
  else if (this.config.credentials && !this.config.credentials.notice) {
423
437
  if (!this.config.credentials?.token) {
424
- this.debugErrorLog('Missing token');
425
- this.debugWarnLog('Cloud Enabled SwitchBot Devices & IR Devices will not work');
438
+ await this.debugErrorLog('Missing token');
439
+ await this.debugWarnLog('Cloud Enabled SwitchBot Devices & IR Devices will not work');
426
440
  }
427
441
  if (this.config.credentials?.token) {
428
442
  if (!this.config.credentials?.secret) {
429
- this.debugErrorLog('Missing secret');
430
- this.debugWarnLog('Cloud Enabled SwitchBot Devices & IR Devices will not work');
443
+ await this.debugErrorLog('Missing secret');
444
+ await this.debugWarnLog('Cloud Enabled SwitchBot Devices & IR Devices will not work');
431
445
  }
432
446
  }
433
447
  }
@@ -435,7 +449,6 @@ export class SwitchBotPlatform {
435
449
  /**
436
450
  * The openToken was old config.
437
451
  * This method saves the openToken as the token in the config.json file
438
- * @param this.config.credentials.openToken
439
452
  */
440
453
  async updateToken() {
441
454
  try {
@@ -447,7 +460,7 @@ export class SwitchBotPlatform {
447
460
  const currentConfig = JSON.parse(readFileSync(this.api.user.configPath(), 'utf8'));
448
461
  // check the platforms section is an array before we do array things on it
449
462
  if (!Array.isArray(currentConfig.platforms)) {
450
- throw new Error('Cannot find platforms array in config');
463
+ throw new TypeError('Cannot find platforms array in config');
451
464
  }
452
465
  // find this plugins current config
453
466
  const pluginConfig = currentConfig.platforms.find((x) => x.platform === PLATFORM_NAME);
@@ -456,17 +469,15 @@ export class SwitchBotPlatform {
456
469
  }
457
470
  // check the .credentials is an object before doing object things with it
458
471
  if (typeof pluginConfig.credentials !== 'object') {
459
- throw new Error('pluginConfig.credentials is not an object');
472
+ throw new TypeError('pluginConfig.credentials is not an object');
460
473
  }
461
474
  // Move openToken to token
462
475
  if (!this.config.credentials.secret) {
463
- this.warnLog('This plugin has been updated to use OpenAPI v1.1, config is set with openToken,'
464
- + ' "openToken" cconfig has been moved to the "token" config');
476
+ 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');
465
477
  this.errorLog('"secret" config is not populated, you must populate then please restart Homebridge.');
466
478
  }
467
479
  else {
468
- this.warnLog('This plugin has been updated to use OpenAPI v1.1, config is set with openToken, '
469
- + '"openToken" config has been moved to the "token" config, please restart Homebridge.');
480
+ 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.');
470
481
  }
471
482
  // set the refresh token
472
483
  pluginConfig.credentials.token = this.config.credentials?.openToken;
@@ -476,10 +487,10 @@ export class SwitchBotPlatform {
476
487
  await this.debugWarnLog(`token: ${pluginConfig.credentials.token}`);
477
488
  // save the config, ensuring we maintain pretty json
478
489
  writeFileSync(this.api.user.configPath(), JSON.stringify(currentConfig, null, 4));
479
- this.verifyConfig();
490
+ await this.verifyConfig();
480
491
  }
481
492
  catch (e) {
482
- this.errorLog(`Update Token: ${e}`);
493
+ await this.errorLog(`Update Token: ${e}`);
483
494
  }
484
495
  }
485
496
  generateHeaders = () => {
@@ -492,340 +503,228 @@ export class SwitchBotPlatform {
492
503
  .digest();
493
504
  const sign = signTerm.toString('base64');
494
505
  return {
495
- Authorization: this.config.credentials?.token,
496
- sign: sign,
497
- nonce: nonce,
498
- t: t,
506
+ 'Authorization': this.config.credentials?.token,
507
+ 'sign': sign,
508
+ 'nonce': nonce,
509
+ 't': t,
499
510
  'Content-Type': 'application/json',
500
511
  };
501
512
  };
502
- /**
503
- * this method discovers devices
504
- *
505
- const t = `${Date.now()}`;
506
- const nonce = 'requestID';
507
- const data = this.config.credentials?.token + t + nonce;
508
- const signTerm = crypto.createHmac('sha256', this.config.credentials?.secret).update(Buffer.from(data, 'utf-8')).digest();
509
- const sign = signTerm.toString('base64');
510
- */
511
513
  async discoverDevices() {
512
- if (this.config.credentials?.token) {
513
- let retryCount = 0;
514
- const maxRetries = this.maxRetries; // Maximum number of retries
515
- const delayBetweenRetries = this.delayBetweenRetries; // Delay between retries in milliseconds
516
- await this.debugWarnLog(`Retry Count: ${retryCount}`);
517
- await this.debugWarnLog(`Max Retries: ${maxRetries}`);
518
- await this.debugWarnLog(`Delay Between Retries: ${delayBetweenRetries}`);
519
- while (retryCount < maxRetries) {
520
- try {
521
- const { body, statusCode } = await request(Devices, {
522
- headers: this.generateHeaders(),
523
- });
524
- await this.debugWarnLog(`statusCode: ${statusCode}`);
525
- const devicesAPI = await body.json();
526
- await this.debugWarnLog(`devicesAPI: ${JSON.stringify(devicesAPI)}`);
527
- await this.debugWarnLog(`devicesAPI Body: ${JSON.stringify(devicesAPI.body)}`);
528
- await this.debugWarnLog(`devicesAPI StatusCode: ${devicesAPI.statusCode}`);
529
- if ((statusCode === 200 || statusCode === 100) && (devicesAPI.statusCode === 200 || devicesAPI.statusCode === 100)) {
530
- await this.debugErrorLog(`statusCode: ${statusCode} & devicesAPI StatusCode: ${devicesAPI.statusCode}`);
531
- // SwitchBot Devices
532
- const deviceLists = devicesAPI.body.deviceList;
533
- await this.debugWarnLog(`DeviceLists: ${JSON.stringify(deviceLists)}`);
534
- await this.debugWarnLog(`DeviceLists Length: ${deviceLists.length}`);
535
- if (!this.config.options?.devices) {
536
- await this.debugLog(`SwitchBot Device Config Not Set: ${JSON.stringify(this.config.options?.devices)}`);
537
- if (deviceLists.length === 0) {
538
- await this.debugLog(`SwitchBot API Has No Devices With Cloud Services Enabled: ${JSON.stringify(devicesAPI.body)}`);
539
- }
540
- else {
541
- const devices = deviceLists.map((v) => v);
542
- for (const device of devices) {
543
- if (device.deviceType) {
544
- if (device.configDeviceName) {
545
- device.deviceName = device.configDeviceName;
546
- }
547
- this.createDevice(device);
548
- }
549
- }
550
- }
551
- }
552
- else if (this.config.credentials?.token && this.config.options.devices) {
553
- await this.debugLog(`SwitchBot Device Config Set: ${JSON.stringify(this.config.options?.devices)}`);
554
- if (deviceLists.length === 0) {
555
- await this.debugLog(`SwitchBot API Has No Devices With Cloud Services Enabled: ${JSON.stringify(devicesAPI.body)}`);
556
- }
557
- else {
558
- const deviceConfigs = this.config.options?.devices;
559
- const mergeBydeviceId = (a1, a2) => a1.map((itm) => ({
560
- ...a2.find((item) => item.deviceId.toUpperCase().replace(/[^A-Z0-9]+/g, '') === itm.deviceId.toUpperCase().replace(/[^A-Z0-9]+/g, '') && item),
561
- ...itm,
562
- }));
563
- const devices = mergeBydeviceId(deviceLists, deviceConfigs);
564
- await this.debugLog(`SwitchBot Devices: ${JSON.stringify(devices)}`);
565
- for (const device of devices) {
566
- if (!device.deviceType) {
567
- device.deviceType = device.configDeviceType;
568
- this.errorLog(`API has displaying no deviceType: ${device.deviceType}, So using configDeviceType: ${device.configDeviceType}`);
569
- }
570
- if (device.deviceType) {
571
- if (device.configDeviceName) {
572
- device.deviceName = device.configDeviceName;
573
- }
574
- this.createDevice(device);
575
- }
576
- }
577
- }
578
- }
579
- else {
580
- this.errorLog('SwitchBot Token Supplied, Issue with Auth.');
581
- }
582
- if (devicesAPI.body.deviceList.length !== 0) {
583
- this.infoLog(`Total SwitchBot Devices Found: ${devicesAPI.body.deviceList.length}`);
584
- }
585
- else {
586
- await this.debugLog(`Total SwitchBot Devices Found: ${devicesAPI.body.deviceList.length}`);
587
- }
588
- // IR Devices
589
- const irDeviceLists = devicesAPI.body.infraredRemoteList;
590
- if (!this.config.options?.irdevices) {
591
- await this.debugLog(`IR Device Config Not Set: ${JSON.stringify(this.config.options?.irdevices)}`);
592
- const devices = irDeviceLists.map((v) => v);
593
- for (const device of devices) {
594
- if (device.remoteType) {
595
- this.createIRDevice(device);
596
- }
597
- }
598
- }
599
- else {
600
- await this.debugLog(`IR Device Config Set: ${JSON.stringify(this.config.options?.irdevices)}`);
601
- const irDeviceConfig = this.config.options?.irdevices;
602
- const mergeIRBydeviceId = (a1, a2) => a1.map((itm) => ({
603
- ...a2.find((item) => item.deviceId.toUpperCase().replace(/[^A-Z0-9]+/g, '') === itm.deviceId.toUpperCase().replace(/[^A-Z0-9]+/g, '') && item),
604
- ...itm,
605
- }));
606
- const devices = mergeIRBydeviceId(irDeviceLists, irDeviceConfig);
607
- await this.debugLog(`IR Devices: ${JSON.stringify(devices)}`);
608
- for (const device of devices) {
609
- this.createIRDevice(device);
610
- }
611
- }
612
- if (devicesAPI.body.infraredRemoteList.length !== 0) {
613
- this.infoLog(`Total IR Devices Found: ${devicesAPI.body.infraredRemoteList.length}`);
614
- }
615
- else {
616
- await this.debugLog(`Total IR Devices Found: ${devicesAPI.body.infraredRemoteList.length}`);
617
- }
618
- break;
619
- }
620
- else {
621
- this.statusCode(statusCode);
622
- this.statusCode(devicesAPI.statusCode);
623
- if (statusCode === 500) {
624
- retryCount++;
625
- this.infoLog(`statusCode: ${statusCode} Attempt ${retryCount} of ${maxRetries}`);
626
- await sleep(delayBetweenRetries);
627
- }
628
- }
514
+ if (!this.config.credentials?.token) {
515
+ return this.handleManualConfig();
516
+ }
517
+ let retryCount = 0;
518
+ const maxRetries = this.maxRetries;
519
+ const delayBetweenRetries = this.delayBetweenRetries;
520
+ await this.debugWarnLog(`Retry Count: ${retryCount}`);
521
+ await this.debugWarnLog(`Max Retries: ${maxRetries}`);
522
+ await this.debugWarnLog(`Delay Between Retries: ${delayBetweenRetries}`);
523
+ while (retryCount < maxRetries) {
524
+ try {
525
+ const { body, statusCode } = await request(Devices, { headers: this.generateHeaders() });
526
+ await this.debugWarnLog(`statusCode: ${statusCode}`);
527
+ const devicesAPI = await body.json();
528
+ await this.debugWarnLog(`devicesAPI: ${JSON.stringify(devicesAPI)}`);
529
+ if (this.isSuccessfulResponse(statusCode, devicesAPI.statusCode)) {
530
+ await this.handleDevices(devicesAPI.body.deviceList);
531
+ await this.handleIRDevices(devicesAPI.body.infraredRemoteList);
532
+ break;
629
533
  }
630
- catch (e) {
534
+ else {
535
+ await this.handleErrorResponse(statusCode, devicesAPI.statusCode, retryCount, maxRetries, delayBetweenRetries);
631
536
  retryCount++;
632
- this.debugErrorLog(`Failed to Discover Devices, Error Message: ${JSON.stringify(e.message)}, Submit Bugs Here: ` + 'https://tinyurl.com/SwitchBotBug');
633
- await this.debugErrorLog(`Failed to Discover Devices, Error: ${e}`);
634
537
  }
635
538
  }
539
+ catch (e) {
540
+ retryCount++;
541
+ await this.debugErrorLog(`Failed to Discover Devices, Error Message: ${JSON.stringify(e.message)}, Submit Bugs Here: https://tinyurl.com/SwitchBotBug`);
542
+ await this.debugErrorLog(`Failed to Discover Devices, Error: ${e}`);
543
+ }
636
544
  }
637
- else if (!this.config.credentials?.token && this.config.options?.devices) {
545
+ }
546
+ async handleManualConfig() {
547
+ if (this.config.options?.devices) {
638
548
  await this.debugLog(`SwitchBot Device Manual Config Set: ${JSON.stringify(this.config.options?.devices)}`);
639
- const deviceConfigs = this.config.options?.devices;
640
- const devices = deviceConfigs.map((v) => v);
549
+ const devices = this.config.options.devices.map((v) => v);
641
550
  for (const device of devices) {
642
551
  device.deviceType = device.configDeviceType;
643
552
  device.deviceName = device.configDeviceName;
644
553
  if (device.deviceType) {
645
- this.createDevice(device);
554
+ await this.createDevice(device);
555
+ }
556
+ }
557
+ }
558
+ else {
559
+ await this.errorLog('Neither SwitchBot Token or Device Config are set.');
560
+ }
561
+ }
562
+ isSuccessfulResponse(statusCode, apiStatusCode) {
563
+ return (statusCode === 200 || statusCode === 100) && (apiStatusCode === 200 || apiStatusCode === 100);
564
+ }
565
+ async handleDevices(deviceLists) {
566
+ if (!this.config.options?.devices) {
567
+ await this.debugLog(`SwitchBot Device Config Not Set: ${JSON.stringify(this.config.options?.devices)}`);
568
+ if (deviceLists.length === 0) {
569
+ await this.debugLog('SwitchBot API Has No Devices With Cloud Services Enabled');
570
+ }
571
+ else {
572
+ for (const device of deviceLists) {
573
+ if (device.deviceType) {
574
+ if (device.configDeviceName) {
575
+ device.deviceName = device.configDeviceName;
576
+ }
577
+ await this.createDevice(device);
578
+ }
579
+ }
580
+ }
581
+ }
582
+ else {
583
+ await this.debugLog(`SwitchBot Device Config Set: ${JSON.stringify(this.config.options?.devices)}`);
584
+ const devices = this.mergeByDeviceId(deviceLists, this.config.options.devices);
585
+ await this.debugLog(`SwitchBot Devices: ${JSON.stringify(devices)}`);
586
+ for (const device of devices) {
587
+ if (!device.deviceType && device.configDeviceType) {
588
+ device.deviceType = device.configDeviceType;
589
+ await this.warnLog(`API is displaying no deviceType: ${device.deviceType}, So using configDeviceType: ${device.configDeviceType}`);
590
+ }
591
+ else if (!device.deviceType && !device.configDeviceName) {
592
+ await this.errorLog('No deviceType or configDeviceType for device. No device will be created.');
593
+ }
594
+ if (device.deviceType) {
595
+ if (device.configDeviceName) {
596
+ device.deviceName = device.configDeviceName;
597
+ }
598
+ await this.createDevice(device);
599
+ }
600
+ }
601
+ }
602
+ }
603
+ async handleIRDevices(irDeviceLists) {
604
+ if (!this.config.options?.irdevices) {
605
+ await this.debugLog(`IR Device Config Not Set: ${JSON.stringify(this.config.options?.irdevices)}`);
606
+ for (const device of irDeviceLists) {
607
+ if (device.remoteType) {
608
+ await this.createIRDevice(device);
646
609
  }
647
610
  }
648
611
  }
649
612
  else {
650
- this.errorLog('Neither SwitchBot Token or Device Config are not set.');
613
+ await this.debugLog(`IR Device Config Set: ${JSON.stringify(this.config.options?.irdevices)}`);
614
+ const devices = this.mergeByDeviceId(irDeviceLists, this.config.options.irdevices);
615
+ await this.debugLog(`IR Devices: ${JSON.stringify(devices)}`);
616
+ for (const device of devices) {
617
+ await this.createIRDevice(device);
618
+ }
619
+ }
620
+ }
621
+ mergeByDeviceId(a1, a2) {
622
+ const normalizeDeviceId = (deviceId) => deviceId.toUpperCase().replace(/[^A-Z0-9]+/g, '');
623
+ return a1.map((itm) => {
624
+ const matchingItem = a2.find(item => normalizeDeviceId(item.deviceId) === normalizeDeviceId(itm.deviceId));
625
+ return { ...matchingItem, ...itm };
626
+ });
627
+ }
628
+ async handleErrorResponse(statusCode, apiStatusCode, retryCount, maxRetries, delayBetweenRetries) {
629
+ await this.statusCode(statusCode);
630
+ await this.statusCode(apiStatusCode);
631
+ if (statusCode === 500) {
632
+ this.infoLog(`statusCode: ${statusCode} Attempt ${retryCount + 1} of ${maxRetries}`);
633
+ await sleep(delayBetweenRetries);
651
634
  }
652
635
  }
653
636
  async createDevice(device) {
654
- switch (device.deviceType) {
655
- case 'Humidifier':
656
- await this.debugLog(`Discovered ${device.deviceType}: ${device.deviceId}`);
657
- this.createHumidifier(device);
658
- break;
659
- case 'Hub Mini':
660
- await this.debugLog(`Discovered ${device.deviceType}: ${device.deviceId}`);
661
- break;
662
- case 'Hub Plus':
663
- await this.debugLog(`Discovered ${device.deviceType}: ${device.deviceId}`);
664
- break;
665
- case 'Hub 2':
666
- await this.debugLog(`Discovered ${device.deviceType}: ${device.deviceId}`);
667
- this.createHub2(device);
668
- break;
669
- case 'Bot':
670
- await this.debugLog(`Discovered ${device.deviceType}: ${device.deviceId}`);
671
- this.createBot(device);
672
- break;
673
- case 'Meter':
674
- await this.debugLog(`Discovered ${device.deviceType}: ${device.deviceId}`);
675
- this.createMeter(device);
676
- break;
677
- case 'MeterPlus':
678
- case 'Meter Plus (JP)':
679
- await this.debugLog(`Discovered ${device.deviceType}: ${device.deviceId}`);
680
- this.createMeterPlus(device);
681
- break;
682
- case 'WoIOSensor':
683
- await this.debugLog(`Discovered ${device.deviceType}: ${device.deviceId}`);
684
- this.createIOSensor(device);
685
- break;
686
- case 'Water Detector':
687
- await this.debugLog(`Discovered ${device.deviceType}: ${device.deviceId}`);
688
- this.createWaterDetector(device);
689
- break;
690
- case 'Motion Sensor':
691
- await this.debugLog(`Discovered ${device.deviceType}: ${device.deviceId}`);
692
- this.createMotion(device);
693
- break;
694
- case 'Contact Sensor':
695
- await this.debugLog(`Discovered ${device.deviceType}: ${device.deviceId}`);
696
- this.createContact(device);
697
- break;
698
- case 'Curtain':
699
- case 'Curtain3':
700
- await this.debugLog(`Discovered ${device.deviceType} ${device.deviceName}: ${device.deviceId}`);
701
- this.createCurtain(device);
702
- break;
703
- case 'Blind Tilt':
704
- await this.debugLog(`Discovered ${device.deviceType} ${device.deviceName}: ${device.deviceId}`);
705
- this.createBlindTilt(device);
706
- break;
707
- case 'Plug':
708
- case 'Plug Mini (US)':
709
- case 'Plug Mini (JP)':
710
- await this.debugLog(`Discovered ${device.deviceType}: ${device.deviceId}`);
711
- this.createPlug(device);
712
- break;
713
- case 'Smart Lock':
714
- case 'Smart Lock Pro':
715
- await this.debugLog(`Discovered ${device.deviceType}: ${device.deviceId}`);
716
- this.createLock(device);
717
- break;
718
- case 'Color Bulb':
719
- await this.debugLog(`Discovered ${device.deviceType}: ${device.deviceId}`);
720
- this.createColorBulb(device);
721
- break;
722
- case 'K10+':
723
- case 'WoSweeper':
724
- case 'WoSweeperMini':
725
- case 'Robot Vacuum Cleaner S1':
726
- case 'Robot Vacuum Cleaner S1 Plus':
727
- case 'Robot Vacuum Cleaner S10':
728
- await this.debugLog(`Discovered ${device.deviceType}: ${device.deviceId}`);
729
- this.createRobotVacuumCleaner(device);
730
- break;
731
- case 'Ceiling Light':
732
- case 'Ceiling Light Pro':
733
- await this.debugLog(`Discovered ${device.deviceType}: ${device.deviceId}`);
734
- this.createCeilingLight(device);
735
- break;
736
- case 'Strip Light':
737
- await this.debugLog(`Discovered ${device.deviceType}: ${device.deviceId}`);
738
- this.createStripLight(device);
739
- break;
740
- case 'Battery Circulator Fan':
741
- await this.debugLog(`Discovered ${device.deviceType}: ${device.deviceId}`);
742
- this.createFan(device);
743
- break;
744
- case 'Remote':
745
- case 'Indoor Cam':
746
- case 'remote with screen+':
747
- await this.debugLog(`Discovered ${device.deviceType}: ${device.deviceId}, is currently not supported, device: ${JSON.stringify(device)}`);
748
- break;
749
- default:
750
- this.warnLog(`Device: ${device.deviceName} with Device Type: ${device.deviceType}, is currently not supported.`, +`Submit Feature Requests Here: https://tinyurl.com/SwitchBotFeatureRequest, device: ${JSON.stringify(device)}`);
637
+ const deviceTypeHandlers = {
638
+ 'Humidifier': this.createHumidifier.bind(this),
639
+ 'Hub 2': this.createHub2.bind(this),
640
+ 'Bot': this.createBot.bind(this),
641
+ 'Meter': this.createMeter.bind(this),
642
+ 'MeterPlus': this.createMeterPlus.bind(this),
643
+ 'Meter Plus (JP)': this.createMeterPlus.bind(this),
644
+ 'WoIOSensor': this.createIOSensor.bind(this),
645
+ 'Water Detector': this.createWaterDetector.bind(this),
646
+ 'Motion Sensor': this.createMotion.bind(this),
647
+ 'Contact Sensor': this.createContact.bind(this),
648
+ 'Curtain': this.createCurtain.bind(this),
649
+ 'Curtain3': this.createCurtain.bind(this),
650
+ 'WoRollerShade': this.createCurtain.bind(this),
651
+ 'Roller Shade': this.createCurtain.bind(this),
652
+ 'Blind Tilt': this.createBlindTilt.bind(this),
653
+ 'Plug': this.createPlug.bind(this),
654
+ 'Plug Mini (US)': this.createPlug.bind(this),
655
+ 'Plug Mini (JP)': this.createPlug.bind(this),
656
+ 'Smart Lock': this.createLock.bind(this),
657
+ 'Smart Lock Pro': this.createLock.bind(this),
658
+ 'Color Bulb': this.createColorBulb.bind(this),
659
+ 'K10+': this.createRobotVacuumCleaner.bind(this),
660
+ 'WoSweeper': this.createRobotVacuumCleaner.bind(this),
661
+ 'WoSweeperMini': this.createRobotVacuumCleaner.bind(this),
662
+ 'Robot Vacuum Cleaner S1': this.createRobotVacuumCleaner.bind(this),
663
+ 'Robot Vacuum Cleaner S1 Plus': this.createRobotVacuumCleaner.bind(this),
664
+ 'Robot Vacuum Cleaner S10': this.createRobotVacuumCleaner.bind(this),
665
+ 'Ceiling Light': this.createCeilingLight.bind(this),
666
+ 'Ceiling Light Pro': this.createCeilingLight.bind(this),
667
+ 'Strip Light': this.createStripLight.bind(this),
668
+ 'Battery Circulator Fan': this.createFan.bind(this),
669
+ };
670
+ if (deviceTypeHandlers[device.deviceType]) {
671
+ await this.debugLog(`Discovered ${device.deviceType}: ${device.deviceId}`);
672
+ await deviceTypeHandlers[device.deviceType](device);
673
+ }
674
+ else if (['Hub Mini', 'Hub Plus', 'Remote', 'Indoor Cam', 'remote with screen'].includes(device.deviceType)) {
675
+ await this.debugLog(`Discovered ${device.deviceType}: ${device.deviceId}, is currently not supported, device: ${JSON.stringify(device)}`);
676
+ }
677
+ else {
678
+ await this.warnLog(`Device: ${device.deviceName} with Device Type: ${device.deviceType}, is currently not supported. Submit Feature Requests Here: https://tinyurl.com/SwitchBotFeatureRequest, device: ${JSON.stringify(device)}`);
751
679
  }
752
680
  }
753
681
  async createIRDevice(device) {
754
- if (device.connectionType === undefined) {
755
- device.connectionType = 'OpenAPI';
756
- }
757
- switch (device.remoteType) {
758
- case 'TV':
759
- case 'DIY TV':
760
- case 'Projector':
761
- case 'DIY Projector':
762
- case 'Set Top Box':
763
- case 'DIY Set Top Box':
764
- case 'IPTV':
765
- case 'DIY IPTV':
766
- case 'DVD':
767
- case 'DIY DVD':
768
- case 'Speaker':
769
- case 'DIY Speaker':
770
- await this.debugLog(`Discovered ${device.remoteType}: ${device.deviceId}`);
771
- if (device.external === undefined) {
772
- device.external = true;
773
- this.createTV(device);
774
- }
775
- else {
776
- this.createTV(device);
777
- }
778
- break;
779
- case 'Fan':
780
- case 'DIY Fan':
781
- await this.debugLog(`Discovered ${device.remoteType}: ${device.deviceId}`);
782
- this.createIRFan(device);
783
- break;
784
- case 'Air Conditioner':
785
- case 'DIY Air Conditioner':
786
- await this.debugLog(`Discovered ${device.remoteType}: ${device.deviceId}`);
787
- this.createAirConditioner(device);
788
- break;
789
- case 'Light':
790
- case 'DIY Light':
791
- await this.debugLog(`Discovered ${device.remoteType}: ${device.deviceId}`);
792
- this.createLight(device);
793
- break;
794
- case 'Air Purifier':
795
- case 'DIY Air Purifier':
796
- await this.debugLog(`Discovered ${device.remoteType}: ${device.deviceId}`);
797
- this.createAirPurifier(device);
798
- break;
799
- case 'Water Heater':
800
- case 'DIY Water Heater':
801
- await this.debugLog(`Discovered ${device.remoteType}: ${device.deviceId}`);
802
- this.createWaterHeater(device);
803
- break;
804
- case 'Vacuum Cleaner':
805
- case 'DIY Vacuum Cleaner':
806
- await this.debugLog(`Discovered ${device.remoteType}: ${device.deviceId}`);
807
- this.createVacuumCleaner(device);
808
- break;
809
- case 'Camera':
810
- case 'DIY Camera':
811
- await this.debugLog(`Discovered ${device.remoteType}: ${device.deviceId}`);
812
- this.createCamera(device);
813
- break;
814
- case 'Others':
815
- await this.debugLog(`Discovered ${device.remoteType}: ${device.deviceId}`);
816
- this.createOthers(device);
817
- break;
818
- default:
819
- await this.debugLog(`Unsupported Device: ${JSON.stringify(device)}`);
820
- this.warnLog(`Device: ${device.deviceName} with Device Type: ${device.remoteType}, is currently not supported.`);
821
- this.warnLog('Submit Feature Requests Here: ' + 'https://tinyurl.com/SwitchBotFeatureRequest');
682
+ device.connectionType = device.connectionType ?? 'OpenAPI';
683
+ const deviceTypeHandlers = {
684
+ 'TV': this.createTV.bind(this),
685
+ 'DIY TV': this.createTV.bind(this),
686
+ 'Projector': this.createTV.bind(this),
687
+ 'DIY Projector': this.createTV.bind(this),
688
+ 'Set Top Box': this.createTV.bind(this),
689
+ 'DIY Set Top Box': this.createTV.bind(this),
690
+ 'IPTV': this.createTV.bind(this),
691
+ 'DIY IPTV': this.createTV.bind(this),
692
+ 'DVD': this.createTV.bind(this),
693
+ 'DIY DVD': this.createTV.bind(this),
694
+ 'Speaker': this.createTV.bind(this),
695
+ 'DIY Speaker': this.createTV.bind(this),
696
+ 'Fan': this.createIRFan.bind(this),
697
+ 'DIY Fan': this.createIRFan.bind(this),
698
+ 'Air Conditioner': this.createAirConditioner.bind(this),
699
+ 'DIY Air Conditioner': this.createAirConditioner.bind(this),
700
+ 'Light': this.createLight.bind(this),
701
+ 'DIY Light': this.createLight.bind(this),
702
+ 'Air Purifier': this.createAirPurifier.bind(this),
703
+ 'DIY Air Purifier': this.createAirPurifier.bind(this),
704
+ 'Water Heater': this.createWaterHeater.bind(this),
705
+ 'DIY Water Heater': this.createWaterHeater.bind(this),
706
+ 'Vacuum Cleaner': this.createVacuumCleaner.bind(this),
707
+ 'DIY Vacuum Cleaner': this.createVacuumCleaner.bind(this),
708
+ 'Camera': this.createCamera.bind(this),
709
+ 'DIY Camera': this.createCamera.bind(this),
710
+ 'Others': this.createOthers.bind(this),
711
+ };
712
+ if (deviceTypeHandlers[device.remoteType]) {
713
+ await this.debugLog(`Discovered ${device.remoteType}: ${device.deviceId}`);
714
+ if (device.remoteType.startsWith('DIY') && device.external === undefined) {
715
+ device.external = true;
716
+ }
717
+ await deviceTypeHandlers[device.remoteType](device);
718
+ }
719
+ else {
720
+ await this.warnLog(`Device: ${device.deviceName} with Device Type: ${device.remoteType}, is currently not supported. Submit Feature Requests Here: https://tinyurl.com/SwitchBotFeatureRequest, device: ${JSON.stringify(device)}`);
822
721
  }
823
722
  }
824
723
  async createHumidifier(device) {
825
724
  const uuid = this.api.hap.uuid.generate(`${device.deviceId}-${device.deviceType}`);
826
725
  // see if an accessory with the same uuid has already been registered and restored from
827
726
  // the cached devices we stored in the `configureAccessory` method above
828
- const existingAccessory = this.accessories.find((accessory) => accessory.UUID === uuid);
727
+ const existingAccessory = this.accessories.find(accessory => accessory.UUID === uuid);
829
728
  if (existingAccessory) {
830
729
  // the accessory already exists
831
730
  if (await this.registerDevice(device)) {
@@ -884,7 +783,7 @@ export class SwitchBotPlatform {
884
783
  const uuid = this.api.hap.uuid.generate(`${device.deviceId}-${device.deviceType}`);
885
784
  // see if an accessory with the same uuid has already been registered and restored from
886
785
  // the cached devices we stored in the `configureAccessory` method above
887
- const existingAccessory = this.accessories.find((accessory) => accessory.UUID === uuid);
786
+ const existingAccessory = this.accessories.find(accessory => accessory.UUID === uuid);
888
787
  if (existingAccessory) {
889
788
  // the accessory already exists
890
789
  if (await this.registerDevice(device)) {
@@ -945,7 +844,7 @@ export class SwitchBotPlatform {
945
844
  const uuid = this.api.hap.uuid.generate(`${device.deviceId}-${device.deviceType}`);
946
845
  // see if an accessory with the same uuid has already been registered and restored from
947
846
  // the cached devices we stored in the `configureAccessory` method above
948
- const existingAccessory = this.accessories.find((accessory) => accessory.UUID === uuid);
847
+ const existingAccessory = this.accessories.find(accessory => accessory.UUID === uuid);
949
848
  if (existingAccessory) {
950
849
  // the accessory already exists
951
850
  if (await this.registerDevice(device)) {
@@ -1005,7 +904,7 @@ export class SwitchBotPlatform {
1005
904
  const uuid = this.api.hap.uuid.generate(`${device.deviceId}-${device.deviceType}`);
1006
905
  // see if an accessory with the same uuid has already been registered and restored from
1007
906
  // the cached devices we stored in the `configureAccessory` method above
1008
- const existingAccessory = this.accessories.find((accessory) => accessory.UUID === uuid);
907
+ const existingAccessory = this.accessories.find(accessory => accessory.UUID === uuid);
1009
908
  if (existingAccessory) {
1010
909
  // the accessory already exists
1011
910
  if (await this.registerDevice(device)) {
@@ -1066,7 +965,7 @@ export class SwitchBotPlatform {
1066
965
  const uuid = this.api.hap.uuid.generate(`${device.deviceId}-${device.deviceType}`);
1067
966
  // see if an accessory with the same uuid has already been registered and restored from
1068
967
  // the cached devices we stored in the `configureAccessory` method above
1069
- const existingAccessory = this.accessories.find((accessory) => accessory.UUID === uuid);
968
+ const existingAccessory = this.accessories.find(accessory => accessory.UUID === uuid);
1070
969
  if (existingAccessory) {
1071
970
  // the accessory already exists
1072
971
  if (await this.registerDevice(device)) {
@@ -1127,7 +1026,7 @@ export class SwitchBotPlatform {
1127
1026
  const uuid = this.api.hap.uuid.generate(`${device.deviceId}-${device.deviceType}`);
1128
1027
  // see if an accessory with the same uuid has already been registered and restored from
1129
1028
  // the cached devices we stored in the `configureAccessory` method above
1130
- const existingAccessory = this.accessories.find((accessory) => accessory.UUID === uuid);
1029
+ const existingAccessory = this.accessories.find(accessory => accessory.UUID === uuid);
1131
1030
  if (existingAccessory) {
1132
1031
  // the accessory already exists
1133
1032
  if (await this.registerDevice(device)) {
@@ -1187,7 +1086,7 @@ export class SwitchBotPlatform {
1187
1086
  const uuid = this.api.hap.uuid.generate(`${device.deviceId}-${device.deviceType}`);
1188
1087
  // see if an accessory with the same uuid has already been registered and restored from
1189
1088
  // the cached devices we stored in the `configureAccessory` method above
1190
- const existingAccessory = this.accessories.find((accessory) => accessory.UUID === uuid);
1089
+ const existingAccessory = this.accessories.find(accessory => accessory.UUID === uuid);
1191
1090
  if (existingAccessory) {
1192
1091
  // the accessory already exists
1193
1092
  if (await this.registerDevice(device)) {
@@ -1247,7 +1146,7 @@ export class SwitchBotPlatform {
1247
1146
  const uuid = this.api.hap.uuid.generate(`${device.deviceId}-${device.deviceType}`);
1248
1147
  // see if an accessory with the same uuid has already been registered and restored from
1249
1148
  // the cached devices we stored in the `configureAccessory` method above
1250
- const existingAccessory = this.accessories.find((accessory) => accessory.UUID === uuid);
1149
+ const existingAccessory = this.accessories.find(accessory => accessory.UUID === uuid);
1251
1150
  if (existingAccessory) {
1252
1151
  // the accessory already exists
1253
1152
  if (await this.registerDevice(device)) {
@@ -1307,7 +1206,7 @@ export class SwitchBotPlatform {
1307
1206
  const uuid = this.api.hap.uuid.generate(`${device.deviceId}-${device.deviceType}`);
1308
1207
  // see if an accessory with the same uuid has already been registered and restored from
1309
1208
  // the cached devices we stored in the `configureAccessory` method above
1310
- const existingAccessory = this.accessories.find((accessory) => accessory.UUID === uuid);
1209
+ const existingAccessory = this.accessories.find(accessory => accessory.UUID === uuid);
1311
1210
  if (existingAccessory) {
1312
1211
  // the accessory already exists
1313
1212
  if (await this.registerDevice(device)) {
@@ -1367,7 +1266,7 @@ export class SwitchBotPlatform {
1367
1266
  const uuid = this.api.hap.uuid.generate(`${device.deviceId}-${device.deviceType}`);
1368
1267
  // see if an accessory with the same uuid has already been registered and restored from
1369
1268
  // the cached devices we stored in the `configureAccessory` method above
1370
- const existingAccessory = this.accessories.find((accessory) => accessory.UUID === uuid);
1269
+ const existingAccessory = this.accessories.find(accessory => accessory.UUID === uuid);
1371
1270
  if (existingAccessory) {
1372
1271
  // the accessory already exists
1373
1272
  if (await this.registerDevice(device)) {
@@ -1395,8 +1294,8 @@ export class SwitchBotPlatform {
1395
1294
  else if (await this.registerDevice(device)) {
1396
1295
  if (isBlindTiltDevice(device)) {
1397
1296
  if (device.group && !device.curtain?.disable_group) {
1398
- this.debugLog('Your Curtains are grouped, ' +
1399
- `, Secondary curtain automatically hidden. Main Curtain: ${device.deviceName}, deviceId: ${device.deviceId}`);
1297
+ this.debugLog('Your Curtains are grouped, '
1298
+ + `, Secondary curtain automatically hidden. Main Curtain: ${device.deviceName}, deviceId: ${device.deviceId}`);
1400
1299
  }
1401
1300
  else {
1402
1301
  if (device.master) {
@@ -1414,7 +1313,6 @@ export class SwitchBotPlatform {
1414
1313
  // store a copy of the device object in the `accessory.context`
1415
1314
  // the `context` property can be used to store any data about the accessory you may need
1416
1315
  accessory.context.device = device;
1417
- ;
1418
1316
  accessory.context.deviceId = device.deviceId;
1419
1317
  accessory.context.deviceType = device.deviceType;
1420
1318
  accessory.context.model = SwitchBotModel.BlindTilt;
@@ -1442,7 +1340,7 @@ export class SwitchBotPlatform {
1442
1340
  const uuid = this.api.hap.uuid.generate(`${device.deviceId}-${device.deviceType}`);
1443
1341
  // see if an accessory with the same uuid has already been registered and restored from
1444
1342
  // the cached devices we stored in the `configureAccessory` method above
1445
- const existingAccessory = this.accessories.find((accessory) => accessory.UUID === uuid);
1343
+ const existingAccessory = this.accessories.find(accessory => accessory.UUID === uuid);
1446
1344
  if (existingAccessory) {
1447
1345
  // the accessory already exists
1448
1346
  if (await this.registerDevice(device)) {
@@ -1470,8 +1368,8 @@ export class SwitchBotPlatform {
1470
1368
  else if (await this.registerDevice(device)) {
1471
1369
  if (isCurtainDevice(device)) {
1472
1370
  if (device.group && !device.curtain?.disable_group) {
1473
- this.debugLog('Your Curtains are grouped, ' +
1474
- `, Secondary curtain automatically hidden. Main Curtain: ${device.deviceName}, deviceId: ${device.deviceId}`);
1371
+ this.debugLog('Your Curtains are grouped, '
1372
+ + `, Secondary curtain automatically hidden. Main Curtain: ${device.deviceName}, deviceId: ${device.deviceId}`);
1475
1373
  }
1476
1374
  else {
1477
1375
  if (device.master) {
@@ -1516,7 +1414,7 @@ export class SwitchBotPlatform {
1516
1414
  const uuid = this.api.hap.uuid.generate(`${device.deviceId}-${device.deviceType}`);
1517
1415
  // see if an accessory with the same uuid has already been registered and restored from
1518
1416
  // the cached devices we stored in the `configureAccessory` method above
1519
- const existingAccessory = this.accessories.find((accessory) => accessory.UUID === uuid);
1417
+ const existingAccessory = this.accessories.find(accessory => accessory.UUID === uuid);
1520
1418
  if (existingAccessory) {
1521
1419
  // the accessory already exists
1522
1420
  if (await this.registerDevice(device)) {
@@ -1524,8 +1422,11 @@ export class SwitchBotPlatform {
1524
1422
  existingAccessory.context.device = device;
1525
1423
  existingAccessory.context.deviceId = device.deviceId;
1526
1424
  existingAccessory.context.deviceType = device.deviceType;
1527
- existingAccessory.context.model = device.deviceType === 'Plug Mini (US)' ? SwitchBotModel.PlugMiniUS : device.deviceType === 'Plug Mini (JP)'
1528
- ? SwitchBotModel.PlugMiniJP : SwitchBotModel.Plug;
1425
+ existingAccessory.context.model = device.deviceType === 'Plug Mini (US)'
1426
+ ? SwitchBotModel.PlugMiniUS
1427
+ : device.deviceType === 'Plug Mini (JP)'
1428
+ ? SwitchBotModel.PlugMiniJP
1429
+ : SwitchBotModel.Plug;
1529
1430
  existingAccessory.displayName = device.configDeviceName
1530
1431
  ? await this.validateAndCleanDisplayName(device.configDeviceName, 'configDeviceName', device.configDeviceName)
1531
1432
  : await this.validateAndCleanDisplayName(device.deviceName, 'deviceName', device.deviceName);
@@ -1552,8 +1453,11 @@ export class SwitchBotPlatform {
1552
1453
  accessory.context.device = device;
1553
1454
  accessory.context.deviceId = device.deviceId;
1554
1455
  accessory.context.deviceType = device.deviceType;
1555
- accessory.context.model = device.deviceType === 'Plug Mini (US)' ? SwitchBotModel.PlugMiniUS : device.deviceType === 'Plug Mini (JP)'
1556
- ? SwitchBotModel.PlugMiniJP : SwitchBotModel.Plug;
1456
+ accessory.context.model = device.deviceType === 'Plug Mini (US)'
1457
+ ? SwitchBotModel.PlugMiniUS
1458
+ : device.deviceType === 'Plug Mini (JP)'
1459
+ ? SwitchBotModel.PlugMiniJP
1460
+ : SwitchBotModel.Plug;
1557
1461
  accessory.displayName = device.configDeviceName
1558
1462
  ? await this.validateAndCleanDisplayName(device.configDeviceName, 'configDeviceName', device.configDeviceName)
1559
1463
  : await this.validateAndCleanDisplayName(device.deviceName, 'deviceName', device.deviceName);
@@ -1578,7 +1482,7 @@ export class SwitchBotPlatform {
1578
1482
  const uuid = this.api.hap.uuid.generate(`${device.deviceId}-${device.deviceType}`);
1579
1483
  // see if an accessory with the same uuid has already been registered and restored from
1580
1484
  // the cached devices we stored in the `configureAccessory` method above
1581
- const existingAccessory = this.accessories.find((accessory) => accessory.UUID === uuid);
1485
+ const existingAccessory = this.accessories.find(accessory => accessory.UUID === uuid);
1582
1486
  if (existingAccessory) {
1583
1487
  // the accessory already exists
1584
1488
  if (await this.registerDevice(device)) {
@@ -1638,7 +1542,7 @@ export class SwitchBotPlatform {
1638
1542
  const uuid = this.api.hap.uuid.generate(`${device.deviceId}-${device.deviceType}`);
1639
1543
  // see if an accessory with the same uuid has already been registered and restored from
1640
1544
  // the cached devices we stored in the `configureAccessory` method above
1641
- const existingAccessory = this.accessories.find((accessory) => accessory.UUID === uuid);
1545
+ const existingAccessory = this.accessories.find(accessory => accessory.UUID === uuid);
1642
1546
  if (existingAccessory) {
1643
1547
  // the accessory already exists
1644
1548
  if (await this.registerDevice(device)) {
@@ -1698,7 +1602,7 @@ export class SwitchBotPlatform {
1698
1602
  const uuid = this.api.hap.uuid.generate(`${device.deviceId}-${device.deviceType}`);
1699
1603
  // see if an accessory with the same uuid has already been registered and restored from
1700
1604
  // the cached devices we stored in the `configureAccessory` method above
1701
- const existingAccessory = this.accessories.find((accessory) => accessory.UUID === uuid);
1605
+ const existingAccessory = this.accessories.find(accessory => accessory.UUID === uuid);
1702
1606
  if (existingAccessory) {
1703
1607
  // the accessory already exists
1704
1608
  if (await this.registerDevice(device)) {
@@ -1758,7 +1662,7 @@ export class SwitchBotPlatform {
1758
1662
  const uuid = this.api.hap.uuid.generate(`${device.deviceId}-${device.deviceType}`);
1759
1663
  // see if an accessory with the same uuid has already been registered and restored from
1760
1664
  // the cached devices we stored in the `configureAccessory` method above
1761
- const existingAccessory = this.accessories.find((accessory) => accessory.UUID === uuid);
1665
+ const existingAccessory = this.accessories.find(accessory => accessory.UUID === uuid);
1762
1666
  if (existingAccessory) {
1763
1667
  // the accessory already exists
1764
1668
  if (await this.registerDevice(device)) {
@@ -1818,7 +1722,7 @@ export class SwitchBotPlatform {
1818
1722
  const uuid = this.api.hap.uuid.generate(`${device.deviceId}-${device.deviceType}`);
1819
1723
  // see if an accessory with the same uuid has already been registered and restored from
1820
1724
  // the cached devices we stored in the `configureAccessory` method above
1821
- const existingAccessory = this.accessories.find((accessory) => accessory.UUID === uuid);
1725
+ const existingAccessory = this.accessories.find(accessory => accessory.UUID === uuid);
1822
1726
  if (existingAccessory) {
1823
1727
  // the accessory already exists
1824
1728
  if (await this.registerDevice(device)) {
@@ -1878,7 +1782,7 @@ export class SwitchBotPlatform {
1878
1782
  const uuid = this.api.hap.uuid.generate(`${device.deviceId}-${device.deviceType}`);
1879
1783
  // see if an accessory with the same uuid has already been registered and restored from
1880
1784
  // the cached devices we stored in the `configureAccessory` method above
1881
- const existingAccessory = this.accessories.find((accessory) => accessory.UUID === uuid);
1785
+ const existingAccessory = this.accessories.find(accessory => accessory.UUID === uuid);
1882
1786
  if (existingAccessory) {
1883
1787
  // the accessory already exists
1884
1788
  if (await this.registerDevice(device)) {
@@ -1886,11 +1790,17 @@ export class SwitchBotPlatform {
1886
1790
  existingAccessory.context.device = device;
1887
1791
  existingAccessory.context.deviceId = device.deviceId;
1888
1792
  existingAccessory.context.deviceType = device.deviceType;
1889
- existingAccessory.context.model = device.deviceType === 'Robot Vacuum Cleaner S1' ? SwitchBotModel.RobotVacuumCleanerS1
1890
- : device.deviceType === 'Robot Vacuum Cleaner S1 Plus' ? SwitchBotModel.RobotVacuumCleanerS1Plus
1891
- : device.deviceType === 'Robot Vacuum Cleaner S10' ? SwitchBotModel.RobotVacuumCleanerS10
1892
- : device.deviceType === 'WoSweeper' ? SwitchBotModel.WoSweeper : device.deviceType === 'WoSweeperMini' ? SwitchBotModel.WoSweeperMini
1893
- : SwitchBotModel.Unknown;
1793
+ existingAccessory.context.model = device.deviceType === 'Robot Vacuum Cleaner S1'
1794
+ ? SwitchBotModel.RobotVacuumCleanerS1
1795
+ : device.deviceType === 'Robot Vacuum Cleaner S1 Plus'
1796
+ ? SwitchBotModel.RobotVacuumCleanerS1Plus
1797
+ : device.deviceType === 'Robot Vacuum Cleaner S10'
1798
+ ? SwitchBotModel.RobotVacuumCleanerS10
1799
+ : device.deviceType === 'WoSweeper'
1800
+ ? SwitchBotModel.WoSweeper
1801
+ : device.deviceType === 'WoSweeperMini'
1802
+ ? SwitchBotModel.WoSweeperMini
1803
+ : SwitchBotModel.Unknown;
1894
1804
  existingAccessory.displayName = device.configDeviceName
1895
1805
  ? await this.validateAndCleanDisplayName(device.configDeviceName, 'configDeviceName', device.configDeviceName)
1896
1806
  : await this.validateAndCleanDisplayName(device.deviceName, 'deviceName', device.deviceName);
@@ -1917,11 +1827,17 @@ export class SwitchBotPlatform {
1917
1827
  accessory.context.device = device;
1918
1828
  accessory.context.deviceId = device.deviceId;
1919
1829
  accessory.context.deviceType = device.deviceType;
1920
- accessory.context.model = device.deviceType === 'Robot Vacuum Cleaner S1' ? SwitchBotModel.RobotVacuumCleanerS1
1921
- : device.deviceType === 'Robot Vacuum Cleaner S1 Plus' ? SwitchBotModel.RobotVacuumCleanerS1Plus
1922
- : device.deviceType === 'Robot Vacuum Cleaner S10' ? SwitchBotModel.RobotVacuumCleanerS10
1923
- : device.deviceType === 'WoSweeper' ? SwitchBotModel.WoSweeper : device.deviceType === 'WoSweeperMini' ? SwitchBotModel.WoSweeperMini
1924
- : SwitchBotModel.Unknown;
1830
+ accessory.context.model = device.deviceType === 'Robot Vacuum Cleaner S1'
1831
+ ? SwitchBotModel.RobotVacuumCleanerS1
1832
+ : device.deviceType === 'Robot Vacuum Cleaner S1 Plus'
1833
+ ? SwitchBotModel.RobotVacuumCleanerS1Plus
1834
+ : device.deviceType === 'Robot Vacuum Cleaner S10'
1835
+ ? SwitchBotModel.RobotVacuumCleanerS10
1836
+ : device.deviceType === 'WoSweeper'
1837
+ ? SwitchBotModel.WoSweeper
1838
+ : device.deviceType === 'WoSweeperMini'
1839
+ ? SwitchBotModel.WoSweeperMini
1840
+ : SwitchBotModel.Unknown;
1925
1841
  accessory.displayName = device.configDeviceName
1926
1842
  ? await this.validateAndCleanDisplayName(device.configDeviceName, 'configDeviceName', device.configDeviceName)
1927
1843
  : await this.validateAndCleanDisplayName(device.deviceName, 'deviceName', device.deviceName);
@@ -1946,7 +1862,7 @@ export class SwitchBotPlatform {
1946
1862
  const uuid = this.api.hap.uuid.generate(`${device.deviceId}-${device.remoteType}`);
1947
1863
  // see if an accessory with the same uuid has already been registered and restored from
1948
1864
  // the cached devices we stored in the `configureAccessory` method above
1949
- const existingAccessory = this.accessories.find((accessory) => accessory.UUID === uuid);
1865
+ const existingAccessory = this.accessories.find(accessory => accessory.UUID === uuid);
1950
1866
  if (!device.hide_device && existingAccessory) {
1951
1867
  // if you need to update the accessory.context then you should run `api.updatePlatformAccessories`. eg.:
1952
1868
  existingAccessory.context.device = device;
@@ -1979,7 +1895,6 @@ export class SwitchBotPlatform {
1979
1895
  ? await this.validateAndCleanDisplayName(device.configDeviceName, 'configDeviceName', device.configDeviceName)
1980
1896
  : await this.validateAndCleanDisplayName(device.deviceName, 'deviceName', device.deviceName);
1981
1897
  accessory.context.connectionType = await this.connectionType(device);
1982
- accessory.context.connectionType = device.connectionType;
1983
1898
  accessory.context.version = device.firmware ?? device.version ?? this.version ?? '0.0.0';
1984
1899
  const newOrExternal = !device.external ? 'Adding new' : 'Loading external';
1985
1900
  await this.infoLog(`${newOrExternal} accessory: ${accessory.displayName} deviceId: ${device.deviceId}`);
@@ -1987,7 +1902,7 @@ export class SwitchBotPlatform {
1987
1902
  // this is imported from `platformAccessory.ts`
1988
1903
  new TV(this, accessory, device);
1989
1904
  await this.debugLog(`${device.remoteType} uuid: ${device.deviceId}-${device.remoteType}, (${accessory.UUID})`);
1990
- this.externalOrPlatformIR(device, accessory);
1905
+ this.externalOrPlatform(device, accessory);
1991
1906
  this.accessories.push(accessory);
1992
1907
  }
1993
1908
  else {
@@ -1998,7 +1913,7 @@ export class SwitchBotPlatform {
1998
1913
  const uuid = this.api.hap.uuid.generate(`${device.deviceId}-${device.remoteType}`);
1999
1914
  // see if an accessory with the same uuid has already been registered and restored from
2000
1915
  // the cached devices we stored in the `configureAccessory` method above
2001
- const existingAccessory = this.accessories.find((accessory) => accessory.UUID === uuid);
1916
+ const existingAccessory = this.accessories.find(accessory => accessory.UUID === uuid);
2002
1917
  if (existingAccessory) {
2003
1918
  // the accessory already exists
2004
1919
  if (!device.hide_device && device.hubDeviceId) {
@@ -2037,7 +1952,6 @@ export class SwitchBotPlatform {
2037
1952
  ? await this.validateAndCleanDisplayName(device.configDeviceName, 'configDeviceName', device.configDeviceName)
2038
1953
  : await this.validateAndCleanDisplayName(device.deviceName, 'deviceName', device.deviceName);
2039
1954
  accessory.context.connectionType = await this.connectionType(device);
2040
- accessory.context.connectionType = device.connectionType;
2041
1955
  accessory.context.version = device.firmware ?? device.version ?? this.version ?? '0.0.0';
2042
1956
  const newOrExternal = !device.external ? 'Adding new' : 'Loading external';
2043
1957
  await this.infoLog(`${newOrExternal} accessory: ${accessory.displayName} deviceId: ${device.deviceId}`);
@@ -2046,7 +1960,7 @@ export class SwitchBotPlatform {
2046
1960
  new IRFan(this, accessory, device);
2047
1961
  await this.debugLog(`${device.remoteType} uuid: ${device.deviceId}-${device.remoteType}, (${accessory.UUID})`);
2048
1962
  // publish device externally or link the accessory to your platform
2049
- this.externalOrPlatformIR(device, accessory);
1963
+ this.externalOrPlatform(device, accessory);
2050
1964
  this.accessories.push(accessory);
2051
1965
  }
2052
1966
  else {
@@ -2057,7 +1971,7 @@ export class SwitchBotPlatform {
2057
1971
  const uuid = this.api.hap.uuid.generate(`${device.deviceId}-${device.remoteType}`);
2058
1972
  // see if an accessory with the same uuid has already been registered and restored from
2059
1973
  // the cached devices we stored in the `configureAccessory` method above
2060
- const existingAccessory = this.accessories.find((accessory) => accessory.UUID === uuid);
1974
+ const existingAccessory = this.accessories.find(accessory => accessory.UUID === uuid);
2061
1975
  if (existingAccessory) {
2062
1976
  // the accessory already exists
2063
1977
  if (!device.hide_device && device.hubDeviceId) {
@@ -2096,7 +2010,6 @@ export class SwitchBotPlatform {
2096
2010
  ? await this.validateAndCleanDisplayName(device.configDeviceName, 'configDeviceName', device.configDeviceName)
2097
2011
  : await this.validateAndCleanDisplayName(device.deviceName, 'deviceName', device.deviceName);
2098
2012
  accessory.context.connectionType = await this.connectionType(device);
2099
- accessory.context.connectionType = device.connectionType;
2100
2013
  accessory.context.version = device.firmware ?? device.version ?? this.version ?? '0.0.0';
2101
2014
  const newOrExternal = !device.external ? 'Adding new' : 'Loading external';
2102
2015
  await this.infoLog(`${newOrExternal} accessory: ${accessory.displayName} deviceId: ${device.deviceId}`);
@@ -2105,7 +2018,7 @@ export class SwitchBotPlatform {
2105
2018
  new Light(this, accessory, device);
2106
2019
  await this.debugLog(`${device.remoteType} uuid: ${device.deviceId}-${device.remoteType}, (${accessory.UUID})`);
2107
2020
  // publish device externally or link the accessory to your platform
2108
- this.externalOrPlatformIR(device, accessory);
2021
+ this.externalOrPlatform(device, accessory);
2109
2022
  this.accessories.push(accessory);
2110
2023
  }
2111
2024
  else {
@@ -2116,7 +2029,7 @@ export class SwitchBotPlatform {
2116
2029
  const uuid = this.api.hap.uuid.generate(`${device.deviceId}-${device.remoteType}`);
2117
2030
  // see if an accessory with the same uuid has already been registered and restored from
2118
2031
  // the cached devices we stored in the `configureAccessory` method above
2119
- const existingAccessory = this.accessories.find((accessory) => accessory.UUID === uuid);
2032
+ const existingAccessory = this.accessories.find(accessory => accessory.UUID === uuid);
2120
2033
  if (existingAccessory) {
2121
2034
  // the accessory already exists
2122
2035
  if (!device.hide_device && device.hubDeviceId) {
@@ -2155,7 +2068,6 @@ export class SwitchBotPlatform {
2155
2068
  ? await this.validateAndCleanDisplayName(device.configDeviceName, 'configDeviceName', device.configDeviceName)
2156
2069
  : await this.validateAndCleanDisplayName(device.deviceName, 'deviceName', device.deviceName);
2157
2070
  accessory.context.connectionType = await this.connectionType(device);
2158
- accessory.context.connectionType = device.connectionType;
2159
2071
  accessory.context.version = device.firmware ?? device.version ?? this.version ?? '0.0.0';
2160
2072
  const newOrExternal = !device.external ? 'Adding new' : 'Loading external';
2161
2073
  await this.infoLog(`${newOrExternal} accessory: ${accessory.displayName} deviceId: ${device.deviceId}`);
@@ -2164,7 +2076,7 @@ export class SwitchBotPlatform {
2164
2076
  new AirConditioner(this, accessory, device);
2165
2077
  await this.debugLog(`${device.remoteType} uuid: ${device.deviceId}-${device.remoteType}, (${accessory.UUID})`);
2166
2078
  // publish device externally or link the accessory to your platform
2167
- this.externalOrPlatformIR(device, accessory);
2079
+ this.externalOrPlatform(device, accessory);
2168
2080
  this.accessories.push(accessory);
2169
2081
  }
2170
2082
  else {
@@ -2175,7 +2087,7 @@ export class SwitchBotPlatform {
2175
2087
  const uuid = this.api.hap.uuid.generate(`${device.deviceId}-${device.remoteType}`);
2176
2088
  // see if an accessory with the same uuid has already been registered and restored from
2177
2089
  // the cached devices we stored in the `configureAccessory` method above
2178
- const existingAccessory = this.accessories.find((accessory) => accessory.UUID === uuid);
2090
+ const existingAccessory = this.accessories.find(accessory => accessory.UUID === uuid);
2179
2091
  if (existingAccessory) {
2180
2092
  // the accessory already exists
2181
2093
  if (!device.hide_device && device.hubDeviceId) {
@@ -2214,7 +2126,6 @@ export class SwitchBotPlatform {
2214
2126
  ? await this.validateAndCleanDisplayName(device.configDeviceName, 'configDeviceName', device.configDeviceName)
2215
2127
  : await this.validateAndCleanDisplayName(device.deviceName, 'deviceName', device.deviceName);
2216
2128
  accessory.context.connectionType = await this.connectionType(device);
2217
- accessory.context.connectionType = device.connectionType;
2218
2129
  accessory.context.version = device.firmware ?? device.version ?? this.version ?? '0.0.0';
2219
2130
  const newOrExternal = !device.external ? 'Adding new' : 'Loading external';
2220
2131
  await this.infoLog(`${newOrExternal} accessory: ${accessory.displayName} deviceId: ${device.deviceId}`);
@@ -2223,7 +2134,7 @@ export class SwitchBotPlatform {
2223
2134
  new AirPurifier(this, accessory, device);
2224
2135
  await this.debugLog(`${device.remoteType} uuid: ${device.deviceId}-${device.remoteType}, (${accessory.UUID})`);
2225
2136
  // publish device externally or link the accessory to your platform
2226
- this.externalOrPlatformIR(device, accessory);
2137
+ this.externalOrPlatform(device, accessory);
2227
2138
  this.accessories.push(accessory);
2228
2139
  }
2229
2140
  else {
@@ -2234,7 +2145,7 @@ export class SwitchBotPlatform {
2234
2145
  const uuid = this.api.hap.uuid.generate(`${device.deviceId}-${device.remoteType}`);
2235
2146
  // see if an accessory with the same uuid has already been registered and restored from
2236
2147
  // the cached devices we stored in the `configureAccessory` method above
2237
- const existingAccessory = this.accessories.find((accessory) => accessory.UUID === uuid);
2148
+ const existingAccessory = this.accessories.find(accessory => accessory.UUID === uuid);
2238
2149
  if (existingAccessory) {
2239
2150
  // the accessory already exists
2240
2151
  if (!device.hide_device && device.hubDeviceId) {
@@ -2273,7 +2184,6 @@ export class SwitchBotPlatform {
2273
2184
  ? await this.validateAndCleanDisplayName(device.configDeviceName, 'configDeviceName', device.configDeviceName)
2274
2185
  : await this.validateAndCleanDisplayName(device.deviceName, 'deviceName', device.deviceName);
2275
2186
  accessory.context.connectionType = await this.connectionType(device);
2276
- accessory.context.connectionType = device.connectionType;
2277
2187
  accessory.context.version = device.firmware ?? device.version ?? this.version ?? '0.0.0';
2278
2188
  const newOrExternal = !device.external ? 'Adding new' : 'Loading external';
2279
2189
  await this.infoLog(`${newOrExternal} accessory: ${accessory.displayName} deviceId: ${device.deviceId}`);
@@ -2282,7 +2192,7 @@ export class SwitchBotPlatform {
2282
2192
  new WaterHeater(this, accessory, device);
2283
2193
  await this.debugLog(`${device.remoteType} uuid: ${device.deviceId}-${device.remoteType}, (${accessory.UUID})`);
2284
2194
  // publish device externally or link the accessory to your platform
2285
- this.externalOrPlatformIR(device, accessory);
2195
+ this.externalOrPlatform(device, accessory);
2286
2196
  this.accessories.push(accessory);
2287
2197
  }
2288
2198
  else {
@@ -2293,7 +2203,7 @@ export class SwitchBotPlatform {
2293
2203
  const uuid = this.api.hap.uuid.generate(`${device.deviceId}-${device.remoteType}`);
2294
2204
  // see if an accessory with the same uuid has already been registered and restored from
2295
2205
  // the cached devices we stored in the `configureAccessory` method above
2296
- const existingAccessory = this.accessories.find((accessory) => accessory.UUID === uuid);
2206
+ const existingAccessory = this.accessories.find(accessory => accessory.UUID === uuid);
2297
2207
  if (existingAccessory) {
2298
2208
  // the accessory already exists
2299
2209
  if (!device.hide_device && device.hubDeviceId) {
@@ -2332,7 +2242,6 @@ export class SwitchBotPlatform {
2332
2242
  ? await this.validateAndCleanDisplayName(device.configDeviceName, 'configDeviceName', device.configDeviceName)
2333
2243
  : await this.validateAndCleanDisplayName(device.deviceName, 'deviceName', device.deviceName);
2334
2244
  accessory.context.connectionType = await this.connectionType(device);
2335
- accessory.context.connectionType = device.connectionType;
2336
2245
  accessory.context.version = device.firmware ?? device.version ?? this.version ?? '0.0.0';
2337
2246
  const newOrExternal = !device.external ? 'Adding new' : 'Loading external';
2338
2247
  await this.infoLog(`${newOrExternal} accessory: ${accessory.displayName} deviceId: ${device.deviceId}`);
@@ -2341,7 +2250,7 @@ export class SwitchBotPlatform {
2341
2250
  new VacuumCleaner(this, accessory, device);
2342
2251
  await this.debugLog(`${device.remoteType} uuid: ${device.deviceId}-${device.remoteType}, (${accessory.UUID})`);
2343
2252
  // publish device externally or link the accessory to your platform
2344
- this.externalOrPlatformIR(device, accessory);
2253
+ this.externalOrPlatform(device, accessory);
2345
2254
  this.accessories.push(accessory);
2346
2255
  }
2347
2256
  else {
@@ -2352,7 +2261,7 @@ export class SwitchBotPlatform {
2352
2261
  const uuid = this.api.hap.uuid.generate(`${device.deviceId}-${device.remoteType}`);
2353
2262
  // see if an accessory with the same uuid has already been registered and restored from
2354
2263
  // the cached devices we stored in the `configureAccessory` method above
2355
- const existingAccessory = this.accessories.find((accessory) => accessory.UUID === uuid);
2264
+ const existingAccessory = this.accessories.find(accessory => accessory.UUID === uuid);
2356
2265
  if (existingAccessory) {
2357
2266
  // the accessory already exists
2358
2267
  if (!device.hide_device && device.hubDeviceId) {
@@ -2391,7 +2300,6 @@ export class SwitchBotPlatform {
2391
2300
  ? await this.validateAndCleanDisplayName(device.configDeviceName, 'configDeviceName', device.configDeviceName)
2392
2301
  : await this.validateAndCleanDisplayName(device.deviceName, 'deviceName', device.deviceName);
2393
2302
  accessory.context.connectionType = await this.connectionType(device);
2394
- accessory.context.connectionType = device.connectionType;
2395
2303
  accessory.context.version = device.firmware ?? device.version ?? this.version ?? '0.0.0';
2396
2304
  const newOrExternal = !device.external ? 'Adding new' : 'Loading external';
2397
2305
  await this.infoLog(`${newOrExternal} accessory: ${accessory.displayName} deviceId: ${device.deviceId}`);
@@ -2400,7 +2308,7 @@ export class SwitchBotPlatform {
2400
2308
  new Camera(this, accessory, device);
2401
2309
  await this.debugLog(`${device.remoteType} uuid: ${device.deviceId}-${device.remoteType}, (${accessory.UUID})`);
2402
2310
  // publish device externally or link the accessory to your platform
2403
- this.externalOrPlatformIR(device, accessory);
2311
+ this.externalOrPlatform(device, accessory);
2404
2312
  this.accessories.push(accessory);
2405
2313
  }
2406
2314
  else {
@@ -2411,7 +2319,7 @@ export class SwitchBotPlatform {
2411
2319
  const uuid = this.api.hap.uuid.generate(`${device.deviceId}-${device.remoteType}`);
2412
2320
  // see if an accessory with the same uuid has already been registered and restored from
2413
2321
  // the cached devices we stored in the `configureAccessory` method above
2414
- const existingAccessory = this.accessories.find((accessory) => accessory.UUID === uuid);
2322
+ const existingAccessory = this.accessories.find(accessory => accessory.UUID === uuid);
2415
2323
  if (existingAccessory) {
2416
2324
  // the accessory already exists
2417
2325
  if (!device.hide_device && device.hubDeviceId) {
@@ -2450,7 +2358,6 @@ export class SwitchBotPlatform {
2450
2358
  ? await this.validateAndCleanDisplayName(device.configDeviceName, 'configDeviceName', device.configDeviceName)
2451
2359
  : await this.validateAndCleanDisplayName(device.deviceName, 'deviceName', device.deviceName);
2452
2360
  accessory.context.connectionType = await this.connectionType(device);
2453
- accessory.context.connectionType = device.connectionType;
2454
2361
  accessory.context.version = device.firmware ?? device.version ?? this.version ?? '0.0.0';
2455
2362
  const newOrExternal = !device.external ? 'Adding new' : 'Loading external';
2456
2363
  await this.infoLog(`${newOrExternal} accessory: ${accessory.displayName} deviceId: ${device.deviceId}`);
@@ -2459,7 +2366,7 @@ export class SwitchBotPlatform {
2459
2366
  new Others(this, accessory, device);
2460
2367
  await this.debugLog(`${device.remoteType} uuid: ${device.deviceId}-${device.remoteType}, (${accessory.UUID})`);
2461
2368
  // publish device externally or link the accessory to your platform
2462
- this.externalOrPlatformIR(device, accessory);
2369
+ this.externalOrPlatform(device, accessory);
2463
2370
  this.accessories.push(accessory);
2464
2371
  }
2465
2372
  else {
@@ -2467,24 +2374,13 @@ export class SwitchBotPlatform {
2467
2374
  }
2468
2375
  }
2469
2376
  async registerCurtains(device) {
2470
- /*function isCurtainDevice(device: device & devicesConfig): device is (curtain | curtain3) & devicesConfig {
2471
- return device.deviceType === 'Curtain' || device.deviceType === 'Curtain3';
2472
- }
2473
-
2474
- function isBlindTiltDevice(device: device & devicesConfig): device is blindTilt & devicesConfig {
2475
- return device.deviceType === 'Blind Tilt';
2476
- }*/
2477
2377
  let registerWindowCovering;
2478
2378
  if (isCurtainDevice(device)) {
2479
- await this.debugWarnLog(`deviceName: ${device.deviceName} deviceId: ${device.deviceId}, curtainDevicesIds: ${device.curtainDevicesIds},`
2480
- + ` master: ${device.master}, group: ${device.group}, disable_group: ${device.curtain?.disable_group},`
2481
- + ` connectionType: ${device.connectionType}`);
2379
+ await this.debugWarnLog(`deviceName: ${device.deviceName} deviceId: ${device.deviceId}, curtainDevicesIds: ${device.curtainDevicesIds},x master: ${device.master}, group: ${device.group}, disable_group: ${device.curtain?.disable_group}, connectionType: ${device.connectionType}`);
2482
2380
  registerWindowCovering = await this.registerWindowCovering(device);
2483
2381
  }
2484
2382
  else if (isBlindTiltDevice(device)) {
2485
- await this.debugWarnLog(`deviceName: ${device.deviceName} deviceId: ${device.deviceId}, blindTiltDevicesIds: ${device.blindTiltDevicesIds},`
2486
- + ` master: ${device.master}, group: ${device.group}, disable_group: ${device.curtain?.disable_group},`
2487
- + ` connectionType: ${device.connectionType}`);
2383
+ await this.debugWarnLog(`deviceName: ${device.deviceName} deviceId: ${device.deviceId}, blindTiltDevicesIds: ${device.blindTiltDevicesIds}, master: ${device.master}, group: ${device.group}, disable_group: ${device.curtain?.disable_group}, connectionType: ${device.connectionType}`);
2488
2384
  registerWindowCovering = await this.registerWindowCovering(device);
2489
2385
  }
2490
2386
  else {
@@ -2498,36 +2394,31 @@ export class SwitchBotPlatform {
2498
2394
  if (device.master && device.group) {
2499
2395
  // OpenAPI: Master Curtains/Blind Tilt in Group
2500
2396
  registerCurtain = true;
2501
- await this.debugLog(`deviceName: ${device.deviceName} [${device.deviceType} Config] device.master: ${device.master},`
2502
- + ` device.group: ${device.group} connectionType; ${device.connectionType}`);
2397
+ await this.debugLog(`deviceName: ${device.deviceName} [${device.deviceType} Config] device.master: ${device.master}, device.group: ${device.group} connectionType; ${device.connectionType}`);
2503
2398
  await this.debugWarnLog(`Device: ${device.deviceName} registerCurtains: ${registerCurtain}`);
2504
2399
  }
2505
2400
  else if (!device.master && device.curtain?.disable_group) {
2506
- //!device.group && device.connectionType === 'BLE'
2401
+ // !device.group && device.connectionType === 'BLE'
2507
2402
  // OpenAPI: Non-Master Curtains/Blind Tilts that has Disable Grouping Checked
2508
2403
  registerCurtain = true;
2509
- await this.debugLog(`deviceName: ${device.deviceName} [${device.deviceType} Config] device.master: ${device.master}, disable_group: `
2510
- + `${device.curtain?.disable_group}, connectionType; ${device.connectionType}`);
2404
+ await this.debugLog(`deviceName: ${device.deviceName} [${device.deviceType} Config] device.master: ${device.master}, disable_group: ${device.curtain?.disable_group}, connectionType; ${device.connectionType}`);
2511
2405
  await this.debugWarnLog(`Device: ${device.deviceName} registerCurtains: ${registerCurtain}`);
2512
2406
  }
2513
2407
  else if (device.master && !device.group) {
2514
2408
  // OpenAPI: Master Curtains/Blind Tilts not in Group
2515
2409
  registerCurtain = true;
2516
- await this.debugLog(`deviceName: ${device.deviceName} [${device.deviceType} Config] device.master: ${device.master},`
2517
- + ` device.group: ${device.group} connectionType; ${device.connectionType}`);
2410
+ await this.debugLog(`deviceName: ${device.deviceName} [${device.deviceType} Config] device.master: ${device.master}, device.group: ${device.group} connectionType; ${device.connectionType}`);
2518
2411
  await this.debugWarnLog(`Device: ${device.deviceName} registerCurtains: ${registerCurtain}`);
2519
2412
  }
2520
2413
  else if (device.connectionType === 'BLE') {
2521
2414
  // BLE: Curtains/Blind Tilt
2522
2415
  registerCurtain = true;
2523
- await this.debugLog(`deviceName: ${device.deviceName} [${device.deviceType} Config] connectionType: ${device.connectionType}, `
2524
- + ` group: ${device.group}`);
2416
+ await this.debugLog(`deviceName: ${device.deviceName} [${device.deviceType} Config] connectionType: ${device.connectionType}, group: ${device.group}`);
2525
2417
  await this.debugWarnLog(`Device: ${device.deviceName} registerCurtains: ${registerCurtain}`);
2526
2418
  }
2527
2419
  else {
2528
2420
  registerCurtain = false;
2529
- await this.debugErrorLog(`deviceName: ${device.deviceName} [${device.deviceType} Config] disable_group: ${device.curtain?.disable_group},`
2530
- + ` device.master: ${device.master}, device.group: ${device.group}`);
2421
+ await this.debugErrorLog(`deviceName: ${device.deviceName} [${device.deviceType} Config] disable_group: ${device.curtain?.disable_group}, device.master: ${device.master}, device.group: ${device.group}`);
2531
2422
  await this.debugWarnLog(`Device: ${device.deviceName} registerCurtains: ${registerCurtain}, device.connectionType: ${device.connectionType}`);
2532
2423
  }
2533
2424
  return registerCurtain;
@@ -2545,189 +2436,93 @@ export class SwitchBotPlatform {
2545
2436
  async registerDevice(device) {
2546
2437
  device.connectionType = await this.connectionType(device);
2547
2438
  let registerDevice;
2548
- if (!device.hide_device && device.connectionType === 'BLE/OpenAPI') {
2549
- switch (device.deviceType) {
2550
- case 'Curtain':
2551
- case 'Curtain3':
2552
- case 'Blind Tilt':
2553
- registerDevice = await this.registerCurtains(device);
2554
- await this.debugWarnLog(`Device: ${device.deviceName} ${device.deviceType} registerDevice: ${registerDevice}`);
2555
- break;
2556
- default:
2557
- registerDevice = true;
2558
- await this.debugWarnLog(`Device: ${device.deviceName} registerDevice: ${registerDevice}`);
2559
- }
2560
- if (registerDevice === true) {
2561
- await this.debugWarnLog(`Device: ${device.deviceName} connectionType: ${device.connectionType}, will display in HomeKit`);
2562
- }
2563
- else {
2564
- await this.debugErrorLog(`Device: ${device.deviceName} connectionType: ${device.connectionType}, will not display in HomeKit`);
2565
- }
2566
- }
2567
- else if (!device.hide_device && device.deviceId && device.configDeviceType && device.configDeviceName && device.connectionType === 'BLE') {
2568
- switch (device.deviceType) {
2569
- case 'Curtain':
2570
- case 'Curtain3':
2571
- case 'Blind Tilt':
2572
- registerDevice = await this.registerCurtains(device);
2573
- await this.debugWarnLog(`Device: ${device.deviceName} ${device.deviceType} registerDevice: ${registerDevice}`);
2574
- break;
2575
- default:
2576
- registerDevice = true;
2577
- await this.debugWarnLog(`Device: ${device.deviceName} registerDevice: ${registerDevice}`);
2578
- }
2579
- if (registerDevice === true) {
2580
- await this.debugWarnLog(`Device: ${device.deviceName} connectionType: ${device.connectionType}, will display in HomeKit`);
2581
- }
2582
- else {
2583
- await this.debugErrorLog(`Device: ${device.deviceName} connectionType: ${device.connectionType}, will not display in HomeKit`);
2584
- }
2585
- }
2586
- else if (!device.hide_device && device.connectionType === 'OpenAPI') {
2587
- switch (device.deviceType) {
2588
- case 'Curtain':
2589
- case 'Curtain3':
2590
- case 'Blind Tilt':
2591
- registerDevice = await this.registerCurtains(device);
2592
- await this.debugWarnLog(`Device: ${device.deviceName} ${device.deviceType} registerDevice: ${registerDevice}`);
2593
- break;
2594
- default:
2595
- registerDevice = true;
2596
- await this.debugWarnLog(`Device: ${device.deviceName} registerDevice: ${registerDevice}`);
2597
- }
2598
- if (registerDevice === true) {
2599
- await this.debugWarnLog(`Device: ${device.deviceName} connectionType: ${device.connectionType}, will display in HomeKit`);
2600
- }
2601
- else {
2602
- await this.debugErrorLog(`Device: ${device.deviceName} connectionType: ${device.connectionType}, will not display in HomeKit`);
2603
- }
2604
- }
2605
- else if (!device.hide_device && device.connectionType === 'Disabled') {
2606
- switch (device.deviceType) {
2607
- case 'Curtain':
2608
- case 'Curtain3':
2609
- case 'Blind Tilt':
2610
- registerDevice = await this.registerCurtains(device);
2611
- await this.debugWarnLog(`Device: ${device.deviceName} ${device.deviceType} registerDevice: ${registerDevice}`);
2612
- break;
2613
- default:
2614
- registerDevice = true;
2615
- await this.debugWarnLog(`Device: ${device.deviceName} registerDevice: ${registerDevice}`);
2616
- }
2617
- await this.debugWarnLog(`Device: ${device.deviceName} connectionType: ${device.connectionType}, will continue to display in HomeKit`);
2618
- }
2619
- else if (!device.connectionType && !device.hide_device) {
2620
- registerDevice = false;
2621
- await this.debugErrorLog(`Device: ${device.deviceName} connectionType: ${device.connectionType}, will not display in HomeKit`);
2622
- }
2623
- else if (device.hide_device) {
2624
- registerDevice = false;
2625
- await this.debugErrorLog(`Device: ${device.deviceName} hide_device: ${device.hide_device}, will not display in HomeKit`);
2439
+ const shouldRegister = !device.hide_device && (device.connectionType === 'BLE/OpenAPI' || (device.deviceId && device.configDeviceType && device.configDeviceName && device.connectionType === 'BLE') || device.connectionType === 'OpenAPI' || device.connectionType === 'Disabled');
2440
+ if (shouldRegister) {
2441
+ registerDevice = await this.handleDeviceRegistration(device);
2626
2442
  }
2627
2443
  else {
2628
2444
  registerDevice = false;
2629
- await this.debugErrorLog(`Device: ${device.deviceName} connectionType: ${device.connectionType}, hide_device: `
2630
- + `${device.hide_device}, will not display in HomeKit`);
2445
+ await this.debugErrorLog(`Device: ${device.deviceName} connectionType: ${device.connectionType}, hide_device: ${device.hide_device}, will not display in HomeKit`);
2631
2446
  }
2632
2447
  return registerDevice;
2633
2448
  }
2634
- async externalOrPlatformIR(device, accessory) {
2635
- /**
2636
- * Publish as external accessory
2637
- * Only one TV can exist per bridge, to bypass this limitation, you should
2638
- * publish your TV as an external accessory.
2639
- */
2640
- if (device.external) {
2641
- await this.debugWarnLog(`${accessory.displayName} External Accessory Mode`);
2642
- this.externalAccessory(accessory);
2449
+ async handleDeviceRegistration(device) {
2450
+ let registerDevice;
2451
+ switch (device.deviceType) {
2452
+ case 'Curtain':
2453
+ case 'Curtain3':
2454
+ case 'Blind Tilt':
2455
+ registerDevice = await this.registerCurtains(device);
2456
+ await this.debugWarnLog(`Device: ${device.deviceName} ${device.deviceType} registerDevice: ${registerDevice}`);
2457
+ break;
2458
+ default:
2459
+ registerDevice = true;
2460
+ await this.debugWarnLog(`Device: ${device.deviceName} registerDevice: ${registerDevice}`);
2461
+ }
2462
+ if (registerDevice) {
2463
+ await this.debugWarnLog(`Device: ${device.deviceName} connectionType: ${device.connectionType}, will display in HomeKit`);
2643
2464
  }
2644
2465
  else {
2645
- await this.debugLog(`${accessory.displayName} External Accessory Mode: ${device.external}`);
2646
- this.api.registerPlatformAccessories(PLUGIN_NAME, PLATFORM_NAME, [accessory]);
2466
+ await this.debugErrorLog(`Device: ${device.deviceName} connectionType: ${device.connectionType}, will not display in HomeKit`);
2647
2467
  }
2468
+ return registerDevice;
2648
2469
  }
2649
2470
  async externalOrPlatform(device, accessory) {
2650
- if (device.external) {
2651
- await this.debugWarnLog(`${accessory.displayName} External Accessory Mode`);
2652
- await this.externalAccessory(accessory);
2471
+ const { displayName } = accessory;
2472
+ const isExternal = device.external ?? false;
2473
+ if (isExternal) {
2474
+ await this.debugWarnLog(`${displayName} External Accessory Mode`);
2475
+ this.api.publishExternalAccessories(PLUGIN_NAME, [accessory]);
2653
2476
  }
2654
2477
  else {
2655
- await this.debugLog(`${accessory.displayName} External Accessory Mode: ${device.external}`);
2478
+ await this.debugLog(`${displayName} External Accessory Mode: ${isExternal}`);
2656
2479
  this.api.registerPlatformAccessories(PLUGIN_NAME, PLATFORM_NAME, [accessory]);
2657
2480
  }
2658
2481
  }
2659
- async externalAccessory(accessory) {
2660
- this.api.publishExternalAccessories(PLUGIN_NAME, [accessory]);
2661
- }
2662
2482
  unregisterPlatformAccessories(existingAccessory) {
2483
+ const { displayName } = existingAccessory;
2663
2484
  // remove platform accessories when no longer present
2664
2485
  this.api.unregisterPlatformAccessories(PLUGIN_NAME, PLATFORM_NAME, [existingAccessory]);
2665
- this.warnLog(`Removing existing accessory from cache: ${existingAccessory.displayName}`);
2486
+ this.warnLog(`Removing existing accessory from cache: ${displayName}`);
2666
2487
  }
2488
+ /**
2489
+ * Handles the status codes returned by the device and logs appropriate messages.
2490
+ *
2491
+ * @param statusCode - The status code returned by the device.
2492
+ * @returns A promise that resolves when the logging is complete.
2493
+ */
2667
2494
  async statusCode(statusCode) {
2668
- switch (statusCode) {
2669
- case 151:
2670
- await this.errorLog(`Command not supported by this device type, statusCode: ${statusCode}, Submit Feature Request Here: ` +
2671
- 'https://tinyurl.com/SwitchBotFeatureRequest');
2672
- break;
2673
- case 152:
2674
- await this.errorLog(`Device not found, statusCode: ${statusCode}`);
2675
- break;
2676
- case 160:
2677
- await this.errorLog(`Command is not supported, statusCode: ${statusCode}, Submit Bugs Here: https://tinyurl.com/SwitchBotBug`);
2678
- break;
2679
- case 161:
2680
- await this.errorLog(`Device is offline, statusCode: ${statusCode}`);
2681
- break;
2682
- case 171:
2683
- await this.errorLog(`is offline, statusCode: ${statusCode}`);
2684
- break;
2685
- case 190:
2686
- await this.errorLog(`Requests reached the daily limit, statusCode: ${statusCode}`);
2687
- break;
2688
- case 100:
2689
- await this.debugLog(`Command successfully sent, statusCode: ${statusCode}`);
2690
- break;
2691
- case 200:
2692
- await this.debugLog(`Request successful, statusCode: ${statusCode}`);
2693
- break;
2694
- case 400:
2695
- await this.errorLog('Bad Request, The client has issued an invalid request. This is commonly used to specify validation errors in a request '
2696
- + `payload, statusCode: ${statusCode}`);
2697
- break;
2698
- case 401:
2699
- await this.errorLog('Unauthorized, Authorization for the API is required, but the request has not been authenticated, '
2700
- + `statusCode: ${statusCode}`);
2701
- break;
2702
- case 403:
2703
- await this.errorLog('Forbidden, The request has been authenticated but does not have appropriate permissions, or a requested resource is not '
2704
- + `found, statusCode: ${statusCode}`);
2705
- break;
2706
- case 404:
2707
- await this.errorLog(`Not Found, Specifies the requested path does not exist, statusCode: ${statusCode}`);
2708
- break;
2709
- case 406:
2710
- await this.errorLog('Not Acceptable, The client has requested a MIME type via the Accept header for a value not supported by the server, '
2711
- + `statusCode: ${statusCode}`);
2712
- break;
2713
- case 415:
2714
- await this.errorLog('Unsupported Media Type, The client has defined a contentType header that is not supported by the server, '
2715
- + `statusCode: ${statusCode}`);
2716
- break;
2717
- case 422:
2718
- await this.errorLog('Unprocessable Entity, The client has made a valid request, but the server cannot process it. This is often used for '
2719
- + `APIs for which certain limits have been exceeded, statusCode: ${statusCode}`);
2720
- break;
2721
- case 429:
2722
- await this.errorLog('Too Many Requests, The client has exceeded the number of requests allowed for a given time window, '
2723
- + `statusCode: ${statusCode}`);
2724
- break;
2725
- case 500:
2726
- await this.errorLog('Internal Server Error, An unexpected error on the SmartThings servers has occurred. These errors should be rare, '
2727
- + `statusCode: ${statusCode}`);
2728
- break;
2729
- default:
2730
- await this.errorLog(`Unknown statusCode, statusCode: ${statusCode}, Submit Bugs Here: ' + 'https://tinyurl.com/SwitchBotBug`);
2495
+ const messages = {
2496
+ 151: `Command not supported by this device type, statusCode: ${statusCode}, Submit Feature Request Here:
2497
+ https://tinyurl.com/SwitchBotFeatureRequest`,
2498
+ 152: `Device not found, statusCode: ${statusCode}`,
2499
+ 160: `Command is not supported, statusCode: ${statusCode}, Submit Bugs Here: https://tinyurl.com/SwitchBotBug`,
2500
+ 161: `Device is offline, statusCode: ${statusCode}`,
2501
+ 171: `is offline, statusCode: ${statusCode}`,
2502
+ 190: `Requests reached the daily limit, statusCode: ${statusCode}`,
2503
+ 100: `Command successfully sent, statusCode: ${statusCode}`,
2504
+ 200: `Request successful, statusCode: ${statusCode}`,
2505
+ 400: `Bad Request, The client has issued an invalid request. This is commonly used to specify validation errors in a request payload,
2506
+ statusCode: ${statusCode}`,
2507
+ 401: `Unauthorized, Authorization for the API is required, but the request has not been authenticated, statusCode: ${statusCode}`,
2508
+ 403: `Forbidden, The request has been authenticated but does not have appropriate permissions, or a requested resource is not found,
2509
+ statusCode: ${statusCode}`,
2510
+ 404: `Not Found, Specifies the requested path does not exist, statusCode: ${statusCode}`,
2511
+ 406: `Not Acceptable, The client has requested a MIME type via the Accept header for a value not supported by the server,
2512
+ statusCode: ${statusCode}`,
2513
+ 415: `Unsupported Media Type, The client has defined a contentType header that is not supported by the server, statusCode: ${statusCode}`,
2514
+ 422: `Unprocessable Entity, The client has made a valid request, but the server cannot process it. This is often used for APIs for which
2515
+ certain limits have been exceeded, statusCode: ${statusCode}`,
2516
+ 429: `Too Many Requests, The client has exceeded the number of requests allowed for a given time window, statusCode: ${statusCode}`,
2517
+ 500: `Internal Server Error, An unexpected error on the SmartThings servers has occurred. These errors should be rare,
2518
+ statusCode: ${statusCode}`,
2519
+ };
2520
+ const message = messages[statusCode] ?? `Unknown statusCode, statusCode: ${statusCode}, Submit Bugs Here: https://tinyurl.com/SwitchBotBug`;
2521
+ if ([100, 200].includes(statusCode)) {
2522
+ await this.debugLog(message);
2523
+ }
2524
+ else {
2525
+ await this.errorLog(message);
2731
2526
  }
2732
2527
  }
2733
2528
  async retryRequest(deviceMaxRetries, deviceDelayBetweenRetries, url, options) {
@@ -2755,57 +2550,43 @@ export class SwitchBotPlatform {
2755
2550
  }
2756
2551
  // BLE Connection
2757
2552
  async connectBLE(accessory, device) {
2758
- let switchbot;
2759
2553
  try {
2760
- const SwitchBot = (await import('node-switchbot')).SwitchBot;
2761
- queueScheduler.schedule(() => (switchbot = new SwitchBot()));
2554
+ const { SwitchBot } = await import('node-switchbot');
2555
+ const switchbot = new SwitchBot();
2556
+ queueScheduler.schedule(async () => switchbot);
2762
2557
  await this.debugLog(`${device.deviceType}: ${accessory.displayName} 'node-switchbot' found: ${switchbot}`);
2558
+ return switchbot;
2763
2559
  }
2764
2560
  catch (e) {
2765
- switchbot = false;
2766
- await this.errorLog(`${device.deviceType}: ${accessory.displayName} 'node-switchbot' found: ${switchbot}, Error: ${e}`);
2561
+ await this.errorLog(`${device.deviceType}: ${accessory.displayName} 'node-switchbot' not found, Error: ${e}`);
2562
+ return false;
2767
2563
  }
2768
- return switchbot;
2769
2564
  }
2770
2565
  async getVersion() {
2771
2566
  const json = JSON.parse(readFileSync(new URL('../package.json', import.meta.url), 'utf-8'));
2772
2567
  await this.debugLog(`Plugin Version: ${json.version}`);
2773
2568
  this.version = json.version;
2569
+ return json.version;
2774
2570
  }
2775
2571
  async getPlatformConfigSettings() {
2572
+ const { options } = this.config;
2776
2573
  const platformConfig = {};
2777
- if (this.config.options) {
2778
- if (this.config.options.logging) {
2779
- platformConfig.logging = this.config.options.logging;
2780
- }
2781
- if (this.config.options.refreshRate) {
2782
- platformConfig.refreshRate = this.config.options.refreshRate;
2783
- }
2784
- if (this.config.options.updateRate) {
2785
- platformConfig.updateRate = this.config.options.updateRate;
2786
- }
2787
- if (this.config.options.pushRate) {
2788
- platformConfig.pushRate = this.config.options.pushRate;
2789
- }
2790
- if (this.config.options.maxRetries) {
2791
- this.maxRetries = this.config.options.maxRetries;
2792
- platformConfig.maxRetries = this.config.options.maxRetries;
2793
- }
2794
- else {
2795
- this.maxRetries = 3;
2796
- this.debugWarnLog('Using Default Max Retries');
2797
- platformConfig.maxRetries = this.maxRetries;
2798
- }
2799
- if (this.config.options.delayBetweenRetries) {
2800
- this.delayBetweenRetries = this.config.options.delayBetweenRetries * 1000;
2801
- platformConfig.delayBetweenRetries = this.config.options.delayBetweenRetries;
2802
- }
2803
- else {
2804
- this.delayBetweenRetries = 3000;
2805
- this.debugWarnLog('Using Default Delay Between Retries');
2806
- platformConfig.delayBetweenRetries = this.delayBetweenRetries / 1000;
2807
- }
2808
- if (Object.entries(platformConfig).length !== 0) {
2574
+ if (options) {
2575
+ platformConfig.logging = options.logging;
2576
+ platformConfig.refreshRate = options.refreshRate;
2577
+ platformConfig.updateRate = options.updateRate;
2578
+ platformConfig.pushRate = options.pushRate;
2579
+ this.maxRetries = options.maxRetries || 3;
2580
+ platformConfig.maxRetries = this.maxRetries;
2581
+ if (!options.maxRetries) {
2582
+ await this.debugWarnLog('Using Default Max Retries');
2583
+ }
2584
+ this.delayBetweenRetries = (options.delayBetweenRetries || 3) * 1000;
2585
+ platformConfig.delayBetweenRetries = this.delayBetweenRetries / 1000;
2586
+ if (!options.delayBetweenRetries) {
2587
+ await this.debugWarnLog('Using Default Delay Between Retries');
2588
+ }
2589
+ if (Object.keys(platformConfig).length) {
2809
2590
  await this.debugLog(`Platform Config: ${JSON.stringify(platformConfig)}`);
2810
2591
  }
2811
2592
  this.platformConfig = platformConfig;
@@ -2828,31 +2609,38 @@ export class SwitchBotPlatform {
2828
2609
  }
2829
2610
  /**
2830
2611
  * Validate and clean a string value for a Name Characteristic.
2831
- * @param displayName
2832
- * @param name
2833
- * @param value
2834
- * @returns string value
2835
- */
2612
+ * @param displayName - The display name of the accessory.
2613
+ * @param name - The name of the characteristic.
2614
+ * @param value - The value to be validated and cleaned.
2615
+ * @returns The cleaned string value.
2616
+ */
2836
2617
  async validateAndCleanDisplayName(displayName, name, value) {
2837
- const validPattern = /^[a-zA-Z0-9][a-zA-Z0-9 ']*[a-zA-Z0-9]$/;
2838
- const invalidCharsPattern = /[^a-zA-Z0-9 ']/g;
2839
- const invalidStartEndPattern = /^[^a-zA-Z0-9]+|[^a-zA-Z0-9]+$/g;
2840
- if (!validPattern.test(value)) {
2841
- this.warnLog(`WARNING: The accessory '${displayName}' has an invalid '${name}' characteristic ('${value}'). Please use only alphanumeric,`
2842
- + ' space, and apostrophe characters. Ensure it starts and ends with an alphabetic or numeric character, and avoid emojis. This may'
2843
- + ' prevent the accessory from being added in the Home App or cause unresponsiveness.');
2844
- // Remove invalid characters
2845
- if (invalidCharsPattern.test(value)) {
2846
- this.warnLog(`Removing invalid characters from '${name}' characteristic`);
2847
- value = value.replace(invalidCharsPattern, '');
2848
- }
2849
- // Ensure it starts and ends with an alphanumeric character
2850
- if (invalidStartEndPattern.test(value)) {
2851
- this.warnLog(`Removing invalid starting or ending characters from '${name}' characteristic`);
2852
- value = value.replace(invalidStartEndPattern, '');
2853
- }
2854
- }
2855
- return value;
2618
+ if (this.config.options?.allowInvalidCharacters) {
2619
+ return value;
2620
+ }
2621
+ else {
2622
+ const validPattern = /^[\p{L}\p{N}][\p{L}\p{N} ']*[\p{L}\p{N}]$/u;
2623
+ const invalidCharsPattern = /[^\p{L}\p{N} ']/gu;
2624
+ const invalidStartEndPattern = /^[^\p{L}\p{N}]+|[^\p{L}\p{N}]+$/gu;
2625
+ if (typeof value === 'string' && !validPattern.test(value)) {
2626
+ await this.warnLog(`WARNING: The accessory '${displayName}' has an invalid '${name}' characteristic ('${value}'). Please use only alphanumeric, space, and apostrophe characters. Ensure it starts and ends with an alphabetic or numeric character, and avoid emojis. This may prevent the accessory from being added in the Home App or cause unresponsiveness.`);
2627
+ // Remove invalid characters
2628
+ if (invalidCharsPattern.test(value)) {
2629
+ const before = value;
2630
+ await this.warnLog(`Removing invalid characters from '${name}' characteristic, if you feel this is incorrect, please enable \'allowInvalidCharacter\' in the config to allow all characters`);
2631
+ value = value.replace(invalidCharsPattern, '');
2632
+ await this.warnLog(`${name} Before: '${before}' After: '${value}'`);
2633
+ }
2634
+ // Ensure it starts and ends with an alphanumeric character
2635
+ if (invalidStartEndPattern.test(value)) {
2636
+ const before = value;
2637
+ await this.warnLog(`Removing invalid starting or ending characters from '${name}' characteristic, if you feel this is incorrect, please enable \'allowInvalidCharacter\' in the config to allow all characters`);
2638
+ value = value.replace(invalidStartEndPattern, '');
2639
+ await this.warnLog(`${name} Before: '${before}' After: '${value}'`);
2640
+ }
2641
+ }
2642
+ return value;
2643
+ }
2856
2644
  }
2857
2645
  /**
2858
2646
  * If device level logging is turned on, log to log.warn