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

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 +1482 -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 +61 -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 +509 -723
  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 +64 -57
  157. package/src/device/blindtilt.ts +537 -456
  158. package/src/device/bot-old.ts +1540 -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 +277 -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 +1491 -1681
  190. package/src/settings.ts +172 -169
  191. package/src/types/bledevicestatus.ts +252 -256
  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 -131
  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 { SwitchBot, 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
  }
@@ -295,7 +308,6 @@ export class SwitchBotPlatform {
295
308
  async setupBlE() {
296
309
  if (this.config.options?.BLE) {
297
310
  await this.debugLog('setupBLE');
298
- const SwitchBot = (await import('node-switchbot')).SwitchBot;
299
311
  const switchbot = new SwitchBot();
300
312
  if (switchbot === undefined) {
301
313
  await this.errorLog(`wasn't able to establish BLE Connection, node-switchbot: ${switchbot}`);
@@ -319,10 +331,10 @@ export class SwitchBotPlatform {
319
331
  this.api.on('shutdown', async () => {
320
332
  try {
321
333
  switchbot.stopScan();
322
- this.infoLog('Stopped BLE scanning to close listening.');
334
+ await this.infoLog('Stopped BLE scanning to close listening.');
323
335
  }
324
336
  catch (e) {
325
- this.errorLog(`Failed to stop Platform BLE scanning. Error:${e.message}`);
337
+ await this.errorLog(`Failed to stop Platform BLE scanning. Error:${e.message}`);
326
338
  }
327
339
  });
328
340
  }
@@ -336,7 +348,8 @@ export class SwitchBotPlatform {
336
348
  * It should be used to setup event handlers for characteristics and update respective values.
337
349
  */
338
350
  async configureAccessory(accessory) {
339
- await this.debugLog(`Loading accessory from cache: ${accessory.displayName}`);
351
+ const { displayName } = accessory;
352
+ await this.debugLog(`Loading accessory from cache: ${displayName}`);
340
353
  // add the restored accessory to the accessories cache so we can track if it has already been registered
341
354
  this.accessories.push(accessory);
342
355
  }
@@ -344,18 +357,18 @@ export class SwitchBotPlatform {
344
357
  * Verify the config passed to the plugin is valid
345
358
  */
346
359
  async verifyConfig() {
347
- this.debugLog('Verifying Config');
360
+ await this.debugLog('Verifying Config');
348
361
  this.config = this.config || {};
349
362
  this.config.options = this.config.options || {};
350
363
  const platformConfig = {};
351
364
  if (this.config.options.logging) {
352
- platformConfig['logging'] = this.config.options.logging;
365
+ platformConfig.logging = this.config.options.logging;
353
366
  }
354
367
  if (this.config.options.logging && this.config.options.refreshRate) {
355
- platformConfig['refreshRate'] = this.config.options.refreshRate;
368
+ platformConfig.refreshRate = this.config.options.refreshRate;
356
369
  }
357
370
  if (this.config.options.logging && this.config.options.pushRate) {
358
- platformConfig['pushRate'] = this.config.options.pushRate;
371
+ platformConfig.pushRate = this.config.options.pushRate;
359
372
  }
360
373
  if (Object.entries(platformConfig).length !== 0) {
361
374
  await this.debugWarnLog(`Platform Config: ${JSON.stringify(platformConfig)}`);
@@ -379,10 +392,10 @@ export class SwitchBotPlatform {
379
392
  for (const irDeviceConfig of this.config.options.irdevices) {
380
393
  if (!irDeviceConfig.hide_device) {
381
394
  if (!irDeviceConfig.deviceId) {
382
- this.errorLog('The devices config section is missing the *Device ID* in the config. Please check your config.');
395
+ await this.errorLog('The devices config section is missing the *Device ID* in the config. Please check your config.');
383
396
  }
384
397
  if (!irDeviceConfig.deviceId && !irDeviceConfig.configRemoteType) {
385
- this.errorLog('The devices config section is missing the *Device Type* in the config. Please check your config.');
398
+ await this.errorLog('The devices config section is missing the *Device Type* in the config. Please check your config.');
386
399
  }
387
400
  }
388
401
  }
@@ -394,16 +407,16 @@ export class SwitchBotPlatform {
394
407
  if (!this.config.options.refreshRate) {
395
408
  // default 120 seconds (2 minutes)
396
409
  this.config.options.refreshRate = 120;
397
- this.debugWarnLog('Using Default Refresh Rate (2 minutes).');
410
+ await this.debugWarnLog('Using Default Refresh Rate (2 minutes).');
398
411
  }
399
412
  if (!this.config.options.pushRate) {
400
413
  // default 100 milliseconds
401
414
  this.config.options.pushRate = 0.1;
402
- this.debugWarnLog('Using Default Push Rate.');
415
+ await this.debugWarnLog('Using Default Push Rate.');
403
416
  }
404
417
  if (!this.config.options.maxRetries) {
405
418
  this.config.options.maxRetries = 5;
406
- this.debugWarnLog('Using Default Max Retries.');
419
+ await this.debugWarnLog('Using Default Max Retries.');
407
420
  }
408
421
  else {
409
422
  this.maxRetries = this.config.options.maxRetries;
@@ -411,23 +424,23 @@ export class SwitchBotPlatform {
411
424
  if (!this.config.options.delayBetweenRetries) {
412
425
  // default 3 seconds
413
426
  this.config.options.delayBetweenRetries = 3000;
414
- this.debugWarnLog('Using Default Delay Between Retries.');
427
+ await this.debugWarnLog('Using Default Delay Between Retries.');
415
428
  }
416
429
  else {
417
430
  this.delayBetweenRetries = this.config.options.delayBetweenRetries * 1000;
418
431
  }
419
432
  if (!this.config.credentials && !this.config.options) {
420
- this.debugWarnLog('Missing Credentials');
433
+ await this.debugWarnLog('Missing Credentials');
421
434
  }
422
435
  else if (this.config.credentials && !this.config.credentials.notice) {
423
436
  if (!this.config.credentials?.token) {
424
- this.debugErrorLog('Missing token');
425
- this.debugWarnLog('Cloud Enabled SwitchBot Devices & IR Devices will not work');
437
+ await this.debugErrorLog('Missing token');
438
+ await this.debugWarnLog('Cloud Enabled SwitchBot Devices & IR Devices will not work');
426
439
  }
427
440
  if (this.config.credentials?.token) {
428
441
  if (!this.config.credentials?.secret) {
429
- this.debugErrorLog('Missing secret');
430
- this.debugWarnLog('Cloud Enabled SwitchBot Devices & IR Devices will not work');
442
+ await this.debugErrorLog('Missing secret');
443
+ await this.debugWarnLog('Cloud Enabled SwitchBot Devices & IR Devices will not work');
431
444
  }
432
445
  }
433
446
  }
@@ -435,7 +448,6 @@ export class SwitchBotPlatform {
435
448
  /**
436
449
  * The openToken was old config.
437
450
  * This method saves the openToken as the token in the config.json file
438
- * @param this.config.credentials.openToken
439
451
  */
440
452
  async updateToken() {
441
453
  try {
@@ -447,7 +459,7 @@ export class SwitchBotPlatform {
447
459
  const currentConfig = JSON.parse(readFileSync(this.api.user.configPath(), 'utf8'));
448
460
  // check the platforms section is an array before we do array things on it
449
461
  if (!Array.isArray(currentConfig.platforms)) {
450
- throw new Error('Cannot find platforms array in config');
462
+ throw new TypeError('Cannot find platforms array in config');
451
463
  }
452
464
  // find this plugins current config
453
465
  const pluginConfig = currentConfig.platforms.find((x) => x.platform === PLATFORM_NAME);
@@ -456,17 +468,15 @@ export class SwitchBotPlatform {
456
468
  }
457
469
  // check the .credentials is an object before doing object things with it
458
470
  if (typeof pluginConfig.credentials !== 'object') {
459
- throw new Error('pluginConfig.credentials is not an object');
471
+ throw new TypeError('pluginConfig.credentials is not an object');
460
472
  }
461
473
  // Move openToken to token
462
474
  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');
475
+ 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
476
  this.errorLog('"secret" config is not populated, you must populate then please restart Homebridge.');
466
477
  }
467
478
  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.');
479
+ 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
480
  }
471
481
  // set the refresh token
472
482
  pluginConfig.credentials.token = this.config.credentials?.openToken;
@@ -476,10 +486,10 @@ export class SwitchBotPlatform {
476
486
  await this.debugWarnLog(`token: ${pluginConfig.credentials.token}`);
477
487
  // save the config, ensuring we maintain pretty json
478
488
  writeFileSync(this.api.user.configPath(), JSON.stringify(currentConfig, null, 4));
479
- this.verifyConfig();
489
+ await this.verifyConfig();
480
490
  }
481
491
  catch (e) {
482
- this.errorLog(`Update Token: ${e}`);
492
+ await this.errorLog(`Update Token: ${e}`);
483
493
  }
484
494
  }
485
495
  generateHeaders = () => {
@@ -492,340 +502,228 @@ export class SwitchBotPlatform {
492
502
  .digest();
493
503
  const sign = signTerm.toString('base64');
494
504
  return {
495
- Authorization: this.config.credentials?.token,
496
- sign: sign,
497
- nonce: nonce,
498
- t: t,
505
+ 'Authorization': this.config.credentials?.token,
506
+ 'sign': sign,
507
+ 'nonce': nonce,
508
+ 't': t,
499
509
  'Content-Type': 'application/json',
500
510
  };
501
511
  };
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
512
  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
- }
513
+ if (!this.config.credentials?.token) {
514
+ return this.handleManualConfig();
515
+ }
516
+ let retryCount = 0;
517
+ const maxRetries = this.maxRetries;
518
+ const delayBetweenRetries = this.delayBetweenRetries;
519
+ await this.debugWarnLog(`Retry Count: ${retryCount}`);
520
+ await this.debugWarnLog(`Max Retries: ${maxRetries}`);
521
+ await this.debugWarnLog(`Delay Between Retries: ${delayBetweenRetries}`);
522
+ while (retryCount < maxRetries) {
523
+ try {
524
+ const { body, statusCode } = await request(Devices, { headers: this.generateHeaders() });
525
+ await this.debugWarnLog(`statusCode: ${statusCode}`);
526
+ const devicesAPI = await body.json();
527
+ await this.debugWarnLog(`devicesAPI: ${JSON.stringify(devicesAPI)}`);
528
+ if (this.isSuccessfulResponse(statusCode, devicesAPI.statusCode)) {
529
+ await this.handleDevices(devicesAPI.body.deviceList);
530
+ await this.handleIRDevices(devicesAPI.body.infraredRemoteList);
531
+ break;
629
532
  }
630
- catch (e) {
533
+ else {
534
+ await this.handleErrorResponse(statusCode, devicesAPI.statusCode, retryCount, maxRetries, delayBetweenRetries);
631
535
  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
536
  }
635
537
  }
538
+ catch (e) {
539
+ retryCount++;
540
+ await this.debugErrorLog(`Failed to Discover Devices, Error Message: ${JSON.stringify(e.message)}, Submit Bugs Here: https://tinyurl.com/SwitchBotBug`);
541
+ await this.debugErrorLog(`Failed to Discover Devices, Error: ${e}`);
542
+ }
636
543
  }
637
- else if (!this.config.credentials?.token && this.config.options?.devices) {
544
+ }
545
+ async handleManualConfig() {
546
+ if (this.config.options?.devices) {
638
547
  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);
548
+ const devices = this.config.options.devices.map((v) => v);
641
549
  for (const device of devices) {
642
550
  device.deviceType = device.configDeviceType;
643
551
  device.deviceName = device.configDeviceName;
644
552
  if (device.deviceType) {
645
- this.createDevice(device);
553
+ await this.createDevice(device);
646
554
  }
647
555
  }
648
556
  }
649
557
  else {
650
- this.errorLog('Neither SwitchBot Token or Device Config are not set.');
558
+ await this.errorLog('Neither SwitchBot Token or Device Config are set.');
559
+ }
560
+ }
561
+ isSuccessfulResponse(statusCode, apiStatusCode) {
562
+ return (statusCode === 200 || statusCode === 100) && (apiStatusCode === 200 || apiStatusCode === 100);
563
+ }
564
+ async handleDevices(deviceLists) {
565
+ if (!this.config.options?.devices) {
566
+ await this.debugLog(`SwitchBot Device Config Not Set: ${JSON.stringify(this.config.options?.devices)}`);
567
+ if (deviceLists.length === 0) {
568
+ await this.debugLog('SwitchBot API Has No Devices With Cloud Services Enabled');
569
+ }
570
+ else {
571
+ for (const device of deviceLists) {
572
+ if (device.deviceType) {
573
+ if (device.configDeviceName) {
574
+ device.deviceName = device.configDeviceName;
575
+ }
576
+ await this.createDevice(device);
577
+ }
578
+ }
579
+ }
580
+ }
581
+ else {
582
+ await this.debugLog(`SwitchBot Device Config Set: ${JSON.stringify(this.config.options?.devices)}`);
583
+ const devices = this.mergeByDeviceId(deviceLists, this.config.options.devices);
584
+ await this.debugLog(`SwitchBot Devices: ${JSON.stringify(devices)}`);
585
+ for (const device of devices) {
586
+ if (!device.deviceType && device.configDeviceType) {
587
+ device.deviceType = device.configDeviceType;
588
+ await this.warnLog(`API is displaying no deviceType: ${device.deviceType}, So using configDeviceType: ${device.configDeviceType}`);
589
+ }
590
+ else if (!device.deviceType && !device.configDeviceName) {
591
+ await this.errorLog('No deviceType or configDeviceType for device. No device will be created.');
592
+ }
593
+ if (device.deviceType) {
594
+ if (device.configDeviceName) {
595
+ device.deviceName = device.configDeviceName;
596
+ }
597
+ await this.createDevice(device);
598
+ }
599
+ }
600
+ }
601
+ }
602
+ async handleIRDevices(irDeviceLists) {
603
+ if (!this.config.options?.irdevices) {
604
+ await this.debugLog(`IR Device Config Not Set: ${JSON.stringify(this.config.options?.irdevices)}`);
605
+ for (const device of irDeviceLists) {
606
+ if (device.remoteType) {
607
+ await this.createIRDevice(device);
608
+ }
609
+ }
610
+ }
611
+ else {
612
+ await this.debugLog(`IR Device Config Set: ${JSON.stringify(this.config.options?.irdevices)}`);
613
+ const devices = this.mergeByDeviceId(irDeviceLists, this.config.options.irdevices);
614
+ await this.debugLog(`IR Devices: ${JSON.stringify(devices)}`);
615
+ for (const device of devices) {
616
+ await this.createIRDevice(device);
617
+ }
618
+ }
619
+ }
620
+ mergeByDeviceId(a1, a2) {
621
+ const normalizeDeviceId = (deviceId) => deviceId.toUpperCase().replace(/[^A-Z0-9]+/g, '');
622
+ return a1.map((itm) => {
623
+ const matchingItem = a2.find(item => normalizeDeviceId(item.deviceId) === normalizeDeviceId(itm.deviceId));
624
+ return { ...matchingItem, ...itm };
625
+ });
626
+ }
627
+ async handleErrorResponse(statusCode, apiStatusCode, retryCount, maxRetries, delayBetweenRetries) {
628
+ await this.statusCode(statusCode);
629
+ await this.statusCode(apiStatusCode);
630
+ if (statusCode === 500) {
631
+ this.infoLog(`statusCode: ${statusCode} Attempt ${retryCount + 1} of ${maxRetries}`);
632
+ await sleep(delayBetweenRetries);
651
633
  }
652
634
  }
653
635
  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)}`);
636
+ const deviceTypeHandlers = {
637
+ 'Humidifier': this.createHumidifier.bind(this),
638
+ 'Hub 2': this.createHub2.bind(this),
639
+ 'Bot': this.createBot.bind(this),
640
+ 'Meter': this.createMeter.bind(this),
641
+ 'MeterPlus': this.createMeterPlus.bind(this),
642
+ 'Meter Plus (JP)': this.createMeterPlus.bind(this),
643
+ 'WoIOSensor': this.createIOSensor.bind(this),
644
+ 'Water Detector': this.createWaterDetector.bind(this),
645
+ 'Motion Sensor': this.createMotion.bind(this),
646
+ 'Contact Sensor': this.createContact.bind(this),
647
+ 'Curtain': this.createCurtain.bind(this),
648
+ 'Curtain3': this.createCurtain.bind(this),
649
+ 'WoRollerShade': this.createCurtain.bind(this),
650
+ 'Roller Shade': this.createCurtain.bind(this),
651
+ 'Blind Tilt': this.createBlindTilt.bind(this),
652
+ 'Plug': this.createPlug.bind(this),
653
+ 'Plug Mini (US)': this.createPlug.bind(this),
654
+ 'Plug Mini (JP)': this.createPlug.bind(this),
655
+ 'Smart Lock': this.createLock.bind(this),
656
+ 'Smart Lock Pro': this.createLock.bind(this),
657
+ 'Color Bulb': this.createColorBulb.bind(this),
658
+ 'K10+': this.createRobotVacuumCleaner.bind(this),
659
+ 'WoSweeper': this.createRobotVacuumCleaner.bind(this),
660
+ 'WoSweeperMini': this.createRobotVacuumCleaner.bind(this),
661
+ 'Robot Vacuum Cleaner S1': this.createRobotVacuumCleaner.bind(this),
662
+ 'Robot Vacuum Cleaner S1 Plus': this.createRobotVacuumCleaner.bind(this),
663
+ 'Robot Vacuum Cleaner S10': this.createRobotVacuumCleaner.bind(this),
664
+ 'Ceiling Light': this.createCeilingLight.bind(this),
665
+ 'Ceiling Light Pro': this.createCeilingLight.bind(this),
666
+ 'Strip Light': this.createStripLight.bind(this),
667
+ 'Battery Circulator Fan': this.createFan.bind(this),
668
+ };
669
+ if (deviceTypeHandlers[device.deviceType]) {
670
+ await this.debugLog(`Discovered ${device.deviceType}: ${device.deviceId}`);
671
+ await deviceTypeHandlers[device.deviceType](device);
672
+ }
673
+ else if (['Hub Mini', 'Hub Plus', 'Remote', 'Indoor Cam', 'remote with screen'].includes(device.deviceType)) {
674
+ await this.debugLog(`Discovered ${device.deviceType}: ${device.deviceId}, is currently not supported, device: ${JSON.stringify(device)}`);
675
+ }
676
+ else {
677
+ 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
678
  }
752
679
  }
753
680
  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');
681
+ device.connectionType = device.connectionType ?? 'OpenAPI';
682
+ const deviceTypeHandlers = {
683
+ 'TV': this.createTV.bind(this),
684
+ 'DIY TV': this.createTV.bind(this),
685
+ 'Projector': this.createTV.bind(this),
686
+ 'DIY Projector': this.createTV.bind(this),
687
+ 'Set Top Box': this.createTV.bind(this),
688
+ 'DIY Set Top Box': this.createTV.bind(this),
689
+ 'IPTV': this.createTV.bind(this),
690
+ 'DIY IPTV': this.createTV.bind(this),
691
+ 'DVD': this.createTV.bind(this),
692
+ 'DIY DVD': this.createTV.bind(this),
693
+ 'Speaker': this.createTV.bind(this),
694
+ 'DIY Speaker': this.createTV.bind(this),
695
+ 'Fan': this.createIRFan.bind(this),
696
+ 'DIY Fan': this.createIRFan.bind(this),
697
+ 'Air Conditioner': this.createAirConditioner.bind(this),
698
+ 'DIY Air Conditioner': this.createAirConditioner.bind(this),
699
+ 'Light': this.createLight.bind(this),
700
+ 'DIY Light': this.createLight.bind(this),
701
+ 'Air Purifier': this.createAirPurifier.bind(this),
702
+ 'DIY Air Purifier': this.createAirPurifier.bind(this),
703
+ 'Water Heater': this.createWaterHeater.bind(this),
704
+ 'DIY Water Heater': this.createWaterHeater.bind(this),
705
+ 'Vacuum Cleaner': this.createVacuumCleaner.bind(this),
706
+ 'DIY Vacuum Cleaner': this.createVacuumCleaner.bind(this),
707
+ 'Camera': this.createCamera.bind(this),
708
+ 'DIY Camera': this.createCamera.bind(this),
709
+ 'Others': this.createOthers.bind(this),
710
+ };
711
+ if (deviceTypeHandlers[device.remoteType]) {
712
+ await this.debugLog(`Discovered ${device.remoteType}: ${device.deviceId}`);
713
+ if (device.remoteType.startsWith('DIY') && device.external === undefined) {
714
+ device.external = true;
715
+ }
716
+ await deviceTypeHandlers[device.remoteType](device);
717
+ }
718
+ else {
719
+ 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
720
  }
823
721
  }
824
722
  async createHumidifier(device) {
825
723
  const uuid = this.api.hap.uuid.generate(`${device.deviceId}-${device.deviceType}`);
826
724
  // see if an accessory with the same uuid has already been registered and restored from
827
725
  // the cached devices we stored in the `configureAccessory` method above
828
- const existingAccessory = this.accessories.find((accessory) => accessory.UUID === uuid);
726
+ const existingAccessory = this.accessories.find(accessory => accessory.UUID === uuid);
829
727
  if (existingAccessory) {
830
728
  // the accessory already exists
831
729
  if (await this.registerDevice(device)) {
@@ -884,7 +782,7 @@ export class SwitchBotPlatform {
884
782
  const uuid = this.api.hap.uuid.generate(`${device.deviceId}-${device.deviceType}`);
885
783
  // see if an accessory with the same uuid has already been registered and restored from
886
784
  // the cached devices we stored in the `configureAccessory` method above
887
- const existingAccessory = this.accessories.find((accessory) => accessory.UUID === uuid);
785
+ const existingAccessory = this.accessories.find(accessory => accessory.UUID === uuid);
888
786
  if (existingAccessory) {
889
787
  // the accessory already exists
890
788
  if (await this.registerDevice(device)) {
@@ -945,7 +843,7 @@ export class SwitchBotPlatform {
945
843
  const uuid = this.api.hap.uuid.generate(`${device.deviceId}-${device.deviceType}`);
946
844
  // see if an accessory with the same uuid has already been registered and restored from
947
845
  // the cached devices we stored in the `configureAccessory` method above
948
- const existingAccessory = this.accessories.find((accessory) => accessory.UUID === uuid);
846
+ const existingAccessory = this.accessories.find(accessory => accessory.UUID === uuid);
949
847
  if (existingAccessory) {
950
848
  // the accessory already exists
951
849
  if (await this.registerDevice(device)) {
@@ -1005,7 +903,7 @@ export class SwitchBotPlatform {
1005
903
  const uuid = this.api.hap.uuid.generate(`${device.deviceId}-${device.deviceType}`);
1006
904
  // see if an accessory with the same uuid has already been registered and restored from
1007
905
  // the cached devices we stored in the `configureAccessory` method above
1008
- const existingAccessory = this.accessories.find((accessory) => accessory.UUID === uuid);
906
+ const existingAccessory = this.accessories.find(accessory => accessory.UUID === uuid);
1009
907
  if (existingAccessory) {
1010
908
  // the accessory already exists
1011
909
  if (await this.registerDevice(device)) {
@@ -1066,7 +964,7 @@ export class SwitchBotPlatform {
1066
964
  const uuid = this.api.hap.uuid.generate(`${device.deviceId}-${device.deviceType}`);
1067
965
  // see if an accessory with the same uuid has already been registered and restored from
1068
966
  // the cached devices we stored in the `configureAccessory` method above
1069
- const existingAccessory = this.accessories.find((accessory) => accessory.UUID === uuid);
967
+ const existingAccessory = this.accessories.find(accessory => accessory.UUID === uuid);
1070
968
  if (existingAccessory) {
1071
969
  // the accessory already exists
1072
970
  if (await this.registerDevice(device)) {
@@ -1127,7 +1025,7 @@ export class SwitchBotPlatform {
1127
1025
  const uuid = this.api.hap.uuid.generate(`${device.deviceId}-${device.deviceType}`);
1128
1026
  // see if an accessory with the same uuid has already been registered and restored from
1129
1027
  // the cached devices we stored in the `configureAccessory` method above
1130
- const existingAccessory = this.accessories.find((accessory) => accessory.UUID === uuid);
1028
+ const existingAccessory = this.accessories.find(accessory => accessory.UUID === uuid);
1131
1029
  if (existingAccessory) {
1132
1030
  // the accessory already exists
1133
1031
  if (await this.registerDevice(device)) {
@@ -1187,7 +1085,7 @@ export class SwitchBotPlatform {
1187
1085
  const uuid = this.api.hap.uuid.generate(`${device.deviceId}-${device.deviceType}`);
1188
1086
  // see if an accessory with the same uuid has already been registered and restored from
1189
1087
  // the cached devices we stored in the `configureAccessory` method above
1190
- const existingAccessory = this.accessories.find((accessory) => accessory.UUID === uuid);
1088
+ const existingAccessory = this.accessories.find(accessory => accessory.UUID === uuid);
1191
1089
  if (existingAccessory) {
1192
1090
  // the accessory already exists
1193
1091
  if (await this.registerDevice(device)) {
@@ -1247,7 +1145,7 @@ export class SwitchBotPlatform {
1247
1145
  const uuid = this.api.hap.uuid.generate(`${device.deviceId}-${device.deviceType}`);
1248
1146
  // see if an accessory with the same uuid has already been registered and restored from
1249
1147
  // the cached devices we stored in the `configureAccessory` method above
1250
- const existingAccessory = this.accessories.find((accessory) => accessory.UUID === uuid);
1148
+ const existingAccessory = this.accessories.find(accessory => accessory.UUID === uuid);
1251
1149
  if (existingAccessory) {
1252
1150
  // the accessory already exists
1253
1151
  if (await this.registerDevice(device)) {
@@ -1307,7 +1205,7 @@ export class SwitchBotPlatform {
1307
1205
  const uuid = this.api.hap.uuid.generate(`${device.deviceId}-${device.deviceType}`);
1308
1206
  // see if an accessory with the same uuid has already been registered and restored from
1309
1207
  // the cached devices we stored in the `configureAccessory` method above
1310
- const existingAccessory = this.accessories.find((accessory) => accessory.UUID === uuid);
1208
+ const existingAccessory = this.accessories.find(accessory => accessory.UUID === uuid);
1311
1209
  if (existingAccessory) {
1312
1210
  // the accessory already exists
1313
1211
  if (await this.registerDevice(device)) {
@@ -1367,7 +1265,7 @@ export class SwitchBotPlatform {
1367
1265
  const uuid = this.api.hap.uuid.generate(`${device.deviceId}-${device.deviceType}`);
1368
1266
  // see if an accessory with the same uuid has already been registered and restored from
1369
1267
  // the cached devices we stored in the `configureAccessory` method above
1370
- const existingAccessory = this.accessories.find((accessory) => accessory.UUID === uuid);
1268
+ const existingAccessory = this.accessories.find(accessory => accessory.UUID === uuid);
1371
1269
  if (existingAccessory) {
1372
1270
  // the accessory already exists
1373
1271
  if (await this.registerDevice(device)) {
@@ -1395,8 +1293,8 @@ export class SwitchBotPlatform {
1395
1293
  else if (await this.registerDevice(device)) {
1396
1294
  if (isBlindTiltDevice(device)) {
1397
1295
  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}`);
1296
+ this.debugLog('Your Curtains are grouped, '
1297
+ + `, Secondary curtain automatically hidden. Main Curtain: ${device.deviceName}, deviceId: ${device.deviceId}`);
1400
1298
  }
1401
1299
  else {
1402
1300
  if (device.master) {
@@ -1414,7 +1312,6 @@ export class SwitchBotPlatform {
1414
1312
  // store a copy of the device object in the `accessory.context`
1415
1313
  // the `context` property can be used to store any data about the accessory you may need
1416
1314
  accessory.context.device = device;
1417
- ;
1418
1315
  accessory.context.deviceId = device.deviceId;
1419
1316
  accessory.context.deviceType = device.deviceType;
1420
1317
  accessory.context.model = SwitchBotModel.BlindTilt;
@@ -1442,7 +1339,7 @@ export class SwitchBotPlatform {
1442
1339
  const uuid = this.api.hap.uuid.generate(`${device.deviceId}-${device.deviceType}`);
1443
1340
  // see if an accessory with the same uuid has already been registered and restored from
1444
1341
  // the cached devices we stored in the `configureAccessory` method above
1445
- const existingAccessory = this.accessories.find((accessory) => accessory.UUID === uuid);
1342
+ const existingAccessory = this.accessories.find(accessory => accessory.UUID === uuid);
1446
1343
  if (existingAccessory) {
1447
1344
  // the accessory already exists
1448
1345
  if (await this.registerDevice(device)) {
@@ -1470,8 +1367,8 @@ export class SwitchBotPlatform {
1470
1367
  else if (await this.registerDevice(device)) {
1471
1368
  if (isCurtainDevice(device)) {
1472
1369
  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}`);
1370
+ this.debugLog('Your Curtains are grouped, '
1371
+ + `, Secondary curtain automatically hidden. Main Curtain: ${device.deviceName}, deviceId: ${device.deviceId}`);
1475
1372
  }
1476
1373
  else {
1477
1374
  if (device.master) {
@@ -1516,7 +1413,7 @@ export class SwitchBotPlatform {
1516
1413
  const uuid = this.api.hap.uuid.generate(`${device.deviceId}-${device.deviceType}`);
1517
1414
  // see if an accessory with the same uuid has already been registered and restored from
1518
1415
  // the cached devices we stored in the `configureAccessory` method above
1519
- const existingAccessory = this.accessories.find((accessory) => accessory.UUID === uuid);
1416
+ const existingAccessory = this.accessories.find(accessory => accessory.UUID === uuid);
1520
1417
  if (existingAccessory) {
1521
1418
  // the accessory already exists
1522
1419
  if (await this.registerDevice(device)) {
@@ -1524,8 +1421,11 @@ export class SwitchBotPlatform {
1524
1421
  existingAccessory.context.device = device;
1525
1422
  existingAccessory.context.deviceId = device.deviceId;
1526
1423
  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;
1424
+ existingAccessory.context.model = device.deviceType === 'Plug Mini (US)'
1425
+ ? SwitchBotModel.PlugMiniUS
1426
+ : device.deviceType === 'Plug Mini (JP)'
1427
+ ? SwitchBotModel.PlugMiniJP
1428
+ : SwitchBotModel.Plug;
1529
1429
  existingAccessory.displayName = device.configDeviceName
1530
1430
  ? await this.validateAndCleanDisplayName(device.configDeviceName, 'configDeviceName', device.configDeviceName)
1531
1431
  : await this.validateAndCleanDisplayName(device.deviceName, 'deviceName', device.deviceName);
@@ -1552,8 +1452,11 @@ export class SwitchBotPlatform {
1552
1452
  accessory.context.device = device;
1553
1453
  accessory.context.deviceId = device.deviceId;
1554
1454
  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;
1455
+ accessory.context.model = device.deviceType === 'Plug Mini (US)'
1456
+ ? SwitchBotModel.PlugMiniUS
1457
+ : device.deviceType === 'Plug Mini (JP)'
1458
+ ? SwitchBotModel.PlugMiniJP
1459
+ : SwitchBotModel.Plug;
1557
1460
  accessory.displayName = device.configDeviceName
1558
1461
  ? await this.validateAndCleanDisplayName(device.configDeviceName, 'configDeviceName', device.configDeviceName)
1559
1462
  : await this.validateAndCleanDisplayName(device.deviceName, 'deviceName', device.deviceName);
@@ -1578,7 +1481,7 @@ export class SwitchBotPlatform {
1578
1481
  const uuid = this.api.hap.uuid.generate(`${device.deviceId}-${device.deviceType}`);
1579
1482
  // see if an accessory with the same uuid has already been registered and restored from
1580
1483
  // the cached devices we stored in the `configureAccessory` method above
1581
- const existingAccessory = this.accessories.find((accessory) => accessory.UUID === uuid);
1484
+ const existingAccessory = this.accessories.find(accessory => accessory.UUID === uuid);
1582
1485
  if (existingAccessory) {
1583
1486
  // the accessory already exists
1584
1487
  if (await this.registerDevice(device)) {
@@ -1638,7 +1541,7 @@ export class SwitchBotPlatform {
1638
1541
  const uuid = this.api.hap.uuid.generate(`${device.deviceId}-${device.deviceType}`);
1639
1542
  // see if an accessory with the same uuid has already been registered and restored from
1640
1543
  // the cached devices we stored in the `configureAccessory` method above
1641
- const existingAccessory = this.accessories.find((accessory) => accessory.UUID === uuid);
1544
+ const existingAccessory = this.accessories.find(accessory => accessory.UUID === uuid);
1642
1545
  if (existingAccessory) {
1643
1546
  // the accessory already exists
1644
1547
  if (await this.registerDevice(device)) {
@@ -1698,7 +1601,7 @@ export class SwitchBotPlatform {
1698
1601
  const uuid = this.api.hap.uuid.generate(`${device.deviceId}-${device.deviceType}`);
1699
1602
  // see if an accessory with the same uuid has already been registered and restored from
1700
1603
  // the cached devices we stored in the `configureAccessory` method above
1701
- const existingAccessory = this.accessories.find((accessory) => accessory.UUID === uuid);
1604
+ const existingAccessory = this.accessories.find(accessory => accessory.UUID === uuid);
1702
1605
  if (existingAccessory) {
1703
1606
  // the accessory already exists
1704
1607
  if (await this.registerDevice(device)) {
@@ -1758,7 +1661,7 @@ export class SwitchBotPlatform {
1758
1661
  const uuid = this.api.hap.uuid.generate(`${device.deviceId}-${device.deviceType}`);
1759
1662
  // see if an accessory with the same uuid has already been registered and restored from
1760
1663
  // the cached devices we stored in the `configureAccessory` method above
1761
- const existingAccessory = this.accessories.find((accessory) => accessory.UUID === uuid);
1664
+ const existingAccessory = this.accessories.find(accessory => accessory.UUID === uuid);
1762
1665
  if (existingAccessory) {
1763
1666
  // the accessory already exists
1764
1667
  if (await this.registerDevice(device)) {
@@ -1818,7 +1721,7 @@ export class SwitchBotPlatform {
1818
1721
  const uuid = this.api.hap.uuid.generate(`${device.deviceId}-${device.deviceType}`);
1819
1722
  // see if an accessory with the same uuid has already been registered and restored from
1820
1723
  // the cached devices we stored in the `configureAccessory` method above
1821
- const existingAccessory = this.accessories.find((accessory) => accessory.UUID === uuid);
1724
+ const existingAccessory = this.accessories.find(accessory => accessory.UUID === uuid);
1822
1725
  if (existingAccessory) {
1823
1726
  // the accessory already exists
1824
1727
  if (await this.registerDevice(device)) {
@@ -1878,7 +1781,7 @@ export class SwitchBotPlatform {
1878
1781
  const uuid = this.api.hap.uuid.generate(`${device.deviceId}-${device.deviceType}`);
1879
1782
  // see if an accessory with the same uuid has already been registered and restored from
1880
1783
  // the cached devices we stored in the `configureAccessory` method above
1881
- const existingAccessory = this.accessories.find((accessory) => accessory.UUID === uuid);
1784
+ const existingAccessory = this.accessories.find(accessory => accessory.UUID === uuid);
1882
1785
  if (existingAccessory) {
1883
1786
  // the accessory already exists
1884
1787
  if (await this.registerDevice(device)) {
@@ -1886,11 +1789,17 @@ export class SwitchBotPlatform {
1886
1789
  existingAccessory.context.device = device;
1887
1790
  existingAccessory.context.deviceId = device.deviceId;
1888
1791
  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;
1792
+ existingAccessory.context.model = device.deviceType === 'Robot Vacuum Cleaner S1'
1793
+ ? SwitchBotModel.RobotVacuumCleanerS1
1794
+ : device.deviceType === 'Robot Vacuum Cleaner S1 Plus'
1795
+ ? SwitchBotModel.RobotVacuumCleanerS1Plus
1796
+ : device.deviceType === 'Robot Vacuum Cleaner S10'
1797
+ ? SwitchBotModel.RobotVacuumCleanerS10
1798
+ : device.deviceType === 'WoSweeper'
1799
+ ? SwitchBotModel.WoSweeper
1800
+ : device.deviceType === 'WoSweeperMini'
1801
+ ? SwitchBotModel.WoSweeperMini
1802
+ : SwitchBotModel.Unknown;
1894
1803
  existingAccessory.displayName = device.configDeviceName
1895
1804
  ? await this.validateAndCleanDisplayName(device.configDeviceName, 'configDeviceName', device.configDeviceName)
1896
1805
  : await this.validateAndCleanDisplayName(device.deviceName, 'deviceName', device.deviceName);
@@ -1917,11 +1826,17 @@ export class SwitchBotPlatform {
1917
1826
  accessory.context.device = device;
1918
1827
  accessory.context.deviceId = device.deviceId;
1919
1828
  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;
1829
+ accessory.context.model = device.deviceType === 'Robot Vacuum Cleaner S1'
1830
+ ? SwitchBotModel.RobotVacuumCleanerS1
1831
+ : device.deviceType === 'Robot Vacuum Cleaner S1 Plus'
1832
+ ? SwitchBotModel.RobotVacuumCleanerS1Plus
1833
+ : device.deviceType === 'Robot Vacuum Cleaner S10'
1834
+ ? SwitchBotModel.RobotVacuumCleanerS10
1835
+ : device.deviceType === 'WoSweeper'
1836
+ ? SwitchBotModel.WoSweeper
1837
+ : device.deviceType === 'WoSweeperMini'
1838
+ ? SwitchBotModel.WoSweeperMini
1839
+ : SwitchBotModel.Unknown;
1925
1840
  accessory.displayName = device.configDeviceName
1926
1841
  ? await this.validateAndCleanDisplayName(device.configDeviceName, 'configDeviceName', device.configDeviceName)
1927
1842
  : await this.validateAndCleanDisplayName(device.deviceName, 'deviceName', device.deviceName);
@@ -1946,7 +1861,7 @@ export class SwitchBotPlatform {
1946
1861
  const uuid = this.api.hap.uuid.generate(`${device.deviceId}-${device.remoteType}`);
1947
1862
  // see if an accessory with the same uuid has already been registered and restored from
1948
1863
  // the cached devices we stored in the `configureAccessory` method above
1949
- const existingAccessory = this.accessories.find((accessory) => accessory.UUID === uuid);
1864
+ const existingAccessory = this.accessories.find(accessory => accessory.UUID === uuid);
1950
1865
  if (!device.hide_device && existingAccessory) {
1951
1866
  // if you need to update the accessory.context then you should run `api.updatePlatformAccessories`. eg.:
1952
1867
  existingAccessory.context.device = device;
@@ -1979,7 +1894,6 @@ export class SwitchBotPlatform {
1979
1894
  ? await this.validateAndCleanDisplayName(device.configDeviceName, 'configDeviceName', device.configDeviceName)
1980
1895
  : await this.validateAndCleanDisplayName(device.deviceName, 'deviceName', device.deviceName);
1981
1896
  accessory.context.connectionType = await this.connectionType(device);
1982
- accessory.context.connectionType = device.connectionType;
1983
1897
  accessory.context.version = device.firmware ?? device.version ?? this.version ?? '0.0.0';
1984
1898
  const newOrExternal = !device.external ? 'Adding new' : 'Loading external';
1985
1899
  await this.infoLog(`${newOrExternal} accessory: ${accessory.displayName} deviceId: ${device.deviceId}`);
@@ -1987,7 +1901,7 @@ export class SwitchBotPlatform {
1987
1901
  // this is imported from `platformAccessory.ts`
1988
1902
  new TV(this, accessory, device);
1989
1903
  await this.debugLog(`${device.remoteType} uuid: ${device.deviceId}-${device.remoteType}, (${accessory.UUID})`);
1990
- this.externalOrPlatformIR(device, accessory);
1904
+ this.externalOrPlatform(device, accessory);
1991
1905
  this.accessories.push(accessory);
1992
1906
  }
1993
1907
  else {
@@ -1998,7 +1912,7 @@ export class SwitchBotPlatform {
1998
1912
  const uuid = this.api.hap.uuid.generate(`${device.deviceId}-${device.remoteType}`);
1999
1913
  // see if an accessory with the same uuid has already been registered and restored from
2000
1914
  // the cached devices we stored in the `configureAccessory` method above
2001
- const existingAccessory = this.accessories.find((accessory) => accessory.UUID === uuid);
1915
+ const existingAccessory = this.accessories.find(accessory => accessory.UUID === uuid);
2002
1916
  if (existingAccessory) {
2003
1917
  // the accessory already exists
2004
1918
  if (!device.hide_device && device.hubDeviceId) {
@@ -2037,7 +1951,6 @@ export class SwitchBotPlatform {
2037
1951
  ? await this.validateAndCleanDisplayName(device.configDeviceName, 'configDeviceName', device.configDeviceName)
2038
1952
  : await this.validateAndCleanDisplayName(device.deviceName, 'deviceName', device.deviceName);
2039
1953
  accessory.context.connectionType = await this.connectionType(device);
2040
- accessory.context.connectionType = device.connectionType;
2041
1954
  accessory.context.version = device.firmware ?? device.version ?? this.version ?? '0.0.0';
2042
1955
  const newOrExternal = !device.external ? 'Adding new' : 'Loading external';
2043
1956
  await this.infoLog(`${newOrExternal} accessory: ${accessory.displayName} deviceId: ${device.deviceId}`);
@@ -2046,7 +1959,7 @@ export class SwitchBotPlatform {
2046
1959
  new IRFan(this, accessory, device);
2047
1960
  await this.debugLog(`${device.remoteType} uuid: ${device.deviceId}-${device.remoteType}, (${accessory.UUID})`);
2048
1961
  // publish device externally or link the accessory to your platform
2049
- this.externalOrPlatformIR(device, accessory);
1962
+ this.externalOrPlatform(device, accessory);
2050
1963
  this.accessories.push(accessory);
2051
1964
  }
2052
1965
  else {
@@ -2057,7 +1970,7 @@ export class SwitchBotPlatform {
2057
1970
  const uuid = this.api.hap.uuid.generate(`${device.deviceId}-${device.remoteType}`);
2058
1971
  // see if an accessory with the same uuid has already been registered and restored from
2059
1972
  // the cached devices we stored in the `configureAccessory` method above
2060
- const existingAccessory = this.accessories.find((accessory) => accessory.UUID === uuid);
1973
+ const existingAccessory = this.accessories.find(accessory => accessory.UUID === uuid);
2061
1974
  if (existingAccessory) {
2062
1975
  // the accessory already exists
2063
1976
  if (!device.hide_device && device.hubDeviceId) {
@@ -2096,7 +2009,6 @@ export class SwitchBotPlatform {
2096
2009
  ? await this.validateAndCleanDisplayName(device.configDeviceName, 'configDeviceName', device.configDeviceName)
2097
2010
  : await this.validateAndCleanDisplayName(device.deviceName, 'deviceName', device.deviceName);
2098
2011
  accessory.context.connectionType = await this.connectionType(device);
2099
- accessory.context.connectionType = device.connectionType;
2100
2012
  accessory.context.version = device.firmware ?? device.version ?? this.version ?? '0.0.0';
2101
2013
  const newOrExternal = !device.external ? 'Adding new' : 'Loading external';
2102
2014
  await this.infoLog(`${newOrExternal} accessory: ${accessory.displayName} deviceId: ${device.deviceId}`);
@@ -2105,7 +2017,7 @@ export class SwitchBotPlatform {
2105
2017
  new Light(this, accessory, device);
2106
2018
  await this.debugLog(`${device.remoteType} uuid: ${device.deviceId}-${device.remoteType}, (${accessory.UUID})`);
2107
2019
  // publish device externally or link the accessory to your platform
2108
- this.externalOrPlatformIR(device, accessory);
2020
+ this.externalOrPlatform(device, accessory);
2109
2021
  this.accessories.push(accessory);
2110
2022
  }
2111
2023
  else {
@@ -2116,7 +2028,7 @@ export class SwitchBotPlatform {
2116
2028
  const uuid = this.api.hap.uuid.generate(`${device.deviceId}-${device.remoteType}`);
2117
2029
  // see if an accessory with the same uuid has already been registered and restored from
2118
2030
  // the cached devices we stored in the `configureAccessory` method above
2119
- const existingAccessory = this.accessories.find((accessory) => accessory.UUID === uuid);
2031
+ const existingAccessory = this.accessories.find(accessory => accessory.UUID === uuid);
2120
2032
  if (existingAccessory) {
2121
2033
  // the accessory already exists
2122
2034
  if (!device.hide_device && device.hubDeviceId) {
@@ -2155,7 +2067,6 @@ export class SwitchBotPlatform {
2155
2067
  ? await this.validateAndCleanDisplayName(device.configDeviceName, 'configDeviceName', device.configDeviceName)
2156
2068
  : await this.validateAndCleanDisplayName(device.deviceName, 'deviceName', device.deviceName);
2157
2069
  accessory.context.connectionType = await this.connectionType(device);
2158
- accessory.context.connectionType = device.connectionType;
2159
2070
  accessory.context.version = device.firmware ?? device.version ?? this.version ?? '0.0.0';
2160
2071
  const newOrExternal = !device.external ? 'Adding new' : 'Loading external';
2161
2072
  await this.infoLog(`${newOrExternal} accessory: ${accessory.displayName} deviceId: ${device.deviceId}`);
@@ -2164,7 +2075,7 @@ export class SwitchBotPlatform {
2164
2075
  new AirConditioner(this, accessory, device);
2165
2076
  await this.debugLog(`${device.remoteType} uuid: ${device.deviceId}-${device.remoteType}, (${accessory.UUID})`);
2166
2077
  // publish device externally or link the accessory to your platform
2167
- this.externalOrPlatformIR(device, accessory);
2078
+ this.externalOrPlatform(device, accessory);
2168
2079
  this.accessories.push(accessory);
2169
2080
  }
2170
2081
  else {
@@ -2175,7 +2086,7 @@ export class SwitchBotPlatform {
2175
2086
  const uuid = this.api.hap.uuid.generate(`${device.deviceId}-${device.remoteType}`);
2176
2087
  // see if an accessory with the same uuid has already been registered and restored from
2177
2088
  // the cached devices we stored in the `configureAccessory` method above
2178
- const existingAccessory = this.accessories.find((accessory) => accessory.UUID === uuid);
2089
+ const existingAccessory = this.accessories.find(accessory => accessory.UUID === uuid);
2179
2090
  if (existingAccessory) {
2180
2091
  // the accessory already exists
2181
2092
  if (!device.hide_device && device.hubDeviceId) {
@@ -2214,7 +2125,6 @@ export class SwitchBotPlatform {
2214
2125
  ? await this.validateAndCleanDisplayName(device.configDeviceName, 'configDeviceName', device.configDeviceName)
2215
2126
  : await this.validateAndCleanDisplayName(device.deviceName, 'deviceName', device.deviceName);
2216
2127
  accessory.context.connectionType = await this.connectionType(device);
2217
- accessory.context.connectionType = device.connectionType;
2218
2128
  accessory.context.version = device.firmware ?? device.version ?? this.version ?? '0.0.0';
2219
2129
  const newOrExternal = !device.external ? 'Adding new' : 'Loading external';
2220
2130
  await this.infoLog(`${newOrExternal} accessory: ${accessory.displayName} deviceId: ${device.deviceId}`);
@@ -2223,7 +2133,7 @@ export class SwitchBotPlatform {
2223
2133
  new AirPurifier(this, accessory, device);
2224
2134
  await this.debugLog(`${device.remoteType} uuid: ${device.deviceId}-${device.remoteType}, (${accessory.UUID})`);
2225
2135
  // publish device externally or link the accessory to your platform
2226
- this.externalOrPlatformIR(device, accessory);
2136
+ this.externalOrPlatform(device, accessory);
2227
2137
  this.accessories.push(accessory);
2228
2138
  }
2229
2139
  else {
@@ -2234,7 +2144,7 @@ export class SwitchBotPlatform {
2234
2144
  const uuid = this.api.hap.uuid.generate(`${device.deviceId}-${device.remoteType}`);
2235
2145
  // see if an accessory with the same uuid has already been registered and restored from
2236
2146
  // the cached devices we stored in the `configureAccessory` method above
2237
- const existingAccessory = this.accessories.find((accessory) => accessory.UUID === uuid);
2147
+ const existingAccessory = this.accessories.find(accessory => accessory.UUID === uuid);
2238
2148
  if (existingAccessory) {
2239
2149
  // the accessory already exists
2240
2150
  if (!device.hide_device && device.hubDeviceId) {
@@ -2273,7 +2183,6 @@ export class SwitchBotPlatform {
2273
2183
  ? await this.validateAndCleanDisplayName(device.configDeviceName, 'configDeviceName', device.configDeviceName)
2274
2184
  : await this.validateAndCleanDisplayName(device.deviceName, 'deviceName', device.deviceName);
2275
2185
  accessory.context.connectionType = await this.connectionType(device);
2276
- accessory.context.connectionType = device.connectionType;
2277
2186
  accessory.context.version = device.firmware ?? device.version ?? this.version ?? '0.0.0';
2278
2187
  const newOrExternal = !device.external ? 'Adding new' : 'Loading external';
2279
2188
  await this.infoLog(`${newOrExternal} accessory: ${accessory.displayName} deviceId: ${device.deviceId}`);
@@ -2282,7 +2191,7 @@ export class SwitchBotPlatform {
2282
2191
  new WaterHeater(this, accessory, device);
2283
2192
  await this.debugLog(`${device.remoteType} uuid: ${device.deviceId}-${device.remoteType}, (${accessory.UUID})`);
2284
2193
  // publish device externally or link the accessory to your platform
2285
- this.externalOrPlatformIR(device, accessory);
2194
+ this.externalOrPlatform(device, accessory);
2286
2195
  this.accessories.push(accessory);
2287
2196
  }
2288
2197
  else {
@@ -2293,7 +2202,7 @@ export class SwitchBotPlatform {
2293
2202
  const uuid = this.api.hap.uuid.generate(`${device.deviceId}-${device.remoteType}`);
2294
2203
  // see if an accessory with the same uuid has already been registered and restored from
2295
2204
  // the cached devices we stored in the `configureAccessory` method above
2296
- const existingAccessory = this.accessories.find((accessory) => accessory.UUID === uuid);
2205
+ const existingAccessory = this.accessories.find(accessory => accessory.UUID === uuid);
2297
2206
  if (existingAccessory) {
2298
2207
  // the accessory already exists
2299
2208
  if (!device.hide_device && device.hubDeviceId) {
@@ -2332,7 +2241,6 @@ export class SwitchBotPlatform {
2332
2241
  ? await this.validateAndCleanDisplayName(device.configDeviceName, 'configDeviceName', device.configDeviceName)
2333
2242
  : await this.validateAndCleanDisplayName(device.deviceName, 'deviceName', device.deviceName);
2334
2243
  accessory.context.connectionType = await this.connectionType(device);
2335
- accessory.context.connectionType = device.connectionType;
2336
2244
  accessory.context.version = device.firmware ?? device.version ?? this.version ?? '0.0.0';
2337
2245
  const newOrExternal = !device.external ? 'Adding new' : 'Loading external';
2338
2246
  await this.infoLog(`${newOrExternal} accessory: ${accessory.displayName} deviceId: ${device.deviceId}`);
@@ -2341,7 +2249,7 @@ export class SwitchBotPlatform {
2341
2249
  new VacuumCleaner(this, accessory, device);
2342
2250
  await this.debugLog(`${device.remoteType} uuid: ${device.deviceId}-${device.remoteType}, (${accessory.UUID})`);
2343
2251
  // publish device externally or link the accessory to your platform
2344
- this.externalOrPlatformIR(device, accessory);
2252
+ this.externalOrPlatform(device, accessory);
2345
2253
  this.accessories.push(accessory);
2346
2254
  }
2347
2255
  else {
@@ -2352,7 +2260,7 @@ export class SwitchBotPlatform {
2352
2260
  const uuid = this.api.hap.uuid.generate(`${device.deviceId}-${device.remoteType}`);
2353
2261
  // see if an accessory with the same uuid has already been registered and restored from
2354
2262
  // the cached devices we stored in the `configureAccessory` method above
2355
- const existingAccessory = this.accessories.find((accessory) => accessory.UUID === uuid);
2263
+ const existingAccessory = this.accessories.find(accessory => accessory.UUID === uuid);
2356
2264
  if (existingAccessory) {
2357
2265
  // the accessory already exists
2358
2266
  if (!device.hide_device && device.hubDeviceId) {
@@ -2391,7 +2299,6 @@ export class SwitchBotPlatform {
2391
2299
  ? await this.validateAndCleanDisplayName(device.configDeviceName, 'configDeviceName', device.configDeviceName)
2392
2300
  : await this.validateAndCleanDisplayName(device.deviceName, 'deviceName', device.deviceName);
2393
2301
  accessory.context.connectionType = await this.connectionType(device);
2394
- accessory.context.connectionType = device.connectionType;
2395
2302
  accessory.context.version = device.firmware ?? device.version ?? this.version ?? '0.0.0';
2396
2303
  const newOrExternal = !device.external ? 'Adding new' : 'Loading external';
2397
2304
  await this.infoLog(`${newOrExternal} accessory: ${accessory.displayName} deviceId: ${device.deviceId}`);
@@ -2400,7 +2307,7 @@ export class SwitchBotPlatform {
2400
2307
  new Camera(this, accessory, device);
2401
2308
  await this.debugLog(`${device.remoteType} uuid: ${device.deviceId}-${device.remoteType}, (${accessory.UUID})`);
2402
2309
  // publish device externally or link the accessory to your platform
2403
- this.externalOrPlatformIR(device, accessory);
2310
+ this.externalOrPlatform(device, accessory);
2404
2311
  this.accessories.push(accessory);
2405
2312
  }
2406
2313
  else {
@@ -2411,7 +2318,7 @@ export class SwitchBotPlatform {
2411
2318
  const uuid = this.api.hap.uuid.generate(`${device.deviceId}-${device.remoteType}`);
2412
2319
  // see if an accessory with the same uuid has already been registered and restored from
2413
2320
  // the cached devices we stored in the `configureAccessory` method above
2414
- const existingAccessory = this.accessories.find((accessory) => accessory.UUID === uuid);
2321
+ const existingAccessory = this.accessories.find(accessory => accessory.UUID === uuid);
2415
2322
  if (existingAccessory) {
2416
2323
  // the accessory already exists
2417
2324
  if (!device.hide_device && device.hubDeviceId) {
@@ -2450,7 +2357,6 @@ export class SwitchBotPlatform {
2450
2357
  ? await this.validateAndCleanDisplayName(device.configDeviceName, 'configDeviceName', device.configDeviceName)
2451
2358
  : await this.validateAndCleanDisplayName(device.deviceName, 'deviceName', device.deviceName);
2452
2359
  accessory.context.connectionType = await this.connectionType(device);
2453
- accessory.context.connectionType = device.connectionType;
2454
2360
  accessory.context.version = device.firmware ?? device.version ?? this.version ?? '0.0.0';
2455
2361
  const newOrExternal = !device.external ? 'Adding new' : 'Loading external';
2456
2362
  await this.infoLog(`${newOrExternal} accessory: ${accessory.displayName} deviceId: ${device.deviceId}`);
@@ -2459,7 +2365,7 @@ export class SwitchBotPlatform {
2459
2365
  new Others(this, accessory, device);
2460
2366
  await this.debugLog(`${device.remoteType} uuid: ${device.deviceId}-${device.remoteType}, (${accessory.UUID})`);
2461
2367
  // publish device externally or link the accessory to your platform
2462
- this.externalOrPlatformIR(device, accessory);
2368
+ this.externalOrPlatform(device, accessory);
2463
2369
  this.accessories.push(accessory);
2464
2370
  }
2465
2371
  else {
@@ -2467,24 +2373,13 @@ export class SwitchBotPlatform {
2467
2373
  }
2468
2374
  }
2469
2375
  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
2376
  let registerWindowCovering;
2478
2377
  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}`);
2378
+ 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
2379
  registerWindowCovering = await this.registerWindowCovering(device);
2483
2380
  }
2484
2381
  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}`);
2382
+ 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
2383
  registerWindowCovering = await this.registerWindowCovering(device);
2489
2384
  }
2490
2385
  else {
@@ -2498,36 +2393,31 @@ export class SwitchBotPlatform {
2498
2393
  if (device.master && device.group) {
2499
2394
  // OpenAPI: Master Curtains/Blind Tilt in Group
2500
2395
  registerCurtain = true;
2501
- await this.debugLog(`deviceName: ${device.deviceName} [${device.deviceType} Config] device.master: ${device.master},`
2502
- + ` device.group: ${device.group} connectionType; ${device.connectionType}`);
2396
+ await this.debugLog(`deviceName: ${device.deviceName} [${device.deviceType} Config] device.master: ${device.master}, device.group: ${device.group} connectionType; ${device.connectionType}`);
2503
2397
  await this.debugWarnLog(`Device: ${device.deviceName} registerCurtains: ${registerCurtain}`);
2504
2398
  }
2505
2399
  else if (!device.master && device.curtain?.disable_group) {
2506
- //!device.group && device.connectionType === 'BLE'
2400
+ // !device.group && device.connectionType === 'BLE'
2507
2401
  // OpenAPI: Non-Master Curtains/Blind Tilts that has Disable Grouping Checked
2508
2402
  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}`);
2403
+ await this.debugLog(`deviceName: ${device.deviceName} [${device.deviceType} Config] device.master: ${device.master}, disable_group: ${device.curtain?.disable_group}, connectionType; ${device.connectionType}`);
2511
2404
  await this.debugWarnLog(`Device: ${device.deviceName} registerCurtains: ${registerCurtain}`);
2512
2405
  }
2513
2406
  else if (device.master && !device.group) {
2514
2407
  // OpenAPI: Master Curtains/Blind Tilts not in Group
2515
2408
  registerCurtain = true;
2516
- await this.debugLog(`deviceName: ${device.deviceName} [${device.deviceType} Config] device.master: ${device.master},`
2517
- + ` device.group: ${device.group} connectionType; ${device.connectionType}`);
2409
+ await this.debugLog(`deviceName: ${device.deviceName} [${device.deviceType} Config] device.master: ${device.master}, device.group: ${device.group} connectionType; ${device.connectionType}`);
2518
2410
  await this.debugWarnLog(`Device: ${device.deviceName} registerCurtains: ${registerCurtain}`);
2519
2411
  }
2520
2412
  else if (device.connectionType === 'BLE') {
2521
2413
  // BLE: Curtains/Blind Tilt
2522
2414
  registerCurtain = true;
2523
- await this.debugLog(`deviceName: ${device.deviceName} [${device.deviceType} Config] connectionType: ${device.connectionType}, `
2524
- + ` group: ${device.group}`);
2415
+ await this.debugLog(`deviceName: ${device.deviceName} [${device.deviceType} Config] connectionType: ${device.connectionType}, group: ${device.group}`);
2525
2416
  await this.debugWarnLog(`Device: ${device.deviceName} registerCurtains: ${registerCurtain}`);
2526
2417
  }
2527
2418
  else {
2528
2419
  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}`);
2420
+ await this.debugErrorLog(`deviceName: ${device.deviceName} [${device.deviceType} Config] disable_group: ${device.curtain?.disable_group}, device.master: ${device.master}, device.group: ${device.group}`);
2531
2421
  await this.debugWarnLog(`Device: ${device.deviceName} registerCurtains: ${registerCurtain}, device.connectionType: ${device.connectionType}`);
2532
2422
  }
2533
2423
  return registerCurtain;
@@ -2545,189 +2435,93 @@ export class SwitchBotPlatform {
2545
2435
  async registerDevice(device) {
2546
2436
  device.connectionType = await this.connectionType(device);
2547
2437
  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`);
2438
+ const shouldRegister = !device.hide_device && (device.connectionType === 'BLE/OpenAPI' || (device.deviceId && device.configDeviceType && device.configDeviceName && device.connectionType === 'BLE') || device.connectionType === 'OpenAPI' || device.connectionType === 'Disabled');
2439
+ if (shouldRegister) {
2440
+ registerDevice = await this.handleDeviceRegistration(device);
2626
2441
  }
2627
2442
  else {
2628
2443
  registerDevice = false;
2629
- await this.debugErrorLog(`Device: ${device.deviceName} connectionType: ${device.connectionType}, hide_device: `
2630
- + `${device.hide_device}, will not display in HomeKit`);
2444
+ await this.debugErrorLog(`Device: ${device.deviceName} connectionType: ${device.connectionType}, hide_device: ${device.hide_device}, will not display in HomeKit`);
2631
2445
  }
2632
2446
  return registerDevice;
2633
2447
  }
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);
2448
+ async handleDeviceRegistration(device) {
2449
+ let registerDevice;
2450
+ switch (device.deviceType) {
2451
+ case 'Curtain':
2452
+ case 'Curtain3':
2453
+ case 'Blind Tilt':
2454
+ registerDevice = await this.registerCurtains(device);
2455
+ await this.debugWarnLog(`Device: ${device.deviceName} ${device.deviceType} registerDevice: ${registerDevice}`);
2456
+ break;
2457
+ default:
2458
+ registerDevice = true;
2459
+ await this.debugWarnLog(`Device: ${device.deviceName} registerDevice: ${registerDevice}`);
2460
+ }
2461
+ if (registerDevice) {
2462
+ await this.debugWarnLog(`Device: ${device.deviceName} connectionType: ${device.connectionType}, will display in HomeKit`);
2643
2463
  }
2644
2464
  else {
2645
- await this.debugLog(`${accessory.displayName} External Accessory Mode: ${device.external}`);
2646
- this.api.registerPlatformAccessories(PLUGIN_NAME, PLATFORM_NAME, [accessory]);
2465
+ await this.debugErrorLog(`Device: ${device.deviceName} connectionType: ${device.connectionType}, will not display in HomeKit`);
2647
2466
  }
2467
+ return registerDevice;
2648
2468
  }
2649
2469
  async externalOrPlatform(device, accessory) {
2650
- if (device.external) {
2651
- await this.debugWarnLog(`${accessory.displayName} External Accessory Mode`);
2652
- await this.externalAccessory(accessory);
2470
+ const { displayName } = accessory;
2471
+ const isExternal = device.external ?? false;
2472
+ if (isExternal) {
2473
+ await this.debugWarnLog(`${displayName} External Accessory Mode`);
2474
+ this.api.publishExternalAccessories(PLUGIN_NAME, [accessory]);
2653
2475
  }
2654
2476
  else {
2655
- await this.debugLog(`${accessory.displayName} External Accessory Mode: ${device.external}`);
2477
+ await this.debugLog(`${displayName} External Accessory Mode: ${isExternal}`);
2656
2478
  this.api.registerPlatformAccessories(PLUGIN_NAME, PLATFORM_NAME, [accessory]);
2657
2479
  }
2658
2480
  }
2659
- async externalAccessory(accessory) {
2660
- this.api.publishExternalAccessories(PLUGIN_NAME, [accessory]);
2661
- }
2662
2481
  unregisterPlatformAccessories(existingAccessory) {
2482
+ const { displayName } = existingAccessory;
2663
2483
  // remove platform accessories when no longer present
2664
2484
  this.api.unregisterPlatformAccessories(PLUGIN_NAME, PLATFORM_NAME, [existingAccessory]);
2665
- this.warnLog(`Removing existing accessory from cache: ${existingAccessory.displayName}`);
2485
+ this.warnLog(`Removing existing accessory from cache: ${displayName}`);
2666
2486
  }
2487
+ /**
2488
+ * Handles the status codes returned by the device and logs appropriate messages.
2489
+ *
2490
+ * @param statusCode - The status code returned by the device.
2491
+ * @returns A promise that resolves when the logging is complete.
2492
+ */
2667
2493
  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`);
2494
+ const messages = {
2495
+ 151: `Command not supported by this device type, statusCode: ${statusCode}, Submit Feature Request Here:
2496
+ https://tinyurl.com/SwitchBotFeatureRequest`,
2497
+ 152: `Device not found, statusCode: ${statusCode}`,
2498
+ 160: `Command is not supported, statusCode: ${statusCode}, Submit Bugs Here: https://tinyurl.com/SwitchBotBug`,
2499
+ 161: `Device is offline, statusCode: ${statusCode}`,
2500
+ 171: `is offline, statusCode: ${statusCode}`,
2501
+ 190: `Requests reached the daily limit, statusCode: ${statusCode}`,
2502
+ 100: `Command successfully sent, statusCode: ${statusCode}`,
2503
+ 200: `Request successful, statusCode: ${statusCode}`,
2504
+ 400: `Bad Request, The client has issued an invalid request. This is commonly used to specify validation errors in a request payload,
2505
+ statusCode: ${statusCode}`,
2506
+ 401: `Unauthorized, Authorization for the API is required, but the request has not been authenticated, statusCode: ${statusCode}`,
2507
+ 403: `Forbidden, The request has been authenticated but does not have appropriate permissions, or a requested resource is not found,
2508
+ statusCode: ${statusCode}`,
2509
+ 404: `Not Found, Specifies the requested path does not exist, statusCode: ${statusCode}`,
2510
+ 406: `Not Acceptable, The client has requested a MIME type via the Accept header for a value not supported by the server,
2511
+ statusCode: ${statusCode}`,
2512
+ 415: `Unsupported Media Type, The client has defined a contentType header that is not supported by the server, statusCode: ${statusCode}`,
2513
+ 422: `Unprocessable Entity, The client has made a valid request, but the server cannot process it. This is often used for APIs for which
2514
+ certain limits have been exceeded, statusCode: ${statusCode}`,
2515
+ 429: `Too Many Requests, The client has exceeded the number of requests allowed for a given time window, statusCode: ${statusCode}`,
2516
+ 500: `Internal Server Error, An unexpected error on the SmartThings servers has occurred. These errors should be rare,
2517
+ statusCode: ${statusCode}`,
2518
+ };
2519
+ const message = messages[statusCode] ?? `Unknown statusCode, statusCode: ${statusCode}, Submit Bugs Here: https://tinyurl.com/SwitchBotBug`;
2520
+ if ([100, 200].includes(statusCode)) {
2521
+ await this.debugLog(message);
2522
+ }
2523
+ else {
2524
+ await this.errorLog(message);
2731
2525
  }
2732
2526
  }
2733
2527
  async retryRequest(deviceMaxRetries, deviceDelayBetweenRetries, url, options) {
@@ -2755,57 +2549,42 @@ export class SwitchBotPlatform {
2755
2549
  }
2756
2550
  // BLE Connection
2757
2551
  async connectBLE(accessory, device) {
2758
- let switchbot;
2759
2552
  try {
2760
- const SwitchBot = (await import('node-switchbot')).SwitchBot;
2761
- queueScheduler.schedule(() => (switchbot = new SwitchBot()));
2553
+ const switchbot = new SwitchBot();
2554
+ queueScheduler.schedule(async () => switchbot);
2762
2555
  await this.debugLog(`${device.deviceType}: ${accessory.displayName} 'node-switchbot' found: ${switchbot}`);
2556
+ return switchbot;
2763
2557
  }
2764
2558
  catch (e) {
2765
- switchbot = false;
2766
- await this.errorLog(`${device.deviceType}: ${accessory.displayName} 'node-switchbot' found: ${switchbot}, Error: ${e}`);
2559
+ await this.errorLog(`${device.deviceType}: ${accessory.displayName} 'node-switchbot' not found, Error: ${e}`);
2560
+ return false;
2767
2561
  }
2768
- return switchbot;
2769
2562
  }
2770
2563
  async getVersion() {
2771
2564
  const json = JSON.parse(readFileSync(new URL('../package.json', import.meta.url), 'utf-8'));
2772
2565
  await this.debugLog(`Plugin Version: ${json.version}`);
2773
2566
  this.version = json.version;
2567
+ return json.version;
2774
2568
  }
2775
2569
  async getPlatformConfigSettings() {
2570
+ const { options } = this.config;
2776
2571
  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) {
2572
+ if (options) {
2573
+ platformConfig.logging = options.logging;
2574
+ platformConfig.refreshRate = options.refreshRate;
2575
+ platformConfig.updateRate = options.updateRate;
2576
+ platformConfig.pushRate = options.pushRate;
2577
+ this.maxRetries = options.maxRetries || 3;
2578
+ platformConfig.maxRetries = this.maxRetries;
2579
+ if (!options.maxRetries) {
2580
+ await this.debugWarnLog('Using Default Max Retries');
2581
+ }
2582
+ this.delayBetweenRetries = (options.delayBetweenRetries || 3) * 1000;
2583
+ platformConfig.delayBetweenRetries = this.delayBetweenRetries / 1000;
2584
+ if (!options.delayBetweenRetries) {
2585
+ await this.debugWarnLog('Using Default Delay Between Retries');
2586
+ }
2587
+ if (Object.keys(platformConfig).length) {
2809
2588
  await this.debugLog(`Platform Config: ${JSON.stringify(platformConfig)}`);
2810
2589
  }
2811
2590
  this.platformConfig = platformConfig;
@@ -2828,31 +2607,38 @@ export class SwitchBotPlatform {
2828
2607
  }
2829
2608
  /**
2830
2609
  * Validate and clean a string value for a Name Characteristic.
2831
- * @param displayName
2832
- * @param name
2833
- * @param value
2834
- * @returns string value
2835
- */
2610
+ * @param displayName - The display name of the accessory.
2611
+ * @param name - The name of the characteristic.
2612
+ * @param value - The value to be validated and cleaned.
2613
+ * @returns The cleaned string value.
2614
+ */
2836
2615
  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;
2616
+ if (this.config.options?.allowInvalidCharacters) {
2617
+ return value;
2618
+ }
2619
+ else {
2620
+ const validPattern = /^[\p{L}\p{N}][\p{L}\p{N} ']*[\p{L}\p{N}]$/u;
2621
+ const invalidCharsPattern = /[^\p{L}\p{N} ']/gu;
2622
+ const invalidStartEndPattern = /^[^\p{L}\p{N}]+|[^\p{L}\p{N}]+$/gu;
2623
+ if (typeof value === 'string' && !validPattern.test(value)) {
2624
+ 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.`);
2625
+ // Remove invalid characters
2626
+ if (invalidCharsPattern.test(value)) {
2627
+ const before = value;
2628
+ 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`);
2629
+ value = value.replace(invalidCharsPattern, '');
2630
+ await this.warnLog(`${name} Before: '${before}' After: '${value}'`);
2631
+ }
2632
+ // Ensure it starts and ends with an alphanumeric character
2633
+ if (invalidStartEndPattern.test(value)) {
2634
+ const before = value;
2635
+ 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`);
2636
+ value = value.replace(invalidStartEndPattern, '');
2637
+ await this.warnLog(`${name} Before: '${before}' After: '${value}'`);
2638
+ }
2639
+ }
2640
+ return value;
2641
+ }
2856
2642
  }
2857
2643
  /**
2858
2644
  * If device level logging is turned on, log to log.warn