]> git.basschouten.com Git - openhab-addons.git/blob
db121ccb13cbfd6bffd992827aae18105e1bf602
[openhab-addons.git] /
1 /**
2  * Copyright (c) 2010-2021 Contributors to the openHAB project
3  *
4  * See the NOTICE file(s) distributed with this work for additional
5  * information.
6  *
7  * This program and the accompanying materials are made available under the
8  * terms of the Eclipse Public License 2.0 which is available at
9  * http://www.eclipse.org/legal/epl-2.0
10  *
11  * SPDX-License-Identifier: EPL-2.0
12  */
13 package org.openhab.binding.homematic.internal.communicator.virtual;
14
15 import static org.openhab.binding.homematic.internal.misc.HomematicConstants.VIRTUAL_DATAPOINT_NAME_BUTTON;
16
17 import org.openhab.binding.homematic.internal.misc.MiscUtils;
18 import org.openhab.binding.homematic.internal.model.HmChannel;
19 import org.openhab.binding.homematic.internal.model.HmDatapoint;
20 import org.openhab.binding.homematic.internal.model.HmDevice;
21 import org.openhab.binding.homematic.internal.model.HmValueType;
22 import org.openhab.core.thing.CommonTriggerEvents;
23 import org.openhab.core.thing.DefaultSystemChannelTypeProvider;
24 import org.slf4j.Logger;
25 import org.slf4j.LoggerFactory;
26
27 /**
28  * A virtual String datapoint which adds a BUTTON datapoint. It will forward key events to the
29  * system channel {@link DefaultSystemChannelTypeProvider#SYSTEM_BUTTON}.
30  *
31  * @author Michael Reitler - Initial contribution
32  */
33 public class ButtonVirtualDatapointHandler extends AbstractVirtualDatapointHandler {
34     private final Logger logger = LoggerFactory.getLogger(ButtonVirtualDatapointHandler.class);
35
36     private static final String LONG_REPEATED_EVENT = "LONG_REPEATED";
37     private static final String LONG_RELEASED_EVENT = "LONG_RELEASED";
38
39     @Override
40     public String getName() {
41         return VIRTUAL_DATAPOINT_NAME_BUTTON;
42     }
43
44     @Override
45     public void initialize(HmDevice device) {
46         for (HmChannel channel : device.getChannels()) {
47             if (channel.hasPressDatapoint()) {
48                 HmDatapoint dp = addDatapoint(device, channel.getNumber(), getName(), HmValueType.STRING, null, false);
49                 dp.setTrigger(true);
50                 dp.setOptions(new String[] { CommonTriggerEvents.SHORT_PRESSED, CommonTriggerEvents.LONG_PRESSED,
51                         LONG_REPEATED_EVENT, LONG_RELEASED_EVENT });
52             }
53         }
54     }
55
56     @Override
57     public boolean canHandleEvent(HmDatapoint dp) {
58         return dp.isPressDatapoint();
59     }
60
61     @Override
62     public void handleEvent(VirtualGateway gateway, HmDatapoint dp) {
63         HmChannel channel = dp.getChannel();
64         HmDatapoint vdp = getVirtualDatapoint(channel);
65         int usPos = dp.getName().indexOf("_");
66         String pressType = usPos == -1 ? dp.getName() : dp.getName().substring(usPos + 1);
67         boolean isLongPressActive = CommonTriggerEvents.LONG_PRESSED.equals(vdp.getValue())
68                 || LONG_REPEATED_EVENT.equals(vdp.getValue());
69         if (MiscUtils.isTrueValue(dp.getValue())) {
70             switch (pressType) {
71                 case "SHORT": {
72                     vdp.setValue(null); // Force sending new event
73                     vdp.setValue(CommonTriggerEvents.SHORT_PRESSED);
74                     break;
75                 }
76                 case "LONG":
77                     if (LONG_REPEATED_EVENT.equals(vdp.getValue())) {
78                         // Suppress long press events during an ongoing long press
79                         vdp.setValue(LONG_REPEATED_EVENT);
80                     } else {
81                         vdp.setValue(CommonTriggerEvents.LONG_PRESSED);
82                     }
83                     break;
84                 case "LONG_RELEASE":
85                     // Only send release events if we sent a pressed event before
86                     vdp.setValue(isLongPressActive ? LONG_RELEASED_EVENT : null);
87                     break;
88                 case "CONT":
89                     // Clear previous value to force re-triggering of repetition
90                     vdp.setValue(null);
91                     // Only send repetitions if there was a pressed event before
92                     // (a CONT might arrive simultaneously with the initial LONG event)
93                     if (isLongPressActive) {
94                         vdp.setValue(LONG_REPEATED_EVENT);
95                     }
96                     break;
97                 default:
98                     vdp.setValue(null);
99                     logger.warn("Unexpected vaule '{}' for PRESS virtual datapoint", pressType);
100             }
101         } else {
102             if ("LONG".equals(pressType) && LONG_REPEATED_EVENT.equals(vdp.getValue())) {
103                 // If we're currently processing a repeated long-press event, don't let the initial LONG
104                 // event time out the repetitions, the CONT delay handler will take care of it
105                 vdp.setValue(LONG_REPEATED_EVENT);
106             } else if (isLongPressActive) {
107                 // We seemingly missed an event (either a CONT or the final LONG_RELEASE),
108                 // so end the long press cycle now
109                 vdp.setValue(LONG_RELEASED_EVENT);
110             } else {
111                 vdp.setValue(null);
112             }
113         }
114         logger.debug("Handled virtual button event on {}:{}: press type {}, value {}, button state {} -> {}",
115                 channel.getDevice().getAddress(), channel.getNumber(), pressType, dp.getValue(), vdp.getPreviousValue(),
116                 vdp.getValue());
117     }
118 }