@switchbot/homebridge-switchbot 2.6.0-beta.4 → 2.6.0

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 (143) hide show
  1. package/.vscode/tasks.json +13 -0
  2. package/CHANGELOG.md +4 -2
  3. package/README.md +18 -9
  4. package/dist/device/blindtilt.d.ts +1 -5
  5. package/dist/device/blindtilt.d.ts.map +1 -1
  6. package/dist/device/blindtilt.js +80 -140
  7. package/dist/device/blindtilt.js.map +1 -1
  8. package/dist/device/bot.d.ts +1 -5
  9. package/dist/device/bot.d.ts.map +1 -1
  10. package/dist/device/bot.js +79 -138
  11. package/dist/device/bot.js.map +1 -1
  12. package/dist/device/ceilinglight.d.ts +2 -6
  13. package/dist/device/ceilinglight.d.ts.map +1 -1
  14. package/dist/device/ceilinglight.js +157 -304
  15. package/dist/device/ceilinglight.js.map +1 -1
  16. package/dist/device/colorbulb.d.ts +2 -6
  17. package/dist/device/colorbulb.d.ts.map +1 -1
  18. package/dist/device/colorbulb.js +164 -311
  19. package/dist/device/colorbulb.js.map +1 -1
  20. package/dist/device/contact.d.ts +1 -5
  21. package/dist/device/contact.d.ts.map +1 -1
  22. package/dist/device/contact.js +36 -72
  23. package/dist/device/contact.js.map +1 -1
  24. package/dist/device/curtain.d.ts +1 -5
  25. package/dist/device/curtain.d.ts.map +1 -1
  26. package/dist/device/curtain.js +78 -138
  27. package/dist/device/curtain.js.map +1 -1
  28. package/dist/device/hub.d.ts +2 -6
  29. package/dist/device/hub.d.ts.map +1 -1
  30. package/dist/device/hub.js +30 -63
  31. package/dist/device/hub.js.map +1 -1
  32. package/dist/device/humidifier.d.ts +1 -5
  33. package/dist/device/humidifier.d.ts.map +1 -1
  34. package/dist/device/humidifier.js +115 -228
  35. package/dist/device/humidifier.js.map +1 -1
  36. package/dist/device/iosensor.d.ts +1 -5
  37. package/dist/device/iosensor.d.ts.map +1 -1
  38. package/dist/device/iosensor.js +38 -74
  39. package/dist/device/iosensor.js.map +1 -1
  40. package/dist/device/{striplight.d.ts → lightstrip.d.ts} +2 -10
  41. package/dist/device/lightstrip.d.ts.map +1 -0
  42. package/dist/device/{striplight.js → lightstrip.js} +138 -194
  43. package/dist/device/lightstrip.js.map +1 -0
  44. package/dist/device/lock.d.ts +1 -5
  45. package/dist/device/lock.d.ts.map +1 -1
  46. package/dist/device/lock.js +66 -126
  47. package/dist/device/lock.js.map +1 -1
  48. package/dist/device/meter.d.ts +1 -5
  49. package/dist/device/meter.d.ts.map +1 -1
  50. package/dist/device/meter.js +38 -74
  51. package/dist/device/meter.js.map +1 -1
  52. package/dist/device/meterplus.d.ts +1 -5
  53. package/dist/device/meterplus.d.ts.map +1 -1
  54. package/dist/device/meterplus.js +39 -75
  55. package/dist/device/meterplus.js.map +1 -1
  56. package/dist/device/motion.d.ts +1 -5
  57. package/dist/device/motion.d.ts.map +1 -1
  58. package/dist/device/motion.js +35 -72
  59. package/dist/device/motion.js.map +1 -1
  60. package/dist/device/plug.d.ts +1 -5
  61. package/dist/device/plug.d.ts.map +1 -1
  62. package/dist/device/plug.js +65 -126
  63. package/dist/device/plug.js.map +1 -1
  64. package/dist/device/robotvacuumcleaner.d.ts +1 -5
  65. package/dist/device/robotvacuumcleaner.d.ts.map +1 -1
  66. package/dist/device/robotvacuumcleaner.js +79 -151
  67. package/dist/device/robotvacuumcleaner.js.map +1 -1
  68. package/dist/irdevice/airconditioner.d.ts +3 -7
  69. package/dist/irdevice/airconditioner.d.ts.map +1 -1
  70. package/dist/irdevice/airconditioner.js +34 -62
  71. package/dist/irdevice/airconditioner.js.map +1 -1
  72. package/dist/irdevice/airpurifier.d.ts +3 -7
  73. package/dist/irdevice/airpurifier.d.ts.map +1 -1
  74. package/dist/irdevice/airpurifier.js +31 -59
  75. package/dist/irdevice/airpurifier.js.map +1 -1
  76. package/dist/irdevice/camera.d.ts +1 -5
  77. package/dist/irdevice/camera.d.ts.map +1 -1
  78. package/dist/irdevice/camera.js +30 -57
  79. package/dist/irdevice/camera.js.map +1 -1
  80. package/dist/irdevice/fan.d.ts +2 -6
  81. package/dist/irdevice/fan.d.ts.map +1 -1
  82. package/dist/irdevice/fan.js +39 -66
  83. package/dist/irdevice/fan.js.map +1 -1
  84. package/dist/irdevice/light.d.ts +1 -5
  85. package/dist/irdevice/light.d.ts.map +1 -1
  86. package/dist/irdevice/light.js +32 -59
  87. package/dist/irdevice/light.js.map +1 -1
  88. package/dist/irdevice/other.d.ts +1 -5
  89. package/dist/irdevice/other.d.ts.map +1 -1
  90. package/dist/irdevice/other.js +30 -57
  91. package/dist/irdevice/other.js.map +1 -1
  92. package/dist/irdevice/tv.d.ts +3 -7
  93. package/dist/irdevice/tv.d.ts.map +1 -1
  94. package/dist/irdevice/tv.js +46 -76
  95. package/dist/irdevice/tv.js.map +1 -1
  96. package/dist/irdevice/vacuumcleaner.d.ts +2 -6
  97. package/dist/irdevice/vacuumcleaner.d.ts.map +1 -1
  98. package/dist/irdevice/vacuumcleaner.js +30 -58
  99. package/dist/irdevice/vacuumcleaner.js.map +1 -1
  100. package/dist/irdevice/waterheater.d.ts +7 -23
  101. package/dist/irdevice/waterheater.d.ts.map +1 -1
  102. package/dist/irdevice/waterheater.js +41 -74
  103. package/dist/irdevice/waterheater.js.map +1 -1
  104. package/dist/platform.d.ts +14 -5
  105. package/dist/platform.d.ts.map +1 -1
  106. package/dist/platform.js +156 -149
  107. package/dist/platform.js.map +1 -1
  108. package/dist/settings.d.ts +4 -0
  109. package/dist/settings.d.ts.map +1 -1
  110. package/dist/settings.js +5 -1
  111. package/dist/settings.js.map +1 -1
  112. package/nodemon.json +1 -1
  113. package/package.json +10 -10
  114. package/src/device/blindtilt.ts +122 -181
  115. package/src/device/bot.ts +96 -149
  116. package/src/device/ceilinglight.ts +172 -315
  117. package/src/device/colorbulb.ts +178 -324
  118. package/src/device/contact.ts +48 -78
  119. package/src/device/curtain.ts +93 -148
  120. package/src/device/hub.ts +34 -63
  121. package/src/device/humidifier.ts +135 -243
  122. package/src/device/iosensor.ts +49 -79
  123. package/src/device/{striplight.ts → lightstrip.ts} +148 -200
  124. package/src/device/lock.ts +78 -134
  125. package/src/device/meter.ts +48 -78
  126. package/src/device/meterplus.ts +50 -80
  127. package/src/device/motion.ts +46 -77
  128. package/src/device/plug.ts +76 -134
  129. package/src/device/robotvacuumcleaner.ts +91 -159
  130. package/src/irdevice/airconditioner.ts +56 -81
  131. package/src/irdevice/airpurifier.ts +41 -67
  132. package/src/irdevice/camera.ts +35 -60
  133. package/src/irdevice/fan.ts +46 -71
  134. package/src/irdevice/light.ts +38 -63
  135. package/src/irdevice/other.ts +35 -60
  136. package/src/irdevice/tv.ts +52 -80
  137. package/src/irdevice/vacuumcleaner.ts +36 -62
  138. package/src/irdevice/waterheater.ts +46 -76
  139. package/src/platform.ts +144 -158
  140. package/src/settings.ts +5 -0
  141. package/.github/npm-version-script.js +0 -81
  142. package/dist/device/striplight.d.ts.map +0 -1
  143. package/dist/device/striplight.js.map +0 -1
@@ -1,9 +1,6 @@
1
- import https from 'https';
2
- import crypto from 'crypto';
3
- import { IncomingMessage } from 'http';
4
- import superStringify from 'super-stringify';
1
+ import { request } from 'undici';
5
2
  import { SwitchBotPlatform } from '../platform';
6
- import { irDevicesConfig, irdevice, HostDomain, DevicePath, body } from '../settings';
3
+ import { irDevicesConfig, irdevice, Devices } from '../settings';
7
4
  import { CharacteristicValue, PlatformAccessory, Service } from 'homebridge';
8
5
 
9
6
  /**
@@ -98,15 +95,15 @@ export class AirConditioner {
98
95
  this.TargetHeaterCoolerState = 1 || 2;
99
96
  this.ValidValues = [1, 2];
100
97
  this.debugLog(
101
- `${this.device.remoteType}: ${this.accessory.displayName} ValidValues: ${superStringify(this.ValidValues)},` +
102
- ` hide_automode: ${this.hide_automode}, TargetHeaterCoolerState: ${this.TargetHeaterCoolerState}`,
98
+ `${this.device.remoteType}: ${this.accessory.displayName} ValidValues: ${JSON.stringify(this.ValidValues)},` +
99
+ ` hide_automode: ${this.hide_automode}, TargetHeaterCoolerState: ${this.TargetHeaterCoolerState}`,
103
100
  );
104
101
  } else {
105
102
  this.TargetHeaterCoolerState = 0 || 1 || 2;
106
103
  this.ValidValues = [0, 1, 2];
107
104
  this.debugLog(
108
- `${this.device.remoteType}: ${this.accessory.displayName} ValidValues: ${superStringify(this.ValidValues)},` +
109
- ` hide_automode: ${this.hide_automode}, TargetHeaterCoolerState: ${this.TargetHeaterCoolerState}`,
105
+ `${this.device.remoteType}: ${this.accessory.displayName} ValidValues: ${JSON.stringify(this.ValidValues)},` +
106
+ ` hide_automode: ${this.hide_automode}, TargetHeaterCoolerState: ${this.TargetHeaterCoolerState}`,
110
107
  );
111
108
  }
112
109
  this.coolerService
@@ -171,11 +168,11 @@ export class AirConditioner {
171
168
  */
172
169
  async pushAirConditionerOnChanges(): Promise<void> {
173
170
  this.debugLog(`${this.device.remoteType}: ${this.accessory.displayName} pushAirConditionerOnChanges Active: ${this.Active},`
174
- + ` disablePushOn: ${this.disablePushOn}`);
171
+ + ` disablePushOn: ${this.disablePushOn}`);
175
172
  if (this.Active === this.platform.Characteristic.Active.ACTIVE && !this.disablePushOn) {
176
173
  const commandType: string = await this.commandType();
177
174
  const command: string = await this.commandOn();
178
- const body = superStringify({
175
+ const body = JSON.stringify({
179
176
  'command': command,
180
177
  'parameter': 'default',
181
178
  'commandType': commandType,
@@ -186,11 +183,11 @@ export class AirConditioner {
186
183
 
187
184
  async pushAirConditionerOffChanges(): Promise<void> {
188
185
  this.debugLog(`${this.device.remoteType}: ${this.accessory.displayName} pushAirConditionerOffChanges Active: ${this.Active},`
189
- + ` disablePushOff: ${this.disablePushOff}`);
186
+ + ` disablePushOff: ${this.disablePushOff}`);
190
187
  if (this.Active === this.platform.Characteristic.Active.INACTIVE && !this.disablePushOff) {
191
188
  const commandType: string = await this.commandType();
192
189
  const command: string = await this.commandOff();
193
- const body = superStringify({
190
+ const body = JSON.stringify({
194
191
  'command': command,
195
192
  'parameter': 'default',
196
193
  'commandType': commandType,
@@ -201,7 +198,7 @@ export class AirConditioner {
201
198
 
202
199
  async pushAirConditionerStatusChanges(): Promise<void> {
203
200
  this.debugLog(`${this.device.remoteType}: ${this.accessory.displayName} pushAirConditionerStatusChanges Active: ${this.Active},`
204
- + ` disablePushOff: ${this.disablePushOff}, disablePushOn: ${this.disablePushOn}`);
201
+ + ` disablePushOff: ${this.disablePushOff}, disablePushOn: ${this.disablePushOn}`);
205
202
  if (!this.Busy) {
206
203
  this.Busy = true;
207
204
  this.CurrentHeaterCoolerState = this.platform.Characteristic.CurrentHeaterCoolerState.IDLE;
@@ -214,7 +211,7 @@ export class AirConditioner {
214
211
 
215
212
  async pushAirConditionerDetailsChanges(): Promise<void> {
216
213
  this.debugLog(`${this.device.remoteType}: ${this.accessory.displayName} pushAirConditionerDetailsChanges Active: ${this.Active},`
217
- + ` disablePushOff: ${this.disablePushOff}, disablePushOn: ${this.disablePushOn}`);
214
+ + ` disablePushOff: ${this.disablePushOff}, disablePushOn: ${this.disablePushOn}`);
218
215
  //await this.context();
219
216
  if (this.CurrentMode === undefined) {
220
217
  this.CurrentMode = 1;
@@ -246,7 +243,7 @@ export class AirConditioner {
246
243
  } else {
247
244
  this.CurrentHeaterCoolerState = this.platform.Characteristic.CurrentHeaterCoolerState.INACTIVE;
248
245
  }
249
- const body = superStringify({
246
+ const body = JSON.stringify({
250
247
  'command': 'setAll',
251
248
  'parameter': `${parameter}`,
252
249
  'commandType': 'command',
@@ -255,59 +252,31 @@ export class AirConditioner {
255
252
  await this.pushChanges(body);
256
253
  }
257
254
 
258
- async pushChanges(body: Array<body>): Promise<void> {
255
+ async pushChanges(body: any): Promise<void> {
256
+ this.debugLog(`${this.device.remoteType}: ${this.accessory.displayName} pushChanges`);
259
257
  if (this.device.connectionType === 'OpenAPI' && !this.disablePushDetail) {
258
+ this.debugLog(`${this.device.remoteType}: ${this.accessory.displayName} Sending request to SwitchBot API, body: ${body},`);
260
259
  try {
261
- this.debugWarnLog(`${this.device.remoteType}: ${this.accessory.displayName} body: ${body}`);
262
- // Make Push On request to the API
263
- const t = Date.now();
264
- const nonce = 'requestID';
265
- const data = this.platform.config.credentials?.token + t + nonce;
266
- const signTerm = crypto.createHmac('sha256', this.platform.config.credentials?.secret)
267
- .update(Buffer.from(data, 'utf-8'))
268
- .digest();
269
- const sign = signTerm.toString('base64');
270
- this.debugLog(`${this.device.remoteType}: ${this.accessory.displayName} sign: ${sign}`);
271
- this.infoLog(`${this.device.remoteType}: ${this.accessory.displayName} Sending request to SwitchBot API. body: ${body},`);
272
- const options = {
273
- hostname: HostDomain,
274
- port: 443,
275
- path: `${DevicePath}/${this.device.deviceId}/commands`,
260
+ const { body, statusCode, headers } = await request(`${Devices}/${this.device.deviceId}/commands`, {
276
261
  method: 'POST',
277
- headers: {
278
- 'Authorization': this.platform.config.credentials?.token,
279
- 'sign': sign,
280
- 'nonce': nonce,
281
- 't': t,
282
- 'Content-Type': 'application/json',
283
- 'Content-Length': body.length,
284
- },
285
- };
286
- const req = https.request(options, res => {
287
- this.debugLog(`${this.device.remoteType}: ${this.accessory.displayName} pushchanges statusCode: ${res.statusCode}`);
288
- this.statusCode({ res });
289
- res.on('data', d => {
290
- this.debugLog(`${this.device.remoteType}: ${this.accessory.displayName} d: ${d}`);
291
- });
262
+ headers: this.platform.generateHeaders(),
292
263
  });
293
- req.on('error', (e: any) => {
294
- this.errorLog(`${this.device.remoteType}: ${this.accessory.displayName} error message: ${e.message}`);
295
- });
296
- req.write(body);
297
- req.end();
298
- this.debugLog(`${this.device.remoteType}: ${this.accessory.displayName} pushchanges: ${superStringify(req)}`);
264
+ const deviceStatus = await body.json();
265
+ this.debugLog(`${this.device.remoteType}: ${this.accessory.displayName} Devices: ${JSON.stringify(deviceStatus.body)}`);
266
+ this.statusCode(statusCode);
267
+ this.debugLog(`${this.device.remoteType}: ${this.accessory.displayName} Headers: ${JSON.stringify(headers)}`);
299
268
  this.updateHomeKitCharacteristics();
300
269
  } catch (e: any) {
301
- this.apiError({ e });
302
- this.errorLog(`${this.device.remoteType}: ${this.accessory.displayName} failed pushChanges with ${this.device.connectionType} Connection,`
303
- + ` Error Message: ${superStringify(e.message)}`,
270
+ this.apiError(e);
271
+ this.errorLog(`${this.device.remoteType}: ${this.accessory.displayName} failed pushChanges with ${this.device.connectionType}`
272
+ + ` Connection, Error Message: ${JSON.stringify(e.message)}`,
304
273
  );
305
274
  }
306
275
  } else {
307
276
  this.warnLog(`${this.device.remoteType}: ${this.accessory.displayName}`
308
- + ` Connection Type: ${this.device.connectionType}, commands will not be sent to OpenAPI`);
277
+ + ` Connection Type: ${this.device.connectionType}, commands will not be sent to OpenAPI`);
309
278
  this.debugLog(`${this.device.remoteType}: ${this.accessory.displayName}`
310
- + ` Connection Type: ${this.device.connectionType}, disablePushDetials: ${this.disablePushDetail}`);
279
+ + ` Connection Type: ${this.device.connectionType}, disablePushDetials: ${this.disablePushDetail}`);
311
280
  this.updateHomeKitCharacteristics();
312
281
  }
313
282
  }
@@ -366,19 +335,19 @@ export class AirConditioner {
366
335
  this.TargetHeaterCoolerState = this.platform.Characteristic.TargetHeaterCoolerState.AUTO;
367
336
  this.debugLog(
368
337
  `${this.device.remoteType}: ${this.accessory.displayName} Get (AUTO) TargetHeaterCoolerState: ${this.CurrentHeaterCoolerState},` +
369
- ` ValidValues: ${this.ValidValues}`,
338
+ ` ValidValues: ${this.ValidValues}`,
370
339
  );
371
340
  } else if (this.ValidValues === this.valid12) {
372
341
  this.TargetHeaterCoolerState =
373
342
  this.platform.Characteristic.TargetHeaterCoolerState.COOL || this.platform.Characteristic.TargetHeaterCoolerState.HEAT;
374
343
  this.debugLog(
375
344
  `${this.device.remoteType}: ${this.accessory.displayName} Get (COOL/HEAT) TargetHeaterCoolerState: ${this.CurrentHeaterCoolerState},` +
376
- ` ValidValues: ${this.ValidValues}`,
345
+ ` ValidValues: ${this.ValidValues}`,
377
346
  );
378
347
  } else {
379
348
  this.debugLog(
380
349
  `${this.device.remoteType}: ${this.accessory.displayName} Get TargetHeaterCoolerState: ${this.CurrentHeaterCoolerState},` +
381
- ` ValidValues: ${this.ValidValues}`,
350
+ ` ValidValues: ${this.ValidValues}`,
382
351
  );
383
352
  }
384
353
  return this.TargetHeaterCoolerState;
@@ -393,7 +362,7 @@ export class AirConditioner {
393
362
  } else {
394
363
  this.errorLog(
395
364
  `${this.device.remoteType}: ${this.accessory.displayName} Set TargetHeaterCoolerState: ${this.TargetHeaterCoolerState},` +
396
- ` hide_automode: ${this.hide_automode} `,
365
+ ` hide_automode: ${this.hide_automode} `,
397
366
  );
398
367
  }
399
368
  } else {
@@ -406,7 +375,7 @@ export class AirConditioner {
406
375
  } else {
407
376
  this.errorLog(
408
377
  `${this.device.remoteType}: ${this.accessory.displayName} Set TargetHeaterCoolerState: ${this.TargetHeaterCoolerState},` +
409
- ` hide_automode: ${this.hide_automode} `,
378
+ ` hide_automode: ${this.hide_automode} `,
410
379
  );
411
380
  }
412
381
  }
@@ -439,16 +408,16 @@ export class AirConditioner {
439
408
  if (this.CurrentTemperature < this.accessory.context.CurrentTemperature) {
440
409
  this.CurrentHeaterCoolerState = this.platform.Characteristic.CurrentHeaterCoolerState.COOLING;
441
410
  this.debugLog(`${this.device.remoteType}: ${this.accessory.displayName}`
442
- +` Get (COOLLING) CurrentHeaterCoolerState: ${this.CurrentHeaterCoolerState}`);
411
+ + ` Get (COOLLING) CurrentHeaterCoolerState: ${this.CurrentHeaterCoolerState}`);
443
412
  } else if (this.CurrentTemperature > this.accessory.context.CurrentTemperature) {
444
413
  this.CurrentHeaterCoolerState = this.platform.Characteristic.CurrentHeaterCoolerState.HEATING;
445
414
  this.debugLog(`${this.device.remoteType}: ${this.accessory.displayName}`
446
- +` Get (HEATING) CurrentHeaterCoolerState: ${this.CurrentHeaterCoolerState}`);
415
+ + ` Get (HEATING) CurrentHeaterCoolerState: ${this.CurrentHeaterCoolerState}`);
447
416
  }
448
417
  } else {
449
418
  this.CurrentHeaterCoolerState = this.platform.Characteristic.CurrentHeaterCoolerState.INACTIVE;
450
419
  this.debugLog(`${this.device.remoteType}: ${this.accessory.displayName}`
451
- +` Get (INACTIVE) CurrentHeaterCoolerState: ${this.CurrentHeaterCoolerState}`);
420
+ + ` Get (INACTIVE) CurrentHeaterCoolerState: ${this.CurrentHeaterCoolerState}`);
452
421
  }
453
422
  return this.CurrentHeaterCoolerState;
454
423
  }
@@ -462,7 +431,7 @@ export class AirConditioner {
462
431
  async HeatingThresholdTemperatureSet(value: CharacteristicValue): Promise<void> {
463
432
  this.CurrentTemperature = value;
464
433
  this.debugLog(`${this.device.remoteType}: ${this.accessory.displayName} Set HeatingThresholdTemperature: ${this.HeatingThresholdTemperature},` +
465
- ` CurrentTemperatureCached: ${this.accessory.context.CurrentTemperature}`);
434
+ ` CurrentTemperatureCached: ${this.accessory.context.CurrentTemperature}`);
466
435
  this.pushAirConditionerStatusChanges();
467
436
  }
468
437
 
@@ -475,7 +444,7 @@ export class AirConditioner {
475
444
  async CoolingThresholdTemperatureSet(value: CharacteristicValue): Promise<void> {
476
445
  this.CurrentTemperature = value;
477
446
  this.debugLog(`${this.device.remoteType}: ${this.accessory.displayName} Set CoolingThresholdTemperature: ${this.CoolingThresholdTemperature},` +
478
- ` CurrentTemperatureCached: ${this.accessory.context.CurrentTemperature}`);
447
+ ` CurrentTemperatureCached: ${this.accessory.context.CurrentTemperature}`);
479
448
  this.pushAirConditionerStatusChanges();
480
449
  }
481
450
 
@@ -596,34 +565,39 @@ export class AirConditioner {
596
565
  return command;
597
566
  }
598
567
 
599
- async statusCode({ res }: { res: IncomingMessage }): Promise<void> {
600
- switch (res.statusCode) {
568
+ async statusCode(statusCode: number): Promise<void> {
569
+ switch (statusCode) {
601
570
  case 151:
602
- this.errorLog(`${this.device.remoteType}: ${this.accessory.displayName} Command not supported by this device type.`);
571
+ this.errorLog(`${this.device.remoteType}: ${this.accessory.displayName} Command not supported by this deviceType, statusCode: ${statusCode}`);
603
572
  break;
604
573
  case 152:
605
- this.errorLog(`${this.device.remoteType}: ${this.accessory.displayName} Device not found.`);
574
+ this.errorLog(`${this.device.remoteType}: ${this.accessory.displayName} Device not found, statusCode: ${statusCode}`);
606
575
  break;
607
576
  case 160:
608
- this.errorLog(`${this.device.remoteType}: ${this.accessory.displayName} Command is not supported.`);
577
+ this.errorLog(`${this.device.remoteType}: ${this.accessory.displayName} Command is not supported, statusCode: ${statusCode}`);
609
578
  break;
610
579
  case 161:
611
- this.errorLog(`${this.device.remoteType}: ${this.accessory.displayName} Device is offline.`);
580
+ this.errorLog(`${this.device.remoteType}: ${this.accessory.displayName} Device is offline, statusCode: ${statusCode}`);
612
581
  break;
613
582
  case 171:
614
- this.errorLog(`${this.device.remoteType}: ${this.accessory.displayName} Hub Device is offline. Hub: ${this.device.hubDeviceId}`);
583
+ this.errorLog(`${this.device.remoteType}: ${this.accessory.displayName} Hub Device is offline, statusCode: ${statusCode}. `
584
+ + `Hub: ${this.device.hubDeviceId}`);
615
585
  break;
616
586
  case 190:
617
587
  this.errorLog(
618
- `${this.device.remoteType}: ${this.accessory.displayName} Device internal error due to device states not synchronized` +
619
- ` with server, Or command: ${superStringify(res)} format is invalid`,
588
+ `${this.device.remoteType}: ${this.accessory.displayName} Device internal error due to device states not synchronized with server,` +
589
+ ` Or command format is invalid, statusCode: ${statusCode}`,
620
590
  );
621
591
  break;
622
592
  case 100:
623
- this.debugLog(`${this.device.remoteType}: ${this.accessory.displayName} Command successfully sent.`);
593
+ this.debugLog(`${this.device.remoteType}: ${this.accessory.displayName} Command successfully sent, statusCode: ${statusCode}`);
594
+ break;
595
+ case 200:
596
+ this.debugLog(`${this.device.remoteType}: ${this.accessory.displayName} Request successful, statusCode: ${statusCode}`);
624
597
  break;
625
598
  default:
626
- this.debugLog(`${this.device.remoteType}: ${this.accessory.displayName} Unknown statusCode.`);
599
+ this.infoLog(`${this.device.remoteType}: ${this.accessory.displayName} Unknown statusCode: `
600
+ + `${statusCode}, Submit Bugs Here: ' + 'https://tinyurl.com/SwitchBotBug`);
627
601
  }
628
602
  }
629
603
 
@@ -640,7 +614,7 @@ export class AirConditioner {
640
614
  FirmwareRevision({ accessory, device }: { accessory: PlatformAccessory; device: irdevice & irDevicesConfig; }): string {
641
615
  let FirmwareRevision: string;
642
616
  this.debugLog(`${this.device.remoteType}: ${this.accessory.displayName}`
643
- + ` accessory.context.FirmwareRevision: ${accessory.context.FirmwareRevision}`);
617
+ + ` accessory.context.FirmwareRevision: ${accessory.context.FirmwareRevision}`);
644
618
  this.debugLog(`${this.device.remoteType}: ${this.accessory.displayName} device.firmware: ${device.firmware}`);
645
619
  this.debugLog(`${this.device.remoteType}: ${this.accessory.displayName} this.platform.version: ${this.platform.version}`);
646
620
  if (accessory.context.FirmwareRevision) {
@@ -721,7 +695,7 @@ export class AirConditioner {
721
695
  config['disablePushDetail'] = device.disablePushDetail;
722
696
  }
723
697
  if (Object.entries(config).length !== 0) {
724
- this.infoLog(`${this.device.remoteType}: ${this.accessory.displayName} Config: ${superStringify(config)}`);
698
+ this.infoLog(`${this.device.remoteType}: ${this.accessory.displayName} Config: ${JSON.stringify(config)}`);
725
699
  }
726
700
  }
727
701
 
@@ -792,3 +766,4 @@ export class AirConditioner {
792
766
  return this.deviceLogging.includes('debug') || this.deviceLogging === 'standard';
793
767
  }
794
768
  }
769
+
@@ -1,9 +1,6 @@
1
- import https from 'https';
2
- import crypto from 'crypto';
3
- import { IncomingMessage } from 'http';
4
- import superStringify from 'super-stringify';
1
+ import { request } from 'undici';
5
2
  import { SwitchBotPlatform } from '../platform';
6
- import { irDevicesConfig, irdevice, HostDomain, DevicePath, body } from '../settings';
3
+ import { irDevicesConfig, irdevice, Devices } from '../settings';
7
4
  import { CharacteristicValue, PlatformAccessory, Service } from 'homebridge';
8
5
 
9
6
  /**
@@ -133,11 +130,11 @@ export class AirPurifier {
133
130
  */
134
131
  async pushAirPurifierOnChanges(): Promise<void> {
135
132
  this.debugLog(`${this.device.remoteType}: ${this.accessory.displayName} pushAirPurifierOnChanges Active: ${this.Active},`
136
- + ` disablePushOn: ${this.disablePushOn}`);
133
+ + ` disablePushOn: ${this.disablePushOn}`);
137
134
  if (this.Active === this.platform.Characteristic.Active.ACTIVE && !this.disablePushOn) {
138
135
  const commandType: string = await this.commandType();
139
136
  const command: string = await this.commandOn();
140
- const body = superStringify({
137
+ const body = JSON.stringify({
141
138
  'command': command,
142
139
  'parameter': 'default',
143
140
  'commandType': commandType,
@@ -148,11 +145,11 @@ export class AirPurifier {
148
145
 
149
146
  async pushAirPurifierOffChanges(): Promise<void> {
150
147
  this.debugLog(`${this.device.remoteType}: ${this.accessory.displayName} pushAirPurifierOffChanges Active: ${this.Active},`
151
- + ` disablePushOff: ${this.disablePushOff}`);
148
+ + ` disablePushOff: ${this.disablePushOff}`);
152
149
  if (this.Active === this.platform.Characteristic.Active.INACTIVE && !this.disablePushOn) {
153
150
  const commandType: string = await this.commandType();
154
151
  const command: string = await this.commandOff();
155
- const body = superStringify({
152
+ const body = JSON.stringify({
156
153
  'command': command,
157
154
  'parameter': 'default',
158
155
  'commandType': commandType,
@@ -163,7 +160,7 @@ export class AirPurifier {
163
160
 
164
161
  async pushAirPurifierStatusChanges(): Promise<void> {
165
162
  this.debugLog(`${this.device.remoteType}: ${this.accessory.displayName} pushAirPurifierStatusChanges Active: ${this.Active},`
166
- + ` disablePushOff: ${this.disablePushOff}, disablePushOn: ${this.disablePushOn}`);
163
+ + ` disablePushOff: ${this.disablePushOff}, disablePushOn: ${this.disablePushOn}`);
167
164
  if (!this.Busy) {
168
165
  this.Busy = true;
169
166
  this.CurrentHeaterCoolerState = this.platform.Characteristic.CurrentHeaterCoolerState.IDLE;
@@ -176,19 +173,19 @@ export class AirPurifier {
176
173
 
177
174
  async pushAirPurifierDetailsChanges(): Promise<void> {
178
175
  this.debugLog(`${this.device.remoteType}: ${this.accessory.displayName} pushAirPurifierDetailsChanges Active: ${this.Active},`
179
- + ` disablePushOff: ${this.disablePushOff}, disablePushOn: ${this.disablePushOn}`);
176
+ + ` disablePushOff: ${this.disablePushOff}, disablePushOn: ${this.disablePushOn}`);
180
177
  this.CurrentAPTemp = this.CurrentTemperature || 24;
181
178
  this.CurrentAPMode = this.CurrentMode || 1;
182
179
  this.CurrentAPFanSpeed = this.CurrentFanSpeed || 1;
183
180
  this.APActive = this.Active === 1 ? 'on' : 'off';
184
181
  const parameter = `${this.CurrentAPTemp},${this.CurrentAPMode},${this.CurrentAPFanSpeed},${this.APActive}`;
185
- const body = superStringify({
182
+ const body = JSON.stringify({
186
183
  'command': 'setAll',
187
184
  'parameter': `${parameter}`,
188
185
  'commandType': 'command',
189
186
  });
190
187
  if (this.Active === 1) {
191
- if ((Number(this.CurrentTemperature)|| 24) < (this.LastTemperature || 30)) {
188
+ if ((Number(this.CurrentTemperature) || 24) < (this.LastTemperature || 30)) {
192
189
  this.CurrentHeaterCoolerState = this.platform.Characteristic.CurrentHeaterCoolerState.COOLING;
193
190
  } else {
194
191
  this.CurrentHeaterCoolerState = this.platform.Characteristic.CurrentHeaterCoolerState.HEATING;
@@ -199,57 +196,29 @@ export class AirPurifier {
199
196
  await this.pushChanges(body);
200
197
  }
201
198
 
202
- async pushChanges(body: Array<body>): Promise<void> {
199
+ async pushChanges(body: any): Promise<void> {
200
+ this.debugLog(`${this.device.remoteType}: ${this.accessory.displayName} pushChanges`);
203
201
  if (this.device.connectionType === 'OpenAPI') {
202
+ this.debugLog(`${this.device.remoteType}: ${this.accessory.displayName} Sending request to SwitchBot API, body: ${body},`);
204
203
  try {
205
- // Make Push On request to the API
206
- const t = Date.now();
207
- const nonce = 'requestID';
208
- const data = this.platform.config.credentials?.token + t + nonce;
209
- const signTerm = crypto.createHmac('sha256', this.platform.config.credentials?.secret)
210
- .update(Buffer.from(data, 'utf-8'))
211
- .digest();
212
- const sign = signTerm.toString('base64');
213
- this.debugLog(`${this.device.remoteType}: ${this.accessory.displayName} sign: ${sign}`);
214
- this.infoLog(`${this.device.remoteType}: ${this.accessory.displayName} Sending request to SwitchBot API. body: ${body},`);
215
- const options = {
216
- hostname: HostDomain,
217
- port: 443,
218
- path: `${DevicePath}/${this.device.deviceId}/commands`,
204
+ const { body, statusCode, headers } = await request(`${Devices}/${this.device.deviceId}/commands`, {
219
205
  method: 'POST',
220
- headers: {
221
- 'Authorization': this.platform.config.credentials?.token,
222
- 'sign': sign,
223
- 'nonce': nonce,
224
- 't': t,
225
- 'Content-Type': 'application/json',
226
- 'Content-Length': body.length,
227
- },
228
- };
229
- const req = https.request(options, res => {
230
- this.debugLog(`${this.device.remoteType}: ${this.accessory.displayName} statusCode: ${res.statusCode}`);
231
- this.statusCode({ res });
232
- res.on('data', d => {
233
- this.debugLog(`${this.device.remoteType}: ${this.accessory.displayName} d: ${d}`);
234
- });
206
+ headers: this.platform.generateHeaders(),
235
207
  });
236
- req.on('error', (e: any) => {
237
- this.errorLog(`${this.device.remoteType}: ${this.accessory.displayName} error message: ${e.message}`);
238
- });
239
- req.write(body);
240
- req.end();
241
- this.debugLog(`${this.device.remoteType}: ${this.accessory.displayName} pushchanges: ${superStringify(req)}`);
208
+ const deviceStatus = await body.json();
209
+ this.debugLog(`${this.device.remoteType}: ${this.accessory.displayName} Devices: ${JSON.stringify(deviceStatus.body)}`);
210
+ this.statusCode(statusCode);
211
+ this.debugLog(`${this.device.remoteType}: ${this.accessory.displayName} Headers: ${JSON.stringify(headers)}`);
242
212
  this.updateHomeKitCharacteristics();
243
- this.accessory.context.CurrentTemperature = this.CurrentTemperature;
244
213
  } catch (e: any) {
245
214
  this.apiError(e);
246
- this.errorLog(`${this.device.remoteType}: ${this.accessory.displayName} failed pushChanges with ${this.device.connectionType} Connection,`
247
- + ` Error Message: ${superStringify(e.message)}`,
215
+ this.errorLog(`${this.device.remoteType}: ${this.accessory.displayName} failed pushChanges with ${this.device.connectionType}`
216
+ + ` Connection, Error Message: ${JSON.stringify(e.message)}`,
248
217
  );
249
218
  }
250
219
  } else {
251
220
  this.warnLog(`${this.device.remoteType}: ${this.accessory.displayName}`
252
- + ` Connection Type: ${this.device.connectionType}, commands will not be sent to OpenAPI`);
221
+ + ` Connection Type: ${this.device.connectionType}, commands will not be sent to OpenAPI`);
253
222
  }
254
223
  }
255
224
 
@@ -267,7 +236,7 @@ export class AirPurifier {
267
236
  this.accessory.context.CurrentAirPurifierState = this.CurrentAirPurifierState;
268
237
  this.airPurifierService?.updateCharacteristic(this.platform.Characteristic.CurrentAirPurifierState, this.CurrentAirPurifierState);
269
238
  this.debugLog(`${this.device.remoteType}: ${this.accessory.displayName}`
270
- + ` updateCharacteristic CurrentAirPurifierState: ${this.CurrentAirPurifierState}`);
239
+ + ` updateCharacteristic CurrentAirPurifierState: ${this.CurrentAirPurifierState}`);
271
240
  }
272
241
  if (this.CurrentHeaterCoolerState === undefined) {
273
242
  this.debugLog(`${this.device.remoteType}: ${this.accessory.displayName} CurrentHeaterCoolerState: ${this.CurrentHeaterCoolerState}`);
@@ -327,34 +296,39 @@ export class AirPurifier {
327
296
  return command;
328
297
  }
329
298
 
330
- async statusCode({ res }: { res: IncomingMessage }): Promise<void> {
331
- switch (res.statusCode) {
299
+ async statusCode(statusCode: number): Promise<void> {
300
+ switch (statusCode) {
332
301
  case 151:
333
- this.errorLog(`${this.device.remoteType}: ${this.accessory.displayName} Command not supported by this device type.`);
302
+ this.errorLog(`${this.device.remoteType}: ${this.accessory.displayName} Command not supported by this deviceType, statusCode: ${statusCode}`);
334
303
  break;
335
304
  case 152:
336
- this.errorLog(`${this.device.remoteType}: ${this.accessory.displayName} Device not found.`);
305
+ this.errorLog(`${this.device.remoteType}: ${this.accessory.displayName} Device not found, statusCode: ${statusCode}`);
337
306
  break;
338
307
  case 160:
339
- this.errorLog(`${this.device.remoteType}: ${this.accessory.displayName} Command is not supported.`);
308
+ this.errorLog(`${this.device.remoteType}: ${this.accessory.displayName} Command is not supported, statusCode: ${statusCode}`);
340
309
  break;
341
310
  case 161:
342
- this.errorLog(`${this.device.remoteType}: ${this.accessory.displayName} Device is offline.`);
311
+ this.errorLog(`${this.device.remoteType}: ${this.accessory.displayName} Device is offline, statusCode: ${statusCode}`);
343
312
  break;
344
313
  case 171:
345
- this.errorLog(`${this.device.remoteType}: ${this.accessory.displayName} Hub Device is offline. Hub: ${this.device.hubDeviceId}`);
314
+ this.errorLog(`${this.device.remoteType}: ${this.accessory.displayName} Hub Device is offline, statusCode: ${statusCode}. `
315
+ + `Hub: ${this.device.hubDeviceId}`);
346
316
  break;
347
317
  case 190:
348
318
  this.errorLog(
349
- `${this.device.remoteType}: ${this.accessory.displayName} Device internal error due to device states not synchronized` +
350
- ` with server, Or command: ${superStringify(res)} format is invalid`,
319
+ `${this.device.remoteType}: ${this.accessory.displayName} Device internal error due to device states not synchronized with server,` +
320
+ ` Or command format is invalid, statusCode: ${statusCode}`,
351
321
  );
352
322
  break;
353
323
  case 100:
354
- this.debugLog(`${this.device.remoteType}: ${this.accessory.displayName} Command successfully sent.`);
324
+ this.debugLog(`${this.device.remoteType}: ${this.accessory.displayName} Command successfully sent, statusCode: ${statusCode}`);
325
+ break;
326
+ case 200:
327
+ this.debugLog(`${this.device.remoteType}: ${this.accessory.displayName} Request successful, statusCode: ${statusCode}`);
355
328
  break;
356
329
  default:
357
- this.debugLog(`${this.device.remoteType}: ${this.accessory.displayName} Unknown statusCode.`);
330
+ this.infoLog(`${this.device.remoteType}: ${this.accessory.displayName} Unknown statusCode: `
331
+ + `${statusCode}, Submit Bugs Here: ' + 'https://tinyurl.com/SwitchBotBug`);
358
332
  }
359
333
  }
360
334
 
@@ -368,7 +342,7 @@ export class AirPurifier {
368
342
  FirmwareRevision(accessory: PlatformAccessory, device: irdevice & irDevicesConfig): string {
369
343
  let FirmwareRevision: string;
370
344
  this.debugLog(`${this.device.remoteType}: ${this.accessory.displayName}`
371
- + ` accessory.context.FirmwareRevision: ${accessory.context.FirmwareRevision}`);
345
+ + ` accessory.context.FirmwareRevision: ${accessory.context.FirmwareRevision}`);
372
346
  this.debugLog(`${this.device.remoteType}: ${this.accessory.displayName} device.firmware: ${device.firmware}`);
373
347
  this.debugLog(`${this.device.remoteType}: ${this.accessory.displayName} this.platform.version: ${this.platform.version}`);
374
348
  if (accessory.context.FirmwareRevision) {
@@ -424,7 +398,7 @@ export class AirPurifier {
424
398
  config['disablePushOff'] = device.disablePushOff;
425
399
  }
426
400
  if (Object.entries(config).length !== 0) {
427
- this.infoLog(`${this.device.remoteType}: ${this.accessory.displayName} Config: ${superStringify(config)}`);
401
+ this.infoLog(`${this.device.remoteType}: ${this.accessory.displayName} Config: ${JSON.stringify(config)}`);
428
402
  }
429
403
  }
430
404