@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 } from '../settings';
3
+ import { irDevicesConfig, irdevice, Devices } from '../settings';
7
4
  import { CharacteristicValue, PlatformAccessory, Service } from 'homebridge';
8
5
 
9
6
  /**
@@ -84,11 +81,11 @@ export class Camera {
84
81
  */
85
82
  async pushOnChanges(): Promise<void> {
86
83
  this.debugLog(`${this.device.remoteType}: ${this.accessory.displayName} pushOnChanges On: ${this.On},`
87
- + ` disablePushOn: ${this.disablePushOn}`);
84
+ + ` disablePushOn: ${this.disablePushOn}`);
88
85
  if (this.On && !this.disablePushOn) {
89
86
  const commandType: string = await this.commandType();
90
87
  const command: string = await this.commandOn();
91
- const body = superStringify({
88
+ const body = JSON.stringify({
92
89
  'command': command,
93
90
  'parameter': 'default',
94
91
  'commandType': commandType,
@@ -99,11 +96,11 @@ export class Camera {
99
96
 
100
97
  async pushOffChanges(): Promise<void> {
101
98
  this.debugLog(`${this.device.remoteType}: ${this.accessory.displayName} pushOffChanges On: ${this.On},`
102
- + ` disablePushOff: ${this.disablePushOff}`);
99
+ + ` disablePushOff: ${this.disablePushOff}`);
103
100
  if (!this.On && !this.disablePushOff) {
104
101
  const commandType: string = await this.commandType();
105
102
  const command: string = await this.commandOff();
106
- const body = superStringify({
103
+ const body = JSON.stringify({
107
104
  'command': command,
108
105
  'parameter': 'default',
109
106
  'commandType': commandType,
@@ -113,55 +110,28 @@ export class Camera {
113
110
  }
114
111
 
115
112
  async pushChanges(body: any): Promise<void> {
113
+ this.debugLog(`${this.device.remoteType}: ${this.accessory.displayName} pushChanges`);
116
114
  if (this.device.connectionType === 'OpenAPI') {
115
+ this.debugLog(`${this.device.remoteType}: ${this.accessory.displayName} Sending request to SwitchBot API, body: ${body},`);
117
116
  try {
118
- // Make Push On request to the API
119
- const t = Date.now();
120
- const nonce = 'requestID';
121
- const data = this.platform.config.credentials?.token + t + nonce;
122
- const signTerm = crypto.createHmac('sha256', this.platform.config.credentials?.secret)
123
- .update(Buffer.from(data, 'utf-8'))
124
- .digest();
125
- const sign = signTerm.toString('base64');
126
- this.debugLog(`${this.device.remoteType}: ${this.accessory.displayName} sign: ${sign}`);
127
- this.infoLog(`${this.device.remoteType}: ${this.accessory.displayName} Sending request to SwitchBot API. body: ${body},`);
128
- const options = {
129
- hostname: HostDomain,
130
- port: 443,
131
- path: `${DevicePath}/${this.device.deviceId}/commands`,
117
+ const { body, statusCode, headers } = await request(`${Devices}/${this.device.deviceId}/commands`, {
132
118
  method: 'POST',
133
- headers: {
134
- 'Authorization': this.platform.config.credentials?.token,
135
- 'sign': sign,
136
- 'nonce': nonce,
137
- 't': t,
138
- 'Content-Type': 'application/json',
139
- 'Content-Length': body.length,
140
- },
141
- };
142
- const req = https.request(options, res => {
143
- this.debugLog(`${this.device.remoteType}: ${this.accessory.displayName} pushchanges statusCode: ${res.statusCode}`);
144
- this.statusCode({ res });
145
- res.on('data', d => {
146
- this.debugLog(`${this.device.remoteType}: ${this.accessory.displayName} d: ${d}`);
147
- });
119
+ headers: this.platform.generateHeaders(),
148
120
  });
149
- req.on('error', (e: any) => {
150
- this.errorLog(`${this.device.remoteType}: ${this.accessory.displayName} error message: ${e.message}`);
151
- });
152
- req.write(body);
153
- req.end();
154
- this.debugLog(`${this.device.remoteType}: ${this.accessory.displayName} pushchanges: ${superStringify(req)}`);
121
+ const deviceStatus = await body.json();
122
+ this.debugLog(`${this.device.remoteType}: ${this.accessory.displayName} Devices: ${JSON.stringify(deviceStatus.body)}`);
123
+ this.statusCode(statusCode);
124
+ this.debugLog(`${this.device.remoteType}: ${this.accessory.displayName} Headers: ${JSON.stringify(headers)}`);
155
125
  this.updateHomeKitCharacteristics();
156
126
  } catch (e: any) {
157
127
  this.apiError(e);
158
- this.errorLog(`${this.device.remoteType}: ${this.accessory.displayName} failed pushChanges with ${this.device.connectionType} Connection,`
159
- + ` Error Message: ${superStringify(e.message)}`,
128
+ this.errorLog(`${this.device.remoteType}: ${this.accessory.displayName} failed pushChanges with ${this.device.connectionType}`
129
+ + ` Connection, Error Message: ${JSON.stringify(e.message)}`,
160
130
  );
161
131
  }
162
132
  } else {
163
133
  this.warnLog(`${this.device.remoteType}: ${this.accessory.displayName}`
164
- + ` Connection Type: ${this.device.connectionType}, commands will not be sent to OpenAPI`);
134
+ + ` Connection Type: ${this.device.connectionType}, commands will not be sent to OpenAPI`);
165
135
  }
166
136
  }
167
137
 
@@ -221,34 +191,39 @@ export class Camera {
221
191
  return command;
222
192
  }
223
193
 
224
- async statusCode({ res }: { res: IncomingMessage }): Promise<void> {
225
- switch (res.statusCode) {
194
+ async statusCode(statusCode: number): Promise<void> {
195
+ switch (statusCode) {
226
196
  case 151:
227
- this.errorLog(`${this.device.remoteType}: ${this.accessory.displayName} Command not supported by this device type.`);
197
+ this.errorLog(`${this.device.remoteType}: ${this.accessory.displayName} Command not supported by this deviceType, statusCode: ${statusCode}`);
228
198
  break;
229
199
  case 152:
230
- this.errorLog(`${this.device.remoteType}: ${this.accessory.displayName} Device not found.`);
200
+ this.errorLog(`${this.device.remoteType}: ${this.accessory.displayName} Device not found, statusCode: ${statusCode}`);
231
201
  break;
232
202
  case 160:
233
- this.errorLog(`${this.device.remoteType}: ${this.accessory.displayName} Command is not supported.`);
203
+ this.errorLog(`${this.device.remoteType}: ${this.accessory.displayName} Command is not supported, statusCode: ${statusCode}`);
234
204
  break;
235
205
  case 161:
236
- this.errorLog(`${this.device.remoteType}: ${this.accessory.displayName} Device is offline.`);
206
+ this.errorLog(`${this.device.remoteType}: ${this.accessory.displayName} Device is offline, statusCode: ${statusCode}`);
237
207
  break;
238
208
  case 171:
239
- this.errorLog(`${this.device.remoteType}: ${this.accessory.displayName} Hub Device is offline. Hub: ${this.device.hubDeviceId}`);
209
+ this.errorLog(`${this.device.remoteType}: ${this.accessory.displayName} Hub Device is offline, statusCode: ${statusCode}. `
210
+ + `Hub: ${this.device.hubDeviceId}`);
240
211
  break;
241
212
  case 190:
242
213
  this.errorLog(
243
- `${this.device.remoteType}: ${this.accessory.displayName} Device internal error due to device states not synchronized` +
244
- ` with server, Or command: ${superStringify(res)} format is invalid`,
214
+ `${this.device.remoteType}: ${this.accessory.displayName} Device internal error due to device states not synchronized with server,` +
215
+ ` Or command format is invalid, statusCode: ${statusCode}`,
245
216
  );
246
217
  break;
247
218
  case 100:
248
- this.debugLog(`${this.device.remoteType}: ${this.accessory.displayName} Command successfully sent.`);
219
+ this.debugLog(`${this.device.remoteType}: ${this.accessory.displayName} Command successfully sent, statusCode: ${statusCode}`);
220
+ break;
221
+ case 200:
222
+ this.debugLog(`${this.device.remoteType}: ${this.accessory.displayName} Request successful, statusCode: ${statusCode}`);
249
223
  break;
250
224
  default:
251
- this.debugLog(`${this.device.remoteType}: ${this.accessory.displayName} Unknown statusCode.`);
225
+ this.infoLog(`${this.device.remoteType}: ${this.accessory.displayName} Unknown statusCode: `
226
+ + `${statusCode}, Submit Bugs Here: ' + 'https://tinyurl.com/SwitchBotBug`);
252
227
  }
253
228
  }
254
229
 
@@ -259,7 +234,7 @@ export class Camera {
259
234
  FirmwareRevision(accessory: PlatformAccessory, device: irdevice & irDevicesConfig): string {
260
235
  let FirmwareRevision: string;
261
236
  this.debugLog(`${this.device.remoteType}: ${this.accessory.displayName}`
262
- + ` accessory.context.FirmwareRevision: ${accessory.context.FirmwareRevision}`);
237
+ + ` accessory.context.FirmwareRevision: ${accessory.context.FirmwareRevision}`);
263
238
  this.debugLog(`${this.device.remoteType}: ${this.accessory.displayName} device.firmware: ${device.firmware}`);
264
239
  this.debugLog(`${this.device.remoteType}: ${this.accessory.displayName} this.platform.version: ${this.platform.version}`);
265
240
  if (accessory.context.FirmwareRevision) {
@@ -310,7 +285,7 @@ export class Camera {
310
285
  config['disablePushOff'] = device.disablePushOff;
311
286
  }
312
287
  if (Object.entries(config).length !== 0) {
313
- this.infoLog(`${this.device.remoteType}: ${this.accessory.displayName} Config: ${superStringify(config)}`);
288
+ this.infoLog(`${this.device.remoteType}: ${this.accessory.displayName} Config: ${JSON.stringify(config)}`);
314
289
  }
315
290
  }
316
291
 
@@ -1,10 +1,7 @@
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
3
  import { CharacteristicValue, PlatformAccessory, Service } from 'homebridge';
7
- import { irdevice, irDevicesConfig, HostDomain, DevicePath } from '../settings';
4
+ import { irdevice, irDevicesConfig, Devices } from '../settings';
8
5
 
9
6
  /**
10
7
  * Platform Accessory
@@ -103,7 +100,7 @@ export class Fan {
103
100
  // eslint-disable-next-line max-len
104
101
  this.debugLog(
105
102
  `${this.device.remoteType}: ${this.accessory.displayName} RotationSpeed Characteristic was not removed/added, ` +
106
- `Clear Cache on ${this.accessory.displayName} to remove Chracteristic`,
103
+ `Clear Cache on ${this.accessory.displayName} to remove Chracteristic`,
107
104
  );
108
105
  }
109
106
 
@@ -118,7 +115,7 @@ export class Fan {
118
115
  // eslint-disable-next-line max-len
119
116
  this.debugLog(
120
117
  `${this.device.remoteType}: ${this.accessory.displayName} Swing Mode Characteristic was not removed/added, ` +
121
- `Clear Cache on ${this.accessory.displayName} To Remove Chracteristic`,
118
+ `Clear Cache on ${this.accessory.displayName} To Remove Chracteristic`,
122
119
  );
123
120
  }
124
121
  }
@@ -174,111 +171,84 @@ export class Fan {
174
171
  */
175
172
  async pushFanOnChanges(): Promise<void> {
176
173
  this.debugLog(`${this.device.remoteType}: ${this.accessory.displayName} pushFanOnChanges Active: ${this.Active},`
177
- + ` disablePushOn: ${this.disablePushOn}`);
174
+ + ` disablePushOn: ${this.disablePushOn}`);
178
175
  if (this.Active === this.platform.Characteristic.Active.ACTIVE && !this.disablePushOn) {
179
176
  const commandType: string = await this.commandType();
180
177
  const command: string = await this.commandOn();
181
- const body = superStringify({
178
+ const body = JSON.stringify({
182
179
  'command': command,
183
180
  'parameter': 'default',
184
181
  'commandType': commandType,
185
182
  });
186
- await this.pushTVChanges(body);
183
+ await this.pushChanges(body);
187
184
  }
188
185
  }
189
186
 
190
187
  async pushFanOffChanges(): Promise<void> {
191
188
  this.debugLog(`${this.device.remoteType}: ${this.accessory.displayName} pushLightOffChanges Active: ${this.Active},`
192
- + ` disablePushOff: ${this.disablePushOff}`);
189
+ + ` disablePushOff: ${this.disablePushOff}`);
193
190
  if (this.Active === this.platform.Characteristic.Active.INACTIVE && !this.disablePushOff) {
194
191
  const commandType: string = await this.commandType();
195
192
  const command: string = await this.commandOff();
196
- const body = superStringify({
193
+ const body = JSON.stringify({
197
194
  'command': command,
198
195
  'parameter': 'default',
199
196
  'commandType': commandType,
200
197
  });
201
- await this.pushTVChanges(body);
198
+ await this.pushChanges(body);
202
199
  }
203
200
  }
204
201
 
205
202
  async pushFanSpeedUpChanges(): Promise<void> {
206
- const body = superStringify({
203
+ const body = JSON.stringify({
207
204
  'command': 'highSpeed',
208
205
  'parameter': 'default',
209
206
  'commandType': 'command',
210
207
  });
211
- await this.pushTVChanges(body);
208
+ await this.pushChanges(body);
212
209
  }
213
210
 
214
211
  async pushFanSpeedDownChanges(): Promise<void> {
215
- const body = superStringify({
212
+ const body = JSON.stringify({
216
213
  'command': 'lowSpeed',
217
214
  'parameter': 'default',
218
215
  'commandType': 'command',
219
216
  });
220
- await this.pushTVChanges(body);
217
+ await this.pushChanges(body);
221
218
  }
222
219
 
223
220
  async pushFanSwingChanges(): Promise<void> {
224
- const body = superStringify({
221
+ const body = JSON.stringify({
225
222
  'command': 'swing',
226
223
  'parameter': 'default',
227
224
  'commandType': 'command',
228
225
  });
229
- await this.pushTVChanges(body);
226
+ await this.pushChanges(body);
230
227
  }
231
228
 
232
- async pushTVChanges(body): Promise<void> {
229
+ async pushChanges(body: any): Promise<void> {
230
+ this.debugLog(`${this.device.remoteType}: ${this.accessory.displayName} pushChanges`);
233
231
  if (this.device.connectionType === 'OpenAPI') {
232
+ this.debugLog(`${this.device.remoteType}: ${this.accessory.displayName} Sending request to SwitchBot API, body: ${body},`);
234
233
  try {
235
- // Make Push On request to the API
236
- const t = Date.now();
237
- const nonce = 'requestID';
238
- const data = this.platform.config.credentials?.token + t + nonce;
239
- const signTerm = crypto.createHmac('sha256', this.platform.config.credentials?.secret)
240
- .update(Buffer.from(data, 'utf-8'))
241
- .digest();
242
- const sign = signTerm.toString('base64');
243
- this.debugLog(`${this.device.remoteType}: ${this.accessory.displayName} sign: ${sign}`);
244
- this.infoLog(`${this.device.remoteType}: ${this.accessory.displayName} Sending request to SwitchBot API. body: ${body},`);
245
- const options = {
246
- hostname: HostDomain,
247
- port: 443,
248
- path: `${DevicePath}/${this.device.deviceId}/commands`,
234
+ const { body, statusCode, headers } = await request(`${Devices}/${this.device.deviceId}/commands`, {
249
235
  method: 'POST',
250
- headers: {
251
- 'Authorization': this.platform.config.credentials?.token,
252
- 'sign': sign,
253
- 'nonce': nonce,
254
- 't': t,
255
- 'Content-Type': 'application/json',
256
- 'Content-Length': body.length,
257
- },
258
- };
259
- const req = https.request(options, res => {
260
- this.debugLog(`${this.device.remoteType}: ${this.accessory.displayName} pushchanges statusCode: ${res.statusCode}`);
261
- this.statusCode({ res });
262
- res.on('data', d => {
263
- this.debugLog(`${this.device.remoteType}: ${this.accessory.displayName} d: ${d}`);
264
- });
236
+ headers: this.platform.generateHeaders(),
265
237
  });
266
- req.on('error', (e: any) => {
267
- this.errorLog(`${this.device.remoteType}: ${this.accessory.displayName} error message: ${e.message}`);
268
- });
269
- req.write(body);
270
- req.end();
271
- this.debugLog(`${this.device.remoteType}: ${this.accessory.displayName} pushchanges: ${superStringify(req)}`);
238
+ const deviceStatus = await body.json();
239
+ this.debugLog(`${this.device.remoteType}: ${this.accessory.displayName} Devices: ${JSON.stringify(deviceStatus.body)}`);
240
+ this.statusCode(statusCode);
241
+ this.debugLog(`${this.device.remoteType}: ${this.accessory.displayName} Headers: ${JSON.stringify(headers)}`);
272
242
  this.updateHomeKitCharacteristics();
273
243
  } catch (e: any) {
274
244
  this.apiError(e);
275
- this.errorLog(`${this.device.remoteType}: ${this.accessory.displayName} failed pushChanges with ${this.device.connectionType} Connection,`
276
- + ` Error Message: ${superStringify(e.message)}`,
245
+ this.errorLog(`${this.device.remoteType}: ${this.accessory.displayName} failed pushChanges with ${this.device.connectionType}`
246
+ + ` Connection, Error Message: ${JSON.stringify(e.message)}`,
277
247
  );
278
248
  }
279
249
  } else {
280
250
  this.warnLog(`${this.device.remoteType}: ${this.accessory.displayName}`
281
- + ` Connection Type: ${this.device.connectionType}, commands will not be sent to OpenAPI`);
251
+ + ` Connection Type: ${this.device.connectionType}, commands will not be sent to OpenAPI`);
282
252
  }
283
253
  }
284
254
 
@@ -352,34 +322,39 @@ export class Fan {
352
322
  return command;
353
323
  }
354
324
 
355
- async statusCode({ res }: { res: IncomingMessage }): Promise<void> {
356
- switch (res.statusCode) {
325
+ async statusCode(statusCode: number): Promise<void> {
326
+ switch (statusCode) {
357
327
  case 151:
358
- this.errorLog(`${this.device.remoteType}: ${this.accessory.displayName} Command not supported by this device type.`);
328
+ this.errorLog(`${this.device.remoteType}: ${this.accessory.displayName} Command not supported by this deviceType, statusCode: ${statusCode}`);
359
329
  break;
360
330
  case 152:
361
- this.errorLog(`${this.device.remoteType}: ${this.accessory.displayName} Device not found.`);
331
+ this.errorLog(`${this.device.remoteType}: ${this.accessory.displayName} Device not found, statusCode: ${statusCode}`);
362
332
  break;
363
333
  case 160:
364
- this.errorLog(`${this.device.remoteType}: ${this.accessory.displayName} Command is not supported.`);
334
+ this.errorLog(`${this.device.remoteType}: ${this.accessory.displayName} Command is not supported, statusCode: ${statusCode}`);
365
335
  break;
366
336
  case 161:
367
- this.errorLog(`${this.device.remoteType}: ${this.accessory.displayName} Device is offline.`);
337
+ this.errorLog(`${this.device.remoteType}: ${this.accessory.displayName} Device is offline, statusCode: ${statusCode}`);
368
338
  break;
369
339
  case 171:
370
- this.errorLog(`${this.device.remoteType}: ${this.accessory.displayName} Hub Device is offline. Hub: ${this.device.hubDeviceId}`);
340
+ this.errorLog(`${this.device.remoteType}: ${this.accessory.displayName} Hub Device is offline, statusCode: ${statusCode}. `
341
+ + `Hub: ${this.device.hubDeviceId}`);
371
342
  break;
372
343
  case 190:
373
344
  this.errorLog(
374
- `${this.device.remoteType}: ${this.accessory.displayName} Device internal error due to device states not synchronized` +
375
- ` with server, Or command: ${superStringify(res)} format is invalid`,
345
+ `${this.device.remoteType}: ${this.accessory.displayName} Device internal error due to device states not synchronized with server,` +
346
+ ` Or command format is invalid, statusCode: ${statusCode}`,
376
347
  );
377
348
  break;
378
349
  case 100:
379
- this.debugLog(`${this.device.remoteType}: ${this.accessory.displayName} Command successfully sent.`);
350
+ this.debugLog(`${this.device.remoteType}: ${this.accessory.displayName} Command successfully sent, statusCode: ${statusCode}`);
351
+ break;
352
+ case 200:
353
+ this.debugLog(`${this.device.remoteType}: ${this.accessory.displayName} Request successful, statusCode: ${statusCode}`);
380
354
  break;
381
355
  default:
382
- this.debugLog(`${this.device.remoteType}: ${this.accessory.displayName} Unknown statusCode.`);
356
+ this.infoLog(`${this.device.remoteType}: ${this.accessory.displayName} Unknown statusCode: `
357
+ + `${statusCode}, Submit Bugs Here: ' + 'https://tinyurl.com/SwitchBotBug`);
383
358
  }
384
359
  }
385
360
 
@@ -392,7 +367,7 @@ export class Fan {
392
367
  FirmwareRevision(accessory: PlatformAccessory, device: irdevice & irDevicesConfig): string {
393
368
  let FirmwareRevision: string;
394
369
  this.debugLog(`${this.device.remoteType}: ${this.accessory.displayName}`
395
- + ` accessory.context.FirmwareRevision: ${accessory.context.FirmwareRevision}`);
370
+ + ` accessory.context.FirmwareRevision: ${accessory.context.FirmwareRevision}`);
396
371
  this.debugLog(`${this.device.remoteType}: ${this.accessory.displayName} device.firmware: ${device.firmware}`);
397
372
  this.debugLog(`${this.device.remoteType}: ${this.accessory.displayName} this.platform.version: ${this.platform.version}`);
398
373
  if (accessory.context.FirmwareRevision) {
@@ -444,7 +419,7 @@ export class Fan {
444
419
  config['disablePushOff'] = device.disablePushOff;
445
420
  }
446
421
  if (Object.entries(config).length !== 0) {
447
- this.infoLog(`${this.device.remoteType}: ${this.accessory.displayName} Config: ${superStringify(config)}`);
422
+ this.infoLog(`${this.device.remoteType}: ${this.accessory.displayName} Config: ${JSON.stringify(config)}`);
448
423
  }
449
424
  }
450
425
 
@@ -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 } from '../settings';
3
+ import { irDevicesConfig, irdevice, Devices } from '../settings';
7
4
  import { CharacteristicValue, PlatformAccessory, Service } from 'homebridge';
8
5
 
9
6
  /**
@@ -88,11 +85,11 @@ export class Light {
88
85
  */
89
86
  async pushLightOnChanges(): Promise<void> {
90
87
  this.debugLog(`${this.device.remoteType}: ${this.accessory.displayName} pushLightOnChanges On: ${this.On},`
91
- + ` disablePushOn: ${this.disablePushOn}`);
88
+ + ` disablePushOn: ${this.disablePushOn}`);
92
89
  if (this.On && !this.disablePushOn) {
93
90
  const commandType: string = await this.commandType();
94
91
  const command: string = await this.commandOn();
95
- const body = superStringify({
92
+ const body = JSON.stringify({
96
93
  'command': command,
97
94
  'parameter': 'default',
98
95
  'commandType': commandType,
@@ -103,11 +100,11 @@ export class Light {
103
100
 
104
101
  async pushLightOffChanges(): Promise<void> {
105
102
  this.debugLog(`${this.device.remoteType}: ${this.accessory.displayName} pushLightOffChanges On: ${this.On},`
106
- + ` disablePushOff: ${this.disablePushOff}`);
103
+ + ` disablePushOff: ${this.disablePushOff}`);
107
104
  if (!this.On && !this.disablePushOff) {
108
105
  const commandType: string = await this.commandType();
109
106
  const command: string = await this.commandOff();
110
- const body = superStringify({
107
+ const body = JSON.stringify({
111
108
  'command': command,
112
109
  'parameter': 'default',
113
110
  'commandType': commandType,
@@ -117,7 +114,7 @@ export class Light {
117
114
  }
118
115
 
119
116
  async pushLightBrightnessUpChanges(): Promise<void> {
120
- const body = superStringify({
117
+ const body = JSON.stringify({
121
118
  'command': 'brightnessUp',
122
119
  'parameter': 'default',
123
120
  'commandType': 'command',
@@ -126,7 +123,7 @@ export class Light {
126
123
  }
127
124
 
128
125
  async pushLightBrightnessDownChanges(): Promise<void> {
129
- const body = superStringify({
126
+ const body = JSON.stringify({
130
127
  'command': 'brightnessDown',
131
128
  'parameter': 'default',
132
129
  'commandType': 'command',
@@ -134,57 +131,30 @@ export class Light {
134
131
  await this.pushChanges(body);
135
132
  }
136
133
 
137
- async pushChanges(body): Promise<void> {
134
+ async pushChanges(body: any): Promise<void> {
135
+ this.debugLog(`${this.device.remoteType}: ${this.accessory.displayName} pushChanges`);
138
136
  if (this.device.connectionType === 'OpenAPI') {
137
+ this.debugLog(`${this.device.remoteType}: ${this.accessory.displayName} Sending request to SwitchBot API, body: ${body},`);
139
138
  try {
140
- // Make Push On request to the API
141
- const t = Date.now();
142
- const nonce = 'requestID';
143
- const data = this.platform.config.credentials?.token + t + nonce;
144
- const signTerm = crypto.createHmac('sha256', this.platform.config.credentials?.secret)
145
- .update(Buffer.from(data, 'utf-8'))
146
- .digest();
147
- const sign = signTerm.toString('base64');
148
- this.debugLog(`${this.device.remoteType}: ${this.accessory.displayName} sign: ${sign}`);
149
- this.infoLog(`${this.device.remoteType}: ${this.accessory.displayName} Sending request to SwitchBot API. body: ${body},`);
150
- const options = {
151
- hostname: HostDomain,
152
- port: 443,
153
- path: `${DevicePath}/${this.device.deviceId}/commands`,
139
+ const { body, statusCode, headers } = await request(`${Devices}/${this.device.deviceId}/commands`, {
154
140
  method: 'POST',
155
- headers: {
156
- 'Authorization': this.platform.config.credentials?.token,
157
- 'sign': sign,
158
- 'nonce': nonce,
159
- 't': t,
160
- 'Content-Type': 'application/json',
161
- 'Content-Length': body.length,
162
- },
163
- };
164
- const req = https.request(options, res => {
165
- this.debugLog(`${this.device.remoteType}: ${this.accessory.displayName} statusCode: ${res.statusCode}`);
166
- this.statusCode({ res });
167
- res.on('data', d => {
168
- this.debugLog(`${this.device.remoteType}: ${this.accessory.displayName} d: ${d}`);
169
- });
141
+ headers: this.platform.generateHeaders(),
170
142
  });
171
- req.on('error', (e: any) => {
172
- this.errorLog(`${this.device.remoteType}: ${this.accessory.displayName} error message: ${e.message}`);
173
- });
174
- req.write(body);
175
- req.end();
176
- this.debugLog(`${this.device.remoteType}: ${this.accessory.displayName} pushchanges: ${superStringify(req)}`);
143
+ const deviceStatus = await body.json();
144
+ this.debugLog(`${this.device.remoteType}: ${this.accessory.displayName} Devices: ${JSON.stringify(deviceStatus.body)}`);
145
+ this.statusCode(statusCode);
146
+ this.debugLog(`${this.device.remoteType}: ${this.accessory.displayName} Headers: ${JSON.stringify(headers)}`);
177
147
  this.accessory.context.On = this.On;
178
148
  this.updateHomeKitCharacteristics();
179
149
  } catch (e: any) {
180
150
  this.apiError(e);
181
- this.errorLog(`${this.device.remoteType}: ${this.accessory.displayName} failed pushChanges with ${this.device.connectionType} Connection,`
182
- + ` Error Message: ${superStringify(e.message)}`,
151
+ this.errorLog(`${this.device.remoteType}: ${this.accessory.displayName} failed pushChanges with ${this.device.connectionType}`
152
+ + ` Connection, Error Message: ${JSON.stringify(e.message)}`,
183
153
  );
184
154
  }
185
155
  } else {
186
156
  this.warnLog(`${this.device.remoteType}: ${this.accessory.displayName}`
187
- + ` Connection Type: ${this.device.connectionType}, commands will not be sent to OpenAPI`);
157
+ + ` Connection Type: ${this.device.connectionType}, commands will not be sent to OpenAPI`);
188
158
  }
189
159
  }
190
160
 
@@ -244,34 +214,39 @@ export class Light {
244
214
  return command;
245
215
  }
246
216
 
247
- async statusCode({ res }: { res: IncomingMessage }): Promise<void> {
248
- switch (res.statusCode) {
217
+ async statusCode(statusCode: number): Promise<void> {
218
+ switch (statusCode) {
249
219
  case 151:
250
- this.errorLog(`${this.device.remoteType}: ${this.accessory.displayName} Command not supported by this device type.`);
220
+ this.errorLog(`${this.device.remoteType}: ${this.accessory.displayName} Command not supported by this deviceType, statusCode: ${statusCode}`);
251
221
  break;
252
222
  case 152:
253
- this.errorLog(`${this.device.remoteType}: ${this.accessory.displayName} Device not found.`);
223
+ this.errorLog(`${this.device.remoteType}: ${this.accessory.displayName} Device not found, statusCode: ${statusCode}`);
254
224
  break;
255
225
  case 160:
256
- this.errorLog(`${this.device.remoteType}: ${this.accessory.displayName} Command is not supported.`);
226
+ this.errorLog(`${this.device.remoteType}: ${this.accessory.displayName} Command is not supported, statusCode: ${statusCode}`);
257
227
  break;
258
228
  case 161:
259
- this.errorLog(`${this.device.remoteType}: ${this.accessory.displayName} Device is offline.`);
229
+ this.errorLog(`${this.device.remoteType}: ${this.accessory.displayName} Device is offline, statusCode: ${statusCode}`);
260
230
  break;
261
231
  case 171:
262
- this.errorLog(`${this.device.remoteType}: ${this.accessory.displayName} Hub Device is offline. Hub: ${this.device.hubDeviceId}`);
232
+ this.errorLog(`${this.device.remoteType}: ${this.accessory.displayName} Hub Device is offline, statusCode: ${statusCode}. `
233
+ + `Hub: ${this.device.hubDeviceId}`);
263
234
  break;
264
235
  case 190:
265
236
  this.errorLog(
266
- `${this.device.remoteType}: ${this.accessory.displayName} Device internal error due to device states not synchronized` +
267
- ` with server, Or command: ${superStringify(res)} format is invalid`,
237
+ `${this.device.remoteType}: ${this.accessory.displayName} Device internal error due to device states not synchronized with server,` +
238
+ ` Or command format is invalid, statusCode: ${statusCode}`,
268
239
  );
269
240
  break;
270
241
  case 100:
271
- this.debugLog(`${this.device.remoteType}: ${this.accessory.displayName} Command successfully sent.`);
242
+ this.debugLog(`${this.device.remoteType}: ${this.accessory.displayName} Command successfully sent, statusCode: ${statusCode}`);
243
+ break;
244
+ case 200:
245
+ this.debugLog(`${this.device.remoteType}: ${this.accessory.displayName} Request successful, statusCode: ${statusCode}`);
272
246
  break;
273
247
  default:
274
- this.debugLog(`${this.device.remoteType}: ${this.accessory.displayName} Unknown statusCode.`);
248
+ this.infoLog(`${this.device.remoteType}: ${this.accessory.displayName} Unknown statusCode: `
249
+ + `${statusCode}, Submit Bugs Here: ' + 'https://tinyurl.com/SwitchBotBug`);
275
250
  }
276
251
  }
277
252
 
@@ -282,7 +257,7 @@ export class Light {
282
257
  FirmwareRevision(accessory: PlatformAccessory, device: irdevice & irDevicesConfig): string {
283
258
  let FirmwareRevision: string;
284
259
  this.debugLog(`${this.device.remoteType}: ${this.accessory.displayName}`
285
- + ` accessory.context.FirmwareRevision: ${accessory.context.FirmwareRevision}`);
260
+ + ` accessory.context.FirmwareRevision: ${accessory.context.FirmwareRevision}`);
286
261
  this.debugLog(`${this.device.remoteType}: ${this.accessory.displayName} device.firmware: ${device.firmware}`);
287
262
  this.debugLog(`${this.device.remoteType}: ${this.accessory.displayName} this.platform.version: ${this.platform.version}`);
288
263
  if (accessory.context.FirmwareRevision) {
@@ -333,7 +308,7 @@ export class Light {
333
308
  config['disablePushOff'] = device.disablePushOff;
334
309
  }
335
310
  if (Object.entries(config).length !== 0) {
336
- this.infoLog(`${this.device.remoteType}: ${this.accessory.displayName} Config: ${superStringify(config)}`);
311
+ this.infoLog(`${this.device.remoteType}: ${this.accessory.displayName} Config: ${JSON.stringify(config)}`);
337
312
  }
338
313
  }
339
314