@switchbot/homebridge-switchbot 2.5.0-beta.3 → 2.5.0-beta.4

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.
@@ -12,11 +12,20 @@ const super_stringify_1 = __importDefault(require("super-stringify"));
12
12
  const operators_1 = require("rxjs/operators");
13
13
  const settings_1 = require("../settings");
14
14
  const utils_1 = require("../utils");
15
+ var BlindTiltMappingMode;
16
+ (function (BlindTiltMappingMode) {
17
+ BlindTiltMappingMode["OnlyUp"] = "only_up";
18
+ BlindTiltMappingMode["OnlyDown"] = "only_down";
19
+ BlindTiltMappingMode["DownAndUp"] = "down_and_up";
20
+ BlindTiltMappingMode["UpAndDown"] = "up_and_down";
21
+ BlindTiltMappingMode["UseTiltForDirection"] = "use_tilt_for_direction";
22
+ })(BlindTiltMappingMode || (BlindTiltMappingMode = {}));
15
23
  class BlindTilt {
16
24
  constructor(platform, accessory, device) {
17
25
  this.platform = platform;
18
26
  this.accessory = accessory;
19
27
  this.device = device;
28
+ this.mappingMode = BlindTiltMappingMode.OnlyUp;
20
29
  //MQTT stuff
21
30
  this.mqttClient = null;
22
31
  // Connection
@@ -29,6 +38,8 @@ class BlindTilt {
29
38
  this.config(device);
30
39
  this.setupMqtt(device);
31
40
  this.context();
41
+ this.mappingMode = device.blindTilt?.mappingMode ?? BlindTiltMappingMode.OnlyUp;
42
+ this.debugLog(`Mapping mode: ${this.mappingMode}`);
32
43
  // this is subject we use to track when we need to POST changes to the SwitchBot API
33
44
  this.doBlindTiltUpdate = new rxjs_1.Subject();
34
45
  this.blindTiltUpdateInProgress = false;
@@ -82,26 +93,27 @@ class BlindTilt {
82
93
  validValueRanges: [0, 100],
83
94
  })
84
95
  .onSet(this.TargetPositionSet.bind(this));
96
+ this.CurrentHorizontalTiltAngle = 90;
85
97
  this.windowCoveringService
86
98
  .getCharacteristic(this.platform.Characteristic.CurrentHorizontalTiltAngle)
87
99
  .setProps({
88
- minStep: 1,
89
- minValue: 0,
90
- maxValue: 1,
91
- validValues: [0, 1],
92
- validValueRanges: [0, 1],
100
+ minStep: 180,
101
+ minValue: -90,
102
+ maxValue: 90,
103
+ validValues: [-90, 90],
93
104
  })
94
105
  .onGet(() => {
106
+ // this.debugLog(`requested CurrentHorizontalTiltAngle: ${this.CurrentHorizontalTiltAngle}`);
95
107
  return this.CurrentHorizontalTiltAngle;
96
108
  });
109
+ this.TargetHorizontalTiltAngle = 90;
97
110
  this.windowCoveringService
98
111
  .getCharacteristic(this.platform.Characteristic.TargetHorizontalTiltAngle)
99
112
  .setProps({
100
- minStep: 1,
101
- minValue: 0,
102
- maxValue: 1,
103
- validValues: [0, 1],
104
- validValueRanges: [0, 1],
113
+ minStep: 180,
114
+ minValue: -90,
115
+ maxValue: 90,
116
+ validValues: [-90, 90],
105
117
  })
106
118
  .onSet(this.TargetHorizontalTiltAngleSet.bind(this));
107
119
  // Battery Service
@@ -201,7 +213,7 @@ class BlindTilt {
201
213
  this.debugLog(`${this.device.deviceType}: ${this.CurrentPosition} DECREASING PositionState: ${this.PositionState}`);
202
214
  }
203
215
  else {
204
- this.debugLog(`${this.device.deviceType}: ${this.CurrentPosition} Standby, CurrentPosition: ${this.CurrentPosition}`);
216
+ this.debugLog(`${this.device.deviceType}: ${this.CurrentPosition} Standby2, CurrentPosition: ${this.CurrentPosition}`);
205
217
  this.PositionState = this.platform.Characteristic.PositionState.STOPPED;
206
218
  this.windowCoveringService.getCharacteristic(this.platform.Characteristic.PositionState).updateValue(this.PositionState);
207
219
  this.debugLog(`${this.device.deviceType}: ${this.CurrentPosition} STOPPED PositionState: ${this.PositionState}`);
@@ -215,6 +227,57 @@ class BlindTilt {
215
227
  }
216
228
  this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} CurrentPosition: ${this.CurrentPosition},` +
217
229
  ` TargetPosition: ${this.TargetPosition}, PositionState: ${this.PositionState},`);
230
+ if (!this.device.curtain?.hide_lightsensor) {
231
+ this.set_minLux = this.minLux();
232
+ this.set_maxLux = this.maxLux();
233
+ this.spaceBetweenLevels = 9;
234
+ // Brightness
235
+ switch (this.lightLevel) {
236
+ case 1:
237
+ this.CurrentAmbientLightLevel = this.set_minLux;
238
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} LightLevel: ${this.lightLevel}`);
239
+ break;
240
+ case 2:
241
+ this.CurrentAmbientLightLevel = (this.set_maxLux - this.set_minLux) / this.spaceBetweenLevels;
242
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} LightLevel: ${this.lightLevel},` +
243
+ ` Calculation: ${(this.set_maxLux - this.set_minLux) / this.spaceBetweenLevels}`);
244
+ break;
245
+ case 3:
246
+ this.CurrentAmbientLightLevel = ((this.set_maxLux - this.set_minLux) / this.spaceBetweenLevels) * 2;
247
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} LightLevel: ${this.lightLevel}`);
248
+ break;
249
+ case 4:
250
+ this.CurrentAmbientLightLevel = ((this.set_maxLux - this.set_minLux) / this.spaceBetweenLevels) * 3;
251
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} LightLevel: ${this.lightLevel}`);
252
+ break;
253
+ case 5:
254
+ this.CurrentAmbientLightLevel = ((this.set_maxLux - this.set_minLux) / this.spaceBetweenLevels) * 4;
255
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} LightLevel: ${this.lightLevel}`);
256
+ break;
257
+ case 6:
258
+ this.CurrentAmbientLightLevel = ((this.set_maxLux - this.set_minLux) / this.spaceBetweenLevels) * 5;
259
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} LightLevel: ${this.lightLevel}`);
260
+ break;
261
+ case 7:
262
+ this.CurrentAmbientLightLevel = ((this.set_maxLux - this.set_minLux) / this.spaceBetweenLevels) * 6;
263
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} LightLevel: ${this.lightLevel}`);
264
+ break;
265
+ case 8:
266
+ this.CurrentAmbientLightLevel = ((this.set_maxLux - this.set_minLux) / this.spaceBetweenLevels) * 7;
267
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} LightLevel: ${this.lightLevel}`);
268
+ break;
269
+ case 9:
270
+ this.CurrentAmbientLightLevel = ((this.set_maxLux - this.set_minLux) / this.spaceBetweenLevels) * 8;
271
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} LightLevel: ${this.lightLevel}`);
272
+ break;
273
+ case 10:
274
+ default:
275
+ this.CurrentAmbientLightLevel = this.set_maxLux;
276
+ this.debugLog();
277
+ }
278
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} LightLevel: ${this.lightLevel},`
279
+ + ` CurrentAmbientLightLevel: ${this.CurrentAmbientLightLevel}`);
280
+ }
218
281
  // Battery
219
282
  this.BatteryLevel = Number(this.battery);
220
283
  if (this.BatteryLevel < 10) {
@@ -228,24 +291,23 @@ class BlindTilt {
228
291
  }
229
292
  async openAPIparseStatus() {
230
293
  this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} openAPIparseStatus`);
294
+ const [homekitPosition, homekitTiltAngle] = this.mapDeviceValuesToHomekitValues(Number(this.slidePosition), String(this.direction));
295
+ this.debugLog(` device: ${this.slidePosition} => HK: ${homekitPosition}`);
296
+ this.CurrentPosition = homekitPosition;
231
297
  // CurrentPosition
232
- if (this.direction === 'Down') {
233
- this.CurrentPosition = Number(this.slidePosition) * 2; //100 - Number(this.slidePosition);
234
- }
235
- else if (this.direction === 'Up') {
236
- this.CurrentPosition = Number(this.slidePosition) / 2;
237
- }
238
- else {
239
- this.CurrentPosition = Number(this.slidePosition);
240
- }
241
298
  await this.setMinMax();
242
299
  this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} CurrentPosition: ${this.CurrentPosition}`);
300
+ if (homekitTiltAngle) {
301
+ this.CurrentHorizontalTiltAngle = homekitTiltAngle;
302
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} CurrentHorizontalTiltAngle: ${this.CurrentHorizontalTiltAngle}`);
303
+ }
243
304
  if (this.setNewTarget) {
244
305
  this.infoLog(`${this.device.deviceType}: ${this.accessory.displayName} Checking Status ...`);
245
306
  }
246
- if (this.setNewTarget && this.moving) {
307
+ this.debugLog(`runStatus: ${this.runStatus}`);
308
+ if (this.setNewTarget || (this.runStatus === undefined || this.runStatus !== 'static')) {
247
309
  await this.setMinMax();
248
- if (this.TargetPosition > this.CurrentPosition) {
310
+ if (this.TargetPosition > this.CurrentPosition || (homekitTiltAngle && (this.TargetHorizontalTiltAngle !== this.CurrentHorizontalTiltAngle))) {
249
311
  this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Closing, CurrentPosition: ${this.CurrentPosition} `);
250
312
  this.PositionState = this.platform.Characteristic.PositionState.INCREASING;
251
313
  this.windowCoveringService.getCharacteristic(this.platform.Characteristic.PositionState).updateValue(this.PositionState);
@@ -258,30 +320,39 @@ class BlindTilt {
258
320
  this.debugLog(`${this.device.deviceType}: ${this.CurrentPosition} DECREASING PositionState: ${this.PositionState}`);
259
321
  }
260
322
  else {
261
- this.debugLog(`${this.device.deviceType}: ${this.CurrentPosition} Standby, CurrentPosition: ${this.CurrentPosition}`);
323
+ this.debugLog(`${this.device.deviceType}: ${this.CurrentPosition} Standby because reached position,` +
324
+ ` CurrentPosition: ${this.CurrentPosition}`);
262
325
  this.PositionState = this.platform.Characteristic.PositionState.STOPPED;
263
326
  this.windowCoveringService.getCharacteristic(this.platform.Characteristic.PositionState).updateValue(this.PositionState);
264
327
  this.debugLog(`${this.device.deviceType}: ${this.CurrentPosition} STOPPED PositionState: ${this.PositionState}`);
265
328
  }
266
329
  }
267
330
  else {
268
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Standby, CurrentPosition: ${this.CurrentPosition}`);
331
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Standby because device not moving,` +
332
+ ` CurrentPosition: ${this.CurrentPosition}`);
269
333
  this.TargetPosition = this.CurrentPosition;
334
+ if (homekitTiltAngle) {
335
+ this.TargetHorizontalTiltAngle = this.CurrentHorizontalTiltAngle;
336
+ }
270
337
  this.PositionState = this.platform.Characteristic.PositionState.STOPPED;
271
338
  this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Stopped`);
272
339
  }
273
- if (this.direction === 'Up') {
274
- this.CurrentHorizontalTiltAngle = 0;
275
- }
276
- else if (this.direction === 'Down') {
277
- this.CurrentHorizontalTiltAngle = 1;
278
- }
279
- else {
280
- this.CurrentHorizontalTiltAngle = 0;
281
- }
282
340
  this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} CurrentPosition: ${this.CurrentPosition},` +
283
- ` TargetPosition: ${this.TargetPosition}, PositionState: ${this.PositionState},` +
284
- ` CurrentHorizontalTiltAngle: ${this.CurrentHorizontalTiltAngle}`);
341
+ ` TargetPosition: ${this.TargetPosition}, PositionState: ${this.PositionState},`);
342
+ if (!this.device.curtain?.hide_lightsensor) {
343
+ this.set_minLux = this.minLux();
344
+ this.set_maxLux = this.maxLux();
345
+ // Brightness
346
+ switch (this.brightness) {
347
+ case 'dim':
348
+ this.CurrentAmbientLightLevel = this.set_minLux;
349
+ break;
350
+ case 'bright':
351
+ default:
352
+ this.CurrentAmbientLightLevel = this.set_maxLux;
353
+ }
354
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} CurrentAmbientLightLevel: ${this.CurrentAmbientLightLevel}`);
355
+ }
285
356
  }
286
357
  async refreshStatus() {
287
358
  if (!this.device.enableCloudService && this.OpenAPI) {
@@ -313,6 +384,7 @@ class BlindTilt {
313
384
  if (switchbot !== false) {
314
385
  switchbot
315
386
  .startScan({
387
+ model: 'c',
316
388
  id: this.device.bleMac,
317
389
  })
318
390
  .then(async () => {
@@ -326,9 +398,11 @@ class BlindTilt {
326
398
  this.battery = ad.serviceData.battery;
327
399
  this.inMotion = ad.serviceData.inMotion;
328
400
  this.position = ad.serviceData.position;
401
+ this.lightLevel = ad.serviceData.lightLevel;
329
402
  this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} serviceData: ${(0, super_stringify_1.default)(ad.serviceData)}`);
330
403
  this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} calibration: ${ad.serviceData.calibration}, ` +
331
- `position: ${ad.serviceData.position}, inMotion: ${ad.serviceData.inMotion}, battery: ${ad.serviceData.battery}`);
404
+ `position: ${ad.serviceData.position}, lightLevel: ${ad.serviceData.lightLevel}, battery: ${ad.serviceData.battery}, ` +
405
+ `inMotion: ${ad.serviceData.inMotion}`);
332
406
  if (this.serviceData) {
333
407
  this.connected = true;
334
408
  this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} connected: ${this.connected}`);
@@ -390,15 +464,11 @@ class BlindTilt {
390
464
  try {
391
465
  this.deviceStatus = JSON.parse(rawData);
392
466
  this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} refreshStatus: ${(0, super_stringify_1.default)(this.deviceStatus)}`);
393
- this.slidePosition = this.deviceStatus.body.slidePosition; // "slidePosition": 0 = Closed Down | 100 = Closed Up | 50 = Fully Open
467
+ this.slidePosition = this.deviceStatus.body.slidePosition;
468
+ this.direction = this.deviceStatus.body.direction;
394
469
  this.moving = this.deviceStatus.body.moving;
395
- this.Battery = this.deviceStatus.body.battery;
396
- this.direction = this.deviceStatus.body.direction; // "Up"/"Down"
397
- this.version = this.deviceStatus.body.version;
398
- if (this.version) {
399
- const firmware = this.version * .10;
400
- this.accessory.context.FirmwareRevision = firmware;
401
- }
470
+ this.runStatus = this.deviceStatus.body.runStatus;
471
+ this.brightness = this.deviceStatus.body.brightness;
402
472
  this.openAPIparseStatus();
403
473
  this.updateHomeKitCharacteristics();
404
474
  }
@@ -451,6 +521,12 @@ class BlindTilt {
451
521
  .join(':')
452
522
  .toLowerCase();
453
523
  this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} BLE Address: ${this.device.bleMac}`);
524
+ this.SilentPerformance();
525
+ const adjustedMode = this.setPositionMode || null;
526
+ if (adjustedMode === null) {
527
+ this.Mode = 'Default Mode';
528
+ }
529
+ this.debugLog(`${this.accessory.displayName} Mode: ${this.Mode}`);
454
530
  if (switchbot !== false) {
455
531
  switchbot
456
532
  .discover({ model: 'c', quick: true, id: this.device.bleMac })
@@ -459,7 +535,7 @@ class BlindTilt {
459
535
  return await this.retry({
460
536
  max: await this.maxRetry(),
461
537
  fn: () => {
462
- return device_list[0].runToPos(100 - Number(this.TargetPosition));
538
+ return device_list[0].runToPos(100 - Number(this.TargetPosition), adjustedMode);
463
539
  },
464
540
  });
465
541
  })
@@ -517,40 +593,12 @@ class BlindTilt {
517
593
  .digest();
518
594
  const sign = signTerm.toString('base64');
519
595
  this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} sign: ${sign}`);
520
- this.debugLog(`Pushing ${this.TargetPosition}`);
521
- let command = '';
522
- let parameter = '';
523
- if (this.TargetHorizontalTiltAngle === 90 && this.TargetPosition === 100) {
524
- command = 'fullyOpen';
525
- parameter = 'default';
526
- }
527
- else if (this.TargetHorizontalTiltAngle === -90 && this.TargetPosition === 100) {
528
- command = 'fullyOpen';
529
- parameter = 'default';
530
- }
531
- else if (this.TargetHorizontalTiltAngle === 90 && this.TargetPosition === 0) {
532
- command = 'closeUp';
533
- parameter = 'default';
534
- }
535
- else if (this.TargetHorizontalTiltAngle === -90 && this.TargetPosition === 0) {
536
- command = 'closeDown';
537
- parameter = 'default';
538
- }
539
- else {
540
- let direction = '';
541
- const position = this.TargetPosition;
542
- if (this.TargetHorizontalTiltAngle === 90) {
543
- direction = 'up';
544
- }
545
- else {
546
- direction = 'down';
547
- }
548
- command = 'setPosition';
549
- parameter = `${direction};${position}`;
550
- }
596
+ const [direction, position] = this.mapHomekitValuesToDeviceValues(Number(this.TargetPosition), Number(this.TargetHorizontalTiltAngle));
597
+ this.debugLog(`Pushing ${this.TargetPosition} (device = ${direction};${position})`);
598
+ this.debugLog(`${this.accessory.displayName} Mode: ${this.Mode}`);
551
599
  const body = (0, super_stringify_1.default)({
552
- 'command': `${command}`,
553
- 'parameter': `${parameter}`,
600
+ 'command': 'setPosition',
601
+ 'parameter': `${direction};${position}`,
554
602
  'commandType': 'command',
555
603
  });
556
604
  this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Sending request to SwitchBot API, body: ${body},`);
@@ -593,6 +641,23 @@ class BlindTilt {
593
641
  + ` Connection, Error Message: ${(0, super_stringify_1.default)(e.message)}`);
594
642
  }
595
643
  }
644
+ /**
645
+ * Handle requests to set the value of the "Target Horizontal Tilt" characteristic
646
+ */
647
+ async TargetHorizontalTiltAngleSet(value) {
648
+ if (this.TargetHorizontalTiltAngle === this.accessory.context.TargetHorizontalTiltAngle) {
649
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} No Changes, Set TargetHorizontalTiltAngle: ${value}`);
650
+ }
651
+ else {
652
+ this.infoLog(`${this.device.deviceType}: ${this.accessory.displayName} Set TargetHorizontalTiltAngle: ${value}`);
653
+ }
654
+ //value = value < 0 ? -90 : 90;
655
+ this.TargetHorizontalTiltAngle = value;
656
+ if (this.device.mqttURL) {
657
+ this.mqttPublish('TargetHorizontalTiltAngle', this.TargetHorizontalTiltAngle);
658
+ }
659
+ this.startUpdatingBlindTiltIfNeeded();
660
+ }
596
661
  /**
597
662
  * Handle requests to set the value of the "Target Position" characteristic
598
663
  */
@@ -607,53 +672,28 @@ class BlindTilt {
607
672
  if (this.device.mqttURL) {
608
673
  this.mqttPublish('TargetPosition', this.TargetPosition);
609
674
  }
675
+ this.startUpdatingBlindTiltIfNeeded();
676
+ }
677
+ async startUpdatingBlindTiltIfNeeded() {
610
678
  await this.setMinMax();
611
- if (value > this.CurrentPosition) {
679
+ this.debugLog('setMinMax');
680
+ if (this.TargetPosition > this.CurrentPosition || (this.TargetHorizontalTiltAngle !== this.CurrentHorizontalTiltAngle)) {
612
681
  this.PositionState = this.platform.Characteristic.PositionState.INCREASING;
613
682
  this.setNewTarget = true;
614
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} value: ${value}, CurrentPosition: ${this.CurrentPosition}`);
683
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} value: ${this.CurrentPosition},` +
684
+ ` CurrentPosition: ${this.CurrentPosition}`);
615
685
  }
616
- else if (value < this.CurrentPosition) {
686
+ else if (this.TargetPosition < this.CurrentPosition) {
617
687
  this.PositionState = this.platform.Characteristic.PositionState.DECREASING;
618
688
  this.setNewTarget = true;
619
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} value: ${value}, CurrentPosition: ${this.CurrentPosition}`);
689
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} value: ${this.CurrentPosition},` +
690
+ ` CurrentPosition: ${this.CurrentPosition}`);
620
691
  }
621
692
  else {
622
693
  this.PositionState = this.platform.Characteristic.PositionState.STOPPED;
623
694
  this.setNewTarget = false;
624
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} value: ${value}, CurrentPosition: ${this.CurrentPosition}`);
625
- }
626
- this.windowCoveringService.setCharacteristic(this.platform.Characteristic.PositionState, this.PositionState);
627
- this.windowCoveringService.getCharacteristic(this.platform.Characteristic.PositionState).updateValue(this.PositionState);
628
- /**
629
- * If Blind Tilt movement time is short, the moving flag from backend is always false.
630
- * The minimum time depends on the network control latency.
631
- */
632
- clearTimeout(this.setNewTargetTimer);
633
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} updateRate: ${this.updateRate}`);
634
- if (this.setNewTarget) {
635
- this.setNewTargetTimer = setTimeout(() => {
636
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} setNewTarget ${this.setNewTarget} timeout`);
637
- this.setNewTarget = false;
638
- }, this.updateRate * 1000);
639
- }
640
- this.doBlindTiltUpdate.next();
641
- }
642
- /**
643
- * Handle requests to set the value of the "Target Position" characteristic
644
- */
645
- async TargetHorizontalTiltAngleSet(value) {
646
- if (this.TargetHorizontalTiltAngle === this.accessory.context.TargetHorizontalTiltAngle) {
647
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} No Changes, Set TargetHorizontalTiltAngle: ${value}`);
648
- }
649
- else {
650
- this.infoLog(`${this.device.deviceType}: ${this.accessory.displayName} Set TargetHorizontalTiltAngle: ${value}`);
651
- }
652
- this.TargetHorizontalTiltAngle = value;
653
- this.CurrentHorizontalTiltAngle = this.TargetHorizontalTiltAngle;
654
- this.accessory.context.TargetHorizontalTiltAngle = this.TargetHorizontalTiltAngle;
655
- if (this.device.mqttURL) {
656
- this.mqttPublish('TargetHorizontalTiltAngle', this.TargetHorizontalTiltAngle);
695
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} value: ${this.CurrentPosition},` +
696
+ ` CurrentPosition: ${this.CurrentPosition}`);
657
697
  }
658
698
  this.windowCoveringService.setCharacteristic(this.platform.Characteristic.PositionState, this.PositionState);
659
699
  this.windowCoveringService.getCharacteristic(this.platform.Characteristic.PositionState).updateValue(this.PositionState);
@@ -673,6 +713,20 @@ class BlindTilt {
673
713
  }
674
714
  async updateHomeKitCharacteristics() {
675
715
  await this.setMinMax();
716
+ if (this.mappingMode === BlindTiltMappingMode.UseTiltForDirection) {
717
+ if (this.CurrentHorizontalTiltAngle === undefined || Number.isNaN(this.CurrentHorizontalTiltAngle)) {
718
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} CurrentHorizontalTiltAngle: ${this.CurrentHorizontalTiltAngle}`);
719
+ }
720
+ else {
721
+ if (this.device.mqttURL) {
722
+ this.mqttPublish('CurrentHorizontalTiltAngle', this.CurrentHorizontalTiltAngle);
723
+ }
724
+ this.accessory.context.CurrentHorizontalTiltAngle = this.CurrentHorizontalTiltAngle;
725
+ this.windowCoveringService.updateCharacteristic(this.platform.Characteristic.CurrentHorizontalTiltAngle, Number(this.CurrentHorizontalTiltAngle));
726
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName}
727
+ updateCharacteristic CurrentHorizontalTiltAngle: ${this.CurrentHorizontalTiltAngle}`);
728
+ }
729
+ }
676
730
  if (this.CurrentPosition === undefined || Number.isNaN(this.CurrentPosition)) {
677
731
  this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} CurrentPosition: ${this.CurrentPosition}`);
678
732
  }
@@ -706,29 +760,19 @@ class BlindTilt {
706
760
  this.windowCoveringService.updateCharacteristic(this.platform.Characteristic.TargetPosition, Number(this.TargetPosition));
707
761
  this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} updateCharacteristic TargetPosition: ${this.TargetPosition}`);
708
762
  }
709
- if (this.TargetHorizontalTiltAngle === undefined || Number.isNaN(this.TargetHorizontalTiltAngle)) {
710
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} TargetHorizontalTiltAngle: ${this.TargetHorizontalTiltAngle}`);
711
- }
712
- else {
713
- if (this.device.mqttURL) {
714
- this.mqttPublish('TargetHorizontalTiltAngle', this.TargetHorizontalTiltAngle);
763
+ if (!this.device.curtain?.hide_lightsensor) {
764
+ if (this.CurrentAmbientLightLevel === undefined || Number.isNaN(this.CurrentAmbientLightLevel)) {
765
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} CurrentAmbientLightLevel: ${this.CurrentAmbientLightLevel}`);
715
766
  }
716
- this.accessory.context.TargetHorizontalTiltAngle = this.TargetHorizontalTiltAngle;
717
- this.windowCoveringService.updateCharacteristic(this.platform.Characteristic.TargetHorizontalTiltAngle, Number(this.TargetHorizontalTiltAngle));
718
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} updateCharacteristic`
719
- + ` TargetHorizontalTiltAngle: ${this.TargetHorizontalTiltAngle}`);
720
- }
721
- if (this.CurrentHorizontalTiltAngle === undefined || Number.isNaN(this.CurrentHorizontalTiltAngle)) {
722
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} CurrentHorizontalTiltAngle: ${this.CurrentHorizontalTiltAngle}`);
723
- }
724
- else {
725
- if (this.device.mqttURL) {
726
- this.mqttPublish('CurrentHorizontalTiltAngle', this.CurrentHorizontalTiltAngle);
767
+ else {
768
+ if (this.device.mqttURL) {
769
+ this.mqttPublish('CurrentAmbientLightLevel', this.CurrentAmbientLightLevel);
770
+ }
771
+ this.accessory.context.CurrentAmbientLightLevel = this.CurrentAmbientLightLevel;
772
+ this.lightSensorService?.updateCharacteristic(this.platform.Characteristic.CurrentAmbientLightLevel, this.CurrentAmbientLightLevel);
773
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName}`
774
+ + ` updateCharacteristic CurrentAmbientLightLevel: ${this.CurrentAmbientLightLevel}`);
727
775
  }
728
- this.accessory.context.CurrentHorizontalTiltAngle = this.CurrentHorizontalTiltAngle;
729
- this.windowCoveringService.updateCharacteristic(this.platform.Characteristic.CurrentHorizontalTiltAngle, Number(this.CurrentHorizontalTiltAngle));
730
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} updateCharacteristic`
731
- + ` CurrentHorizontalTiltAngle: ${this.CurrentHorizontalTiltAngle}`);
732
776
  }
733
777
  if (this.BLE) {
734
778
  if (this.BatteryLevel === undefined) {
@@ -826,6 +870,28 @@ class BlindTilt {
826
870
  await this.openAPIRefreshStatus();
827
871
  }
828
872
  }
873
+ async SilentPerformance() {
874
+ if (this.TargetPosition > 50) {
875
+ if (this.device.curtain?.setOpenMode === '1') {
876
+ this.setPositionMode = 1;
877
+ this.Mode = 'Silent Mode';
878
+ }
879
+ else {
880
+ this.setPositionMode = 0;
881
+ this.Mode = 'Performance Mode';
882
+ }
883
+ }
884
+ else {
885
+ if (this.device.curtain?.setCloseMode === '1') {
886
+ this.setPositionMode = 1;
887
+ this.Mode = 'Silent Mode';
888
+ }
889
+ else {
890
+ this.setPositionMode = 0;
891
+ this.Mode = 'Performance Mode';
892
+ }
893
+ }
894
+ }
829
895
  async setMinMax() {
830
896
  if (this.device.curtain?.set_min) {
831
897
  if (this.CurrentPosition <= this.device.curtain?.set_min) {
@@ -837,6 +903,9 @@ class BlindTilt {
837
903
  this.CurrentPosition = 100;
838
904
  }
839
905
  }
906
+ if (this.mappingMode === BlindTiltMappingMode.UseTiltForDirection) {
907
+ this.CurrentHorizontalTiltAngle = this.CurrentHorizontalTiltAngle < 0 ? -90 : 90;
908
+ }
840
909
  }
841
910
  minStep(device) {
842
911
  if (device.curtain?.set_minStep) {
@@ -937,6 +1006,9 @@ class BlindTilt {
937
1006
  this.windowCoveringService.updateCharacteristic(this.platform.Characteristic.CurrentPosition, e);
938
1007
  this.windowCoveringService.updateCharacteristic(this.platform.Characteristic.PositionState, e);
939
1008
  this.windowCoveringService.updateCharacteristic(this.platform.Characteristic.TargetPosition, e);
1009
+ if (!this.device.curtain?.hide_lightsensor) {
1010
+ this.lightSensorService?.updateCharacteristic(this.platform.Characteristic.CurrentAmbientLightLevel, e);
1011
+ }
940
1012
  if (this.BLE) {
941
1013
  this.batteryService?.updateCharacteristic(this.platform.Characteristic.BatteryLevel, e);
942
1014
  this.batteryService?.updateCharacteristic(this.platform.Characteristic.StatusLowBattery, e);
@@ -949,18 +1021,12 @@ class BlindTilt {
949
1021
  + ` accessory.context.FirmwareRevision: ${accessory.context.FirmwareRevision}`);
950
1022
  this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} device.firmware: ${device.firmware}`);
951
1023
  this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} this.platform.version: ${this.platform.version}`);
952
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} API version: ${this.version}`);
953
1024
  if (accessory.context.FirmwareRevision) {
954
1025
  FirmwareRevision = accessory.context.FirmwareRevision;
955
1026
  }
956
1027
  else if (device.firmware) {
957
1028
  FirmwareRevision = device.firmware;
958
1029
  }
959
- else if (this.version) {
960
- const firmware = this.version * .10;
961
- accessory.context.FirmwareRevision = firmware;
962
- FirmwareRevision = (0, super_stringify_1.default)(firmware);
963
- }
964
1030
  else {
965
1031
  FirmwareRevision = this.platform.version;
966
1032
  }
@@ -979,18 +1045,6 @@ class BlindTilt {
979
1045
  else {
980
1046
  this.TargetPosition = this.accessory.context.TargetPosition;
981
1047
  }
982
- if (this.TargetHorizontalTiltAngle === undefined) {
983
- this.TargetHorizontalTiltAngle = 0;
984
- }
985
- else {
986
- this.TargetHorizontalTiltAngle = this.accessory.context.TargetHorizontalTiltAngle;
987
- }
988
- if (this.CurrentHorizontalTiltAngle === undefined) {
989
- this.CurrentHorizontalTiltAngle = 0;
990
- }
991
- else {
992
- this.CurrentHorizontalTiltAngle = this.accessory.context.CurrentHorizontalTiltAngle;
993
- }
994
1048
  if (this.PositionState === undefined) {
995
1049
  this.PositionState = this.platform.Characteristic.PositionState.STOPPED;
996
1050
  }
@@ -998,6 +1052,120 @@ class BlindTilt {
998
1052
  this.PositionState = this.accessory.context.PositionState;
999
1053
  }
1000
1054
  }
1055
+ /**
1056
+ * Maps device values to homekit values
1057
+ *
1058
+ * @param devicePosition the position as reported by the devide
1059
+ * @param direction the direction as reported by the device
1060
+ * @returns [homekit position, homekit tiltAngle]
1061
+ */
1062
+ mapDeviceValuesToHomekitValues(devicePosition, deviceDirection) {
1063
+ // device position 0 => closed down
1064
+ // device position 50 => open
1065
+ // device position 100 => closed up
1066
+ // homekit position 0 => closed
1067
+ // homekit position 100 => open
1068
+ deviceDirection;
1069
+ switch (this.mappingMode) {
1070
+ case BlindTiltMappingMode.OnlyUp:
1071
+ // we only close upwards, so we see anything that is tilted downwards(<50) as open
1072
+ if (devicePosition < 50) {
1073
+ return [100, undefined]; // fully open in homekit
1074
+ }
1075
+ else {
1076
+ // we range from 50->100, with 100 being closed, so map to homekit by scaling to 0..100 and then reversing
1077
+ return [100 - (devicePosition - 50) * 2, undefined];
1078
+ }
1079
+ case BlindTiltMappingMode.OnlyDown:
1080
+ // we only close downwards, so we see anything that is tilted upwards(>50) as upwards
1081
+ if (devicePosition > 50) {
1082
+ return [100, undefined]; // fully open in homekit
1083
+ }
1084
+ else {
1085
+ // we range from 0..50 so scale to homekit and then reverse
1086
+ return [devicePosition * 2, undefined];
1087
+ }
1088
+ case BlindTiltMappingMode.DownAndUp:
1089
+ // we close both ways with closed downwards being 0 in homekit and closed upwards in homekit being 100. Open is 50 in homekit
1090
+ return [devicePosition, undefined];
1091
+ case BlindTiltMappingMode.UpAndDown:
1092
+ // we close both ways with closed downwards being 1000 in homekit and closed upwards in homekit being 0. Open is 50 in homekit.,
1093
+ // so we reverse the value
1094
+ return [100 - devicePosition, undefined];
1095
+ case BlindTiltMappingMode.UseTiltForDirection:
1096
+ // we use tilt for direction, so being closed downwards is 0 in homekit with -90 tilt, while being closed upwards is 0 with 90 tilt.
1097
+ if (devicePosition <= 50) {
1098
+ // downwards tilted, so we range from 0..50, with 0 being closed and 50 being open, so scale.
1099
+ return [devicePosition * 2, -90];
1100
+ }
1101
+ else {
1102
+ // upwards tilted, so we range from 50..100, with 50 being open and 100 being closed, so scale and rever
1103
+ return [100 - (devicePosition - 50) * 2, 90];
1104
+ }
1105
+ }
1106
+ }
1107
+ /**
1108
+ * Maps homekit values to device values
1109
+ *
1110
+ * @param homekitPosition the position as reported by homekit
1111
+ * @param homekitTiltAngle? the tilt angle as reported by homekit
1112
+ * @returns [device position, device direction]
1113
+ */
1114
+ mapHomekitValuesToDeviceValues(homekitPosition, homekitTiltAngle) {
1115
+ // homekit position 0 => closed
1116
+ // homekit position 100 => open
1117
+ // device position [up, 0] = closed upwards
1118
+ // device position [down, 0] = closed downwards
1119
+ // device position [up, 100] = open
1120
+ // device position [down, 100] = open
1121
+ switch (this.mappingMode) {
1122
+ case BlindTiltMappingMode.OnlyUp:
1123
+ // invert
1124
+ return ['up', homekitPosition];
1125
+ case BlindTiltMappingMode.OnlyDown:
1126
+ // invert
1127
+ return ['down', homekitPosition];
1128
+ case BlindTiltMappingMode.DownAndUp:
1129
+ // homekit 0 = downwards closed,
1130
+ // homekit 50 = open,
1131
+ // homekit 100 = upwards closed
1132
+ if (homekitPosition <= 50) {
1133
+ // homekit 0..50 -> device 100..0 so scale and invert
1134
+ return ['down', 100 - homekitPosition * 2];
1135
+ }
1136
+ else {
1137
+ // homekit 50..100 -> device 0..100, so rebase, scale and invert
1138
+ return ['up', (homekitPosition - 50) * 2];
1139
+ }
1140
+ case BlindTiltMappingMode.UpAndDown:
1141
+ // homekit 0 = upwards closed,
1142
+ // homekit 50 = open,
1143
+ // homekit 100 = upwards closed
1144
+ if (homekitPosition <= 50) {
1145
+ // homekit 0..50 -> device 0..100 so scale and invert
1146
+ return ['up', homekitPosition * 2];
1147
+ }
1148
+ else {
1149
+ // homekit 50..100 -> device 100...0 so scale
1150
+ return ['down', 100 - homekitPosition * 2];
1151
+ }
1152
+ case BlindTiltMappingMode.UseTiltForDirection:
1153
+ // tilt -90, homekit 0 = closed downwards
1154
+ // tilt -90, homekit 100 = open
1155
+ // tilt 90, homekit 0 = closed upwards
1156
+ // tilt 90, homekit 100 = open
1157
+ if (homekitTiltAngle <= 0) {
1158
+ // downwards
1159
+ // homekit 0..100 -> device 0..100, so invert
1160
+ return ['down', homekitPosition];
1161
+ }
1162
+ else {
1163
+ // upwards
1164
+ // homekit 0..100 -> device 0..100, so invert
1165
+ return ['up,', homekitPosition];
1166
+ }
1167
+ }
1168
+ }
1001
1169
  async refreshRate(device) {
1002
1170
  // refreshRate
1003
1171
  if (device.refreshRate) {
@@ -1009,19 +1177,19 @@ class BlindTilt {
1009
1177
  this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Using Platform Config refreshRate: ${this.deviceRefreshRate}`);
1010
1178
  }
1011
1179
  // updateRate
1012
- if (device?.curtain?.updateRate) {
1013
- this.updateRate = device?.curtain?.updateRate;
1180
+ if (device?.blindTilt?.updateRate) {
1181
+ this.updateRate = device?.blindTilt?.updateRate;
1014
1182
  this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Using Device Config Blind Tilt updateRate: ${this.updateRate}`);
1015
1183
  }
1016
1184
  else {
1017
- this.updateRate = 7;
1185
+ this.updateRate = 2;
1018
1186
  this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Using Default Blind Tilt updateRate: ${this.updateRate}`);
1019
1187
  }
1020
1188
  }
1021
1189
  async config(device) {
1022
1190
  let config = {};
1023
- if (device.curtain) {
1024
- config = device.curtain;
1191
+ if (device.blindTilt) {
1192
+ config = device.blindTilt;
1025
1193
  }
1026
1194
  if (device.connectionType !== undefined) {
1027
1195
  config['connectionType'] = device.connectionType;
@@ -1044,6 +1212,12 @@ class BlindTilt {
1044
1212
  if (device.maxRetry !== undefined) {
1045
1213
  config['maxRetry'] = device.maxRetry;
1046
1214
  }
1215
+ if (device.blindTilt?.mappingMode === undefined) {
1216
+ config['mappingMode'] = BlindTiltMappingMode.OnlyUp;
1217
+ }
1218
+ else {
1219
+ config['mappingMode'] = device.blindTilt?.mappingMode;
1220
+ }
1047
1221
  if (Object.entries(config).length !== 0) {
1048
1222
  this.infoLog(`${this.device.deviceType}: ${this.accessory.displayName} Config: ${(0, super_stringify_1.default)(config)}`);
1049
1223
  }