@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.
- package/.github/ISSUE_TEMPLATE/bug-report.yml +1 -0
- package/.github/ISSUE_TEMPLATE/feature-request.yml +1 -0
- package/.github/ISSUE_TEMPLATE/support-request.yml +1 -0
- package/.prettierrc +1 -1
- package/CHANGELOG.md +9 -0
- package/dist/device/bot.d.ts +8 -7
- package/dist/device/bot.d.ts.map +1 -1
- package/dist/device/bot.js +97 -21
- package/dist/device/bot.js.map +1 -1
- package/dist/device/colorbulb.d.ts +8 -7
- package/dist/device/colorbulb.d.ts.map +1 -1
- package/dist/device/colorbulb.js +221 -56
- package/dist/device/colorbulb.js.map +1 -1
- package/dist/device/contact.d.ts +3 -3
- package/dist/device/contact.d.ts.map +1 -1
- package/dist/device/contact.js +50 -7
- package/dist/device/contact.js.map +1 -1
- package/dist/device/curtain.d.ts +9 -8
- package/dist/device/curtain.d.ts.map +1 -1
- package/dist/device/curtain.js +95 -21
- package/dist/device/curtain.js.map +1 -1
- package/dist/device/humidifier.d.ts +8 -7
- package/dist/device/humidifier.d.ts.map +1 -1
- package/dist/device/humidifier.js +180 -59
- package/dist/device/humidifier.js.map +1 -1
- package/dist/device/lock.d.ts +8 -7
- package/dist/device/lock.d.ts.map +1 -1
- package/dist/device/lock.js +98 -22
- package/dist/device/lock.js.map +1 -1
- package/dist/device/meter.d.ts +4 -4
- package/dist/device/meter.d.ts.map +1 -1
- package/dist/device/meter.js +51 -8
- package/dist/device/meter.js.map +1 -1
- package/dist/device/meterplus.d.ts +3 -3
- package/dist/device/meterplus.d.ts.map +1 -1
- package/dist/device/meterplus.js +49 -6
- package/dist/device/meterplus.js.map +1 -1
- package/dist/device/motion.d.ts +3 -3
- package/dist/device/motion.d.ts.map +1 -1
- package/dist/device/motion.js +49 -9
- package/dist/device/motion.js.map +1 -1
- package/dist/device/plug.d.ts +8 -7
- package/dist/device/plug.d.ts.map +1 -1
- package/dist/device/plug.js +96 -20
- package/dist/device/plug.js.map +1 -1
- package/dist/device/striplight.d.ts +8 -7
- package/dist/device/striplight.d.ts.map +1 -1
- package/dist/device/striplight.js +186 -47
- package/dist/device/striplight.js.map +1 -1
- package/dist/irdevice/airconditioner.d.ts +7 -6
- package/dist/irdevice/airconditioner.d.ts.map +1 -1
- package/dist/irdevice/airconditioner.js +65 -28
- package/dist/irdevice/airconditioner.js.map +1 -1
- package/dist/irdevice/airpurifier.d.ts +7 -6
- package/dist/irdevice/airpurifier.d.ts.map +1 -1
- package/dist/irdevice/airpurifier.js +65 -28
- package/dist/irdevice/airpurifier.js.map +1 -1
- package/dist/irdevice/camera.d.ts +7 -6
- package/dist/irdevice/camera.d.ts.map +1 -1
- package/dist/irdevice/camera.js +58 -22
- package/dist/irdevice/camera.js.map +1 -1
- package/dist/irdevice/fan.d.ts +8 -7
- package/dist/irdevice/fan.d.ts.map +1 -1
- package/dist/irdevice/fan.js +76 -40
- package/dist/irdevice/fan.js.map +1 -1
- package/dist/irdevice/light.d.ts +7 -6
- package/dist/irdevice/light.d.ts.map +1 -1
- package/dist/irdevice/light.js +71 -35
- package/dist/irdevice/light.js.map +1 -1
- package/dist/irdevice/other.d.ts +7 -6
- package/dist/irdevice/other.d.ts.map +1 -1
- package/dist/irdevice/other.js +58 -22
- package/dist/irdevice/other.js.map +1 -1
- package/dist/irdevice/tv.d.ts +8 -7
- package/dist/irdevice/tv.d.ts.map +1 -1
- package/dist/irdevice/tv.js +112 -76
- package/dist/irdevice/tv.js.map +1 -1
- package/dist/irdevice/vacuumcleaner.d.ts +7 -6
- package/dist/irdevice/vacuumcleaner.d.ts.map +1 -1
- package/dist/irdevice/vacuumcleaner.js +58 -22
- package/dist/irdevice/vacuumcleaner.js.map +1 -1
- package/dist/irdevice/waterheater.d.ts +7 -6
- package/dist/irdevice/waterheater.d.ts.map +1 -1
- package/dist/irdevice/waterheater.js +58 -22
- package/dist/irdevice/waterheater.js.map +1 -1
- package/dist/platform.d.ts +3 -5
- package/dist/platform.d.ts.map +1 -1
- package/dist/platform.js +143 -87
- package/dist/platform.js.map +1 -1
- package/dist/settings.d.ts +2 -21
- package/dist/settings.d.ts.map +1 -1
- package/dist/settings.js +3 -3
- package/dist/settings.js.map +1 -1
- package/package.json +10 -12
- package/src/device/bot.ts +97 -30
- package/src/device/colorbulb.ts +225 -93
- package/src/device/contact.ts +49 -10
- package/src/device/curtain.ts +98 -31
- package/src/device/humidifier.ts +182 -77
- package/src/device/lock.ts +97 -30
- package/src/device/meter.ts +51 -12
- package/src/device/meterplus.ts +48 -9
- package/src/device/motion.ts +48 -12
- package/src/device/plug.ts +97 -29
- package/src/device/striplight.ts +189 -68
- package/src/irdevice/airconditioner.ts +64 -34
- package/src/irdevice/airpurifier.ts +64 -36
- package/src/irdevice/camera.ts +57 -27
- package/src/irdevice/fan.ts +76 -46
- package/src/irdevice/light.ts +69 -39
- package/src/irdevice/other.ts +57 -27
- package/src/irdevice/tv.ts +112 -82
- package/src/irdevice/vacuumcleaner.ts +57 -27
- package/src/irdevice/waterheater.ts +57 -27
- package/src/platform.ts +157 -100
- package/src/settings.ts +2 -25
|
@@ -1,6 +1,8 @@
|
|
|
1
|
-
import
|
|
1
|
+
import https from 'https';
|
|
2
|
+
import crypto from 'crypto';
|
|
3
|
+
import { IncomingMessage } from 'http';
|
|
2
4
|
import { SwitchBotPlatform } from '../platform';
|
|
3
|
-
import { irDevicesConfig,
|
|
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
|
|
185
|
-
|
|
186
|
-
parameter: 'default',
|
|
187
|
-
|
|
188
|
-
}
|
|
189
|
-
await this.pushChanges(
|
|
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
|
|
195
|
-
|
|
196
|
-
parameter: 'default',
|
|
197
|
-
|
|
198
|
-
}
|
|
199
|
-
await this.pushChanges(
|
|
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
|
-
|
|
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(
|
|
252
|
+
await this.pushChanges(body);
|
|
251
253
|
}
|
|
252
254
|
|
|
253
|
-
async pushChanges(
|
|
255
|
+
async pushChanges(body): Promise<void> {
|
|
254
256
|
try {
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
this.
|
|
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(
|
|
283
|
-
switch (
|
|
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(
|
|
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
|
|
1
|
+
import https from 'https';
|
|
2
|
+
import crypto from 'crypto';
|
|
3
|
+
import { IncomingMessage } from 'http';
|
|
2
4
|
import { SwitchBotPlatform } from '../platform';
|
|
3
|
-
import { irDevicesConfig,
|
|
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
|
|
160
|
-
|
|
161
|
-
parameter: 'default',
|
|
162
|
-
|
|
163
|
-
}
|
|
164
|
-
await this.pushChanges(
|
|
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
|
|
171
|
-
|
|
172
|
-
parameter: 'default',
|
|
173
|
-
|
|
174
|
-
}
|
|
175
|
-
await this.pushChanges(
|
|
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
|
-
|
|
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(
|
|
215
|
+
async pushChanges(body): Promise<void> {
|
|
216
216
|
try {
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
this.
|
|
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(
|
|
241
|
-
switch (
|
|
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(
|
|
288
|
+
` with server, Or command: ${JSON.stringify(res)} format is invalid`,
|
|
261
289
|
);
|
|
262
290
|
break;
|
|
263
291
|
case 100:
|
package/src/irdevice/camera.ts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
|
-
import
|
|
1
|
+
import https from 'https';
|
|
2
|
+
import crypto from 'crypto';
|
|
3
|
+
import { IncomingMessage } from 'http';
|
|
2
4
|
import { SwitchBotPlatform } from '../platform';
|
|
3
|
-
import { irDevicesConfig,
|
|
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
|
|
88
|
-
|
|
89
|
-
parameter: 'default',
|
|
90
|
-
|
|
91
|
-
}
|
|
92
|
-
await this.pushChanges(
|
|
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
|
|
99
|
-
|
|
100
|
-
parameter: 'default',
|
|
101
|
-
|
|
102
|
-
}
|
|
103
|
-
await this.pushChanges(
|
|
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(
|
|
109
|
+
async pushChanges(body): Promise<void> {
|
|
108
110
|
try {
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
this.
|
|
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(
|
|
133
|
-
switch (
|
|
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(
|
|
182
|
+
` with server, Or command: ${JSON.stringify(res)} format is invalid`,
|
|
153
183
|
);
|
|
154
184
|
break;
|
|
155
185
|
case 100:
|
package/src/irdevice/fan.ts
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
|
-
import
|
|
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 {
|
|
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!:
|
|
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
|
|
190
|
-
|
|
191
|
-
parameter: 'default',
|
|
192
|
-
|
|
193
|
-
}
|
|
194
|
-
await this.pushTVChanges(
|
|
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
|
|
200
|
-
|
|
201
|
-
parameter: 'default',
|
|
202
|
-
|
|
203
|
-
}
|
|
204
|
-
await this.pushTVChanges(
|
|
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
|
|
209
|
-
|
|
210
|
-
parameter: 'default',
|
|
211
|
-
|
|
212
|
-
}
|
|
213
|
-
await this.pushTVChanges(
|
|
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
|
|
218
|
-
|
|
219
|
-
parameter: 'default',
|
|
220
|
-
|
|
221
|
-
}
|
|
222
|
-
await this.pushTVChanges(
|
|
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
|
|
227
|
-
|
|
228
|
-
parameter: 'default',
|
|
229
|
-
|
|
230
|
-
}
|
|
231
|
-
await this.pushTVChanges(
|
|
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(
|
|
236
|
+
async pushTVChanges(body): Promise<void> {
|
|
235
237
|
try {
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
this.
|
|
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(
|
|
258
|
-
switch (
|
|
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(
|
|
307
|
+
` with server, Or command: ${JSON.stringify(res)} format is invalid`,
|
|
278
308
|
);
|
|
279
309
|
break;
|
|
280
310
|
case 100:
|