@switchbot/homebridge-switchbot 1.15.1-beta.1 → 1.15.1-beta.11

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 (116) hide show
  1. package/.github/ISSUE_TEMPLATE/bug-report.yml +1 -0
  2. package/.github/ISSUE_TEMPLATE/feature-request.yml +1 -0
  3. package/.github/ISSUE_TEMPLATE/support-request.yml +1 -0
  4. package/.prettierrc +1 -1
  5. package/CHANGELOG.md +9 -0
  6. package/dist/device/bot.d.ts +8 -7
  7. package/dist/device/bot.d.ts.map +1 -1
  8. package/dist/device/bot.js +97 -21
  9. package/dist/device/bot.js.map +1 -1
  10. package/dist/device/colorbulb.d.ts +8 -7
  11. package/dist/device/colorbulb.d.ts.map +1 -1
  12. package/dist/device/colorbulb.js +221 -56
  13. package/dist/device/colorbulb.js.map +1 -1
  14. package/dist/device/contact.d.ts +3 -3
  15. package/dist/device/contact.d.ts.map +1 -1
  16. package/dist/device/contact.js +50 -7
  17. package/dist/device/contact.js.map +1 -1
  18. package/dist/device/curtain.d.ts +9 -8
  19. package/dist/device/curtain.d.ts.map +1 -1
  20. package/dist/device/curtain.js +95 -21
  21. package/dist/device/curtain.js.map +1 -1
  22. package/dist/device/humidifier.d.ts +8 -7
  23. package/dist/device/humidifier.d.ts.map +1 -1
  24. package/dist/device/humidifier.js +180 -59
  25. package/dist/device/humidifier.js.map +1 -1
  26. package/dist/device/lock.d.ts +8 -7
  27. package/dist/device/lock.d.ts.map +1 -1
  28. package/dist/device/lock.js +98 -22
  29. package/dist/device/lock.js.map +1 -1
  30. package/dist/device/meter.d.ts +4 -4
  31. package/dist/device/meter.d.ts.map +1 -1
  32. package/dist/device/meter.js +51 -8
  33. package/dist/device/meter.js.map +1 -1
  34. package/dist/device/meterplus.d.ts +3 -3
  35. package/dist/device/meterplus.d.ts.map +1 -1
  36. package/dist/device/meterplus.js +49 -6
  37. package/dist/device/meterplus.js.map +1 -1
  38. package/dist/device/motion.d.ts +3 -3
  39. package/dist/device/motion.d.ts.map +1 -1
  40. package/dist/device/motion.js +49 -9
  41. package/dist/device/motion.js.map +1 -1
  42. package/dist/device/plug.d.ts +8 -7
  43. package/dist/device/plug.d.ts.map +1 -1
  44. package/dist/device/plug.js +96 -20
  45. package/dist/device/plug.js.map +1 -1
  46. package/dist/device/striplight.d.ts +8 -7
  47. package/dist/device/striplight.d.ts.map +1 -1
  48. package/dist/device/striplight.js +186 -47
  49. package/dist/device/striplight.js.map +1 -1
  50. package/dist/irdevice/airconditioner.d.ts +7 -6
  51. package/dist/irdevice/airconditioner.d.ts.map +1 -1
  52. package/dist/irdevice/airconditioner.js +65 -28
  53. package/dist/irdevice/airconditioner.js.map +1 -1
  54. package/dist/irdevice/airpurifier.d.ts +7 -6
  55. package/dist/irdevice/airpurifier.d.ts.map +1 -1
  56. package/dist/irdevice/airpurifier.js +65 -28
  57. package/dist/irdevice/airpurifier.js.map +1 -1
  58. package/dist/irdevice/camera.d.ts +7 -6
  59. package/dist/irdevice/camera.d.ts.map +1 -1
  60. package/dist/irdevice/camera.js +58 -22
  61. package/dist/irdevice/camera.js.map +1 -1
  62. package/dist/irdevice/fan.d.ts +8 -7
  63. package/dist/irdevice/fan.d.ts.map +1 -1
  64. package/dist/irdevice/fan.js +76 -40
  65. package/dist/irdevice/fan.js.map +1 -1
  66. package/dist/irdevice/light.d.ts +7 -6
  67. package/dist/irdevice/light.d.ts.map +1 -1
  68. package/dist/irdevice/light.js +71 -35
  69. package/dist/irdevice/light.js.map +1 -1
  70. package/dist/irdevice/other.d.ts +7 -6
  71. package/dist/irdevice/other.d.ts.map +1 -1
  72. package/dist/irdevice/other.js +58 -22
  73. package/dist/irdevice/other.js.map +1 -1
  74. package/dist/irdevice/tv.d.ts +8 -7
  75. package/dist/irdevice/tv.d.ts.map +1 -1
  76. package/dist/irdevice/tv.js +112 -76
  77. package/dist/irdevice/tv.js.map +1 -1
  78. package/dist/irdevice/vacuumcleaner.d.ts +7 -6
  79. package/dist/irdevice/vacuumcleaner.d.ts.map +1 -1
  80. package/dist/irdevice/vacuumcleaner.js +58 -22
  81. package/dist/irdevice/vacuumcleaner.js.map +1 -1
  82. package/dist/irdevice/waterheater.d.ts +7 -6
  83. package/dist/irdevice/waterheater.d.ts.map +1 -1
  84. package/dist/irdevice/waterheater.js +58 -22
  85. package/dist/irdevice/waterheater.js.map +1 -1
  86. package/dist/platform.d.ts +3 -5
  87. package/dist/platform.d.ts.map +1 -1
  88. package/dist/platform.js +143 -87
  89. package/dist/platform.js.map +1 -1
  90. package/dist/settings.d.ts +2 -21
  91. package/dist/settings.d.ts.map +1 -1
  92. package/dist/settings.js +3 -3
  93. package/dist/settings.js.map +1 -1
  94. package/package.json +10 -12
  95. package/src/device/bot.ts +97 -30
  96. package/src/device/colorbulb.ts +225 -93
  97. package/src/device/contact.ts +49 -10
  98. package/src/device/curtain.ts +98 -31
  99. package/src/device/humidifier.ts +182 -77
  100. package/src/device/lock.ts +97 -30
  101. package/src/device/meter.ts +51 -12
  102. package/src/device/meterplus.ts +48 -9
  103. package/src/device/motion.ts +48 -12
  104. package/src/device/plug.ts +97 -29
  105. package/src/device/striplight.ts +189 -68
  106. package/src/irdevice/airconditioner.ts +64 -34
  107. package/src/irdevice/airpurifier.ts +64 -36
  108. package/src/irdevice/camera.ts +57 -27
  109. package/src/irdevice/fan.ts +76 -46
  110. package/src/irdevice/light.ts +69 -39
  111. package/src/irdevice/other.ts +57 -27
  112. package/src/irdevice/tv.ts +112 -82
  113. package/src/irdevice/vacuumcleaner.ts +57 -27
  114. package/src/irdevice/waterheater.ts +57 -27
  115. package/src/platform.ts +157 -100
  116. package/src/settings.ts +2 -25
@@ -1,6 +1,8 @@
1
- import { AxiosResponse } from 'axios';
1
+ import https from 'https';
2
+ import crypto from 'crypto';
3
+ import { IncomingMessage } from 'http';
2
4
  import { SwitchBotPlatform } from '../platform';
3
- import { irDevicesConfig, DeviceURL, irdevice, payload } from '../settings';
5
+ import { irDevicesConfig, irdevice, HostDomain, DevicePath } from '../settings';
4
6
  import { CharacteristicValue, PlatformAccessory, Service } from 'homebridge';
5
7
 
6
8
  /**
@@ -181,22 +183,22 @@ export class AirConditioner {
181
183
  */
182
184
  async pushAirConditionerOnChanges(): Promise<void> {
183
185
  if (this.Active !== this.platform.Characteristic.Active.ACTIVE || this.pushOn) {
184
- const payload = {
185
- commandType: 'command',
186
- parameter: 'default',
187
- command: 'turnOn',
188
- } as any;
189
- await this.pushChanges(payload);
186
+ const body = JSON.stringify({
187
+ 'command': 'turnOn',
188
+ 'parameter': 'default',
189
+ 'commandType': 'command',
190
+ });
191
+ await this.pushChanges(body);
190
192
  }
191
193
  }
192
194
 
193
195
  async pushAirConditionerOffChanges(): Promise<void> {
194
- const payload = {
195
- commandType: 'command',
196
- parameter: 'default',
197
- command: 'turnOff',
198
- } as any;
199
- await this.pushChanges(payload);
196
+ const body = JSON.stringify({
197
+ 'command': 'turnOff',
198
+ 'parameter': 'default',
199
+ 'commandType': 'command',
200
+ });
201
+ await this.pushChanges(body);
200
202
  }
201
203
 
202
204
  async pushAirConditionerStatusChanges(): Promise<void> {
@@ -211,11 +213,6 @@ export class AirConditioner {
211
213
  }
212
214
 
213
215
  async pushAirConditionerDetailsChanges(): Promise<void> {
214
- const payload = {
215
- commandType: 'command',
216
- command: 'setAll',
217
- } as any;
218
-
219
216
  this.CurrentTemperatureUndefined();
220
217
  if (this.CurrentMode === undefined) {
221
218
  this.CurrentMode = 1;
@@ -234,7 +231,7 @@ export class AirConditioner {
234
231
  `Air Conditioner: ${this.accessory.displayName} CurrentMode: ${this.CurrentMode},` + ` CurrentTemperature: ${this.CurrentTemperature}`,
235
232
  );
236
233
  }
237
- payload.parameter = `${this.CurrentTemperature},${this.CurrentMode},${this.CurrentFanSpeed},${this.state}`;
234
+ const parameter = `${this.CurrentTemperature},${this.CurrentMode},${this.CurrentFanSpeed},${this.state}`;
238
235
 
239
236
  if (this.Active === this.platform.Characteristic.Active.ACTIVE) {
240
237
  this.CurrentTemperatureUndefined();
@@ -246,21 +243,54 @@ export class AirConditioner {
246
243
  } else {
247
244
  this.CurrentHeaterCoolerState = this.platform.Characteristic.CurrentHeaterCoolerState.INACTIVE;
248
245
  }
246
+ const body = JSON.stringify({
247
+ 'command': 'setAll',
248
+ 'parameter': `${parameter}`,
249
+ 'commandType': 'command',
250
+ });
249
251
 
250
- await this.pushChanges(payload);
252
+ await this.pushChanges(body);
251
253
  }
252
254
 
253
- async pushChanges(payload: payload): Promise<void> {
255
+ async pushChanges(body): Promise<void> {
254
256
  try {
255
- this.infoLog(
256
- `Air Conditioner: ${this.accessory.displayName} Sending request to SwitchBot API. command: ${payload.command},` +
257
- ` parameter: [${payload.parameter}], commandType: ${payload.commandType}`,
258
- );
259
-
260
- // Make the API request
261
- const push: any = await this.platform.axios.post(`${DeviceURL}/${this.device.deviceId}/commands`, payload);
262
- this.debugLog(`Air Conditioner: ${this.accessory.displayName} pushChanges: ${JSON.stringify(push.data)}`);
263
- this.statusCode(push);
257
+ // Make Push On request to the API
258
+ const t = Date.now();
259
+ const nonce = 'requestID';
260
+ const data = this.platform.config.credentials?.token + t + nonce;
261
+ const signTerm = crypto.createHmac('sha256', this.platform.config.credentials?.secret)
262
+ .update(Buffer.from(data, 'utf-8'))
263
+ .digest();
264
+ const sign = signTerm.toString('base64');
265
+ this.debugLog(`Air Conditioner: ${this.accessory.displayName} sign: ${sign}`);
266
+ this.infoLog(`Air Conditioner: ${this.accessory.displayName} Sending request to SwitchBot API. body: ${body},`);
267
+ const options = {
268
+ hostname: HostDomain,
269
+ port: 443,
270
+ path: `${DevicePath}/${this.device.deviceId}/commands`,
271
+ method: 'POST',
272
+ headers: {
273
+ 'Authorization': this.platform.config.credentials?.token,
274
+ 'sign': sign,
275
+ 'nonce': nonce,
276
+ 't': t,
277
+ 'Content-Type': 'application/json',
278
+ 'Content-Length': body.length,
279
+ },
280
+ };
281
+ const req = https.request(options, res => {
282
+ this.debugLog(`Air Conditioner: ${this.accessory.displayName} statusCode: ${res.statusCode}`);
283
+ this.statusCode({ res });
284
+ res.on('data', d => {
285
+ this.debugLog(`Air Conditioner: ${this.accessory.displayName} d: ${d}`);
286
+ });
287
+ });
288
+ req.on('error', (e: any) => {
289
+ this.errorLog(`Air Conditioner: ${this.accessory.displayName} error message: ${e.message}`);
290
+ });
291
+ req.write(body);
292
+ req.end();
293
+ this.debugLog(`Air Conditioner: ${this.accessory.displayName} pushchanges: ${JSON.stringify(req)}`);
264
294
  this.CurrentTemperatureCached = this.CurrentTemperature;
265
295
  this.accessory.context.CurrentTemperature = this.CurrentTemperatureCached;
266
296
  this.HeatingThresholdTemperature = this.CurrentTemperatureCached;
@@ -279,8 +309,8 @@ export class AirConditioner {
279
309
  }
280
310
  }
281
311
 
282
- async statusCode(push: AxiosResponse<{ statusCode: number }>): Promise<void> {
283
- switch (push.data.statusCode) {
312
+ async statusCode({ res }: { res: IncomingMessage }): Promise<void> {
313
+ switch (res.statusCode) {
284
314
  case 151:
285
315
  this.errorLog(`Air Conditioner: ${this.accessory.displayName} Command not supported by this device type.`);
286
316
  break;
@@ -299,7 +329,7 @@ export class AirConditioner {
299
329
  case 190:
300
330
  this.errorLog(
301
331
  `Air Conditioner: ${this.accessory.displayName} Device internal error due to device states not synchronized` +
302
- ` with server, Or command: ${JSON.stringify(push.data)} format is invalid`,
332
+ ` with server, Or command: ${JSON.stringify(res)} format is invalid`,
303
333
  );
304
334
  break;
305
335
  case 100:
@@ -1,6 +1,8 @@
1
- import { AxiosResponse } from 'axios';
1
+ import https from 'https';
2
+ import crypto from 'crypto';
3
+ import { IncomingMessage } from 'http';
2
4
  import { SwitchBotPlatform } from '../platform';
3
- import { irDevicesConfig, DeviceURL, irdevice, payload } from '../settings';
5
+ import { irDevicesConfig, irdevice, HostDomain, DevicePath } from '../settings';
4
6
  import { CharacteristicValue, PlatformAccessory, Service } from 'homebridge';
5
7
 
6
8
  /**
@@ -156,23 +158,23 @@ export class AirPurifier {
156
158
  */
157
159
  async pushAirPurifierOnChanges(): Promise<void> {
158
160
  if (this.Active !== 1) {
159
- const payload = {
160
- commandType: 'command',
161
- parameter: 'default',
162
- command: 'turnOn',
163
- } as payload;
164
- await this.pushChanges(payload);
161
+ const body = JSON.stringify({
162
+ 'command': 'turnOn',
163
+ 'parameter': 'default',
164
+ 'commandType': 'command',
165
+ });
166
+ await this.pushChanges(body);
165
167
  }
166
168
  }
167
169
 
168
170
  async pushAirPurifierOffChanges(): Promise<void> {
169
171
  if (this.Active !== 0) {
170
- const payload = {
171
- commandType: 'command',
172
- parameter: 'default',
173
- command: 'turnOff',
174
- } as payload;
175
- await this.pushChanges(payload);
172
+ const body = JSON.stringify({
173
+ 'command': 'turnOff',
174
+ 'parameter': 'default',
175
+ 'commandType': 'command',
176
+ });
177
+ await this.pushChanges(body);
176
178
  }
177
179
  }
178
180
 
@@ -188,17 +190,16 @@ export class AirPurifier {
188
190
  }
189
191
 
190
192
  async pushAirConditionerDetailsChanges(): Promise<void> {
191
- const payload = {
192
- commandType: 'command',
193
- command: 'setAll',
194
- } as payload;
195
-
196
193
  this.CurrentAPTemp = this.CurrentTemperature || 24;
197
194
  this.CurrentAPMode = this.CurrentMode || 1;
198
195
  this.CurrentAPFanSpeed = this.CurrentFanSpeed || 1;
199
196
  this.APActive = this.Active === 1 ? 'on' : 'off';
200
- payload.parameter = `${this.CurrentAPTemp},${this.CurrentAPMode},${this.CurrentAPFanSpeed},${this.APActive}`;
201
-
197
+ const parameter = `${this.CurrentAPTemp},${this.CurrentAPMode},${this.CurrentAPFanSpeed},${this.APActive}`;
198
+ const body = JSON.stringify({
199
+ 'command': 'setAll',
200
+ 'parameter': `${parameter}`,
201
+ 'commandType': 'command',
202
+ });
202
203
  if (this.Active === 1) {
203
204
  if ((this.CurrentTemperature || 24) < (this.LastTemperature || 30)) {
204
205
  this.CurrentHeaterCoolerState = this.platform.Characteristic.CurrentHeaterCoolerState.COOLING;
@@ -208,21 +209,48 @@ export class AirPurifier {
208
209
  } else {
209
210
  this.CurrentHeaterCoolerState = this.platform.Characteristic.CurrentHeaterCoolerState.INACTIVE;
210
211
  }
211
-
212
- await this.pushChanges(payload);
212
+ await this.pushChanges(body);
213
213
  }
214
214
 
215
- async pushChanges(payload: payload): Promise<void> {
215
+ async pushChanges(body): Promise<void> {
216
216
  try {
217
- this.infoLog(
218
- `Air Purifier: ${this.accessory.displayName} Sending request to SwitchBot API. command: ${payload.command},` +
219
- ` parameter: ${payload.parameter}, commandType: ${payload.commandType}`,
220
- );
221
-
222
- // Make the API request
223
- const push = await this.platform.axios.post(`${DeviceURL}/${this.device.deviceId}/commands`, payload);
224
- this.debugLog(`Air Purifier: ${this.accessory.displayName} pushChanges: ${push.data}`);
225
- this.statusCode(push);
217
+ // Make Push On request to the API
218
+ const t = Date.now();
219
+ const nonce = 'requestID';
220
+ const data = this.platform.config.credentials?.token + t + nonce;
221
+ const signTerm = crypto.createHmac('sha256', this.platform.config.credentials?.secret)
222
+ .update(Buffer.from(data, 'utf-8'))
223
+ .digest();
224
+ const sign = signTerm.toString('base64');
225
+ this.debugLog(`Air Purifier: ${this.accessory.displayName} sign: ${sign}`);
226
+ this.infoLog(`Air Purifier: ${this.accessory.displayName} Sending request to SwitchBot API. body: ${body},`);
227
+ const options = {
228
+ hostname: HostDomain,
229
+ port: 443,
230
+ path: `${DevicePath}/${this.device.deviceId}/commands`,
231
+ method: 'POST',
232
+ headers: {
233
+ 'Authorization': this.platform.config.credentials?.token,
234
+ 'sign': sign,
235
+ 'nonce': nonce,
236
+ 't': t,
237
+ 'Content-Type': 'application/json',
238
+ 'Content-Length': body.length,
239
+ },
240
+ };
241
+ const req = https.request(options, res => {
242
+ this.debugLog(`Air Purifier: ${this.accessory.displayName} statusCode: ${res.statusCode}`);
243
+ this.statusCode({ res });
244
+ res.on('data', d => {
245
+ this.debugLog(`Air Purifier: ${this.accessory.displayName} d: ${d}`);
246
+ });
247
+ });
248
+ req.on('error', (e: any) => {
249
+ this.errorLog(`Air Purifier: ${this.accessory.displayName} error message: ${e.message}`);
250
+ });
251
+ req.write(body);
252
+ req.end();
253
+ this.debugLog(`Air Purifier: ${this.accessory.displayName} pushchanges: ${JSON.stringify(req)}`);
226
254
  this.updateHomeKitCharacteristics();
227
255
  this.CurrentTemperatureCached = this.CurrentTemperature;
228
256
  this.accessory.context.CurrentTemperature = this.CurrentTemperatureCached;
@@ -237,8 +265,8 @@ export class AirPurifier {
237
265
  }
238
266
  }
239
267
 
240
- async statusCode(push: AxiosResponse<{ statusCode: number }>): Promise<void> {
241
- switch (push.data.statusCode) {
268
+ async statusCode({ res }: { res: IncomingMessage }): Promise<void> {
269
+ switch (res.statusCode) {
242
270
  case 151:
243
271
  this.errorLog(`Air Purifier: ${this.accessory.displayName} Command not supported by this device type.`);
244
272
  break;
@@ -257,7 +285,7 @@ export class AirPurifier {
257
285
  case 190:
258
286
  this.errorLog(
259
287
  `Air Purifier: ${this.accessory.displayName} Device internal error due to device states not synchronized` +
260
- ` with server, Or command: ${JSON.stringify(push.data)} format is invalid`,
288
+ ` with server, Or command: ${JSON.stringify(res)} format is invalid`,
261
289
  );
262
290
  break;
263
291
  case 100:
@@ -1,6 +1,8 @@
1
- import { AxiosResponse } from 'axios';
1
+ import https from 'https';
2
+ import crypto from 'crypto';
3
+ import { IncomingMessage } from 'http';
2
4
  import { SwitchBotPlatform } from '../platform';
3
- import { irDevicesConfig, DeviceURL, irdevice, payload } from '../settings';
5
+ import { irDevicesConfig, irdevice, HostDomain, DevicePath } from '../settings';
4
6
  import { CharacteristicValue, PlatformAccessory, Service } from 'homebridge';
5
7
 
6
8
  /**
@@ -84,37 +86,65 @@ export class Camera {
84
86
  */
85
87
  async pushOnChanges(): Promise<void> {
86
88
  if (this.On) {
87
- const payload = {
88
- commandType: 'command',
89
- parameter: 'default',
90
- command: 'turnOn',
91
- } as payload;
92
- await this.pushChanges(payload);
89
+ const body = JSON.stringify({
90
+ 'command': 'turnOn',
91
+ 'parameter': 'default',
92
+ 'commandType': 'command',
93
+ });
94
+ await this.pushChanges(body);
93
95
  }
94
96
  }
95
97
 
96
98
  async pushOffChanges(): Promise<void> {
97
99
  if (!this.On) {
98
- const payload = {
99
- commandType: 'command',
100
- parameter: 'default',
101
- command: 'turnOff',
102
- } as payload;
103
- await this.pushChanges(payload);
100
+ const body = JSON.stringify({
101
+ 'command': 'turnOff',
102
+ 'parameter': 'default',
103
+ 'commandType': 'command',
104
+ });
105
+ await this.pushChanges(body);
104
106
  }
105
107
  }
106
108
 
107
- async pushChanges(payload: payload): Promise<void> {
109
+ async pushChanges(body): Promise<void> {
108
110
  try {
109
- this.infoLog(
110
- `Camera: ${this.accessory.displayName} Sending request to SwitchBot API. command: ${payload.command},` +
111
- ` parameter: ${payload.parameter}, commandType: ${payload.commandType}`,
112
- );
113
-
114
- // Make the API request
115
- const push = await this.platform.axios.post(`${DeviceURL}/${this.device.deviceId}/commands`, payload);
116
- this.debugLog(`Camera: ${this.accessory.displayName} pushChanges: ${push.data}`);
117
- this.statusCode(push);
111
+ // Make Push On request to the API
112
+ const t = Date.now();
113
+ const nonce = 'requestID';
114
+ const data = this.platform.config.credentials?.token + t + nonce;
115
+ const signTerm = crypto.createHmac('sha256', this.platform.config.credentials?.secret)
116
+ .update(Buffer.from(data, 'utf-8'))
117
+ .digest();
118
+ const sign = signTerm.toString('base64');
119
+ this.debugLog(`Camera: ${this.accessory.displayName} sign: ${sign}`);
120
+ this.infoLog(`Camera: ${this.accessory.displayName} Sending request to SwitchBot API. body: ${body},`);
121
+ const options = {
122
+ hostname: HostDomain,
123
+ port: 443,
124
+ path: `${DevicePath}/${this.device.deviceId}/commands`,
125
+ method: 'POST',
126
+ headers: {
127
+ 'Authorization': this.platform.config.credentials?.token,
128
+ 'sign': sign,
129
+ 'nonce': nonce,
130
+ 't': t,
131
+ 'Content-Type': 'application/json',
132
+ 'Content-Length': body.length,
133
+ },
134
+ };
135
+ const req = https.request(options, res => {
136
+ this.debugLog(`Camera: ${this.accessory.displayName} statusCode: ${res.statusCode}`);
137
+ this.statusCode({ res });
138
+ res.on('data', d => {
139
+ this.debugLog(`Camera: ${this.accessory.displayName} d: ${d}`);
140
+ });
141
+ });
142
+ req.on('error', (e: any) => {
143
+ this.errorLog(`Camera: ${this.accessory.displayName} error message: ${e.message}`);
144
+ });
145
+ req.write(body);
146
+ req.end();
147
+ this.debugLog(`Camera: ${this.accessory.displayName} pushchanges: ${JSON.stringify(req)}`);
118
148
  this.updateHomeKitCharacteristics();
119
149
  this.OnCached = this.On;
120
150
  this.accessory.context.On = this.OnCached;
@@ -129,8 +159,8 @@ export class Camera {
129
159
  }
130
160
  }
131
161
 
132
- async statusCode(push: AxiosResponse<{ statusCode: number }>): Promise<void> {
133
- switch (push.data.statusCode) {
162
+ async statusCode({ res }: { res: IncomingMessage }): Promise<void> {
163
+ switch (res.statusCode) {
134
164
  case 151:
135
165
  this.errorLog(`Camera: ${this.accessory.displayName} Command not supported by this device type.`);
136
166
  break;
@@ -149,7 +179,7 @@ export class Camera {
149
179
  case 190:
150
180
  this.errorLog(
151
181
  `Camera: ${this.accessory.displayName} Device internal error due to device states not synchronized` +
152
- ` with server, Or command: ${JSON.stringify(push.data)} format is invalid`,
182
+ ` with server, Or command: ${JSON.stringify(res)} format is invalid`,
153
183
  );
154
184
  break;
155
185
  case 100:
@@ -1,7 +1,9 @@
1
- import { AxiosResponse } from 'axios';
1
+ import https from 'https';
2
+ import crypto from 'crypto';
3
+ import { IncomingMessage } from 'http';
2
4
  import { SwitchBotPlatform } from '../platform';
3
5
  import { CharacteristicValue, PlatformAccessory, Service } from 'homebridge';
4
- import { DeviceURL, irdevice, deviceStatusResponse, irDevicesConfig, payload } from '../settings';
6
+ import { irdevice, irDevicesConfig, HostDomain, DevicePath } from '../settings';
5
7
 
6
8
  /**
7
9
  * Platform Accessory
@@ -21,7 +23,7 @@ export class Fan {
21
23
  RotationDirection!: CharacteristicValue;
22
24
 
23
25
  // Others
24
- deviceStatus!: deviceStatusResponse;
26
+ deviceStatus!: any;
25
27
 
26
28
  // Config
27
29
  minStep?: number;
@@ -186,62 +188,90 @@ export class Fan {
186
188
  */
187
189
  async pushFanOnChanges(): Promise<void> {
188
190
  if (this.Active !== 1) {
189
- const payload = {
190
- commandType: 'command',
191
- parameter: 'default',
192
- command: 'turnOn',
193
- } as payload;
194
- await this.pushTVChanges(payload);
191
+ const body = JSON.stringify({
192
+ 'command': 'turnOn',
193
+ 'parameter': 'default',
194
+ 'commandType': 'command',
195
+ });
196
+ await this.pushTVChanges(body);
195
197
  }
196
198
  }
197
199
 
198
200
  async pushFanOffChanges(): Promise<void> {
199
- const payload = {
200
- commandType: 'command',
201
- parameter: 'default',
202
- command: 'turnOff',
203
- } as payload;
204
- await this.pushTVChanges(payload);
201
+ const body = JSON.stringify({
202
+ 'command': 'turnOff',
203
+ 'parameter': 'default',
204
+ 'commandType': 'command',
205
+ });
206
+ await this.pushTVChanges(body);
205
207
  }
206
208
 
207
209
  async pushFanSpeedUpChanges(): Promise<void> {
208
- const payload = {
209
- commandType: 'command',
210
- parameter: 'default',
211
- command: 'highSpeed',
212
- } as payload;
213
- await this.pushTVChanges(payload);
210
+ const body = JSON.stringify({
211
+ 'command': 'highSpeed',
212
+ 'parameter': 'default',
213
+ 'commandType': 'command',
214
+ });
215
+ await this.pushTVChanges(body);
214
216
  }
215
217
 
216
218
  async pushFanSpeedDownChanges(): Promise<void> {
217
- const payload = {
218
- commandType: 'command',
219
- parameter: 'default',
220
- command: 'lowSpeed',
221
- } as payload;
222
- await this.pushTVChanges(payload);
219
+ const body = JSON.stringify({
220
+ 'command': 'lowSpeed',
221
+ 'parameter': 'default',
222
+ 'commandType': 'command',
223
+ });
224
+ await this.pushTVChanges(body);
223
225
  }
224
226
 
225
227
  async pushFanSwingChanges(): Promise<void> {
226
- const payload = {
227
- commandType: 'command',
228
- parameter: 'default',
229
- command: 'swing',
230
- } as payload;
231
- await this.pushTVChanges(payload);
228
+ const body = JSON.stringify({
229
+ 'command': 'swing',
230
+ 'parameter': 'default',
231
+ 'commandType': 'command',
232
+ });
233
+ await this.pushTVChanges(body);
232
234
  }
233
235
 
234
- async pushTVChanges(payload: payload): Promise<void> {
236
+ async pushTVChanges(body): Promise<void> {
235
237
  try {
236
- this.infoLog(
237
- `Fan: ${this.accessory.displayName} Sending request to SwitchBot API. command: ${payload.command},` +
238
- ` parameter: ${payload.parameter}, commandType: ${payload.commandType}`,
239
- );
240
-
241
- // Make the API request
242
- const push = await this.platform.axios.post(`${DeviceURL}/${this.device.deviceId}/commands`, payload);
243
- this.debugLog(`Fan: ${this.accessory.displayName} pushTVChanges: ${push.data}`);
244
- this.statusCode(push);
238
+ // Make Push On request to the API
239
+ const t = Date.now();
240
+ const nonce = 'requestID';
241
+ const data = this.platform.config.credentials?.token + t + nonce;
242
+ const signTerm = crypto.createHmac('sha256', this.platform.config.credentials?.secret)
243
+ .update(Buffer.from(data, 'utf-8'))
244
+ .digest();
245
+ const sign = signTerm.toString('base64');
246
+ this.debugLog(`Fan: ${this.accessory.displayName} sign: ${sign}`);
247
+ this.infoLog(`Fan: ${this.accessory.displayName} Sending request to SwitchBot API. body: ${body},`);
248
+ const options = {
249
+ hostname: HostDomain,
250
+ port: 443,
251
+ path: `${DevicePath}/${this.device.deviceId}/commands`,
252
+ method: 'POST',
253
+ headers: {
254
+ 'Authorization': this.platform.config.credentials?.token,
255
+ 'sign': sign,
256
+ 'nonce': nonce,
257
+ 't': t,
258
+ 'Content-Type': 'application/json',
259
+ 'Content-Length': body.length,
260
+ },
261
+ };
262
+ const req = https.request(options, res => {
263
+ this.debugLog(`Fan: ${this.accessory.displayName} statusCode: ${res.statusCode}`);
264
+ this.statusCode({ res });
265
+ res.on('data', d => {
266
+ this.debugLog(`Fan: ${this.accessory.displayName} d: ${d}`);
267
+ });
268
+ });
269
+ req.on('error', (e: any) => {
270
+ this.errorLog(`Fan: ${this.accessory.displayName} error message: ${e.message}`);
271
+ });
272
+ req.write(body);
273
+ req.end();
274
+ this.debugLog(`Fan: ${this.accessory.displayName} pushchanges: ${JSON.stringify(req)}`);
245
275
  this.updateHomeKitCharacteristics();
246
276
  } catch (e: any) {
247
277
  this.errorLog(`Fan: ${this.accessory.displayName} failed pushChanges with OpenAPI Connection`);
@@ -254,8 +284,8 @@ export class Fan {
254
284
  }
255
285
  }
256
286
 
257
- async statusCode(push: AxiosResponse<{ statusCode: number }>): Promise<void> {
258
- switch (push.data.statusCode) {
287
+ async statusCode({ res }: { res: IncomingMessage }): Promise<void> {
288
+ switch (res.statusCode) {
259
289
  case 151:
260
290
  this.errorLog(`Fan: ${this.accessory.displayName} Command not supported by this device type.`);
261
291
  break;
@@ -274,7 +304,7 @@ export class Fan {
274
304
  case 190:
275
305
  this.errorLog(
276
306
  `Fan: ${this.accessory.displayName} Device internal error due to device states not synchronized` +
277
- ` with server, Or command: ${JSON.stringify(push.data)} format is invalid`,
307
+ ` with server, Or command: ${JSON.stringify(res)} format is invalid`,
278
308
  );
279
309
  break;
280
310
  case 100: