]> git.basschouten.com Git - openhab-addons.git/commitdiff
[homematic] Fix duplication of LONG_REPEATED events for HM devices (#15906)
authormaniac103 <dannybaumann@web.de>
Sat, 18 Nov 2023 19:38:55 +0000 (20:38 +0100)
committerGitHub <noreply@github.com>
Sat, 18 Nov 2023 19:38:55 +0000 (20:38 +0100)
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 <dannybaumann@web.de>
bundles/org.openhab.binding.homematic/src/main/java/org/openhab/binding/homematic/internal/communicator/virtual/ButtonVirtualDatapointHandler.java
bundles/org.openhab.binding.homematic/src/test/java/org/openhab/binding/homematic/internal/communicator/virtual/ButtonDatapointTest.java

index 5caa73d36fdf3cb07d0cdc48848c35ebd5a30593..589c015c550880477b1f3a1b9f6ed378e38b4b29 100644 (file)
@@ -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
index c7106c5b6cb4bc3b9a99350622e6690970fc55b9..dc49e38781bf7c6da681d335a20d43610dc43529 100644 (file)
@@ -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);