]> git.basschouten.com Git - openhab-addons.git/blob
1b2d5f6f31e7256c39193a248e5a958a075e323f
[openhab-addons.git] /
1 /**
2  * Copyright (c) 2010-2023 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.avmfritz.internal.handler;
14
15 import static org.openhab.binding.avmfritz.internal.AVMFritzBindingConstants.*;
16
17 import java.math.BigDecimal;
18 import java.time.Instant;
19 import java.time.ZoneId;
20 import java.time.ZonedDateTime;
21 import java.util.List;
22 import java.util.Optional;
23
24 import org.eclipse.jdt.annotation.NonNullByDefault;
25 import org.eclipse.jdt.annotation.Nullable;
26 import org.openhab.binding.avmfritz.internal.dto.AVMFritzBaseModel;
27 import org.openhab.binding.avmfritz.internal.dto.BatteryModel;
28 import org.openhab.binding.avmfritz.internal.dto.ButtonModel;
29 import org.openhab.binding.avmfritz.internal.dto.DeviceModel;
30 import org.openhab.binding.avmfritz.internal.dto.HumidityModel;
31 import org.openhab.binding.avmfritz.internal.dto.TemperatureModel;
32 import org.openhab.core.library.types.DateTimeType;
33 import org.openhab.core.library.types.DecimalType;
34 import org.openhab.core.library.types.OnOffType;
35 import org.openhab.core.library.types.QuantityType;
36 import org.openhab.core.library.unit.SIUnits;
37 import org.openhab.core.library.unit.Units;
38 import org.openhab.core.thing.Channel;
39 import org.openhab.core.thing.ChannelUID;
40 import org.openhab.core.thing.CommonTriggerEvents;
41 import org.openhab.core.thing.Thing;
42 import org.openhab.core.thing.ThingUID;
43 import org.openhab.core.types.UnDefType;
44 import org.slf4j.Logger;
45 import org.slf4j.LoggerFactory;
46
47 /**
48  * Handler for a FRITZ! buttons. Handles commands, which are sent to one of the channels.
49  *
50  * @author Christoph Weitkamp - Initial contribution
51  */
52 @NonNullByDefault
53 public class AVMFritzButtonHandler extends DeviceHandler {
54
55     private static final String TOP_RIGHT_SUFFIX = "-1";
56     private static final String BOTTOM_RIGHT_SUFFIX = "-3";
57     private static final String BOTTOM_LEFT_SUFFIX = "-5";
58     private static final String TOP_LEFT_SUFFIX = "-7";
59
60     private final Logger logger = LoggerFactory.getLogger(AVMFritzButtonHandler.class);
61     /**
62      * keeps track of the last timestamp for handling trigger events
63      */
64     private Instant lastTimestamp;
65
66     /**
67      * Constructor
68      *
69      * @param thing Thing object representing a FRITZ! button
70      */
71     public AVMFritzButtonHandler(Thing thing) {
72         super(thing);
73         lastTimestamp = Instant.now();
74     }
75
76     @Override
77     public void onDeviceUpdated(ThingUID thingUID, AVMFritzBaseModel device) {
78         if (thing.getUID().equals(thingUID)) {
79             super.onDeviceUpdated(thingUID, device);
80
81             if (device instanceof DeviceModel deviceModel) {
82                 if (deviceModel.isHANFUNButton()) {
83                     updateHANFUNButton(deviceModel.getButtons());
84                 }
85                 if (deviceModel.isButton()) {
86                     if (DECT400_THING_TYPE.equals(thing.getThingTypeUID())) {
87                         updateShortLongPressButton(deviceModel.getButtons());
88                     } else if (DECT440_THING_TYPE.equals(thing.getThingTypeUID())) {
89                         updateButtons(deviceModel.getButtons());
90                     }
91                     updateBattery(deviceModel);
92                 }
93             }
94         }
95     }
96
97     @Override
98     protected void updateTemperatureSensor(@Nullable TemperatureModel temperatureModel) {
99         if (temperatureModel != null) {
100             String channelId = (DECT440_THING_TYPE.equals(thing.getThingTypeUID())
101                     ? CHANNEL_GROUP_SENSORS + ChannelUID.CHANNEL_GROUP_SEPARATOR
102                     : "") + CHANNEL_TEMPERATURE;
103             updateThingChannelState(channelId, new QuantityType<>(temperatureModel.getCelsius(), SIUnits.CELSIUS));
104             updateThingChannelConfiguration(channelId, CONFIG_CHANNEL_TEMP_OFFSET, temperatureModel.getOffset());
105         }
106     }
107
108     @Override
109     protected void updateHumiditySensor(@Nullable HumidityModel humidityModel) {
110         if (humidityModel != null) {
111             String channelId = (DECT440_THING_TYPE.equals(thing.getThingTypeUID())
112                     ? CHANNEL_GROUP_SENSORS + ChannelUID.CHANNEL_GROUP_SEPARATOR
113                     : "") + CHANNEL_HUMIDITY;
114             updateThingChannelState(channelId, new QuantityType<>(humidityModel.getRelativeHumidity(), Units.PERCENT));
115         }
116     }
117
118     @Override
119     protected void updateBattery(BatteryModel batteryModel) {
120         String batteryLevelChannelId = (DECT440_THING_TYPE.equals(thing.getThingTypeUID())
121                 ? CHANNEL_GROUP_DEVICE + ChannelUID.CHANNEL_GROUP_SEPARATOR
122                 : "") + CHANNEL_BATTERY;
123         BigDecimal batteryLevel = batteryModel.getBattery();
124         updateThingChannelState(batteryLevelChannelId,
125                 batteryLevel == null ? UnDefType.UNDEF : new DecimalType(batteryLevel));
126         String lowBatteryChannelId = (DECT440_THING_TYPE.equals(thing.getThingTypeUID())
127                 ? CHANNEL_GROUP_DEVICE + ChannelUID.CHANNEL_GROUP_SEPARATOR
128                 : "") + CHANNEL_BATTERY_LOW;
129         BigDecimal lowBattery = batteryModel.getBatterylow();
130         if (lowBattery == null) {
131             updateThingChannelState(lowBatteryChannelId, UnDefType.UNDEF);
132         } else {
133             updateThingChannelState(lowBatteryChannelId,
134                     BatteryModel.BATTERY_ON.equals(lowBattery) ? OnOffType.ON : OnOffType.OFF);
135         }
136     }
137
138     private void updateShortLongPressButton(List<ButtonModel> buttons) {
139         ButtonModel shortPressButton = !buttons.isEmpty() ? buttons.get(0) : null;
140         ButtonModel longPressButton = buttons.size() > 1 ? buttons.get(1) : null;
141         ButtonModel lastPressedButton = shortPressButton != null && (longPressButton == null
142                 || shortPressButton.getLastpressedtimestamp() > longPressButton.getLastpressedtimestamp())
143                         ? shortPressButton
144                         : longPressButton;
145         if (lastPressedButton != null) {
146             updateButton(lastPressedButton,
147                     lastPressedButton.equals(shortPressButton) ? CommonTriggerEvents.SHORT_PRESSED
148                             : CommonTriggerEvents.LONG_PRESSED);
149         }
150     }
151
152     private void updateButtons(List<ButtonModel> buttons) {
153         Optional<ButtonModel> topLeft = buttons.stream().filter(b -> b.getIdentifier().endsWith(TOP_LEFT_SUFFIX))
154                 .findFirst();
155         if (topLeft.isPresent()) {
156             updateButton(topLeft.get(), CommonTriggerEvents.PRESSED, CHANNEL_GROUP_TOP_LEFT);
157         }
158         Optional<ButtonModel> bottomLeft = buttons.stream().filter(b -> b.getIdentifier().endsWith(BOTTOM_LEFT_SUFFIX))
159                 .findFirst();
160         if (bottomLeft.isPresent()) {
161             updateButton(bottomLeft.get(), CommonTriggerEvents.PRESSED, CHANNEL_GROUP_BOTTOM_LEFT);
162         }
163         Optional<ButtonModel> topRight = buttons.stream().filter(b -> b.getIdentifier().endsWith(TOP_RIGHT_SUFFIX))
164                 .findFirst();
165         if (topRight.isPresent()) {
166             updateButton(topRight.get(), CommonTriggerEvents.PRESSED, CHANNEL_GROUP_TOP_RIGHT);
167         }
168         Optional<ButtonModel> bottomRight = buttons.stream()
169                 .filter(b -> b.getIdentifier().endsWith(BOTTOM_RIGHT_SUFFIX)).findFirst();
170         if (bottomRight.isPresent()) {
171             updateButton(bottomRight.get(), CommonTriggerEvents.PRESSED, CHANNEL_GROUP_BOTTOM_RIGHT);
172         }
173     }
174
175     private void updateHANFUNButton(List<ButtonModel> buttons) {
176         if (!buttons.isEmpty()) {
177             updateButton(buttons.get(0), CommonTriggerEvents.PRESSED);
178         }
179     }
180
181     private void updateButton(ButtonModel buttonModel, String event) {
182         updateButton(buttonModel, event, null);
183     }
184
185     private void updateButton(ButtonModel buttonModel, String event, @Nullable String channelGroupId) {
186         int lastPressedTimestamp = buttonModel.getLastpressedtimestamp();
187         if (lastPressedTimestamp == 0) {
188             updateThingChannelState(
189                     channelGroupId == null ? CHANNEL_LAST_CHANGE
190                             : channelGroupId + ChannelUID.CHANNEL_GROUP_SEPARATOR + CHANNEL_LAST_CHANGE,
191                     UnDefType.UNDEF);
192         } else {
193             ZonedDateTime timestamp = ZonedDateTime.ofInstant(Instant.ofEpochSecond(lastPressedTimestamp),
194                     ZoneId.systemDefault());
195             Instant then = timestamp.toInstant();
196             // Avoid dispatching events if "lastpressedtimestamp" is older than now "lastTimestamp" (e.g. during
197             // restart)
198             if (then.isAfter(lastTimestamp)) {
199                 lastTimestamp = then;
200                 triggerThingChannel(channelGroupId == null ? CHANNEL_PRESS
201                         : channelGroupId + ChannelUID.CHANNEL_GROUP_SEPARATOR + CHANNEL_PRESS, event);
202             }
203             updateThingChannelState(
204                     channelGroupId == null ? CHANNEL_LAST_CHANGE
205                             : channelGroupId + ChannelUID.CHANNEL_GROUP_SEPARATOR + CHANNEL_LAST_CHANGE,
206                     new DateTimeType(timestamp));
207         }
208     }
209
210     /**
211      * Triggers thing channels.
212      *
213      * @param channelId ID of the channel to be triggered.
214      * @param event Event to emit
215      */
216     private void triggerThingChannel(String channelId, String event) {
217         Channel channel = thing.getChannel(channelId);
218         if (channel != null) {
219             triggerChannel(channel.getUID(), event);
220         } else {
221             logger.debug("Channel '{}' in thing '{}' does not exist.", channelId, thing.getUID());
222         }
223     }
224 }