[homematic] Fix long button press handling for HM-IP devices (#11982)

* [homematic] Fix long button press handling for HM-IP devices

HM devices have the following long press cycle:
PRESS_CONT
PRESS_LONG
PRESS_CONT (N times for repetion)
PRESS_LONG_RELEASE

while (at least some) HM-IP devices use this one:
PRESS_LONG
PRESS_LONG_START
PRESS_LONG (N times for repetition)
PRESS_LONG_RELEASE

Add support for the latter case while keeping support for the former
case.

Signed-off-by: Danny Baumann <dannybaumann@web.de>

* [homematic] Track 'uses LONG_START datapoint' flag per-device
This commit is contained in:
maniac103 2022-01-13 09:09:19 +01:00 committed by GitHub
parent a1e6a4e35c
commit a4c579b753
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 34 additions and 4 deletions

View File

@ -14,6 +14,8 @@ package org.openhab.binding.homematic.internal.communicator.virtual;
import static org.openhab.binding.homematic.internal.misc.HomematicConstants.VIRTUAL_DATAPOINT_NAME_BUTTON; import static org.openhab.binding.homematic.internal.misc.HomematicConstants.VIRTUAL_DATAPOINT_NAME_BUTTON;
import java.util.HashSet;
import org.openhab.binding.homematic.internal.misc.MiscUtils; import org.openhab.binding.homematic.internal.misc.MiscUtils;
import org.openhab.binding.homematic.internal.model.HmChannel; import org.openhab.binding.homematic.internal.model.HmChannel;
import org.openhab.binding.homematic.internal.model.HmDatapoint; import org.openhab.binding.homematic.internal.model.HmDatapoint;
@ -36,6 +38,8 @@ public class ButtonVirtualDatapointHandler extends AbstractVirtualDatapointHandl
private static final String LONG_REPEATED_EVENT = "LONG_REPEATED"; private static final String LONG_REPEATED_EVENT = "LONG_REPEATED";
private static final String LONG_RELEASED_EVENT = "LONG_RELEASED"; private static final String LONG_RELEASED_EVENT = "LONG_RELEASED";
private HashSet<String> devicesUsingLongStartEvent = new HashSet<>();
@Override @Override
public String getName() { public String getName() {
return VIRTUAL_DATAPOINT_NAME_BUTTON; return VIRTUAL_DATAPOINT_NAME_BUTTON;
@ -61,6 +65,7 @@ public class ButtonVirtualDatapointHandler extends AbstractVirtualDatapointHandl
@Override @Override
public void handleEvent(VirtualGateway gateway, HmDatapoint dp) { public void handleEvent(VirtualGateway gateway, HmDatapoint dp) {
HmChannel channel = dp.getChannel(); HmChannel channel = dp.getChannel();
String deviceSerial = channel.getDevice().getAddress();
HmDatapoint vdp = getVirtualDatapoint(channel); HmDatapoint vdp = getVirtualDatapoint(channel);
int usPos = dp.getName().indexOf("_"); int usPos = dp.getName().indexOf("_");
String pressType = usPos == -1 ? dp.getName() : dp.getName().substring(usPos + 1); String pressType = usPos == -1 ? dp.getName() : dp.getName().substring(usPos + 1);
@ -74,13 +79,20 @@ public class ButtonVirtualDatapointHandler extends AbstractVirtualDatapointHandl
break; break;
} }
case "LONG": case "LONG":
if (LONG_REPEATED_EVENT.equals(vdp.getValue())) { if (isLongPressActive) {
// Suppress long press events during an ongoing long press // 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); vdp.setValue(LONG_REPEATED_EVENT);
} else { } else {
// HM devices start long press via LONG events
vdp.setValue(CommonTriggerEvents.LONG_PRESSED); vdp.setValue(CommonTriggerEvents.LONG_PRESSED);
} }
break; break;
case "LONG_START":
vdp.setValue(CommonTriggerEvents.LONG_PRESSED);
devicesUsingLongStartEvent.add(deviceSerial);
break;
case "LONG_RELEASE": case "LONG_RELEASE":
// Only send release events if we sent a pressed event before // Only send release events if we sent a pressed event before
vdp.setValue(isLongPressActive ? LONG_RELEASED_EVENT : null); vdp.setValue(isLongPressActive ? LONG_RELEASED_EVENT : null);
@ -99,7 +111,8 @@ public class ButtonVirtualDatapointHandler extends AbstractVirtualDatapointHandl
logger.warn("Unexpected vaule '{}' for PRESS virtual datapoint", pressType); logger.warn("Unexpected vaule '{}' for PRESS virtual datapoint", pressType);
} }
} else { } else {
if ("LONG".equals(pressType) && LONG_REPEATED_EVENT.equals(vdp.getValue())) { String usedStartEvent = devicesUsingLongStartEvent.contains(deviceSerial) ? "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 // 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 // event time out the repetitions, the CONT delay handler will take care of it
vdp.setValue(LONG_REPEATED_EVENT); vdp.setValue(LONG_REPEATED_EVENT);

View File

@ -60,7 +60,7 @@ public class ButtonDatapointTest extends JavaTest {
} }
@Test @Test
public void testLongPress() throws IOException, HomematicClientException { public void testLongPressHm() throws IOException, HomematicClientException {
HmDatapoint longPressDp = createPressDatapoint("PRESS_LONG", Boolean.TRUE); HmDatapoint longPressDp = createPressDatapoint("PRESS_LONG", Boolean.TRUE);
HmDatapoint buttonVirtualDatapoint = getButtonVirtualDatapoint(longPressDp); HmDatapoint buttonVirtualDatapoint = getButtonVirtualDatapoint(longPressDp);
@ -76,6 +76,23 @@ public class ButtonDatapointTest extends JavaTest {
assertThat(buttonVirtualDatapoint.getValue(), is("LONG_RELEASED")); assertThat(buttonVirtualDatapoint.getValue(), is("LONG_RELEASED"));
} }
@Test
public void testLongPressHmIp() throws IOException, HomematicClientException {
HmDatapoint longPressDp = createPressDatapoint("PRESS_LONG_START", Boolean.TRUE);
HmDatapoint buttonVirtualDatapoint = getButtonVirtualDatapoint(longPressDp);
mockEventReceiver.eventReceived(longPressDp);
assertThat(buttonVirtualDatapoint.getValue(), is(CommonTriggerEvents.LONG_PRESSED));
HmDatapoint contPressDp = createPressDatapointFrom(longPressDp, "PRESS_LONG", Boolean.TRUE);
mockEventReceiver.eventReceived(contPressDp);
assertThat(buttonVirtualDatapoint.getValue(), is("LONG_REPEATED"));
HmDatapoint releaseDp = createPressDatapointFrom(longPressDp, "PRESS_LONG_RELEASE", Boolean.TRUE);
mockEventReceiver.eventReceived(releaseDp);
assertThat(buttonVirtualDatapoint.getValue(), is("LONG_RELEASED"));
}
@Test @Test
public void testUnsupportedEvents() throws IOException, HomematicClientException { public void testUnsupportedEvents() throws IOException, HomematicClientException {
HmDatapoint contPressDp = createPressDatapoint("PRESS_CONT", Boolean.TRUE); HmDatapoint contPressDp = createPressDatapoint("PRESS_CONT", Boolean.TRUE);