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