@switchbot/homebridge-switchbot 2.5.0-beta.2 → 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,6 +93,7 @@ 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({
@@ -89,11 +101,12 @@ class BlindTilt {
89
101
  minValue: -90,
90
102
  maxValue: 90,
91
103
  validValues: [-90, 90],
92
- validValueRanges: [-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({
@@ -101,7 +114,6 @@ class BlindTilt {
101
114
  minValue: -90,
102
115
  maxValue: 90,
103
116
  validValues: [-90, 90],
104
- validValueRanges: [-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,16 +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
- this.CurrentPosition = 100 - Number(this.slidePosition);
233
298
  await this.setMinMax();
234
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
+ }
235
304
  if (this.setNewTarget) {
236
305
  this.infoLog(`${this.device.deviceType}: ${this.accessory.displayName} Checking Status ...`);
237
306
  }
238
- if (this.setNewTarget && this.moving) {
307
+ this.debugLog(`runStatus: ${this.runStatus}`);
308
+ if (this.setNewTarget || (this.runStatus === undefined || this.runStatus !== 'static')) {
239
309
  await this.setMinMax();
240
- if (this.TargetPosition > this.CurrentPosition) {
310
+ if (this.TargetPosition > this.CurrentPosition || (homekitTiltAngle && (this.TargetHorizontalTiltAngle !== this.CurrentHorizontalTiltAngle))) {
241
311
  this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Closing, CurrentPosition: ${this.CurrentPosition} `);
242
312
  this.PositionState = this.platform.Characteristic.PositionState.INCREASING;
243
313
  this.windowCoveringService.getCharacteristic(this.platform.Characteristic.PositionState).updateValue(this.PositionState);
@@ -250,30 +320,39 @@ class BlindTilt {
250
320
  this.debugLog(`${this.device.deviceType}: ${this.CurrentPosition} DECREASING PositionState: ${this.PositionState}`);
251
321
  }
252
322
  else {
253
- 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}`);
254
325
  this.PositionState = this.platform.Characteristic.PositionState.STOPPED;
255
326
  this.windowCoveringService.getCharacteristic(this.platform.Characteristic.PositionState).updateValue(this.PositionState);
256
327
  this.debugLog(`${this.device.deviceType}: ${this.CurrentPosition} STOPPED PositionState: ${this.PositionState}`);
257
328
  }
258
329
  }
259
330
  else {
260
- 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}`);
261
333
  this.TargetPosition = this.CurrentPosition;
334
+ if (homekitTiltAngle) {
335
+ this.TargetHorizontalTiltAngle = this.CurrentHorizontalTiltAngle;
336
+ }
262
337
  this.PositionState = this.platform.Characteristic.PositionState.STOPPED;
263
338
  this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Stopped`);
264
339
  }
265
- if (this.direction === 'Up') {
266
- this.CurrentHorizontalTiltAngle = 90;
267
- }
268
- else if (this.direction === 'Down') {
269
- this.CurrentHorizontalTiltAngle = -90;
270
- }
271
- else {
272
- this.CurrentHorizontalTiltAngle = 0;
273
- }
274
340
  this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} CurrentPosition: ${this.CurrentPosition},` +
275
- ` TargetPosition: ${this.TargetPosition}, PositionState: ${this.PositionState},` +
276
- ` 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
+ }
277
356
  }
278
357
  async refreshStatus() {
279
358
  if (!this.device.enableCloudService && this.OpenAPI) {
@@ -305,6 +384,7 @@ class BlindTilt {
305
384
  if (switchbot !== false) {
306
385
  switchbot
307
386
  .startScan({
387
+ model: 'c',
308
388
  id: this.device.bleMac,
309
389
  })
310
390
  .then(async () => {
@@ -318,9 +398,11 @@ class BlindTilt {
318
398
  this.battery = ad.serviceData.battery;
319
399
  this.inMotion = ad.serviceData.inMotion;
320
400
  this.position = ad.serviceData.position;
401
+ this.lightLevel = ad.serviceData.lightLevel;
321
402
  this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} serviceData: ${(0, super_stringify_1.default)(ad.serviceData)}`);
322
403
  this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} calibration: ${ad.serviceData.calibration}, ` +
323
- `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}`);
324
406
  if (this.serviceData) {
325
407
  this.connected = true;
326
408
  this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} connected: ${this.connected}`);
@@ -382,10 +464,11 @@ class BlindTilt {
382
464
  try {
383
465
  this.deviceStatus = JSON.parse(rawData);
384
466
  this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} refreshStatus: ${(0, super_stringify_1.default)(this.deviceStatus)}`);
385
- 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;
386
469
  this.moving = this.deviceStatus.body.moving;
387
- this.Battery = this.deviceStatus.body.battery;
388
- this.direction = this.deviceStatus.body.direction; // "Up"/"Down"
470
+ this.runStatus = this.deviceStatus.body.runStatus;
471
+ this.brightness = this.deviceStatus.body.brightness;
389
472
  this.openAPIparseStatus();
390
473
  this.updateHomeKitCharacteristics();
391
474
  }
@@ -438,6 +521,12 @@ class BlindTilt {
438
521
  .join(':')
439
522
  .toLowerCase();
440
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}`);
441
530
  if (switchbot !== false) {
442
531
  switchbot
443
532
  .discover({ model: 'c', quick: true, id: this.device.bleMac })
@@ -446,7 +535,7 @@ class BlindTilt {
446
535
  return await this.retry({
447
536
  max: await this.maxRetry(),
448
537
  fn: () => {
449
- return device_list[0].runToPos(100 - Number(this.TargetPosition));
538
+ return device_list[0].runToPos(100 - Number(this.TargetPosition), adjustedMode);
450
539
  },
451
540
  });
452
541
  })
@@ -504,40 +593,12 @@ class BlindTilt {
504
593
  .digest();
505
594
  const sign = signTerm.toString('base64');
506
595
  this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} sign: ${sign}`);
507
- this.debugLog(`Pushing ${this.TargetPosition}`);
508
- let command = '';
509
- let parameter = '';
510
- if (this.TargetHorizontalTiltAngle === 90 && this.TargetPosition === 100) {
511
- command = 'fullyOpen';
512
- parameter = 'default';
513
- }
514
- else if (this.TargetHorizontalTiltAngle === -90 && this.TargetPosition === 100) {
515
- command = 'fullyOpen';
516
- parameter = 'default';
517
- }
518
- else if (this.TargetHorizontalTiltAngle === 90 && this.TargetPosition === 0) {
519
- command = 'closeUp';
520
- parameter = 'default';
521
- }
522
- else if (this.TargetHorizontalTiltAngle === -90 && this.TargetPosition === 0) {
523
- command = 'closeDown';
524
- parameter = 'default';
525
- }
526
- else {
527
- let direction = '';
528
- const position = this.TargetPosition;
529
- if (this.TargetHorizontalTiltAngle === 90) {
530
- direction = 'up';
531
- }
532
- else {
533
- direction = 'down';
534
- }
535
- command = 'setPosition';
536
- parameter = `${direction};${position}`;
537
- }
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}`);
538
599
  const body = (0, super_stringify_1.default)({
539
- 'command': `${command}`,
540
- 'parameter': `${parameter}`,
600
+ 'command': 'setPosition',
601
+ 'parameter': `${direction};${position}`,
541
602
  'commandType': 'command',
542
603
  });
543
604
  this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Sending request to SwitchBot API, body: ${body},`);
@@ -580,6 +641,23 @@ class BlindTilt {
580
641
  + ` Connection, Error Message: ${(0, super_stringify_1.default)(e.message)}`);
581
642
  }
582
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
+ }
583
661
  /**
584
662
  * Handle requests to set the value of the "Target Position" characteristic
585
663
  */
@@ -594,52 +672,28 @@ class BlindTilt {
594
672
  if (this.device.mqttURL) {
595
673
  this.mqttPublish('TargetPosition', this.TargetPosition);
596
674
  }
675
+ this.startUpdatingBlindTiltIfNeeded();
676
+ }
677
+ async startUpdatingBlindTiltIfNeeded() {
597
678
  await this.setMinMax();
598
- if (value > this.CurrentPosition) {
679
+ this.debugLog('setMinMax');
680
+ if (this.TargetPosition > this.CurrentPosition || (this.TargetHorizontalTiltAngle !== this.CurrentHorizontalTiltAngle)) {
599
681
  this.PositionState = this.platform.Characteristic.PositionState.INCREASING;
600
682
  this.setNewTarget = true;
601
- 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}`);
602
685
  }
603
- else if (value < this.CurrentPosition) {
686
+ else if (this.TargetPosition < this.CurrentPosition) {
604
687
  this.PositionState = this.platform.Characteristic.PositionState.DECREASING;
605
688
  this.setNewTarget = true;
606
- 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}`);
607
691
  }
608
692
  else {
609
693
  this.PositionState = this.platform.Characteristic.PositionState.STOPPED;
610
694
  this.setNewTarget = false;
611
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} value: ${value}, CurrentPosition: ${this.CurrentPosition}`);
612
- }
613
- this.windowCoveringService.setCharacteristic(this.platform.Characteristic.PositionState, this.PositionState);
614
- this.windowCoveringService.getCharacteristic(this.platform.Characteristic.PositionState).updateValue(this.PositionState);
615
- /**
616
- * If Blind Tilt movement time is short, the moving flag from backend is always false.
617
- * The minimum time depends on the network control latency.
618
- */
619
- clearTimeout(this.setNewTargetTimer);
620
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} updateRate: ${this.updateRate}`);
621
- if (this.setNewTarget) {
622
- this.setNewTargetTimer = setTimeout(() => {
623
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} setNewTarget ${this.setNewTarget} timeout`);
624
- this.setNewTarget = false;
625
- }, this.updateRate * 1000);
626
- }
627
- this.doBlindTiltUpdate.next();
628
- }
629
- /**
630
- * Handle requests to set the value of the "Target Position" characteristic
631
- */
632
- async TargetHorizontalTiltAngleSet(value) {
633
- if (this.TargetHorizontalTiltAngle === this.accessory.context.TargetHorizontalTiltAngle) {
634
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} No Changes, Set TargetHorizontalTiltAngle: ${value}`);
635
- }
636
- else {
637
- this.infoLog(`${this.device.deviceType}: ${this.accessory.displayName} Set TargetHorizontalTiltAngle: ${value}`);
638
- }
639
- this.TargetHorizontalTiltAngle = value;
640
- this.accessory.context.TargetHorizontalTiltAngle = this.TargetHorizontalTiltAngle;
641
- if (this.device.mqttURL) {
642
- this.mqttPublish('TargetHorizontalTiltAngle', this.TargetHorizontalTiltAngle);
695
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} value: ${this.CurrentPosition},` +
696
+ ` CurrentPosition: ${this.CurrentPosition}`);
643
697
  }
644
698
  this.windowCoveringService.setCharacteristic(this.platform.Characteristic.PositionState, this.PositionState);
645
699
  this.windowCoveringService.getCharacteristic(this.platform.Characteristic.PositionState).updateValue(this.PositionState);
@@ -659,6 +713,20 @@ class BlindTilt {
659
713
  }
660
714
  async updateHomeKitCharacteristics() {
661
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
+ }
662
730
  if (this.CurrentPosition === undefined || Number.isNaN(this.CurrentPosition)) {
663
731
  this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} CurrentPosition: ${this.CurrentPosition}`);
664
732
  }
@@ -692,17 +760,19 @@ class BlindTilt {
692
760
  this.windowCoveringService.updateCharacteristic(this.platform.Characteristic.TargetPosition, Number(this.TargetPosition));
693
761
  this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} updateCharacteristic TargetPosition: ${this.TargetPosition}`);
694
762
  }
695
- if (this.TargetHorizontalTiltAngle === undefined || Number.isNaN(this.TargetHorizontalTiltAngle)) {
696
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} TargetHorizontalTiltAngle: ${this.TargetHorizontalTiltAngle}`);
697
- }
698
- else {
699
- if (this.device.mqttURL) {
700
- 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}`);
766
+ }
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}`);
701
775
  }
702
- this.accessory.context.TargetHorizontalTiltAngle = this.TargetHorizontalTiltAngle;
703
- this.windowCoveringService.updateCharacteristic(this.platform.Characteristic.TargetHorizontalTiltAngle, Number(this.TargetHorizontalTiltAngle));
704
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} updateCharacteristic`
705
- + ` TargetHorizontalTiltAngle: ${this.TargetHorizontalTiltAngle}`);
706
776
  }
707
777
  if (this.BLE) {
708
778
  if (this.BatteryLevel === undefined) {
@@ -800,6 +870,28 @@ class BlindTilt {
800
870
  await this.openAPIRefreshStatus();
801
871
  }
802
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
+ }
803
895
  async setMinMax() {
804
896
  if (this.device.curtain?.set_min) {
805
897
  if (this.CurrentPosition <= this.device.curtain?.set_min) {
@@ -811,13 +903,16 @@ class BlindTilt {
811
903
  this.CurrentPosition = 100;
812
904
  }
813
905
  }
906
+ if (this.mappingMode === BlindTiltMappingMode.UseTiltForDirection) {
907
+ this.CurrentHorizontalTiltAngle = this.CurrentHorizontalTiltAngle < 0 ? -90 : 90;
908
+ }
814
909
  }
815
910
  minStep(device) {
816
911
  if (device.curtain?.set_minStep) {
817
912
  this.set_minStep = device.curtain?.set_minStep;
818
913
  }
819
914
  else {
820
- this.set_minStep = 90;
915
+ this.set_minStep = 1;
821
916
  }
822
917
  return this.set_minStep;
823
918
  }
@@ -911,6 +1006,9 @@ class BlindTilt {
911
1006
  this.windowCoveringService.updateCharacteristic(this.platform.Characteristic.CurrentPosition, e);
912
1007
  this.windowCoveringService.updateCharacteristic(this.platform.Characteristic.PositionState, e);
913
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
+ }
914
1012
  if (this.BLE) {
915
1013
  this.batteryService?.updateCharacteristic(this.platform.Characteristic.BatteryLevel, e);
916
1014
  this.batteryService?.updateCharacteristic(this.platform.Characteristic.StatusLowBattery, e);
@@ -947,12 +1045,6 @@ class BlindTilt {
947
1045
  else {
948
1046
  this.TargetPosition = this.accessory.context.TargetPosition;
949
1047
  }
950
- if (this.TargetHorizontalTiltAngle === undefined) {
951
- this.TargetHorizontalTiltAngle = 0;
952
- }
953
- else {
954
- this.TargetHorizontalTiltAngle = this.accessory.context.TargetHorizontalTiltAngle;
955
- }
956
1048
  if (this.PositionState === undefined) {
957
1049
  this.PositionState = this.platform.Characteristic.PositionState.STOPPED;
958
1050
  }
@@ -960,6 +1052,120 @@ class BlindTilt {
960
1052
  this.PositionState = this.accessory.context.PositionState;
961
1053
  }
962
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
+ }
963
1169
  async refreshRate(device) {
964
1170
  // refreshRate
965
1171
  if (device.refreshRate) {
@@ -971,19 +1177,19 @@ class BlindTilt {
971
1177
  this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Using Platform Config refreshRate: ${this.deviceRefreshRate}`);
972
1178
  }
973
1179
  // updateRate
974
- if (device?.curtain?.updateRate) {
975
- this.updateRate = device?.curtain?.updateRate;
1180
+ if (device?.blindTilt?.updateRate) {
1181
+ this.updateRate = device?.blindTilt?.updateRate;
976
1182
  this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Using Device Config Blind Tilt updateRate: ${this.updateRate}`);
977
1183
  }
978
1184
  else {
979
- this.updateRate = 7;
1185
+ this.updateRate = 2;
980
1186
  this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Using Default Blind Tilt updateRate: ${this.updateRate}`);
981
1187
  }
982
1188
  }
983
1189
  async config(device) {
984
1190
  let config = {};
985
- if (device.curtain) {
986
- config = device.curtain;
1191
+ if (device.blindTilt) {
1192
+ config = device.blindTilt;
987
1193
  }
988
1194
  if (device.connectionType !== undefined) {
989
1195
  config['connectionType'] = device.connectionType;
@@ -1006,6 +1212,12 @@ class BlindTilt {
1006
1212
  if (device.maxRetry !== undefined) {
1007
1213
  config['maxRetry'] = device.maxRetry;
1008
1214
  }
1215
+ if (device.blindTilt?.mappingMode === undefined) {
1216
+ config['mappingMode'] = BlindTiltMappingMode.OnlyUp;
1217
+ }
1218
+ else {
1219
+ config['mappingMode'] = device.blindTilt?.mappingMode;
1220
+ }
1009
1221
  if (Object.entries(config).length !== 0) {
1010
1222
  this.infoLog(`${this.device.deviceType}: ${this.accessory.displayName} Config: ${(0, super_stringify_1.default)(config)}`);
1011
1223
  }