@switchbot/homebridge-switchbot 1.15.1-beta.6 → 1.15.1-beta.8

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 (112) hide show
  1. package/.prettierrc +1 -1
  2. package/dist/device/bot.d.ts +8 -7
  3. package/dist/device/bot.d.ts.map +1 -1
  4. package/dist/device/bot.js +83 -11
  5. package/dist/device/bot.js.map +1 -1
  6. package/dist/device/colorbulb.d.ts +8 -7
  7. package/dist/device/colorbulb.d.ts.map +1 -1
  8. package/dist/device/colorbulb.js +182 -23
  9. package/dist/device/colorbulb.js.map +1 -1
  10. package/dist/device/contact.d.ts +3 -3
  11. package/dist/device/contact.d.ts.map +1 -1
  12. package/dist/device/contact.js +50 -7
  13. package/dist/device/contact.js.map +1 -1
  14. package/dist/device/curtain.d.ts +9 -8
  15. package/dist/device/curtain.d.ts.map +1 -1
  16. package/dist/device/curtain.js +86 -14
  17. package/dist/device/curtain.js.map +1 -1
  18. package/dist/device/humidifier.d.ts +8 -7
  19. package/dist/device/humidifier.d.ts.map +1 -1
  20. package/dist/device/humidifier.js +152 -27
  21. package/dist/device/humidifier.js.map +1 -1
  22. package/dist/device/lock.d.ts +8 -7
  23. package/dist/device/lock.d.ts.map +1 -1
  24. package/dist/device/lock.js +84 -12
  25. package/dist/device/lock.js.map +1 -1
  26. package/dist/device/meter.d.ts +4 -4
  27. package/dist/device/meter.d.ts.map +1 -1
  28. package/dist/device/meter.js +51 -8
  29. package/dist/device/meter.js.map +1 -1
  30. package/dist/device/meterplus.d.ts +3 -3
  31. package/dist/device/meterplus.d.ts.map +1 -1
  32. package/dist/device/meterplus.js +49 -6
  33. package/dist/device/meterplus.js.map +1 -1
  34. package/dist/device/motion.d.ts +3 -3
  35. package/dist/device/motion.d.ts.map +1 -1
  36. package/dist/device/motion.js +49 -9
  37. package/dist/device/motion.js.map +1 -1
  38. package/dist/device/plug.d.ts +8 -7
  39. package/dist/device/plug.d.ts.map +1 -1
  40. package/dist/device/plug.js +83 -11
  41. package/dist/device/plug.js.map +1 -1
  42. package/dist/device/striplight.d.ts +8 -7
  43. package/dist/device/striplight.d.ts.map +1 -1
  44. package/dist/device/striplight.js +149 -19
  45. package/dist/device/striplight.js.map +1 -1
  46. package/dist/irdevice/airconditioner.d.ts +5 -4
  47. package/dist/irdevice/airconditioner.d.ts.map +1 -1
  48. package/dist/irdevice/airconditioner.js +40 -6
  49. package/dist/irdevice/airconditioner.js.map +1 -1
  50. package/dist/irdevice/airpurifier.d.ts +5 -4
  51. package/dist/irdevice/airpurifier.d.ts.map +1 -1
  52. package/dist/irdevice/airpurifier.js +40 -6
  53. package/dist/irdevice/airpurifier.js.map +1 -1
  54. package/dist/irdevice/camera.d.ts +5 -4
  55. package/dist/irdevice/camera.d.ts.map +1 -1
  56. package/dist/irdevice/camera.js +40 -6
  57. package/dist/irdevice/camera.js.map +1 -1
  58. package/dist/irdevice/fan.d.ts +7 -6
  59. package/dist/irdevice/fan.d.ts.map +1 -1
  60. package/dist/irdevice/fan.js +40 -6
  61. package/dist/irdevice/fan.js.map +1 -1
  62. package/dist/irdevice/light.d.ts +5 -4
  63. package/dist/irdevice/light.d.ts.map +1 -1
  64. package/dist/irdevice/light.js +40 -6
  65. package/dist/irdevice/light.js.map +1 -1
  66. package/dist/irdevice/other.d.ts +5 -4
  67. package/dist/irdevice/other.d.ts.map +1 -1
  68. package/dist/irdevice/other.js +40 -6
  69. package/dist/irdevice/other.js.map +1 -1
  70. package/dist/irdevice/tv.d.ts +7 -6
  71. package/dist/irdevice/tv.d.ts.map +1 -1
  72. package/dist/irdevice/tv.js +40 -6
  73. package/dist/irdevice/tv.js.map +1 -1
  74. package/dist/irdevice/vacuumcleaner.d.ts +5 -4
  75. package/dist/irdevice/vacuumcleaner.d.ts.map +1 -1
  76. package/dist/irdevice/vacuumcleaner.js +40 -6
  77. package/dist/irdevice/vacuumcleaner.js.map +1 -1
  78. package/dist/irdevice/waterheater.d.ts +5 -4
  79. package/dist/irdevice/waterheater.d.ts.map +1 -1
  80. package/dist/irdevice/waterheater.js +40 -6
  81. package/dist/irdevice/waterheater.js.map +1 -1
  82. package/dist/platform.d.ts +3 -5
  83. package/dist/platform.d.ts.map +1 -1
  84. package/dist/platform.js +142 -92
  85. package/dist/platform.js.map +1 -1
  86. package/dist/settings.d.ts +2 -16
  87. package/dist/settings.d.ts.map +1 -1
  88. package/dist/settings.js +3 -3
  89. package/dist/settings.js.map +1 -1
  90. package/package.json +6 -7
  91. package/src/device/bot.ts +87 -15
  92. package/src/device/colorbulb.ts +186 -41
  93. package/src/device/contact.ts +49 -10
  94. package/src/device/curtain.ts +92 -19
  95. package/src/device/humidifier.ts +164 -30
  96. package/src/device/lock.ts +88 -16
  97. package/src/device/meter.ts +51 -12
  98. package/src/device/meterplus.ts +48 -9
  99. package/src/device/motion.ts +48 -12
  100. package/src/device/plug.ts +87 -15
  101. package/src/device/striplight.ts +161 -24
  102. package/src/irdevice/airconditioner.ts +43 -8
  103. package/src/irdevice/airpurifier.ts +43 -8
  104. package/src/irdevice/camera.ts +43 -8
  105. package/src/irdevice/fan.ts +44 -9
  106. package/src/irdevice/light.ts +43 -8
  107. package/src/irdevice/other.ts +43 -8
  108. package/src/irdevice/tv.ts +44 -9
  109. package/src/irdevice/vacuumcleaner.ts +43 -8
  110. package/src/irdevice/waterheater.ts +43 -8
  111. package/src/platform.ts +155 -105
  112. package/src/settings.ts +6 -10
package/src/platform.ts CHANGED
@@ -18,13 +18,13 @@ import { AirPurifier } from './irdevice/airpurifier';
18
18
  import { WaterHeater } from './irdevice/waterheater';
19
19
  import { VacuumCleaner } from './irdevice/vacuumcleaner';
20
20
  import { AirConditioner } from './irdevice/airconditioner';
21
+ import https from 'https';
22
+ import crypto from 'crypto';
21
23
  import { Buffer } from 'buffer';
22
- import CryptoJS from 'crypto-js';
23
24
  import fakegato from 'fakegato-history';
24
25
  import { readFileSync, writeFileSync } from 'fs';
25
- import axios, { AxiosInstance, AxiosRequestConfig } from 'axios';
26
26
  import { API, DynamicPlatformPlugin, Logger, PlatformAccessory, Service, Characteristic } from 'homebridge';
27
- import { PLATFORM_NAME, PLUGIN_NAME, DeviceURL, irdevice, device, SwitchBotPlatformConfig, deviceResponses, devicesConfig } from './settings';
27
+ import { PLATFORM_NAME, PLUGIN_NAME, irdevice, device, SwitchBotPlatformConfig, devicesConfig, DevicePath, HostDomain } from './settings';
28
28
 
29
29
  /**
30
30
  * HomebridgePlatform
@@ -38,12 +38,8 @@ export class SwitchBotPlatform implements DynamicPlatformPlugin {
38
38
  // this is used to track restored cached accessories
39
39
  public readonly accessories: PlatformAccessory[] = [];
40
40
 
41
- public axios: AxiosInstance = axios.create({
42
- responseType: 'json',
43
- });
44
-
45
41
  version = require('../package.json').version || '1.12.8'; // eslint-disable-line @typescript-eslint/no-var-requires
46
- deviceStatus!: deviceResponses;
42
+ deviceStatus!: any;
47
43
  registeringDevice!: boolean;
48
44
  debugMode!: boolean;
49
45
  platformLogging?: string;
@@ -52,11 +48,6 @@ export class SwitchBotPlatform implements DynamicPlatformPlugin {
52
48
 
53
49
  constructor(public readonly log: Logger, public readonly config: SwitchBotPlatformConfig, public readonly api: API) {
54
50
  this.logs();
55
- const t = (new Date().getTime())?.toString();
56
- const nonce = '';
57
- const data = this.config.credentials?.token + t + nonce;
58
- const Hmac_SHA256 = CryptoJS.HmacSHA256(this.config.credentials?.secret, data).toString();
59
- const sign = Buffer.from(Hmac_SHA256, 'binary').toString('base64');
60
51
 
61
52
  this.debugLog('Finished initializing platform:', this.config.name);
62
53
  // only load if configured
@@ -81,16 +72,6 @@ export class SwitchBotPlatform implements DynamicPlatformPlugin {
81
72
  return;
82
73
  }
83
74
 
84
- // setup axios interceptor to add headers / api key to each request
85
- this.axios.interceptors.request.use((request: AxiosRequestConfig) => {
86
- request.headers!.Authorization = this.config.credentials?.token;
87
- request.headers!.sign = sign;
88
- request.headers!.t = t;
89
- request.headers!.nonce = nonce;
90
- request.headers!['Content-Type'] = 'application/json; charset=utf8';
91
- return request;
92
- });
93
-
94
75
  // import fakegato-history module
95
76
  this.fakegatoAPI = fakegato(api);
96
77
 
@@ -295,90 +276,128 @@ export class SwitchBotPlatform implements DynamicPlatformPlugin {
295
276
  async discoverDevices() {
296
277
  try {
297
278
  if (this.config.credentials?.token) {
298
- const devicesAPI: any = (await this.axios.get(DeviceURL)).data;
299
- this.deviceListInfo(devicesAPI);
300
- this.debugLog(JSON.stringify(devicesAPI));
279
+ const t = Date.now();
280
+ const nonce = 'requestID';
281
+ const data = this.config.credentials?.token + t + nonce;
282
+ const signTerm = crypto.createHmac('sha256', this.config.credentials?.secret).update(Buffer.from(data, 'utf-8')).digest();
283
+ const sign = signTerm.toString('base64');
284
+ this.debugLog(sign);
285
+ const options = {
286
+ hostname: HostDomain,
287
+ port: 443,
288
+ path: DevicePath,
289
+ method: 'GET',
290
+ headers: {
291
+ 'Authorization': this.config.credentials?.token,
292
+ 'sign': sign,
293
+ 'nonce': nonce,
294
+ 't': t,
295
+ 'Content-Type': 'application/json',
296
+ },
297
+ };
298
+ const req = https.request(options, (res) => {
299
+ this.debugLog(`statusCode: ${res.statusCode}`);
300
+ this.debugLog(`headers: ${JSON.stringify(res.headers)}`);
301
+ let rawData = '';
302
+ res.on('data', (d) => {
303
+ rawData += d;
304
+ this.debugLog(`d: ${d}`);
305
+ });
306
+ res.on('end', () => {
307
+ try {
308
+ const devicesAPI = JSON.parse(rawData);
309
+ this.debugLog(`devicesAPI: ${JSON.stringify(devicesAPI.body)}`);
310
+
311
+ // SwitchBot Devices
312
+ if (devicesAPI.body.deviceList.length !== 0) {
313
+ this.infoLog(`Total SwitchBot Devices Found: ${devicesAPI.body.deviceList.length}`);
314
+ } else {
315
+ this.debugLog(`Total SwitchBot Devices Found: ${devicesAPI.body.deviceList.length}`);
316
+ }
317
+ const deviceLists = devicesAPI.body.deviceList;
318
+ if (!this.config.options?.devices) {
319
+ this.debugLog(`SwitchBot Device Config Not Set: ${JSON.stringify(this.config.options?.devices)}`);
320
+ const devices = deviceLists.map((v: any) => v);
321
+ for (const device of devices) {
322
+ if (device.deviceType) {
323
+ if (device.configDeviceName) {
324
+ device.deviceName = device.configDeviceName;
325
+ }
326
+ this.createDevice(device);
327
+ }
328
+ }
329
+ } else if (this.config.credentials?.token && this.config.options.devices) {
330
+ this.debugLog(`SwitchBot Device Config Set: ${JSON.stringify(this.config.options?.devices)}`);
331
+ const deviceConfigs = this.config.options?.devices;
332
+
333
+ const mergeBydeviceId = (a1: { deviceId: string }[], a2: any[]) =>
334
+ a1.map((itm: { deviceId: string }) => ({
335
+ ...a2.find(
336
+ (item: { deviceId: string }) =>
337
+ item.deviceId.toUpperCase().replace(/[^A-Z0-9]+/g, '') === itm.deviceId.toUpperCase().replace(/[^A-Z0-9]+/g, '') && item,
338
+ ),
339
+ ...itm,
340
+ }));
341
+
342
+ const devices = mergeBydeviceId(deviceLists, deviceConfigs);
343
+ this.debugLog(`SwitchBot Devices: ${JSON.stringify(devices)}`);
344
+ for (const device of devices) {
345
+ if (device.deviceType) {
346
+ if (device.configDeviceName) {
347
+ device.deviceName = device.configDeviceName;
348
+ }
349
+ this.createDevice(device);
350
+ }
351
+ }
352
+ } else {
353
+ this.errorLog('SwitchBot Token Supplied, Issue with Auth.');
354
+ }
301
355
 
302
- // SwitchBot Devices
303
- if (devicesAPI.body.deviceList.length !== 0) {
304
- this.infoLog(`Total SwitchBot Devices Found: ${devicesAPI.body.deviceList.length}`);
305
- } else {
306
- this.debugLog(`Total SwitchBot Devices Found: ${devicesAPI.body.deviceList.length}`);
307
- }
308
- const deviceLists = devicesAPI.body.deviceList;
309
- if (!this.config.options?.devices) {
310
- this.debugLog(`SwitchBot Device Config Not Set: ${JSON.stringify(this.config.options?.devices)}`);
311
- const devices = deviceLists.map((v: any) => v);
312
- for (const device of devices) {
313
- if (device.deviceType) {
314
- if (device.configDeviceName) {
315
- device.deviceName = device.configDeviceName;
356
+ // IR Devices
357
+ if (devicesAPI.body.infraredRemoteList.length !== 0) {
358
+ this.infoLog(`Total IR Devices Found: ${devicesAPI.body.infraredRemoteList.length}`);
359
+ } else {
360
+ this.debugLog(`Total IR Devices Found: ${devicesAPI.body.infraredRemoteList.length}`);
316
361
  }
317
- this.createDevice(device);
318
- }
319
- }
320
- } else if (this.config.credentials.token && this.config.options.devices) {
321
- this.debugLog(`SwitchBot Device Config Set: ${JSON.stringify(this.config.options?.devices)}`);
322
- const deviceConfigs = this.config.options?.devices;
323
-
324
- const mergeBydeviceId = (a1: { deviceId: string }[], a2: any[]) =>
325
- a1.map((itm: { deviceId: string }) => ({
326
- ...a2.find(
327
- (item: { deviceId: string }) =>
328
- item.deviceId.toUpperCase().replace(/[^A-Z0-9]+/g, '') === itm.deviceId.toUpperCase().replace(/[^A-Z0-9]+/g, '') && item,
329
- ),
330
- ...itm,
331
- }));
332
-
333
- const devices = mergeBydeviceId(deviceLists, deviceConfigs);
334
- this.debugLog(`SwitchBot Devices: ${JSON.stringify(devices)}`);
335
- for (const device of devices) {
336
- if (device.deviceType) {
337
- if (device.configDeviceName) {
338
- device.deviceName = device.configDeviceName;
362
+ const irDeviceLists = devicesAPI.body.infraredRemoteList;
363
+ if (!this.config.options?.irdevices) {
364
+ this.debugLog(`IR Device Config Not Set: ${JSON.stringify(this.config.options?.irdevices)}`);
365
+ const devices = irDeviceLists.map((v: any) => v);
366
+ for (const device of devices) {
367
+ if (device.remoteType) {
368
+ this.createIRDevice(device);
369
+ }
370
+ }
371
+ } else {
372
+ this.debugLog(`IR Device Config Set: ${JSON.stringify(this.config.options?.irdevices)}`);
373
+ const irDeviceConfig = this.config.options?.irdevices;
374
+
375
+ const mergeIRBydeviceId = (a1: { deviceId: string }[], a2: any[]) =>
376
+ a1.map((itm: { deviceId: string }) => ({
377
+ ...a2.find(
378
+ (item: { deviceId: string }) =>
379
+ item.deviceId.toUpperCase().replace(/[^A-Z0-9]+/g, '') === itm.deviceId.toUpperCase().replace(/[^A-Z0-9]+/g, '') && item,
380
+ ),
381
+ ...itm,
382
+ }));
383
+
384
+ const devices = mergeIRBydeviceId(irDeviceLists, irDeviceConfig);
385
+ this.debugLog(`IR Devices: ${JSON.stringify(devices)}`);
386
+ for (const device of devices) {
387
+ if (device.remoteType) {
388
+ this.createIRDevice(device);
389
+ }
390
+ }
339
391
  }
340
- this.createDevice(device);
392
+ } catch (e:any) {
393
+ this.errorLog(e.message);
341
394
  }
342
- }
343
- } else {
344
- this.errorLog('Neither SwitchBot Token or Device Config are not set.');
345
- }
346
- // IR Devices
347
- if (devicesAPI.body.infraredRemoteList.length !== 0) {
348
- this.infoLog(`Total IR Devices Found: ${devicesAPI.body.infraredRemoteList.length}`);
349
- } else {
350
- this.debugLog(`Total IR Devices Found: ${devicesAPI.body.infraredRemoteList.length}`);
351
- }
352
- const irDeviceLists = devicesAPI.body.infraredRemoteList;
353
- if (!this.config.options?.irdevices) {
354
- this.debugLog(`IR Device Config Not Set: ${JSON.stringify(this.config.options?.irdevices)}`);
355
- const devices = irDeviceLists.map((v: any) => v);
356
- for (const device of devices) {
357
- if (device.remoteType) {
358
- this.createIRDevice(device);
359
- }
360
- }
361
- } else {
362
- this.debugLog(`IR Device Config Set: ${JSON.stringify(this.config.options?.irdevices)}`);
363
- const irDeviceConfig = this.config.options?.irdevices;
364
-
365
- const mergeIRBydeviceId = (a1: { deviceId: string }[], a2: any[]) =>
366
- a1.map((itm: { deviceId: string }) => ({
367
- ...a2.find(
368
- (item: { deviceId: string }) =>
369
- item.deviceId.toUpperCase().replace(/[^A-Z0-9]+/g, '') === itm.deviceId.toUpperCase().replace(/[^A-Z0-9]+/g, '') && item,
370
- ),
371
- ...itm,
372
- }));
373
-
374
- const devices = mergeIRBydeviceId(irDeviceLists, irDeviceConfig);
375
- this.debugLog(`IR Devices: ${JSON.stringify(devices)}`);
376
- for (const device of devices) {
377
- if (device.remoteType) {
378
- this.createIRDevice(device);
379
- }
380
- }
381
- }
395
+ });
396
+ });
397
+ req.on('error', (error) => {
398
+ this.errorLog(error);
399
+ });
400
+ req.end();
382
401
  } else if (!this.config.credentials?.token && this.config.options?.devices) {
383
402
  this.debugLog(`SwitchBot Device Manual Config Set: ${JSON.stringify(this.config.options?.devices)}`);
384
403
  const deviceConfigs = this.config.options?.devices;
@@ -1751,7 +1770,7 @@ export class SwitchBotPlatform implements DynamicPlatformPlugin {
1751
1770
  this.warnLog(`Removing existing accessory from cache: ${existingAccessory.displayName}`);
1752
1771
  }
1753
1772
 
1754
- public deviceListInfo(devices: deviceResponses) {
1773
+ public deviceListInfo(devices) {
1755
1774
  if (this.platformLogging?.includes('debug')) {
1756
1775
  this.warnLog(`deviceListInfoStatus: ${JSON.stringify(devices)}`);
1757
1776
  }
@@ -1760,7 +1779,38 @@ export class SwitchBotPlatform implements DynamicPlatformPlugin {
1760
1779
  public async deviceInfo(device: (irdevice & devicesConfig) | (device & devicesConfig)) {
1761
1780
  if (this.platformLogging?.includes('debug')) {
1762
1781
  this.warnLog(JSON.stringify(device));
1763
- this.deviceStatus = (await this.axios.get(`${DeviceURL}/${device.deviceId}/status`)).data;
1782
+
1783
+ const t = Date.now();
1784
+ const nonce = 'requestID';
1785
+ const data = this.config.credentials?.token + t + nonce;
1786
+ const signTerm = crypto.createHmac('sha256', this.config.credentials?.secret).update(Buffer.from(data, 'utf-8')).digest();
1787
+ const sign = signTerm.toString('base64');
1788
+ this.debugLog(sign);
1789
+ const options = {
1790
+ hostname: HostDomain,
1791
+ port: 443,
1792
+ path: `${DevicePath}/${device.deviceId}/status`,
1793
+ method: 'GET',
1794
+ headers: {
1795
+ Authorization: this.config.credentials?.token,
1796
+ sign: sign,
1797
+ nonce: nonce,
1798
+ t: t,
1799
+ 'Content-Type': 'application/json',
1800
+ },
1801
+ };
1802
+ const req = https.request(options, (res) => {
1803
+ this.debugLog(`statusCode: ${res.statusCode}`);
1804
+ res.on('data', (d) => {
1805
+ process.stdout.write(d);
1806
+ });
1807
+ });
1808
+ req.on('error', (error) => {
1809
+ this.errorLog(error);
1810
+ });
1811
+ req.end();
1812
+
1813
+ this.deviceStatus = req;
1764
1814
  if (this.deviceStatus.message === 'success') {
1765
1815
  this.warnLog(`${device.deviceName} deviceInfoStatus: ${JSON.stringify(this.deviceStatus)}`);
1766
1816
  } else {
package/src/settings.ts CHANGED
@@ -13,12 +13,12 @@ export const PLUGIN_NAME = '@switchbot/homebridge-switchbot';
13
13
  /**
14
14
  * This is the main url used to access SwitchBot API
15
15
  */
16
- export const AuthURL = 'https://api.switch-bot.com';
16
+ export const HostDomain = 'api.switch-bot.com';
17
17
 
18
18
  /**
19
19
  * This is the main url used to access SwitchBot API
20
20
  */
21
- export const DeviceURL = 'https://api.switch-bot.com/v1.1/devices';
21
+ export const DevicePath = '/v1.1/devices';
22
22
 
23
23
  //Config
24
24
  export interface SwitchBotPlatformConfig extends PlatformConfig {
@@ -183,16 +183,12 @@ export type payload = {
183
183
  command: string;
184
184
  };
185
185
 
186
- export interface AxiosRequestConfig {
187
- params?: Record<string, unknown>;
188
- headers?: any;
189
- }
190
-
186
+ /*
191
187
  export type deviceResponses = {
192
188
  statusCode: number | string;
193
189
  message: string;
194
190
  body: deviceList | infraredRemoteList;
195
- };
191
+ };*/
196
192
 
197
193
  //a list of physical devices.
198
194
  export type deviceList = {
@@ -236,11 +232,11 @@ export type irdevice = {
236
232
  hubDeviceId: string; //remote device's parent Hub ID
237
233
  };
238
234
 
239
- export type deviceStatusResponse = {
235
+ /*export type deviceStatusResponse = {
240
236
  statusCode: number;
241
237
  message: string;
242
238
  body: deviceStatus;
243
- };
239
+ };*/
244
240
 
245
241
  export type deviceStatus = {
246
242
  //device ID.