From 87ae9e2a37eccb68ee9c827fa1f60c3a8b92dc4b Mon Sep 17 00:00:00 2001 From: maniac103 Date: Sat, 18 Nov 2023 20:38:55 +0100 Subject: [PATCH] [homematic] Fix duplication of LONG_REPEATED events for HM devices (#15906) Depending on device configuration and used central [1], HM devices may indicate long press repetition either by a single PRESS_CONT event or by a PRESS_CONT + PRESS_LONG combination. In the latter case, make sure to not generate a LONG_REPEATED trigger channel event for both PRESS_CONT and PRESS_LONG, but instead keep LONG_REPEATED generation to the PRESS_CONT handling. [1] I'm not sure what a real CCU is doing, but for Homegear, a configured long press timeout of less than 1s generates only PRESS_CONT, while a timeout of more than 1s generates PRESS_CONT + PRESS_LONG ... see [2]. [2] https://github.com/Homegear/Homegear-HomeMaticBidCoS/blob/master/src/BidCoSPeer.cpp#L1711-L1716 Signed-off-by: Danny Baumann --- .../ButtonVirtualDatapointHandler.java | 19 ++++++++++++------- .../virtual/ButtonDatapointTest.java | 7 +++++++ 2 files changed, 19 insertions(+), 7 deletions(-) diff --git a/bundles/org.openhab.binding.homematic/src/main/java/org/openhab/binding/homematic/internal/communicator/virtual/ButtonVirtualDatapointHandler.java b/bundles/org.openhab.binding.homematic/src/main/java/org/openhab/binding/homematic/internal/communicator/virtual/ButtonVirtualDatapointHandler.java index 5caa73d36fd..589c015c550 100644 --- a/bundles/org.openhab.binding.homematic/src/main/java/org/openhab/binding/homematic/internal/communicator/virtual/ButtonVirtualDatapointHandler.java +++ b/bundles/org.openhab.binding.homematic/src/main/java/org/openhab/binding/homematic/internal/communicator/virtual/ButtonVirtualDatapointHandler.java @@ -68,6 +68,7 @@ public class ButtonVirtualDatapointHandler extends AbstractVirtualDatapointHandl HmDatapoint vdp = getVirtualDatapoint(channel); int usPos = dp.getName().indexOf("_"); String pressType = usPos == -1 ? dp.getName() : dp.getName().substring(usPos + 1); + boolean usesLongStart = devicesUsingLongStartEvent.contains(deviceSerial); boolean isLongPressActive = CommonTriggerEvents.LONG_PRESSED.equals(vdp.getValue()) || LONG_REPEATED_EVENT.equals(vdp.getValue()); if (MiscUtils.isTrueValue(dp.getValue())) { @@ -78,14 +79,18 @@ public class ButtonVirtualDatapointHandler extends AbstractVirtualDatapointHandl break; } case "LONG": - if (isLongPressActive) { + if (usesLongStart) { // HM-IP devices do long press repetitions via LONG instead of CONT events, // so clear previous value to force re-triggering of event - vdp.setValue(null); - vdp.setValue(LONG_REPEATED_EVENT); + if (isLongPressActive) { + vdp.setValue(null); + vdp.setValue(LONG_REPEATED_EVENT); + } } else { - // HM devices start long press via LONG events - vdp.setValue(CommonTriggerEvents.LONG_PRESSED); + // HM devices start long press via LONG events, but also may keep sending them + // alongside CONT repetition events. In case a long press is already active, we just + // acknowledge those events by setting the value again, to make sure to not re-trigger events + vdp.setValue(isLongPressActive ? LONG_REPEATED_EVENT : CommonTriggerEvents.LONG_PRESSED); } break; case "LONG_START": @@ -107,10 +112,10 @@ public class ButtonVirtualDatapointHandler extends AbstractVirtualDatapointHandl break; default: vdp.setValue(null); - logger.warn("Unexpected vaule '{}' for PRESS virtual datapoint", pressType); + logger.warn("Unexpected value '{}' for PRESS virtual datapoint", pressType); } } else { - String usedStartEvent = devicesUsingLongStartEvent.contains(deviceSerial) ? "LONG_START" : "LONG"; + String usedStartEvent = usesLongStart ? "LONG_START" : "LONG"; if (usedStartEvent.equals(pressType) && LONG_REPEATED_EVENT.equals(vdp.getValue())) { // If we're currently processing a repeated long-press event, don't let the initial LONG // event time out the repetitions, the CONT delay handler will take care of it diff --git a/bundles/org.openhab.binding.homematic/src/test/java/org/openhab/binding/homematic/internal/communicator/virtual/ButtonDatapointTest.java b/bundles/org.openhab.binding.homematic/src/test/java/org/openhab/binding/homematic/internal/communicator/virtual/ButtonDatapointTest.java index c7106c5b6cb..dc49e38781b 100644 --- a/bundles/org.openhab.binding.homematic/src/test/java/org/openhab/binding/homematic/internal/communicator/virtual/ButtonDatapointTest.java +++ b/bundles/org.openhab.binding.homematic/src/test/java/org/openhab/binding/homematic/internal/communicator/virtual/ButtonDatapointTest.java @@ -70,6 +70,12 @@ public class ButtonDatapointTest extends JavaTest { HmDatapoint contPressDp = createPressDatapointFrom(longPressDp, "PRESS_CONT", Boolean.TRUE); mockEventReceiver.eventReceived(contPressDp); assertThat(buttonVirtualDatapoint.getValue(), is("LONG_REPEATED")); + assertThat(buttonVirtualDatapoint.getPreviousValue(), nullValue()); + + // Receiving another LONG event during the long press should be ignored + mockEventReceiver.eventReceived(longPressDp); + assertThat(buttonVirtualDatapoint.getValue(), is("LONG_REPEATED")); + assertThat(buttonVirtualDatapoint.getPreviousValue(), is("LONG_REPEATED")); HmDatapoint releaseDp = createPressDatapointFrom(longPressDp, "PRESS_LONG_RELEASE", Boolean.TRUE); mockEventReceiver.eventReceived(releaseDp); @@ -87,6 +93,7 @@ public class ButtonDatapointTest extends JavaTest { HmDatapoint contPressDp = createPressDatapointFrom(longPressDp, "PRESS_LONG", Boolean.TRUE); mockEventReceiver.eventReceived(contPressDp); assertThat(buttonVirtualDatapoint.getValue(), is("LONG_REPEATED")); + assertThat(buttonVirtualDatapoint.getPreviousValue(), nullValue()); HmDatapoint releaseDp = createPressDatapointFrom(longPressDp, "PRESS_LONG_RELEASE", Boolean.TRUE); mockEventReceiver.eventReceived(releaseDp);