@@ -180,9 +180,10 @@ Component::Type WindowCovering::type() const {
180
180
}
181
181
182
182
StatusOr<std::string> WindowCovering::GetInfo () const {
183
- return mgos::SPrintf (" c:%d mp:%.2f mt_ms:%d cp:%.2f tp:%.2f lemd:%d" ,
183
+ return mgos::SPrintf (" c:%d mp:%.2f mt_ms:%d cp:%.2f tp:%.2f lemd:%d lhmd:%d " ,
184
184
cfg_->calibrated , cfg_->move_power , cfg_->move_time_ms ,
185
- cur_pos_, tgt_pos_, (int ) last_ext_move_dir_);
185
+ cur_pos_, tgt_pos_, (int ) last_ext_move_dir_,
186
+ (int ) last_hap_move_dir_);
186
187
}
187
188
188
189
StatusOr<std::string> WindowCovering::GetInfoJSON () const {
@@ -331,19 +332,35 @@ void WindowCovering::SetTgtPos(float new_tgt_pos, const char *src) {
331
332
tgt_pos_char_->RaiseEvent ();
332
333
}
333
334
335
+ // We want tile taps to cycle the open-stop-close-stop sequence.
336
+ // Problem is, tile taps behave as "prefer close": Home will send
337
+ // 0 ("fully close") if tile is tapped while in the intermediate position.
338
+ // We try to detect this case and ignore the target setting, instead
339
+ // we use the opposite of last action. This results in more natural and
340
+ // intuitive behavior (originally requested in
341
+ // https://github.com/mongoose-os-apps/shelly-homekit/issues/181).
342
+ // However, this causes issues with automations (reported in
343
+ // https://github.com/mongoose-os-apps/shelly-homekit/issues/254).
344
+ // To address this, we "expire" last state after 1 minute. This provides
345
+ // intuitive behavior within short time span so short-term interactive use
346
+ // is unaffected and allow automated changes to work properly.
334
347
void WindowCovering::HAPSetTgtPos (float value) {
335
- LOG (LL_INFO, (" WC %d: HAPSetTgtPos %.2f cur %.2f tgt %.2f lemd %d" , id (),
336
- value, cur_pos_, tgt_pos_, (int ) last_ext_move_dir_));
348
+ // If last action was a while ago, ignore it.
349
+ if (mgos_uptime_micros () - last_hap_set_tgt_pos_ > 60 * 1000000 ) {
350
+ last_hap_move_dir_ = Direction::kNone ;
351
+ }
352
+ LOG (LL_INFO, (" WC %d: HAPSetTgtPos %.2f cur %.2f tgt %.2f lhmd %d" , id (),
353
+ value, cur_pos_, tgt_pos_, (int ) last_hap_move_dir_));
337
354
// If the specified position is intermediate, just do what we are told.
338
355
if ((value != kFullyClosed && value != kFullyOpen ) ||
339
- last_ext_move_dir_ == Direction::kNone ) {
356
+ last_hap_move_dir_ == Direction::kNone ) {
340
357
SetTgtPos (value, " HAP" );
341
358
if (value == kFullyClosed ) {
342
- last_ext_move_dir_ = Direction::kClose ;
359
+ last_hap_move_dir_ = Direction::kClose ;
343
360
} else if (value == kFullyOpen ) {
344
- last_ext_move_dir_ = Direction::kOpen ;
361
+ last_hap_move_dir_ = Direction::kOpen ;
345
362
} else {
346
- last_ext_move_dir_ = Direction::kNone ;
363
+ last_hap_move_dir_ = Direction::kNone ;
347
364
}
348
365
} else if ((value == kFullyClosed &&
349
366
(cur_pos_ == kFullyClosed || tgt_pos_ == kFullyClosed )) ||
@@ -352,8 +369,9 @@ void WindowCovering::HAPSetTgtPos(float value) {
352
369
// Nothing to do.
353
370
} else {
354
371
// This is most likely a tap on the tile.
355
- HandleInputSingle (" HAPalt" );
372
+ HandleInputSingle (" HAPalt" , &last_hap_move_dir_ );
356
373
}
374
+ last_hap_set_tgt_pos_ = mgos_uptime_micros ();
357
375
// Run state machine immediately to improve reaction time,
358
376
RunOnce ();
359
377
}
@@ -622,6 +640,7 @@ void WindowCovering::HandleInputEvent01(Direction dir, Input::Event ev,
622
640
if (state) {
623
641
if (moving_dir_ == Direction::kNone || moving_dir_ != dir) {
624
642
float pos = (dir == Direction::kOpen ? kFullyOpen : kFullyClosed );
643
+ last_ext_move_dir_ = dir;
625
644
SetTgtPos (pos, " ext" );
626
645
} else {
627
646
stop = true ;
@@ -634,6 +653,7 @@ void WindowCovering::HandleInputEvent01(Direction dir, Input::Event ev,
634
653
RunOnce ();
635
654
SetTgtPos (cur_pos_, " ext" );
636
655
}
656
+ last_hap_move_dir_ = Direction::kNone ;
637
657
// Run the state machine immediately for quicker response.
638
658
RunOnce ();
639
659
}
@@ -645,7 +665,8 @@ void WindowCovering::HandleInputEvent2(Input::Event ev, bool state) {
645
665
}
646
666
if (ev != Input::Event::kChange ) return ;
647
667
if (!state) return ;
648
- HandleInputSingle (" ext" );
668
+ HandleInputSingle (" ext" , &last_ext_move_dir_);
669
+ last_hap_move_dir_ = Direction::kNone ;
649
670
// Run the state machine immediately for quicker response.
650
671
RunOnce ();
651
672
}
@@ -665,15 +686,16 @@ void WindowCovering::HandleInputEventNotCalibrated() {
665
686
out_close_->SetState (want_close, " ext" );
666
687
}
667
688
668
- void WindowCovering::HandleInputSingle (const char *src) {
689
+ void WindowCovering::HandleInputSingle (const char *src,
690
+ Direction *last_move_dir) {
669
691
switch (moving_dir_) {
670
692
case Direction::kNone : {
671
- if (cur_pos_ == kFullyClosed || last_ext_move_dir_ != Direction::kOpen ) {
693
+ if (cur_pos_ == kFullyClosed || *last_move_dir != Direction::kOpen ) {
672
694
SetTgtPos (kFullyOpen , src);
673
- last_ext_move_dir_ = Direction::kOpen ;
695
+ *last_move_dir = Direction::kOpen ;
674
696
} else {
675
697
SetTgtPos (kFullyClosed , src);
676
- last_ext_move_dir_ = Direction::kClose ;
698
+ *last_move_dir = Direction::kClose ;
677
699
}
678
700
break ;
679
701
}
0 commit comments