@switchbot/homebridge-switchbot 2.0.0-beta.3 → 2.0.0-beta.30
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/CHANGELOG.md +10 -1
- package/README.md +1 -2
- package/config.schema.json +102 -20
- package/dist/device/bot.d.ts +34 -28
- package/dist/device/bot.d.ts.map +1 -1
- package/dist/device/bot.js +655 -649
- package/dist/device/bot.js.map +1 -1
- package/dist/device/colorbulb.d.ts +36 -19
- package/dist/device/colorbulb.d.ts.map +1 -1
- package/dist/device/colorbulb.js +483 -309
- package/dist/device/colorbulb.js.map +1 -1
- package/dist/device/contact.d.ts +18 -8
- package/dist/device/contact.d.ts.map +1 -1
- package/dist/device/contact.js +303 -237
- package/dist/device/contact.js.map +1 -1
- package/dist/device/curtain.d.ts +23 -16
- package/dist/device/curtain.d.ts.map +1 -1
- package/dist/device/curtain.js +541 -498
- package/dist/device/curtain.js.map +1 -1
- package/dist/device/humidifier.d.ts +24 -18
- package/dist/device/humidifier.d.ts.map +1 -1
- package/dist/device/humidifier.js +450 -369
- package/dist/device/humidifier.js.map +1 -1
- package/dist/device/lock.d.ts +27 -8
- package/dist/device/lock.d.ts.map +1 -1
- package/dist/device/lock.js +302 -148
- package/dist/device/lock.js.map +1 -1
- package/dist/device/meter.d.ts +22 -16
- package/dist/device/meter.d.ts.map +1 -1
- package/dist/device/meter.js +340 -262
- package/dist/device/meter.js.map +1 -1
- package/dist/device/meterplus.d.ts +24 -12
- package/dist/device/meterplus.d.ts.map +1 -1
- package/dist/device/meterplus.js +359 -213
- package/dist/device/meterplus.js.map +1 -1
- package/dist/device/motion.d.ts +18 -8
- package/dist/device/motion.d.ts.map +1 -1
- package/dist/device/motion.js +276 -216
- package/dist/device/motion.js.map +1 -1
- package/dist/device/plug.d.ts +27 -17
- package/dist/device/plug.d.ts.map +1 -1
- package/dist/device/plug.js +292 -251
- package/dist/device/plug.js.map +1 -1
- package/dist/device/striplight.d.ts +43 -19
- package/dist/device/striplight.d.ts.map +1 -1
- package/dist/device/striplight.js +503 -262
- package/dist/device/striplight.js.map +1 -1
- package/dist/irdevice/airconditioner.d.ts +9 -12
- package/dist/irdevice/airconditioner.d.ts.map +1 -1
- package/dist/irdevice/airconditioner.js +275 -230
- package/dist/irdevice/airconditioner.js.map +1 -1
- package/dist/irdevice/airpurifier.d.ts +5 -3
- package/dist/irdevice/airpurifier.d.ts.map +1 -1
- package/dist/irdevice/airpurifier.js +151 -104
- package/dist/irdevice/airpurifier.js.map +1 -1
- package/dist/irdevice/camera.d.ts +11 -8
- package/dist/irdevice/camera.d.ts.map +1 -1
- package/dist/irdevice/camera.js +130 -86
- package/dist/irdevice/camera.js.map +1 -1
- package/dist/irdevice/fan.d.ts +10 -7
- package/dist/irdevice/fan.d.ts.map +1 -1
- package/dist/irdevice/fan.js +157 -109
- package/dist/irdevice/fan.js.map +1 -1
- package/dist/irdevice/light.d.ts +11 -8
- package/dist/irdevice/light.d.ts.map +1 -1
- package/dist/irdevice/light.js +134 -103
- package/dist/irdevice/light.js.map +1 -1
- package/dist/irdevice/other.d.ts +11 -8
- package/dist/irdevice/other.d.ts.map +1 -1
- package/dist/irdevice/other.js +142 -98
- package/dist/irdevice/other.js.map +1 -1
- package/dist/irdevice/tv.d.ts +12 -9
- package/dist/irdevice/tv.d.ts.map +1 -1
- package/dist/irdevice/tv.js +140 -93
- package/dist/irdevice/tv.js.map +1 -1
- package/dist/irdevice/vacuumcleaner.d.ts +9 -10
- package/dist/irdevice/vacuumcleaner.d.ts.map +1 -1
- package/dist/irdevice/vacuumcleaner.js +129 -89
- package/dist/irdevice/vacuumcleaner.js.map +1 -1
- package/dist/irdevice/waterheater.d.ts +8 -9
- package/dist/irdevice/waterheater.d.ts.map +1 -1
- package/dist/irdevice/waterheater.js +129 -89
- package/dist/irdevice/waterheater.js.map +1 -1
- package/dist/platform.d.ts +14 -12
- package/dist/platform.d.ts.map +1 -1
- package/dist/platform.js +479 -434
- package/dist/platform.js.map +1 -1
- package/dist/settings.d.ts +18 -11
- package/dist/settings.d.ts.map +1 -1
- package/dist/settings.js.map +1 -1
- package/package.json +12 -10
- package/src/device/bot.ts +654 -660
- package/src/device/colorbulb.ts +487 -344
- package/src/device/contact.ts +306 -241
- package/src/device/curtain.ts +546 -512
- package/src/device/humidifier.ts +453 -403
- package/src/device/lock.ts +311 -149
- package/src/device/meter.ts +351 -275
- package/src/device/meterplus.ts +369 -219
- package/src/device/motion.ts +282 -222
- package/src/device/plug.ts +296 -260
- package/src/device/striplight.ts +519 -289
- package/src/irdevice/airconditioner.ts +279 -241
- package/src/irdevice/airpurifier.ts +148 -103
- package/src/irdevice/camera.ts +128 -85
- package/src/irdevice/fan.ts +154 -106
- package/src/irdevice/light.ts +132 -103
- package/src/irdevice/other.ts +140 -97
- package/src/irdevice/tv.ts +139 -93
- package/src/irdevice/vacuumcleaner.ts +128 -89
- package/src/irdevice/waterheater.ts +127 -89
- package/src/platform.ts +469 -456
- package/src/settings.ts +18 -11
package/src/device/curtain.ts
CHANGED
|
@@ -5,6 +5,7 @@ import { MqttClient } from 'mqtt';
|
|
|
5
5
|
import { IncomingMessage } from 'http';
|
|
6
6
|
import { interval, Subject } from 'rxjs';
|
|
7
7
|
import { connectAsync } from 'async-mqtt';
|
|
8
|
+
import superStringify from 'super-stringify';
|
|
8
9
|
import { SwitchBotPlatform } from '../platform';
|
|
9
10
|
import { debounceTime, skipWhile, take, tap } from 'rxjs/operators';
|
|
10
11
|
import { Service, PlatformAccessory, CharacteristicValue } from 'homebridge';
|
|
@@ -35,7 +36,6 @@ export class Curtain {
|
|
|
35
36
|
// BLE Others
|
|
36
37
|
connected?: boolean;
|
|
37
38
|
switchbot!: switchbot;
|
|
38
|
-
SwitchToOpenAPI?: boolean;
|
|
39
39
|
serviceData!: serviceData;
|
|
40
40
|
spaceBetweenLevels!: number;
|
|
41
41
|
address!: ad['address'];
|
|
@@ -48,6 +48,9 @@ export class Curtain {
|
|
|
48
48
|
setNewTarget!: boolean;
|
|
49
49
|
setNewTargetTimer!: NodeJS.Timeout;
|
|
50
50
|
|
|
51
|
+
//MQTT stuff
|
|
52
|
+
mqttClient: MqttClient | null = null;
|
|
53
|
+
|
|
51
54
|
// Config
|
|
52
55
|
set_minStep!: number;
|
|
53
56
|
updateRate!: number;
|
|
@@ -63,8 +66,9 @@ export class Curtain {
|
|
|
63
66
|
curtainUpdateInProgress!: boolean;
|
|
64
67
|
doCurtainUpdate!: Subject<void>;
|
|
65
68
|
|
|
66
|
-
//
|
|
67
|
-
|
|
69
|
+
// Connection
|
|
70
|
+
private readonly BLE = (this.device.connectionType === 'BLE' || this.device.connectionType === 'BLE/OpenAPI');
|
|
71
|
+
private readonly OpenAPI = (this.device.connectionType === 'OpenAPI' || this.device.connectionType === 'BLE/OpenAPI');
|
|
68
72
|
|
|
69
73
|
constructor(private readonly platform: SwitchBotPlatform, private accessory: PlatformAccessory, public device: device & devicesConfig) {
|
|
70
74
|
// default placeholders
|
|
@@ -73,9 +77,7 @@ export class Curtain {
|
|
|
73
77
|
this.scan(device);
|
|
74
78
|
this.config(device);
|
|
75
79
|
this.setupMqtt(device);
|
|
76
|
-
this.
|
|
77
|
-
this.TargetPosition = 0;
|
|
78
|
-
this.PositionState = this.platform.Characteristic.PositionState.STOPPED;
|
|
80
|
+
this.context();
|
|
79
81
|
|
|
80
82
|
// this is subject we use to track when we need to POST changes to the SwitchBot API
|
|
81
83
|
this.doCurtainUpdate = new Subject();
|
|
@@ -137,33 +139,33 @@ export class Curtain {
|
|
|
137
139
|
|
|
138
140
|
// Light Sensor Service
|
|
139
141
|
if (device.curtain?.hide_lightsensor) {
|
|
140
|
-
this.debugLog(
|
|
142
|
+
this.debugLog(`${this.device.deviceType}: ${accessory.displayName} Removing Light Sensor Service`);
|
|
141
143
|
this.lightSensorService = this.accessory.getService(this.platform.Service.LightSensor);
|
|
142
144
|
accessory.removeService(this.lightSensorService!);
|
|
143
145
|
} else if (!this.lightSensorService) {
|
|
144
|
-
this.debugLog(
|
|
146
|
+
this.debugLog(`${this.device.deviceType}: ${accessory.displayName} Add Light Sensor Service`);
|
|
145
147
|
(this.lightSensorService =
|
|
146
148
|
this.accessory.getService(this.platform.Service.LightSensor) || this.accessory.addService(this.platform.Service.LightSensor)),
|
|
147
149
|
`${accessory.displayName} Light Sensor`;
|
|
148
150
|
|
|
149
151
|
this.lightSensorService.setCharacteristic(this.platform.Characteristic.Name, `${accessory.displayName} Light Sensor`);
|
|
150
152
|
} else {
|
|
151
|
-
this.debugLog(
|
|
153
|
+
this.debugLog(`${this.device.deviceType}: ${accessory.displayName} Light Sensor Service Not Added`);
|
|
152
154
|
}
|
|
153
155
|
|
|
154
156
|
// Battery Service
|
|
155
|
-
if (!
|
|
156
|
-
this.debugLog(
|
|
157
|
+
if (!this.BLE) {
|
|
158
|
+
this.debugLog(`${this.device.deviceType}: ${accessory.displayName} Removing Battery Service`);
|
|
157
159
|
this.batteryService = this.accessory.getService(this.platform.Service.Battery);
|
|
158
160
|
accessory.removeService(this.batteryService!);
|
|
159
|
-
} else if (
|
|
160
|
-
this.debugLog(
|
|
161
|
+
} else if (this.BLE && !this.batteryService) {
|
|
162
|
+
this.debugLog(`${this.device.deviceType}: ${accessory.displayName} Add Battery Service`);
|
|
161
163
|
(this.batteryService = this.accessory.getService(this.platform.Service.Battery) || this.accessory.addService(this.platform.Service.Battery)),
|
|
162
164
|
`${accessory.displayName} Battery`;
|
|
163
165
|
|
|
164
166
|
this.batteryService.setCharacteristic(this.platform.Characteristic.Name, `${accessory.displayName} Battery`);
|
|
165
167
|
} else {
|
|
166
|
-
this.debugLog(
|
|
168
|
+
this.debugLog(`${this.device.deviceType}: ${accessory.displayName} Battery Service Not Added`);
|
|
167
169
|
}
|
|
168
170
|
|
|
169
171
|
// Update Homekit
|
|
@@ -183,7 +185,7 @@ export class Curtain {
|
|
|
183
185
|
if (this.PositionState === this.platform.Characteristic.PositionState.STOPPED) {
|
|
184
186
|
return;
|
|
185
187
|
}
|
|
186
|
-
this.debugLog(
|
|
188
|
+
this.debugLog(`${this.device.deviceType}: ${accessory.displayName} Refresh Status When Moving, PositionState: ${this.PositionState}`);
|
|
187
189
|
await this.refreshStatus();
|
|
188
190
|
});
|
|
189
191
|
|
|
@@ -200,95 +202,64 @@ export class Curtain {
|
|
|
200
202
|
try {
|
|
201
203
|
await this.pushChanges();
|
|
202
204
|
} catch (e: any) {
|
|
203
|
-
this.errorLog(`Curtain: ${this.accessory.displayName} failed pushChanges`);
|
|
204
|
-
if (this.deviceLogging.includes('debug')) {
|
|
205
|
-
this.errorLog(`Curtain: ${this.accessory.displayName} failed pushChanges,` + ` Error Message: ${JSON.stringify(e.message)}`);
|
|
206
|
-
}
|
|
207
205
|
this.apiError(e);
|
|
206
|
+
this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} failed pushChanges with ${this.device.connectionType} Connection,`
|
|
207
|
+
+ ` Error Message: ${superStringify(e.message)}`);
|
|
208
208
|
}
|
|
209
209
|
this.curtainUpdateInProgress = false;
|
|
210
210
|
});
|
|
211
211
|
}
|
|
212
212
|
|
|
213
|
-
/*
|
|
214
|
-
* Publish MQTT message for topics of
|
|
215
|
-
* 'homebridge-switchbot/curtain/xx:xx:xx:xx:xx:xx'
|
|
216
|
-
*/
|
|
217
|
-
mqttPublish(topic: string, message: any) {
|
|
218
|
-
const mac = this.device.deviceId
|
|
219
|
-
?.toLowerCase()
|
|
220
|
-
.match(/[\s\S]{1,2}/g)
|
|
221
|
-
?.join(':');
|
|
222
|
-
const options = this.device.mqttPubOptions || {};
|
|
223
|
-
this.mqttClient?.publish(`homebridge-switchbot/curtain/${mac}/${topic}`, `${message}`, options);
|
|
224
|
-
this.debugLog(`Meter: ${this.accessory.displayName} MQTT message: ${topic}/${message} options:${JSON.stringify(options)}`);
|
|
225
|
-
}
|
|
226
|
-
|
|
227
|
-
/*
|
|
228
|
-
* Setup MQTT hadler if URL is specifed.
|
|
229
|
-
*/
|
|
230
|
-
async setupMqtt(device: device & devicesConfig): Promise<void> {
|
|
231
|
-
if (device.mqttURL) {
|
|
232
|
-
try {
|
|
233
|
-
this.mqttClient = await connectAsync(device.mqttURL, device.mqttOptions || {});
|
|
234
|
-
this.debugLog(`Meter: ${this.accessory.displayName} MQTT connection has been established successfully.`);
|
|
235
|
-
this.mqttClient.on('error', (e: Error) => {
|
|
236
|
-
this.errorLog(`Meter: ${this.accessory.displayName} Failed to publish MQTT messages. ${e}`);
|
|
237
|
-
});
|
|
238
|
-
} catch (e) {
|
|
239
|
-
this.mqttClient = null;
|
|
240
|
-
this.errorLog(`Meter: ${this.accessory.displayName} Failed to establish MQTT connection. ${e}`);
|
|
241
|
-
}
|
|
242
|
-
}
|
|
243
|
-
}
|
|
244
|
-
|
|
245
213
|
/**
|
|
246
214
|
* Parse the device status from the SwitchBot api
|
|
247
215
|
*/
|
|
248
216
|
async parseStatus(): Promise<void> {
|
|
249
|
-
if (this.
|
|
217
|
+
if (this.BLE) {
|
|
218
|
+
await this.BLEparseStatus();
|
|
219
|
+
} else if (this.OpenAPI && this.platform.config.credentials?.token) {
|
|
250
220
|
await this.openAPIparseStatus();
|
|
251
221
|
} else {
|
|
252
|
-
|
|
222
|
+
this.debugWarnLog(`${this.device.deviceType}: ${this.accessory.displayName} Connection Type:`
|
|
223
|
+
+ ` ${this.device.connectionType}, parseStatus will not happen.`);
|
|
253
224
|
}
|
|
254
225
|
}
|
|
255
226
|
|
|
256
227
|
async BLEparseStatus(): Promise<void> {
|
|
257
|
-
this.debugLog(
|
|
228
|
+
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} BLEparseStatus`);
|
|
258
229
|
// CurrentPosition
|
|
259
230
|
this.CurrentPosition = 100 - Number(this.position);
|
|
260
231
|
await this.setMinMax();
|
|
261
|
-
this.debugLog(
|
|
232
|
+
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} CurrentPosition ${this.CurrentPosition}`);
|
|
262
233
|
if (this.setNewTarget) {
|
|
263
|
-
this.infoLog(
|
|
234
|
+
this.infoLog(`${this.device.deviceType}: ${this.accessory.displayName} Checking Status ...`);
|
|
264
235
|
}
|
|
265
236
|
|
|
266
237
|
if (this.setNewTarget) {
|
|
267
238
|
await this.setMinMax();
|
|
268
239
|
if (this.TargetPosition > this.CurrentPosition) {
|
|
269
|
-
this.debugLog(
|
|
240
|
+
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Closing, CurrentPosition: ${this.CurrentPosition}`);
|
|
270
241
|
this.PositionState = this.platform.Characteristic.PositionState.INCREASING;
|
|
271
242
|
this.windowCoveringService.getCharacteristic(this.platform.Characteristic.PositionState).updateValue(this.PositionState);
|
|
272
|
-
this.debugLog(
|
|
243
|
+
this.debugLog(`${this.device.deviceType}: ${this.CurrentPosition} INCREASING PositionState: ${this.PositionState}`);
|
|
273
244
|
} else if (this.TargetPosition < this.CurrentPosition) {
|
|
274
|
-
this.debugLog(
|
|
245
|
+
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Opening, CurrentPosition: ${this.CurrentPosition}`);
|
|
275
246
|
this.PositionState = this.platform.Characteristic.PositionState.DECREASING;
|
|
276
247
|
this.windowCoveringService.getCharacteristic(this.platform.Characteristic.PositionState).updateValue(this.PositionState);
|
|
277
|
-
this.debugLog(
|
|
248
|
+
this.debugLog(`${this.device.deviceType}: ${this.CurrentPosition} DECREASING PositionState: ${this.PositionState}`);
|
|
278
249
|
} else {
|
|
279
|
-
this.debugLog(
|
|
250
|
+
this.debugLog(`${this.device.deviceType}: ${this.CurrentPosition} Standby, CurrentPosition: ${this.CurrentPosition}`);
|
|
280
251
|
this.PositionState = this.platform.Characteristic.PositionState.STOPPED;
|
|
281
252
|
this.windowCoveringService.getCharacteristic(this.platform.Characteristic.PositionState).updateValue(this.PositionState);
|
|
282
|
-
this.debugLog(
|
|
253
|
+
this.debugLog(`${this.device.deviceType}: ${this.CurrentPosition} STOPPED PositionState: ${this.PositionState}`);
|
|
283
254
|
}
|
|
284
255
|
} else {
|
|
285
|
-
this.debugLog(
|
|
256
|
+
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Standby, CurrentPosition: ${this.CurrentPosition}`);
|
|
286
257
|
this.TargetPosition = this.CurrentPosition;
|
|
287
258
|
this.PositionState = this.platform.Characteristic.PositionState.STOPPED;
|
|
288
|
-
this.debugLog(
|
|
259
|
+
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Stopped`);
|
|
289
260
|
}
|
|
290
261
|
this.debugLog(
|
|
291
|
-
|
|
262
|
+
`${this.device.deviceType}: ${this.accessory.displayName} CurrentPosition: ${this.CurrentPosition},` +
|
|
292
263
|
` TargetPosition: ${this.TargetPosition}, PositionState: ${this.PositionState},`,
|
|
293
264
|
);
|
|
294
265
|
|
|
@@ -301,42 +272,42 @@ export class Curtain {
|
|
|
301
272
|
switch (this.lightLevel) {
|
|
302
273
|
case 1:
|
|
303
274
|
this.CurrentAmbientLightLevel = this.set_minLux;
|
|
304
|
-
this.debugLog(
|
|
275
|
+
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} LightLevel: ${this.lightLevel}`);
|
|
305
276
|
break;
|
|
306
277
|
case 2:
|
|
307
278
|
this.CurrentAmbientLightLevel = (this.set_maxLux - this.set_minLux) / this.spaceBetweenLevels;
|
|
308
279
|
this.debugLog(
|
|
309
|
-
|
|
280
|
+
`${this.device.deviceType}: ${this.accessory.displayName} LightLevel: ${this.lightLevel},` +
|
|
310
281
|
` Calculation: ${(this.set_maxLux - this.set_minLux) / this.spaceBetweenLevels}`,
|
|
311
282
|
);
|
|
312
283
|
break;
|
|
313
284
|
case 3:
|
|
314
285
|
this.CurrentAmbientLightLevel = ((this.set_maxLux - this.set_minLux) / this.spaceBetweenLevels) * 2;
|
|
315
|
-
this.debugLog(
|
|
286
|
+
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} LightLevel: ${this.lightLevel}`);
|
|
316
287
|
break;
|
|
317
288
|
case 4:
|
|
318
289
|
this.CurrentAmbientLightLevel = ((this.set_maxLux - this.set_minLux) / this.spaceBetweenLevels) * 3;
|
|
319
|
-
this.debugLog(
|
|
290
|
+
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} LightLevel: ${this.lightLevel}`);
|
|
320
291
|
break;
|
|
321
292
|
case 5:
|
|
322
293
|
this.CurrentAmbientLightLevel = ((this.set_maxLux - this.set_minLux) / this.spaceBetweenLevels) * 4;
|
|
323
|
-
this.debugLog(
|
|
294
|
+
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} LightLevel: ${this.lightLevel}`);
|
|
324
295
|
break;
|
|
325
296
|
case 6:
|
|
326
297
|
this.CurrentAmbientLightLevel = ((this.set_maxLux - this.set_minLux) / this.spaceBetweenLevels) * 5;
|
|
327
|
-
this.debugLog(
|
|
298
|
+
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} LightLevel: ${this.lightLevel}`);
|
|
328
299
|
break;
|
|
329
300
|
case 7:
|
|
330
301
|
this.CurrentAmbientLightLevel = ((this.set_maxLux - this.set_minLux) / this.spaceBetweenLevels) * 6;
|
|
331
|
-
this.debugLog(
|
|
302
|
+
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} LightLevel: ${this.lightLevel}`);
|
|
332
303
|
break;
|
|
333
304
|
case 8:
|
|
334
305
|
this.CurrentAmbientLightLevel = ((this.set_maxLux - this.set_minLux) / this.spaceBetweenLevels) * 7;
|
|
335
|
-
this.debugLog(
|
|
306
|
+
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} LightLevel: ${this.lightLevel}`);
|
|
336
307
|
break;
|
|
337
308
|
case 9:
|
|
338
309
|
this.CurrentAmbientLightLevel = ((this.set_maxLux - this.set_minLux) / this.spaceBetweenLevels) * 8;
|
|
339
|
-
this.debugLog(
|
|
310
|
+
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} LightLevel: ${this.lightLevel}`);
|
|
340
311
|
break;
|
|
341
312
|
case 10:
|
|
342
313
|
default:
|
|
@@ -344,7 +315,8 @@ export class Curtain {
|
|
|
344
315
|
this.debugLog();
|
|
345
316
|
}
|
|
346
317
|
this.debugLog(
|
|
347
|
-
|
|
318
|
+
`${this.device.deviceType}: ${this.accessory.displayName} LightLevel: ${this.lightLevel},`
|
|
319
|
+
+ ` CurrentAmbientLightLevel: ${this.CurrentAmbientLightLevel}`,
|
|
348
320
|
);
|
|
349
321
|
}
|
|
350
322
|
// Battery
|
|
@@ -354,89 +326,87 @@ export class Curtain {
|
|
|
354
326
|
} else {
|
|
355
327
|
this.StatusLowBattery = this.platform.Characteristic.StatusLowBattery.BATTERY_LEVEL_NORMAL;
|
|
356
328
|
}
|
|
357
|
-
this.debugLog(
|
|
329
|
+
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} BatteryLevel: ${this.BatteryLevel},`
|
|
330
|
+
+` StatusLowBattery: ${this.StatusLowBattery}`);
|
|
358
331
|
}
|
|
359
332
|
|
|
360
333
|
async openAPIparseStatus(): Promise<void> {
|
|
361
|
-
|
|
362
|
-
|
|
334
|
+
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} openAPIparseStatus`);
|
|
335
|
+
// CurrentPosition
|
|
336
|
+
this.CurrentPosition = 100 - Number(this.slidePosition);
|
|
337
|
+
await this.setMinMax();
|
|
338
|
+
this.debugLog(`Curtain ${this.accessory.displayName} CurrentPosition: ${this.CurrentPosition}`);
|
|
339
|
+
if (this.setNewTarget) {
|
|
340
|
+
this.infoLog(`${this.device.deviceType}: ${this.accessory.displayName} Checking Status ...`);
|
|
363
341
|
}
|
|
364
|
-
if (this.platform.config.credentials?.token) {
|
|
365
|
-
this.debugLog(`Curtain: ${this.accessory.displayName} OpenAPI parseStatus`);
|
|
366
|
-
// CurrentPosition
|
|
367
|
-
this.CurrentPosition = 100 - Number(this.slidePosition);
|
|
368
|
-
await this.setMinMax();
|
|
369
|
-
this.debugLog(`Curtain ${this.accessory.displayName} CurrentPosition: ${this.CurrentPosition}`);
|
|
370
|
-
if (this.setNewTarget) {
|
|
371
|
-
this.infoLog(`Curtain: ${this.accessory.displayName} Checking Status ...`);
|
|
372
|
-
}
|
|
373
342
|
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
} else {
|
|
387
|
-
this.debugLog(`Curtain: ${this.CurrentPosition} Standby, CurrentPosition: ${this.CurrentPosition}`);
|
|
388
|
-
this.PositionState = this.platform.Characteristic.PositionState.STOPPED;
|
|
389
|
-
this.windowCoveringService.getCharacteristic(this.platform.Characteristic.PositionState).updateValue(this.PositionState);
|
|
390
|
-
this.debugLog(`Curtain: ${this.CurrentPosition} STOPPED PositionState: ${this.PositionState}`);
|
|
391
|
-
}
|
|
343
|
+
if (this.setNewTarget && this.moving) {
|
|
344
|
+
await this.setMinMax();
|
|
345
|
+
if (this.TargetPosition > this.CurrentPosition) {
|
|
346
|
+
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Closing, CurrentPosition: ${this.CurrentPosition} `);
|
|
347
|
+
this.PositionState = this.platform.Characteristic.PositionState.INCREASING;
|
|
348
|
+
this.windowCoveringService.getCharacteristic(this.platform.Characteristic.PositionState).updateValue(this.PositionState);
|
|
349
|
+
this.debugLog(`${this.device.deviceType}: ${this.CurrentPosition} INCREASING PositionState: ${this.PositionState}`);
|
|
350
|
+
} else if (this.TargetPosition < this.CurrentPosition) {
|
|
351
|
+
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Opening, CurrentPosition: ${this.CurrentPosition} `);
|
|
352
|
+
this.PositionState = this.platform.Characteristic.PositionState.DECREASING;
|
|
353
|
+
this.windowCoveringService.getCharacteristic(this.platform.Characteristic.PositionState).updateValue(this.PositionState);
|
|
354
|
+
this.debugLog(`${this.device.deviceType}: ${this.CurrentPosition} DECREASING PositionState: ${this.PositionState}`);
|
|
392
355
|
} else {
|
|
393
|
-
this.debugLog(
|
|
394
|
-
this.TargetPosition = this.CurrentPosition;
|
|
356
|
+
this.debugLog(`${this.device.deviceType}: ${this.CurrentPosition} Standby, CurrentPosition: ${this.CurrentPosition}`);
|
|
395
357
|
this.PositionState = this.platform.Characteristic.PositionState.STOPPED;
|
|
396
|
-
this.
|
|
358
|
+
this.windowCoveringService.getCharacteristic(this.platform.Characteristic.PositionState).updateValue(this.PositionState);
|
|
359
|
+
this.debugLog(`${this.device.deviceType}: ${this.CurrentPosition} STOPPED PositionState: ${this.PositionState}`);
|
|
397
360
|
}
|
|
398
|
-
|
|
399
|
-
|
|
361
|
+
} else {
|
|
362
|
+
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Standby, CurrentPosition: ${this.CurrentPosition}`);
|
|
363
|
+
this.TargetPosition = this.CurrentPosition;
|
|
364
|
+
this.PositionState = this.platform.Characteristic.PositionState.STOPPED;
|
|
365
|
+
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Stopped`);
|
|
366
|
+
}
|
|
367
|
+
this.debugLog(
|
|
368
|
+
`${this.device.deviceType}: ${this.accessory.displayName} CurrentPosition: ${this.CurrentPosition},` +
|
|
400
369
|
` TargetPosition: ${this.TargetPosition}, PositionState: ${this.PositionState},`,
|
|
401
|
-
|
|
370
|
+
);
|
|
402
371
|
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
}
|
|
415
|
-
this.debugLog(`Curtain: ${this.accessory.displayName} CurrentAmbientLightLevel: ${this.CurrentAmbientLightLevel}`);
|
|
372
|
+
if (!this.device.curtain?.hide_lightsensor) {
|
|
373
|
+
this.set_minLux = this.minLux();
|
|
374
|
+
this.set_maxLux = this.maxLux();
|
|
375
|
+
// Brightness
|
|
376
|
+
switch (this.brightness) {
|
|
377
|
+
case 'dim':
|
|
378
|
+
this.CurrentAmbientLightLevel = this.set_minLux;
|
|
379
|
+
break;
|
|
380
|
+
case 'bright':
|
|
381
|
+
default:
|
|
382
|
+
this.CurrentAmbientLightLevel = this.set_maxLux;
|
|
416
383
|
}
|
|
384
|
+
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} CurrentAmbientLightLevel: ${this.CurrentAmbientLightLevel}`);
|
|
417
385
|
}
|
|
418
386
|
}
|
|
419
387
|
|
|
420
388
|
async refreshStatus(): Promise<void> {
|
|
421
|
-
if (this.
|
|
389
|
+
if (this.BLE) {
|
|
422
390
|
await this.BLERefreshStatus();
|
|
423
|
-
} else {
|
|
391
|
+
} else if (this.OpenAPI && this.platform.config.credentials?.token) {
|
|
424
392
|
await this.openAPIRefreshStatus();
|
|
393
|
+
} else {
|
|
394
|
+
this.debugWarnLog(`${this.device.deviceType}: ${this.accessory.displayName} Connection Type:`
|
|
395
|
+
+ ` ${this.device.connectionType}, refreshStatus will not happen.`);
|
|
425
396
|
}
|
|
426
397
|
}
|
|
427
398
|
|
|
428
399
|
async BLERefreshStatus(): Promise<void> {
|
|
429
|
-
this.debugLog(
|
|
400
|
+
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} BLERefreshStatus`);
|
|
430
401
|
const switchbot = await this.platform.connectBLE();
|
|
431
402
|
// Convert to BLE Address
|
|
432
403
|
this.device.bleMac = this.device
|
|
433
404
|
.deviceId!.match(/.{1,2}/g)!
|
|
434
405
|
.join(':')
|
|
435
406
|
.toLowerCase();
|
|
436
|
-
this.debugLog(
|
|
407
|
+
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} BLE Address: ${this.device.bleMac}`);
|
|
437
408
|
this.getCustomBLEAddress(switchbot);
|
|
438
409
|
// Start to monitor advertisement packets
|
|
439
|
-
this.errorLog(`Color Bulb: ${this.accessory.displayName} switchbot: ${JSON.stringify(switchbot)}`);
|
|
440
410
|
if (switchbot !== false) {
|
|
441
411
|
switchbot
|
|
442
412
|
.startScan({
|
|
@@ -447,29 +417,25 @@ export class Curtain {
|
|
|
447
417
|
// Set an event hander
|
|
448
418
|
switchbot.onadvertisement = (ad: any) => {
|
|
449
419
|
this.address = ad.address;
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
this.infoLog(this.device.bleMac);
|
|
453
|
-
this.infoLog(`Curtain: ${this.accessory.displayName} BLE Address Found: ${this.address}`);
|
|
454
|
-
this.infoLog(`Curtain: ${this.accessory.displayName} Config BLE Address: ${this.device.bleMac}`);
|
|
455
|
-
}
|
|
420
|
+
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Config BLE Address: ${this.device.bleMac},`
|
|
421
|
+
+ ` BLE Address Found: ${this.address}`);
|
|
456
422
|
this.serviceData = ad.serviceData;
|
|
457
423
|
this.calibration = ad.serviceData.calibration;
|
|
458
424
|
this.battery = ad.serviceData.battery;
|
|
459
425
|
this.position = ad.serviceData.position;
|
|
460
426
|
this.lightLevel = ad.serviceData.lightLevel;
|
|
461
|
-
this.debugLog(
|
|
427
|
+
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} serviceData: ${superStringify(ad.serviceData)}`);
|
|
462
428
|
this.debugLog(
|
|
463
|
-
|
|
429
|
+
`${this.device.deviceType}: ${this.accessory.displayName} calibration: ${ad.serviceData.calibration}, ` +
|
|
464
430
|
`position: ${ad.serviceData.position}, lightLevel: ${ad.serviceData.lightLevel}, battery: ${ad.serviceData.battery}`,
|
|
465
431
|
);
|
|
466
432
|
|
|
467
433
|
if (this.serviceData) {
|
|
468
434
|
this.connected = true;
|
|
469
|
-
this.debugLog(
|
|
435
|
+
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} connected: ${this.connected}`);
|
|
470
436
|
} else {
|
|
471
437
|
this.connected = false;
|
|
472
|
-
this.debugLog(
|
|
438
|
+
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} connected: ${this.connected}`);
|
|
473
439
|
}
|
|
474
440
|
};
|
|
475
441
|
// Wait 2 seconds
|
|
@@ -479,164 +445,104 @@ export class Curtain {
|
|
|
479
445
|
// Stop to monitor
|
|
480
446
|
switchbot.stopScan();
|
|
481
447
|
if (this.connected) {
|
|
482
|
-
this.
|
|
448
|
+
this.BLEparseStatus();
|
|
483
449
|
this.updateHomeKitCharacteristics();
|
|
484
450
|
} else {
|
|
485
|
-
this.
|
|
486
|
-
if (this.platform.config.credentials?.token) {
|
|
487
|
-
this.warnLog(`Curtain: ${this.accessory.displayName} Using OpenAPI Connection`);
|
|
488
|
-
this.SwitchToOpenAPI = true;
|
|
489
|
-
await this.openAPIRefreshStatus();
|
|
490
|
-
}
|
|
451
|
+
await this.BLERefreshConnection(switchbot);
|
|
491
452
|
}
|
|
492
453
|
})
|
|
493
454
|
.catch(async (e: any) => {
|
|
494
|
-
this.errorLog(`Curtain: ${this.accessory.displayName} failed refreshStatus with BLE Connection`);
|
|
495
|
-
if (this.deviceLogging.includes('debug')) {
|
|
496
|
-
this.errorLog(
|
|
497
|
-
`Curtain: ${this.accessory.displayName} failed refreshStatus with BLE Connection,` + ` Error Message: ${JSON.stringify(e.message)}`,
|
|
498
|
-
);
|
|
499
|
-
}
|
|
500
|
-
if (this.platform.config.credentials?.token) {
|
|
501
|
-
this.warnLog(`Curtain: ${this.accessory.displayName} Using OpenAPI Connection`);
|
|
502
|
-
this.SwitchToOpenAPI = true;
|
|
503
|
-
await this.openAPIRefreshStatus();
|
|
504
|
-
}
|
|
505
455
|
this.apiError(e);
|
|
456
|
+
this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} failed BLERefreshStatus with ${this.device.connectionType}`
|
|
457
|
+
+ ` Connection, Error Message: ${superStringify(e.message)}`);
|
|
458
|
+
await this.BLERefreshConnection(switchbot);
|
|
506
459
|
});
|
|
507
460
|
} else {
|
|
508
|
-
await this.
|
|
509
|
-
}
|
|
510
|
-
}
|
|
511
|
-
|
|
512
|
-
async getCustomBLEAddress(switchbot: any) {
|
|
513
|
-
if (this.device.customBLEaddress && this.deviceLogging.includes('debug')) {
|
|
514
|
-
(async () => {
|
|
515
|
-
// Start to monitor advertisement packets
|
|
516
|
-
await switchbot.startScan({
|
|
517
|
-
model: 'c',
|
|
518
|
-
});
|
|
519
|
-
// Set an event handler
|
|
520
|
-
switchbot.onadvertisement = (ad: any) => {
|
|
521
|
-
this.warnLog(`Curtain: ${this.accessory.displayName} ad: ${JSON.stringify(ad, null, ' ')}`);
|
|
522
|
-
};
|
|
523
|
-
await switchbot.wait(10000);
|
|
524
|
-
// Stop to monitor
|
|
525
|
-
switchbot.stopScan();
|
|
526
|
-
})();
|
|
527
|
-
}
|
|
528
|
-
}
|
|
529
|
-
|
|
530
|
-
async BLEconnection(switchbot: any): Promise<void> {
|
|
531
|
-
this.errorLog(`Curtain: ${this.accessory.displayName} wasn't able to establish BLE Connection, node-switchbot: ${switchbot}`);
|
|
532
|
-
if (this.platform.config.credentials?.token) {
|
|
533
|
-
this.warnLog(`Curtain: ${this.accessory.displayName} Using OpenAPI Connection`);
|
|
534
|
-
this.SwitchToOpenAPI = true;
|
|
535
|
-
await this.openAPIRefreshStatus();
|
|
461
|
+
await this.BLERefreshConnection(switchbot);
|
|
536
462
|
}
|
|
537
463
|
}
|
|
538
464
|
|
|
539
465
|
async openAPIRefreshStatus(): Promise<void> {
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
this.debugLog(`Curtain: ${this.accessory.displayName} d: ${d}`);
|
|
568
|
-
});
|
|
569
|
-
|
|
570
|
-
res.on('end', () => {
|
|
571
|
-
try {
|
|
572
|
-
this.deviceStatus = JSON.parse(rawData);
|
|
573
|
-
this.debugLog(`Curtain: ${this.accessory.displayName} refreshStatus: ${JSON.stringify(this.deviceStatus)}`);
|
|
574
|
-
this.slidePosition = this.deviceStatus.body.slidePosition;
|
|
575
|
-
this.moving = this.deviceStatus.body.moving;
|
|
576
|
-
this.brightness = this.deviceStatus.body.brightness;
|
|
577
|
-
this.parseStatus();
|
|
578
|
-
this.updateHomeKitCharacteristics();
|
|
579
|
-
} catch (e: any) {
|
|
580
|
-
this.errorLog(`Curtain: ${this.accessory.displayName} error message: ${e.message}`);
|
|
581
|
-
}
|
|
582
|
-
});
|
|
466
|
+
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} openAPIRefreshStatus`);
|
|
467
|
+
try {
|
|
468
|
+
const t = Date.now();
|
|
469
|
+
const nonce = 'requestID';
|
|
470
|
+
const data = this.platform.config.credentials?.token + t + nonce;
|
|
471
|
+
const signTerm = crypto.createHmac('sha256', this.platform.config.credentials?.secret).update(Buffer.from(data, 'utf-8')).digest();
|
|
472
|
+
const sign = signTerm.toString('base64');
|
|
473
|
+
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} sign: ${sign}`);
|
|
474
|
+
const options = {
|
|
475
|
+
hostname: HostDomain,
|
|
476
|
+
port: 443,
|
|
477
|
+
path: `${DevicePath}/${this.device.deviceId}/status`,
|
|
478
|
+
method: 'GET',
|
|
479
|
+
headers: {
|
|
480
|
+
Authorization: this.platform.config.credentials?.token,
|
|
481
|
+
sign: sign,
|
|
482
|
+
nonce: nonce,
|
|
483
|
+
t: t,
|
|
484
|
+
'Content-Type': 'application/json',
|
|
485
|
+
},
|
|
486
|
+
};
|
|
487
|
+
const req = https.request(options, (res) => {
|
|
488
|
+
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} statusCode: ${res.statusCode}`);
|
|
489
|
+
let rawData = '';
|
|
490
|
+
res.on('data', (d) => {
|
|
491
|
+
rawData += d;
|
|
492
|
+
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} d: ${d}`);
|
|
583
493
|
});
|
|
584
|
-
|
|
585
|
-
|
|
494
|
+
res.on('end', () => {
|
|
495
|
+
try {
|
|
496
|
+
this.deviceStatus = JSON.parse(rawData);
|
|
497
|
+
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} refreshStatus: ${superStringify(this.deviceStatus)}`);
|
|
498
|
+
this.slidePosition = this.deviceStatus.body.slidePosition;
|
|
499
|
+
this.moving = this.deviceStatus.body.moving;
|
|
500
|
+
this.brightness = this.deviceStatus.body.brightness;
|
|
501
|
+
this.openAPIparseStatus();
|
|
502
|
+
this.updateHomeKitCharacteristics();
|
|
503
|
+
} catch (e: any) {
|
|
504
|
+
this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} error message: ${e.message}`);
|
|
505
|
+
}
|
|
586
506
|
});
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
this.errorLog(
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
}
|
|
507
|
+
});
|
|
508
|
+
req.on('error', (e: any) => {
|
|
509
|
+
this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} error message: ${e.message}`);
|
|
510
|
+
});
|
|
511
|
+
req.end();
|
|
512
|
+
} catch (e: any) {
|
|
513
|
+
this.apiError(e);
|
|
514
|
+
this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} failed openAPIRefreshStatus with ${this.device.connectionType}`
|
|
515
|
+
+ ` Connection, Error Message: ${superStringify(e.message)}`);
|
|
597
516
|
}
|
|
598
517
|
}
|
|
599
518
|
|
|
600
519
|
async pushChanges(): Promise<void> {
|
|
601
|
-
if (this.
|
|
602
|
-
await this.
|
|
603
|
-
} else {
|
|
520
|
+
if (this.BLE) {
|
|
521
|
+
await this.BLERefreshStatus();
|
|
522
|
+
} else if (this.OpenAPI && this.platform.config.credentials?.token) {
|
|
604
523
|
await this.openAPIpushChanges();
|
|
524
|
+
} else {
|
|
525
|
+
this.debugWarnLog(`${this.device.deviceType}: ${this.accessory.displayName} Connection Type:`
|
|
526
|
+
+ ` ${this.device.connectionType}, pushChanges will not happen.`);
|
|
605
527
|
}
|
|
606
528
|
interval(this.updateRate * 1000)
|
|
607
|
-
.pipe(take(
|
|
529
|
+
.pipe(take(1))
|
|
608
530
|
.subscribe(async () => {
|
|
609
531
|
await this.refreshStatus();
|
|
610
532
|
});
|
|
611
533
|
}
|
|
612
534
|
|
|
613
535
|
async BLEpushChanges(): Promise<void> {
|
|
536
|
+
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} BLEpushChanges`);
|
|
614
537
|
if (this.TargetPosition !== this.CurrentPosition) {
|
|
615
|
-
this.debugLog(`Curtain: ${this.accessory.displayName} BLE pushChanges`);
|
|
616
538
|
const switchbot = await this.platform.connectBLE();
|
|
617
539
|
// Convert to BLE Address
|
|
618
540
|
this.device.bleMac = this.device
|
|
619
541
|
.deviceId!.match(/.{1,2}/g)!
|
|
620
542
|
.join(':')
|
|
621
543
|
.toLowerCase();
|
|
622
|
-
this.debugLog(
|
|
623
|
-
|
|
624
|
-
if (this.device.curtain?.setOpenMode === '1') {
|
|
625
|
-
this.setPositionMode = 1;
|
|
626
|
-
this.Mode = 'Silent Mode';
|
|
627
|
-
} else {
|
|
628
|
-
this.setPositionMode = 0;
|
|
629
|
-
this.Mode = 'Performance Mode';
|
|
630
|
-
}
|
|
631
|
-
} else {
|
|
632
|
-
if (this.device.curtain?.setCloseMode === '1') {
|
|
633
|
-
this.setPositionMode = 1;
|
|
634
|
-
this.Mode = 'Silent Mode';
|
|
635
|
-
} else {
|
|
636
|
-
this.setPositionMode = 0;
|
|
637
|
-
this.Mode = 'Performance Mode';
|
|
638
|
-
}
|
|
639
|
-
}
|
|
544
|
+
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} BLE Address: ${this.device.bleMac}`);
|
|
545
|
+
this.SilentPerformance();
|
|
640
546
|
const adjustedMode = this.setPositionMode || null;
|
|
641
547
|
if (adjustedMode === null) {
|
|
642
548
|
this.Mode = 'Default Mode';
|
|
@@ -645,256 +551,290 @@ export class Curtain {
|
|
|
645
551
|
if (switchbot !== false) {
|
|
646
552
|
switchbot
|
|
647
553
|
.discover({ model: 'c', quick: true, id: this.device.bleMac })
|
|
648
|
-
.then((device_list) => {
|
|
554
|
+
.then((device_list: any) => {
|
|
649
555
|
this.infoLog(`${this.accessory.displayName} Target Position: ${this.TargetPosition}`);
|
|
650
556
|
return device_list[0].runToPos(100 - Number(this.TargetPosition), adjustedMode);
|
|
651
557
|
})
|
|
652
558
|
.then(() => {
|
|
653
|
-
this.debugLog(
|
|
559
|
+
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Done.`);
|
|
654
560
|
})
|
|
655
561
|
.catch(async (e: any) => {
|
|
656
|
-
this.errorLog(`Curtain: ${this.accessory.displayName} failed pushChanges with BLE Connection`);
|
|
657
|
-
if (this.deviceLogging.includes('debug')) {
|
|
658
|
-
this.errorLog(
|
|
659
|
-
`Curtain: ${this.accessory.displayName} failed pushChanges with BLE Connection,` + ` Error Message: ${JSON.stringify(e.message)}`,
|
|
660
|
-
);
|
|
661
|
-
}
|
|
662
|
-
if (this.platform.config.credentials?.token) {
|
|
663
|
-
this.warnLog(`Curtain: ${this.accessory.displayName} Using OpenAPI Connection`);
|
|
664
|
-
await this.openAPIpushChanges();
|
|
665
|
-
}
|
|
666
562
|
this.apiError(e);
|
|
563
|
+
this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} failed BLEpushChanges with ${this.device.connectionType}`
|
|
564
|
+
+ ` Connection, Error Message: ${superStringify(e.message)}`);
|
|
565
|
+
await this.BLEPushConnection();
|
|
667
566
|
});
|
|
668
567
|
} else {
|
|
669
|
-
this.errorLog(
|
|
670
|
-
|
|
671
|
-
this.warnLog(`Curtain: ${this.accessory.displayName} Using OpenAPI Connection`);
|
|
672
|
-
await this.openAPIpushChanges();
|
|
673
|
-
}
|
|
568
|
+
this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} wasn't able to establish BLE Connection`);
|
|
569
|
+
await this.BLEPushConnection();
|
|
674
570
|
}
|
|
675
571
|
} else {
|
|
676
|
-
this.debugLog(
|
|
677
|
-
`Curtain: ${this.accessory.displayName} No BLE Changes, CurrentPosition & TargetPosition Are the Same.` +
|
|
572
|
+
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} No BLEpushChanges, CurrentPosition & TargetPosition Are the Same.` +
|
|
678
573
|
` CurrentPosition: ${this.CurrentPosition}, TargetPosition ${this.TargetPosition}`,
|
|
679
574
|
);
|
|
680
575
|
}
|
|
681
576
|
}
|
|
682
577
|
|
|
683
578
|
async openAPIpushChanges(): Promise<void> {
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
this.setPositionMode = this.device.curtain?.setOpenMode;
|
|
701
|
-
} else {
|
|
702
|
-
this.setPositionMode = this.device.curtain?.setCloseMode;
|
|
703
|
-
}
|
|
704
|
-
if (this.setPositionMode === '1') {
|
|
705
|
-
this.Mode = 'Silent Mode';
|
|
706
|
-
} else if (this.setPositionMode === '0') {
|
|
707
|
-
this.Mode = 'Performance Mode';
|
|
708
|
-
} else {
|
|
709
|
-
this.Mode = 'Default Mode';
|
|
710
|
-
}
|
|
711
|
-
this.debugLog(`${this.accessory.displayName} Mode: ${this.Mode}`);
|
|
712
|
-
const adjustedMode = this.setPositionMode || 'ff';
|
|
713
|
-
const body = JSON.stringify({
|
|
714
|
-
'command': 'setPosition',
|
|
715
|
-
'parameter': `0,${adjustedMode},${adjustedTargetPosition}`,
|
|
716
|
-
'commandType': 'command',
|
|
717
|
-
});
|
|
718
|
-
this.infoLog(`Curtain: ${this.accessory.displayName} Sending request to SwitchBot API. body: ${body},`);
|
|
719
|
-
const options = {
|
|
720
|
-
hostname: HostDomain,
|
|
721
|
-
port: 443,
|
|
722
|
-
path: `${DevicePath}/${this.device.deviceId}/commands`,
|
|
723
|
-
method: 'POST',
|
|
724
|
-
headers: {
|
|
725
|
-
'Authorization': this.platform.config.credentials?.token,
|
|
726
|
-
'sign': sign,
|
|
727
|
-
'nonce': nonce,
|
|
728
|
-
't': t,
|
|
729
|
-
'Content-Type': 'application/json',
|
|
730
|
-
'Content-Length': body.length,
|
|
731
|
-
},
|
|
732
|
-
};
|
|
733
|
-
const req = https.request(options, res => {
|
|
734
|
-
this.debugLog(`Curtain: ${this.accessory.displayName} statusCode: ${res.statusCode}`);
|
|
735
|
-
this.statusCode({ res });
|
|
736
|
-
res.on('data', d => {
|
|
737
|
-
this.debugLog(`Curtain: ${this.accessory.displayName} d: ${d}`);
|
|
738
|
-
});
|
|
739
|
-
});
|
|
740
|
-
req.on('error', (e: any) => {
|
|
741
|
-
this.errorLog(`Curtain: ${this.accessory.displayName} error message: ${e.message}`);
|
|
742
|
-
});
|
|
743
|
-
req.write(body);
|
|
744
|
-
req.end();
|
|
745
|
-
this.debugLog(`Curtain: ${this.accessory.displayName} openAPIpushChanges: ${JSON.stringify(req)}`);
|
|
579
|
+
try {
|
|
580
|
+
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} OpenAPI pushChanges`);
|
|
581
|
+
if (this.TargetPosition !== this.CurrentPosition) {
|
|
582
|
+
// Make Push On request to the API
|
|
583
|
+
const t = Date.now();
|
|
584
|
+
const nonce = 'requestID';
|
|
585
|
+
const data = this.platform.config.credentials?.token + t + nonce;
|
|
586
|
+
const signTerm = crypto.createHmac('sha256', this.platform.config.credentials?.secret)
|
|
587
|
+
.update(Buffer.from(data, 'utf-8'))
|
|
588
|
+
.digest();
|
|
589
|
+
const sign = signTerm.toString('base64');
|
|
590
|
+
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} sign: ${sign}`);
|
|
591
|
+
this.debugLog(`Pushing ${this.TargetPosition}`);
|
|
592
|
+
const adjustedTargetPosition = 100 - Number(this.TargetPosition);
|
|
593
|
+
if (this.TargetPosition > 50) {
|
|
594
|
+
this.setPositionMode = this.device.curtain?.setOpenMode;
|
|
746
595
|
} else {
|
|
747
|
-
this.
|
|
748
|
-
`Curtain: ${this.accessory.displayName} No OpenAPI Changes, CurrentPosition & TargetPosition Are the Same.` +
|
|
749
|
-
` CurrentPosition: ${this.CurrentPosition}, TargetPosition ${this.TargetPosition}`,
|
|
750
|
-
);
|
|
596
|
+
this.setPositionMode = this.device.curtain?.setCloseMode;
|
|
751
597
|
}
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
if (this.
|
|
755
|
-
this.
|
|
756
|
-
|
|
757
|
-
|
|
598
|
+
if (this.setPositionMode === '1') {
|
|
599
|
+
this.Mode = 'Silent Mode';
|
|
600
|
+
} else if (this.setPositionMode === '0') {
|
|
601
|
+
this.Mode = 'Performance Mode';
|
|
602
|
+
} else {
|
|
603
|
+
this.Mode = 'Default Mode';
|
|
758
604
|
}
|
|
759
|
-
this.
|
|
605
|
+
this.debugLog(`${this.accessory.displayName} Mode: ${this.Mode}`);
|
|
606
|
+
const adjustedMode = this.setPositionMode || 'ff';
|
|
607
|
+
const body = superStringify({
|
|
608
|
+
'command': 'setPosition',
|
|
609
|
+
'parameter': `0,${adjustedMode},${adjustedTargetPosition}`,
|
|
610
|
+
'commandType': 'command',
|
|
611
|
+
});
|
|
612
|
+
this.infoLog(`${this.device.deviceType}: ${this.accessory.displayName} Sending request to SwitchBot API. body: ${body},`);
|
|
613
|
+
const options = {
|
|
614
|
+
hostname: HostDomain,
|
|
615
|
+
port: 443,
|
|
616
|
+
path: `${DevicePath}/${this.device.deviceId}/commands`,
|
|
617
|
+
method: 'POST',
|
|
618
|
+
headers: {
|
|
619
|
+
'Authorization': this.platform.config.credentials?.token,
|
|
620
|
+
'sign': sign,
|
|
621
|
+
'nonce': nonce,
|
|
622
|
+
't': t,
|
|
623
|
+
'Content-Type': 'application/json',
|
|
624
|
+
'Content-Length': body.length,
|
|
625
|
+
},
|
|
626
|
+
};
|
|
627
|
+
const req = https.request(options, res => {
|
|
628
|
+
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} openAPIpushChanges statusCode: ${res.statusCode}`);
|
|
629
|
+
this.statusCode({ res });
|
|
630
|
+
res.on('data', d => {
|
|
631
|
+
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} d: ${d}`);
|
|
632
|
+
});
|
|
633
|
+
});
|
|
634
|
+
req.on('error', (e: any) => {
|
|
635
|
+
this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} error message: ${e.message}`);
|
|
636
|
+
});
|
|
637
|
+
req.write(body);
|
|
638
|
+
req.end();
|
|
639
|
+
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} openAPIpushChanges: ${superStringify(req)}`);
|
|
640
|
+
} else {
|
|
641
|
+
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} No OpenAPI Changes, CurrentPosition & TargetPosition Are the Same.`
|
|
642
|
+
+` CurrentPosition: ${this.CurrentPosition}, TargetPosition ${this.TargetPosition}`,
|
|
643
|
+
);
|
|
760
644
|
}
|
|
645
|
+
} catch (e: any) {
|
|
646
|
+
this.apiError(e);
|
|
647
|
+
this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} failed pushBrightnessChanges with ${this.device.connectionType}`
|
|
648
|
+
+ ` Connection, Error Message: ${superStringify(e.message)}`,
|
|
649
|
+
);
|
|
761
650
|
}
|
|
762
651
|
}
|
|
763
652
|
|
|
653
|
+
/**
|
|
654
|
+
* Handle requests to set the value of the "Target Position" characteristic
|
|
655
|
+
*/
|
|
656
|
+
async TargetPositionSet(value: CharacteristicValue): Promise<void> {
|
|
657
|
+
if (this.TargetPosition === this.accessory.context.TargetPosition) {
|
|
658
|
+
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} No Changes, Set TargetPosition: ${value}`);
|
|
659
|
+
} else {
|
|
660
|
+
this.infoLog(`${this.device.deviceType}: ${this.accessory.displayName} Set TargetPosition: ${value}`);
|
|
661
|
+
}
|
|
662
|
+
|
|
663
|
+
this.TargetPosition = value;
|
|
664
|
+
this.mqttPublish('TargetPosition', this.TargetPosition);
|
|
665
|
+
|
|
666
|
+
await this.setMinMax();
|
|
667
|
+
if (value > this.CurrentPosition) {
|
|
668
|
+
this.PositionState = this.platform.Characteristic.PositionState.INCREASING;
|
|
669
|
+
this.setNewTarget = true;
|
|
670
|
+
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} value: ${value}, CurrentPosition: ${this.CurrentPosition}`);
|
|
671
|
+
} else if (value < this.CurrentPosition) {
|
|
672
|
+
this.PositionState = this.platform.Characteristic.PositionState.DECREASING;
|
|
673
|
+
this.setNewTarget = true;
|
|
674
|
+
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} value: ${value}, CurrentPosition: ${this.CurrentPosition}`);
|
|
675
|
+
} else {
|
|
676
|
+
this.PositionState = this.platform.Characteristic.PositionState.STOPPED;
|
|
677
|
+
this.setNewTarget = false;
|
|
678
|
+
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} value: ${value}, CurrentPosition: ${this.CurrentPosition}`);
|
|
679
|
+
}
|
|
680
|
+
this.windowCoveringService.setCharacteristic(this.platform.Characteristic.PositionState, this.PositionState);
|
|
681
|
+
this.windowCoveringService.getCharacteristic(this.platform.Characteristic.PositionState).updateValue(this.PositionState);
|
|
682
|
+
|
|
683
|
+
/**
|
|
684
|
+
* If Curtain movement time is short, the moving flag from backend is always false.
|
|
685
|
+
* The minimum time depends on the network control latency.
|
|
686
|
+
*/
|
|
687
|
+
clearTimeout(this.setNewTargetTimer);
|
|
688
|
+
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} updateRate: ${this.updateRate}`);
|
|
689
|
+
if (this.setNewTarget) {
|
|
690
|
+
this.setNewTargetTimer = setTimeout(() => {
|
|
691
|
+
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} setNewTarget ${this.setNewTarget} timeout`);
|
|
692
|
+
this.setNewTarget = false;
|
|
693
|
+
}, this.updateRate * 1000);
|
|
694
|
+
}
|
|
695
|
+
this.doCurtainUpdate.next();
|
|
696
|
+
}
|
|
697
|
+
|
|
764
698
|
async updateHomeKitCharacteristics(): Promise<void> {
|
|
765
699
|
await this.setMinMax();
|
|
766
700
|
if (this.CurrentPosition === undefined || Number.isNaN(this.CurrentPosition)) {
|
|
767
|
-
this.debugLog(
|
|
701
|
+
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} CurrentPosition: ${this.CurrentPosition}`);
|
|
768
702
|
} else {
|
|
703
|
+
this.accessory.context.CurrentPosition = this.CurrentPosition;
|
|
769
704
|
this.windowCoveringService.updateCharacteristic(this.platform.Characteristic.CurrentPosition, Number(this.CurrentPosition));
|
|
770
|
-
this.debugLog(
|
|
705
|
+
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} updateCharacteristic CurrentPosition: ${this.CurrentPosition}`);
|
|
771
706
|
this.mqttPublish('CurrentPosition', this.CurrentPosition);
|
|
772
707
|
}
|
|
773
708
|
if (this.PositionState === undefined) {
|
|
774
|
-
this.debugLog(
|
|
709
|
+
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} PositionState: ${this.PositionState}`);
|
|
775
710
|
} else {
|
|
711
|
+
this.accessory.context.PositionState = this.PositionState;
|
|
776
712
|
this.windowCoveringService.updateCharacteristic(this.platform.Characteristic.PositionState, Number(this.PositionState));
|
|
777
|
-
this.debugLog(
|
|
713
|
+
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} updateCharacteristic PositionState: ${this.PositionState}`);
|
|
778
714
|
this.mqttPublish('PositionState', this.PositionState);
|
|
779
715
|
}
|
|
780
716
|
if (this.TargetPosition === undefined || Number.isNaN(this.TargetPosition)) {
|
|
781
|
-
this.debugLog(
|
|
717
|
+
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} TargetPosition: ${this.TargetPosition}`);
|
|
782
718
|
} else {
|
|
719
|
+
this.accessory.context.TargetPosition = this.TargetPosition;
|
|
783
720
|
this.windowCoveringService.updateCharacteristic(this.platform.Characteristic.TargetPosition, Number(this.TargetPosition));
|
|
784
|
-
this.debugLog(
|
|
721
|
+
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} updateCharacteristic TargetPosition: ${this.TargetPosition}`);
|
|
785
722
|
this.mqttPublish('TargetPosition', this.TargetPosition);
|
|
786
723
|
}
|
|
787
724
|
if (!this.device.curtain?.hide_lightsensor) {
|
|
788
725
|
if (this.CurrentAmbientLightLevel === undefined || Number.isNaN(this.CurrentAmbientLightLevel)) {
|
|
789
|
-
this.debugLog(
|
|
726
|
+
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} CurrentAmbientLightLevel: ${this.CurrentAmbientLightLevel}`);
|
|
790
727
|
} else {
|
|
728
|
+
this.accessory.context.CurrentAmbientLightLevel = this.CurrentAmbientLightLevel;
|
|
791
729
|
this.lightSensorService?.updateCharacteristic(this.platform.Characteristic.CurrentAmbientLightLevel, this.CurrentAmbientLightLevel);
|
|
792
|
-
this.debugLog(
|
|
730
|
+
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName}`
|
|
731
|
+
+ ` updateCharacteristic CurrentAmbientLightLevel: ${this.CurrentAmbientLightLevel}`);
|
|
793
732
|
this.mqttPublish('CurrentAmbientLightLevel', this.CurrentAmbientLightLevel);
|
|
794
733
|
}
|
|
795
734
|
}
|
|
796
|
-
if (this.
|
|
735
|
+
if (this.BLE) {
|
|
797
736
|
if (this.BatteryLevel === undefined) {
|
|
798
|
-
this.debugLog(
|
|
737
|
+
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} BatteryLevel: ${this.BatteryLevel}`);
|
|
799
738
|
} else {
|
|
739
|
+
this.accessory.context.BatteryLevel = this.BatteryLevel;
|
|
800
740
|
this.batteryService?.updateCharacteristic(this.platform.Characteristic.BatteryLevel, this.BatteryLevel);
|
|
801
|
-
this.debugLog(
|
|
741
|
+
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} updateCharacteristic BatteryLevel: ${this.BatteryLevel}`);
|
|
802
742
|
this.mqttPublish('BatteryLevel', this.BatteryLevel);
|
|
803
743
|
}
|
|
804
744
|
if (this.StatusLowBattery === undefined) {
|
|
805
|
-
this.debugLog(
|
|
745
|
+
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} StatusLowBattery: ${this.StatusLowBattery}`);
|
|
806
746
|
} else {
|
|
747
|
+
this.accessory.context.StatusLowBattery = this.StatusLowBattery;
|
|
807
748
|
this.batteryService?.updateCharacteristic(this.platform.Characteristic.StatusLowBattery, this.StatusLowBattery);
|
|
808
|
-
this.debugLog(
|
|
749
|
+
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} updateCharacteristic StatusLowBattery: ${this.StatusLowBattery}`);
|
|
809
750
|
this.mqttPublish('StatusLowBattery', this.StatusLowBattery);
|
|
810
751
|
}
|
|
811
752
|
}
|
|
812
753
|
}
|
|
813
754
|
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
}
|
|
825
|
-
|
|
755
|
+
/*
|
|
756
|
+
* Publish MQTT message for topics of
|
|
757
|
+
* 'homebridge-switchbot/curtain/xx:xx:xx:xx:xx:xx'
|
|
758
|
+
*/
|
|
759
|
+
mqttPublish(topic: string, message: any) {
|
|
760
|
+
const mac = this.device.deviceId
|
|
761
|
+
?.toLowerCase()
|
|
762
|
+
.match(/[\s\S]{1,2}/g)
|
|
763
|
+
?.join(':');
|
|
764
|
+
const options = this.device.mqttPubOptions || {};
|
|
765
|
+
this.mqttClient?.publish(`homebridge-switchbot/curtain/${mac}/${topic}`, `${message}`, options);
|
|
766
|
+
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} MQTT message: ${topic}/${message} options:${superStringify(options)}`);
|
|
826
767
|
}
|
|
827
768
|
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
this.
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
this.
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
this.errorLog(`Curtain: ${this.accessory.displayName} Hub Device is offline. Hub: ${this.device.hubDeviceId}`);
|
|
844
|
-
break;
|
|
845
|
-
case 190:
|
|
846
|
-
this.errorLog(
|
|
847
|
-
`Curtain: ${this.accessory.displayName} Device internal error due to device states not synchronized with server,` +
|
|
848
|
-
` Or command: ${JSON.stringify(res)} format is invalid`,
|
|
849
|
-
);
|
|
850
|
-
break;
|
|
851
|
-
case 100:
|
|
852
|
-
this.debugLog(`Curtain: ${this.accessory.displayName} Command successfully sent.`);
|
|
853
|
-
break;
|
|
854
|
-
default:
|
|
855
|
-
this.debugLog(`Curtain: ${this.accessory.displayName} Unknown statusCode.`);
|
|
769
|
+
/*
|
|
770
|
+
* Setup MQTT hadler if URL is specifed.
|
|
771
|
+
*/
|
|
772
|
+
async setupMqtt(device: device & devicesConfig): Promise<void> {
|
|
773
|
+
if (device.mqttURL) {
|
|
774
|
+
try {
|
|
775
|
+
this.mqttClient = await connectAsync(device.mqttURL, device.mqttOptions || {});
|
|
776
|
+
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} MQTT connection has been established successfully.`);
|
|
777
|
+
this.mqttClient.on('error', (e: Error) => {
|
|
778
|
+
this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} Failed to publish MQTT messages. ${e}`);
|
|
779
|
+
});
|
|
780
|
+
} catch (e) {
|
|
781
|
+
this.mqttClient = null;
|
|
782
|
+
this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} Failed to establish MQTT connection. ${e}`);
|
|
783
|
+
}
|
|
856
784
|
}
|
|
857
785
|
}
|
|
858
786
|
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
787
|
+
async getCustomBLEAddress(switchbot: any) {
|
|
788
|
+
if (this.device.customBLEaddress && this.deviceLogging.includes('debug')) {
|
|
789
|
+
(async () => {
|
|
790
|
+
// Start to monitor advertisement packets
|
|
791
|
+
await switchbot.startScan({
|
|
792
|
+
model: 'c',
|
|
793
|
+
});
|
|
794
|
+
// Set an event handler
|
|
795
|
+
switchbot.onadvertisement = (ad: any) => {
|
|
796
|
+
this.warnLog(`${this.device.deviceType}: ${this.accessory.displayName} ad: ${superStringify(ad, null, ' ')}`);
|
|
797
|
+
};
|
|
798
|
+
await switchbot.wait(10000);
|
|
799
|
+
// Stop to monitor
|
|
800
|
+
switchbot.stopScan();
|
|
801
|
+
})();
|
|
802
|
+
}
|
|
803
|
+
}
|
|
864
804
|
|
|
865
|
-
|
|
866
|
-
this.
|
|
805
|
+
async BLEPushConnection() {
|
|
806
|
+
if (this.platform.config.credentials?.token && this.device.connectionType === 'BLE/OpenAPI') {
|
|
807
|
+
this.warnLog(`${this.device.deviceType}: ${this.accessory.displayName} Using OpenAPI Connection to Push Changes`);
|
|
808
|
+
await this.openAPIpushChanges();
|
|
809
|
+
}
|
|
810
|
+
}
|
|
867
811
|
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
this.
|
|
872
|
-
this.
|
|
873
|
-
} else if (value < this.CurrentPosition) {
|
|
874
|
-
this.PositionState = this.platform.Characteristic.PositionState.DECREASING;
|
|
875
|
-
this.setNewTarget = true;
|
|
876
|
-
this.debugLog(`Curtain: ${this.accessory.displayName} value: ${value}, CurrentPosition: ${this.CurrentPosition}`);
|
|
877
|
-
} else {
|
|
878
|
-
this.PositionState = this.platform.Characteristic.PositionState.STOPPED;
|
|
879
|
-
this.setNewTarget = false;
|
|
880
|
-
this.debugLog(`Curtain: ${this.accessory.displayName} value: ${value}, CurrentPosition: ${this.CurrentPosition}`);
|
|
812
|
+
async BLERefreshConnection(switchbot: any): Promise<void> {
|
|
813
|
+
this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} wasn't able to establish BLE Connection, node-switchbot: ${switchbot}`);
|
|
814
|
+
if (this.platform.config.credentials?.token && this.device.connectionType === 'BLE/OpenAPI') {
|
|
815
|
+
this.warnLog(`${this.device.deviceType}: ${this.accessory.displayName} Using OpenAPI Connection to Refresh Status`);
|
|
816
|
+
await this.openAPIRefreshStatus();
|
|
881
817
|
}
|
|
882
|
-
|
|
883
|
-
this.windowCoveringService.getCharacteristic(this.platform.Characteristic.PositionState).updateValue(this.PositionState);
|
|
818
|
+
}
|
|
884
819
|
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
820
|
+
async SilentPerformance() {
|
|
821
|
+
if (this.TargetPosition > 50) {
|
|
822
|
+
if (this.device.curtain?.setOpenMode === '1') {
|
|
823
|
+
this.setPositionMode = 1;
|
|
824
|
+
this.Mode = 'Silent Mode';
|
|
825
|
+
} else {
|
|
826
|
+
this.setPositionMode = 0;
|
|
827
|
+
this.Mode = 'Performance Mode';
|
|
828
|
+
}
|
|
829
|
+
} else {
|
|
830
|
+
if (this.device.curtain?.setCloseMode === '1') {
|
|
831
|
+
this.setPositionMode = 1;
|
|
832
|
+
this.Mode = 'Silent Mode';
|
|
833
|
+
} else {
|
|
834
|
+
this.setPositionMode = 0;
|
|
835
|
+
this.Mode = 'Performance Mode';
|
|
836
|
+
}
|
|
896
837
|
}
|
|
897
|
-
this.doCurtainUpdate.next();
|
|
898
838
|
}
|
|
899
839
|
|
|
900
840
|
async setMinMax(): Promise<void> {
|
|
@@ -910,92 +850,120 @@ export class Curtain {
|
|
|
910
850
|
}
|
|
911
851
|
}
|
|
912
852
|
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
if (device.ble) {
|
|
919
|
-
config['ble'] = device.ble;
|
|
920
|
-
}
|
|
921
|
-
if (device.logging !== undefined) {
|
|
922
|
-
config['logging'] = device.logging;
|
|
923
|
-
}
|
|
924
|
-
if (device.refreshRate !== undefined) {
|
|
925
|
-
config['refreshRate'] = device.refreshRate;
|
|
926
|
-
}
|
|
927
|
-
if (device.scanDuration !== undefined) {
|
|
928
|
-
config['scanDuration'] = device.scanDuration;
|
|
929
|
-
}
|
|
930
|
-
if (Object.entries(config).length !== 0) {
|
|
931
|
-
this.infoLog(`Curtain: ${this.accessory.displayName} Config: ${JSON.stringify(config)}`);
|
|
853
|
+
minStep(device: device & devicesConfig): number {
|
|
854
|
+
if (device.curtain?.set_minStep) {
|
|
855
|
+
this.set_minStep = device.curtain?.set_minStep;
|
|
856
|
+
} else {
|
|
857
|
+
this.set_minStep = 1;
|
|
932
858
|
}
|
|
859
|
+
return this.set_minStep;
|
|
933
860
|
}
|
|
934
861
|
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
this.
|
|
940
|
-
} else if (this.platform.config.options!.refreshRate) {
|
|
941
|
-
this.deviceRefreshRate = this.accessory.context.refreshRate = this.platform.config.options!.refreshRate;
|
|
942
|
-
this.debugLog(`Curtain: ${this.accessory.displayName} Using Platform Config refreshRate: ${this.deviceRefreshRate}`);
|
|
862
|
+
minLux(): number {
|
|
863
|
+
if (this.device.curtain?.set_minLux) {
|
|
864
|
+
this.set_minLux = this.device.curtain?.set_minLux;
|
|
865
|
+
} else {
|
|
866
|
+
this.set_minLux = 1;
|
|
943
867
|
}
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
868
|
+
return this.set_minLux;
|
|
869
|
+
}
|
|
870
|
+
|
|
871
|
+
maxLux(): number {
|
|
872
|
+
if (this.device.curtain?.set_maxLux) {
|
|
873
|
+
this.set_maxLux = this.device.curtain?.set_maxLux;
|
|
948
874
|
} else {
|
|
949
|
-
this.
|
|
950
|
-
this.debugLog(`Curtain: ${this.accessory.displayName} Using Default Curtain Refresh Rate.`);
|
|
875
|
+
this.set_maxLux = 6001;
|
|
951
876
|
}
|
|
877
|
+
return this.set_maxLux;
|
|
952
878
|
}
|
|
953
879
|
|
|
954
880
|
async scan(device: device & devicesConfig): Promise<void> {
|
|
955
881
|
if (device.scanDuration) {
|
|
956
882
|
if (this.updateRate > device.scanDuration) {
|
|
957
883
|
this.scanDuration = this.updateRate;
|
|
958
|
-
this.warnLog(
|
|
884
|
+
this.warnLog(`${this.device.deviceType}: `
|
|
885
|
+
+ `${this.accessory.displayName} scanDuration is less then updateRate, overriding scanDuration with updateRate`);
|
|
959
886
|
} else {
|
|
960
887
|
this.scanDuration = this.accessory.context.scanDuration = device.scanDuration;
|
|
961
888
|
}
|
|
962
|
-
if (
|
|
963
|
-
this.debugLog(
|
|
889
|
+
if (this.BLE) {
|
|
890
|
+
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Using Device Config scanDuration: ${this.scanDuration}`);
|
|
964
891
|
}
|
|
965
892
|
} else {
|
|
966
893
|
if (this.updateRate > 1) {
|
|
967
894
|
this.scanDuration = this.updateRate;
|
|
968
|
-
this.warnLog(
|
|
895
|
+
this.warnLog(`${this.device.deviceType}: `
|
|
896
|
+
+ `${this.accessory.displayName} scanDuration is less then updateRate, overriding scanDuration with updateRate`);
|
|
969
897
|
} else {
|
|
970
898
|
this.scanDuration = this.accessory.context.scanDuration = 1;
|
|
971
899
|
}
|
|
972
|
-
if (this.
|
|
973
|
-
this.debugLog(
|
|
900
|
+
if (this.BLE) {
|
|
901
|
+
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Using Default scanDuration: ${this.scanDuration}`);
|
|
974
902
|
}
|
|
975
903
|
}
|
|
976
904
|
}
|
|
977
905
|
|
|
978
|
-
async
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
906
|
+
async statusCode({ res }: { res: IncomingMessage }): Promise<void> {
|
|
907
|
+
switch (res.statusCode) {
|
|
908
|
+
case 151:
|
|
909
|
+
this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} Command not supported by this device type.`);
|
|
910
|
+
break;
|
|
911
|
+
case 152:
|
|
912
|
+
this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} Device not found.`);
|
|
913
|
+
break;
|
|
914
|
+
case 160:
|
|
915
|
+
this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} Command is not supported.`);
|
|
916
|
+
break;
|
|
917
|
+
case 161:
|
|
918
|
+
this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} Device is offline.`);
|
|
919
|
+
this.offlineOff();
|
|
920
|
+
break;
|
|
921
|
+
case 171:
|
|
922
|
+
this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} Hub Device is offline. Hub: ${this.device.hubDeviceId}`);
|
|
923
|
+
this.offlineOff();
|
|
924
|
+
break;
|
|
925
|
+
case 190:
|
|
926
|
+
this.errorLog(
|
|
927
|
+
`${this.device.deviceType}: ${this.accessory.displayName} Device internal error due to device states not synchronized with server,` +
|
|
928
|
+
` Or command: ${superStringify(res)} format is invalid`,
|
|
929
|
+
);
|
|
930
|
+
break;
|
|
931
|
+
case 100:
|
|
932
|
+
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Command successfully sent.`);
|
|
933
|
+
break;
|
|
934
|
+
default:
|
|
935
|
+
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Unknown statusCode.`);
|
|
936
|
+
}
|
|
937
|
+
}
|
|
938
|
+
|
|
939
|
+
async offlineOff(): Promise<void> {
|
|
940
|
+
if (this.device.offline) {
|
|
941
|
+
this.CurrentPosition = 100;
|
|
942
|
+
this.windowCoveringService.getCharacteristic(this.platform.Characteristic.On).updateValue(this.CurrentPosition);
|
|
943
|
+
await this.updateHomeKitCharacteristics();
|
|
944
|
+
}
|
|
945
|
+
}
|
|
946
|
+
|
|
947
|
+
async apiError(e: any): Promise<void> {
|
|
948
|
+
this.windowCoveringService.updateCharacteristic(this.platform.Characteristic.CurrentPosition, e);
|
|
949
|
+
this.windowCoveringService.updateCharacteristic(this.platform.Characteristic.PositionState, e);
|
|
950
|
+
this.windowCoveringService.updateCharacteristic(this.platform.Characteristic.TargetPosition, e);
|
|
951
|
+
if (!this.device.curtain?.hide_lightsensor) {
|
|
952
|
+
this.lightSensorService?.updateCharacteristic(this.platform.Characteristic.CurrentAmbientLightLevel, e);
|
|
953
|
+
}
|
|
954
|
+
if (this.BLE) {
|
|
955
|
+
this.batteryService?.updateCharacteristic(this.platform.Characteristic.BatteryLevel, e);
|
|
956
|
+
this.batteryService?.updateCharacteristic(this.platform.Characteristic.StatusLowBattery, e);
|
|
991
957
|
}
|
|
958
|
+
//throw new this.platform.api.hap.HapStatusError(HAPStatus.SERVICE_COMMUNICATION_FAILURE);
|
|
992
959
|
}
|
|
993
960
|
|
|
994
961
|
FirmwareRevision(accessory: PlatformAccessory<Context>, device: device & devicesConfig): CharacteristicValue {
|
|
995
962
|
let FirmwareRevision: string;
|
|
996
|
-
this.debugLog(
|
|
997
|
-
|
|
998
|
-
this.debugLog(
|
|
963
|
+
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName}`
|
|
964
|
+
+ ` accessory.context.FirmwareRevision: ${accessory.context.FirmwareRevision}`);
|
|
965
|
+
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} device.firmware: ${device.firmware}`);
|
|
966
|
+
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} this.platform.version: ${this.platform.version}`);
|
|
999
967
|
if (accessory.context.FirmwareRevision) {
|
|
1000
968
|
FirmwareRevision = accessory.context.FirmwareRevision;
|
|
1001
969
|
} else if (device.firmware) {
|
|
@@ -1006,31 +974,81 @@ export class Curtain {
|
|
|
1006
974
|
return FirmwareRevision;
|
|
1007
975
|
}
|
|
1008
976
|
|
|
1009
|
-
|
|
1010
|
-
if (
|
|
1011
|
-
this.
|
|
977
|
+
async context() {
|
|
978
|
+
if (this.CurrentPosition === undefined) {
|
|
979
|
+
this.CurrentPosition = 0;
|
|
1012
980
|
} else {
|
|
1013
|
-
this.
|
|
981
|
+
this.CurrentPosition = this.accessory.context.CurrentPosition;
|
|
982
|
+
}
|
|
983
|
+
|
|
984
|
+
if (this.TargetPosition === undefined) {
|
|
985
|
+
this.TargetPosition = 0;
|
|
986
|
+
} else {
|
|
987
|
+
this.TargetPosition = this.accessory.context.TargetPosition;
|
|
988
|
+
}
|
|
989
|
+
|
|
990
|
+
if (this.PositionState === undefined) {
|
|
991
|
+
this.PositionState = this.platform.Characteristic.PositionState.STOPPED;
|
|
992
|
+
} else {
|
|
993
|
+
this.PositionState = this.accessory.context.PositionState;
|
|
1014
994
|
}
|
|
1015
|
-
return this.set_minStep;
|
|
1016
995
|
}
|
|
1017
996
|
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
997
|
+
async refreshRate(device: device & devicesConfig): Promise<void> {
|
|
998
|
+
// refreshRate
|
|
999
|
+
if (device.refreshRate) {
|
|
1000
|
+
this.deviceRefreshRate = this.accessory.context.refreshRate = device.refreshRate;
|
|
1001
|
+
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Using Device Config refreshRate: ${this.deviceRefreshRate}`);
|
|
1002
|
+
} else if (this.platform.config.options!.refreshRate) {
|
|
1003
|
+
this.deviceRefreshRate = this.accessory.context.refreshRate = this.platform.config.options!.refreshRate;
|
|
1004
|
+
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Using Platform Config refreshRate: ${this.deviceRefreshRate}`);
|
|
1005
|
+
}
|
|
1006
|
+
// updateRate
|
|
1007
|
+
if (device?.curtain?.updateRate) {
|
|
1008
|
+
this.updateRate = device?.curtain?.updateRate;
|
|
1009
|
+
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Using Device Config Curtain refreshRate: ${this.deviceRefreshRate}`);
|
|
1021
1010
|
} else {
|
|
1022
|
-
this.
|
|
1011
|
+
this.updateRate = 7;
|
|
1012
|
+
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Using Default Curtain Refresh Rate.`);
|
|
1023
1013
|
}
|
|
1024
|
-
return this.set_minLux;
|
|
1025
1014
|
}
|
|
1026
1015
|
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1016
|
+
async config(device: device & devicesConfig): Promise<void> {
|
|
1017
|
+
let config = {};
|
|
1018
|
+
if (device.curtain) {
|
|
1019
|
+
config = device.curtain;
|
|
1020
|
+
}
|
|
1021
|
+
if (device.connectionType !== undefined) {
|
|
1022
|
+
config['connectionType'] = device.connectionType;
|
|
1023
|
+
}
|
|
1024
|
+
if (device.logging !== undefined) {
|
|
1025
|
+
config['logging'] = device.logging;
|
|
1026
|
+
}
|
|
1027
|
+
if (device.refreshRate !== undefined) {
|
|
1028
|
+
config['refreshRate'] = device.refreshRate;
|
|
1029
|
+
}
|
|
1030
|
+
if (device.scanDuration !== undefined) {
|
|
1031
|
+
config['scanDuration'] = device.scanDuration;
|
|
1032
|
+
}
|
|
1033
|
+
if (Object.entries(config).length !== 0) {
|
|
1034
|
+
this.infoLog(`${this.device.deviceType}: ${this.accessory.displayName} Config: ${superStringify(config)}`);
|
|
1035
|
+
}
|
|
1036
|
+
}
|
|
1037
|
+
|
|
1038
|
+
async logs(device: device & devicesConfig): Promise<void> {
|
|
1039
|
+
if (this.platform.debugMode) {
|
|
1040
|
+
this.deviceLogging = this.accessory.context.logging = 'debugMode';
|
|
1041
|
+
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Using Debug Mode Logging: ${this.deviceLogging}`);
|
|
1042
|
+
} else if (device.logging) {
|
|
1043
|
+
this.deviceLogging = this.accessory.context.logging = device.logging;
|
|
1044
|
+
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Using Device Config Logging: ${this.deviceLogging}`);
|
|
1045
|
+
} else if (this.platform.config.options?.logging) {
|
|
1046
|
+
this.deviceLogging = this.accessory.context.logging = this.platform.config.options?.logging;
|
|
1047
|
+
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Using Platform Config Logging: ${this.deviceLogging}`);
|
|
1030
1048
|
} else {
|
|
1031
|
-
this.
|
|
1049
|
+
this.deviceLogging = this.accessory.context.logging = 'standard';
|
|
1050
|
+
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Logging Not Set, Using: ${this.deviceLogging}`);
|
|
1032
1051
|
}
|
|
1033
|
-
return this.set_maxLux;
|
|
1034
1052
|
}
|
|
1035
1053
|
|
|
1036
1054
|
/**
|
|
@@ -1048,12 +1066,28 @@ export class Curtain {
|
|
|
1048
1066
|
}
|
|
1049
1067
|
}
|
|
1050
1068
|
|
|
1069
|
+
debugWarnLog(...log: any[]): void {
|
|
1070
|
+
if (this.enablingDeviceLogging()) {
|
|
1071
|
+
if (this.deviceLogging?.includes('debug')) {
|
|
1072
|
+
this.platform.log.warn('[DEBUG]', String(...log));
|
|
1073
|
+
}
|
|
1074
|
+
}
|
|
1075
|
+
}
|
|
1076
|
+
|
|
1051
1077
|
errorLog(...log: any[]): void {
|
|
1052
1078
|
if (this.enablingDeviceLogging()) {
|
|
1053
1079
|
this.platform.log.error(String(...log));
|
|
1054
1080
|
}
|
|
1055
1081
|
}
|
|
1056
1082
|
|
|
1083
|
+
debugErrorLog(...log: any[]): void {
|
|
1084
|
+
if (this.enablingDeviceLogging()) {
|
|
1085
|
+
if (this.deviceLogging?.includes('debug')) {
|
|
1086
|
+
this.platform.log.error('[DEBUG]', String(...log));
|
|
1087
|
+
}
|
|
1088
|
+
}
|
|
1089
|
+
}
|
|
1090
|
+
|
|
1057
1091
|
debugLog(...log: any[]): void {
|
|
1058
1092
|
if (this.enablingDeviceLogging()) {
|
|
1059
1093
|
if (this.deviceLogging === 'debug') {
|