]> git.basschouten.com Git - openhab-addons.git/blob
5923c06c9ba1efb68ee80dac5d55ed22caeac254
[openhab-addons.git] /
1 /**
2  * Copyright (c) 2010-2024 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.tado.internal.handler;
14
15 import java.io.IOException;
16 import java.util.concurrent.ScheduledFuture;
17 import java.util.concurrent.TimeUnit;
18
19 import org.eclipse.jdt.annotation.NonNullByDefault;
20 import org.eclipse.jdt.annotation.Nullable;
21 import org.openhab.binding.tado.internal.TadoBindingConstants;
22 import org.openhab.binding.tado.internal.api.ApiException;
23 import org.openhab.binding.tado.internal.api.model.MobileDevice;
24 import org.openhab.binding.tado.internal.config.TadoMobileDeviceConfig;
25 import org.openhab.core.library.types.OnOffType;
26 import org.openhab.core.thing.Bridge;
27 import org.openhab.core.thing.ChannelUID;
28 import org.openhab.core.thing.Thing;
29 import org.openhab.core.thing.ThingStatus;
30 import org.openhab.core.thing.ThingStatusDetail;
31 import org.openhab.core.thing.ThingStatusInfo;
32 import org.openhab.core.types.Command;
33 import org.openhab.core.types.RefreshType;
34 import org.slf4j.Logger;
35 import org.slf4j.LoggerFactory;
36
37 /**
38  * The {@link TadoMobileDeviceHandler} is responsible for handling commands of mobile devices and update their state.
39  *
40  * @author Dennis Frommknecht - Initial contribution
41  */
42 @NonNullByDefault
43 public class TadoMobileDeviceHandler extends BaseHomeThingHandler {
44
45     private Logger logger = LoggerFactory.getLogger(TadoMobileDeviceHandler.class);
46
47     private TadoMobileDeviceConfig configuration;
48     private @Nullable ScheduledFuture<?> refreshTimer;
49
50     public TadoMobileDeviceHandler(Thing thing) {
51         super(thing);
52         configuration = getConfigAs(TadoMobileDeviceConfig.class);
53     }
54
55     @Override
56     public void handleCommand(ChannelUID channelUID, Command command) {
57         if (command == RefreshType.REFRESH) {
58             logger.debug("Refreshing {}", channelUID);
59             updateState();
60         } else {
61             logger.warn("This Thing is read-only and can only handle REFRESH command");
62         }
63     }
64
65     @Override
66     public void initialize() {
67         configuration = getConfigAs(TadoMobileDeviceConfig.class);
68         if (configuration.refreshInterval <= 0) {
69             updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, "Refresh interval of zone "
70                     + configuration.id + " of home " + getHomeId() + " must be greater than zero");
71             return;
72         }
73
74         Bridge bridge = getBridge();
75         if (bridge != null) {
76             bridgeStatusChanged(bridge.getStatusInfo());
77         }
78     }
79
80     @Override
81     public void bridgeStatusChanged(ThingStatusInfo bridgeStatusInfo) {
82         if (bridgeStatusInfo.getStatus() == ThingStatus.ONLINE) {
83             try {
84                 MobileDevice device = getMobileDevice();
85                 updateProperty(TadoBindingConstants.PROPERTY_MOBILE_DEVICE_NAME, device.getName());
86
87                 if (!device.getSettings().isGeoTrackingEnabled()) {
88                     updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
89                             "Geotracking is disabled on mobile device " + device.getName());
90                     return;
91                 }
92             } catch (IOException | ApiException e) {
93                 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
94                         "Could not connect to server due to " + e.getMessage());
95                 cancelScheduledStateUpdate();
96                 return;
97             }
98
99             scheduleZoneStateUpdate();
100             updateStatus(ThingStatus.ONLINE);
101         } else {
102             updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.BRIDGE_OFFLINE);
103             cancelScheduledStateUpdate();
104         }
105     }
106
107     private void updateState() {
108         try {
109             MobileDevice device = getMobileDevice();
110             updateState(TadoBindingConstants.CHANNEL_MOBILE_DEVICE_AT_HOME,
111                     OnOffType.from(device.getLocation().isAtHome()));
112         } catch (IOException | ApiException e) {
113             logger.debug("Status update of mobile device with id {} failed: {}", configuration.id, e.getMessage());
114         }
115     }
116
117     private MobileDevice getMobileDevice() throws IOException, ApiException {
118         MobileDevice device = null;
119
120         try {
121             device = getApi().listMobileDevices(getHomeId()).stream().filter(m -> m.getId() == configuration.id)
122                     .findFirst().orElse(null);
123         } catch (IOException | ApiException e) {
124             updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
125                     "Could not connect to server due to " + e.getMessage());
126             throw e;
127         }
128
129         if (device == null) {
130             String message = "Mobile device with id " + configuration.id + " unknown or does not belong to home "
131                     + getHomeId();
132             updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, message);
133             throw new IOException(message);
134         }
135
136         onSuccessfulOperation();
137         return device;
138     }
139
140     private void scheduleZoneStateUpdate() {
141         ScheduledFuture<?> refreshTimer = this.refreshTimer;
142         if (refreshTimer == null || refreshTimer.isCancelled()) {
143             this.refreshTimer = scheduler.scheduleWithFixedDelay(this::updateState, 5, configuration.refreshInterval,
144                     TimeUnit.SECONDS);
145         }
146     }
147
148     private void cancelScheduledStateUpdate() {
149         ScheduledFuture<?> refreshTimer = this.refreshTimer;
150         if (refreshTimer != null) {
151             refreshTimer.cancel(false);
152         }
153     }
154 }