2 * Copyright (c) 2010-2022 Contributors to the openHAB project
4 * See the NOTICE file(s) distributed with this work for additional
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
11 * SPDX-License-Identifier: EPL-2.0
13 package org.openhab.binding.tado.internal.handler;
15 import java.io.IOException;
16 import java.util.List;
17 import java.util.concurrent.ScheduledFuture;
18 import java.util.concurrent.TimeUnit;
20 import org.eclipse.jdt.annotation.NonNullByDefault;
21 import org.eclipse.jdt.annotation.Nullable;
22 import org.openhab.binding.tado.internal.TadoBindingConstants;
23 import org.openhab.binding.tado.internal.TadoBindingConstants.TemperatureUnit;
24 import org.openhab.binding.tado.internal.api.ApiException;
25 import org.openhab.binding.tado.internal.api.HomeApiFactory;
26 import org.openhab.binding.tado.internal.api.client.HomeApi;
27 import org.openhab.binding.tado.internal.api.model.HomeInfo;
28 import org.openhab.binding.tado.internal.api.model.HomePresence;
29 import org.openhab.binding.tado.internal.api.model.HomeState;
30 import org.openhab.binding.tado.internal.api.model.PresenceState;
31 import org.openhab.binding.tado.internal.api.model.User;
32 import org.openhab.binding.tado.internal.api.model.UserHomes;
33 import org.openhab.binding.tado.internal.config.TadoHomeConfig;
34 import org.openhab.core.library.types.OnOffType;
35 import org.openhab.core.thing.Bridge;
36 import org.openhab.core.thing.ChannelUID;
37 import org.openhab.core.thing.Thing;
38 import org.openhab.core.thing.ThingStatus;
39 import org.openhab.core.thing.ThingStatusDetail;
40 import org.openhab.core.thing.binding.BaseBridgeHandler;
41 import org.openhab.core.thing.binding.ThingHandler;
42 import org.openhab.core.types.Command;
43 import org.openhab.core.types.RefreshType;
44 import org.openhab.core.types.State;
45 import org.openhab.core.types.UnDefType;
46 import org.slf4j.Logger;
47 import org.slf4j.LoggerFactory;
50 * The {@link TadoHomeHandler} is the bridge of all home-based things.
52 * @author Dennis Frommknecht - Initial contribution
55 public class TadoHomeHandler extends BaseBridgeHandler {
57 private Logger logger = LoggerFactory.getLogger(TadoHomeHandler.class);
59 private TadoHomeConfig configuration;
60 private final HomeApi api;
62 private @Nullable Long homeId;
63 private @Nullable TadoBatteryChecker batteryChecker;
64 private @Nullable ScheduledFuture<?> initializationFuture;
66 public TadoHomeHandler(Bridge bridge) {
68 batteryChecker = new TadoBatteryChecker(this);
69 configuration = getConfigAs(TadoHomeConfig.class);
70 api = new HomeApiFactory().create(configuration.username, configuration.password);
73 public TemperatureUnit getTemperatureUnit() {
74 String temperatureUnitStr = this.thing.getProperties()
75 .getOrDefault(TadoBindingConstants.PROPERTY_HOME_TEMPERATURE_UNIT, "CELSIUS");
76 return TemperatureUnit.valueOf(temperatureUnitStr);
80 public void initialize() {
81 configuration = getConfigAs(TadoHomeConfig.class);
82 ScheduledFuture<?> initializationFuture = this.initializationFuture;
83 if (initializationFuture == null || initializationFuture.isDone()) {
84 this.initializationFuture = scheduler.scheduleWithFixedDelay(
85 this::initializeBridgeStatusAndPropertiesIfOffline, 0, 300, TimeUnit.SECONDS);
89 private void initializeBridgeStatusAndPropertiesIfOffline() {
90 if (getThing().getStatus() == ThingStatus.ONLINE) {
91 for (Thing thing : getThing().getThings()) {
92 ThingHandler handler = thing.getHandler();
93 if ((handler instanceof BaseHomeThingHandler) && (thing.getStatus() == ThingStatus.OFFLINE)
94 && (thing.getStatusInfo().getStatusDetail() == ThingStatusDetail.COMMUNICATION_ERROR)) {
95 scheduler.submit(() -> handler.bridgeStatusChanged(getThing().getStatusInfo()));
101 // if we are already online, don't make unnecessary calls on the server
102 if (getThing().getStatus() != ThingStatus.ONLINE) {
103 // Get user info to verify successful authentication and connection to server
104 User user = api.showUser();
106 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
107 "Cannot connect to server. Username and/or password might be invalid");
111 List<UserHomes> homes = user.getHomes();
112 if (homes == null || homes.isEmpty()) {
113 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
114 "User does not have access to any home");
118 Integer firstHomeId = homes.get(0).getId();
119 if (firstHomeId == null) {
120 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, "Missing Home Id");
124 homeId = firstHomeId.longValue();
127 // but always make one server call as a 'ping' to confirm we are really still online
128 HomeInfo homeInfo = api.showHome(homeId);
129 TemperatureUnit temperatureUnit = org.openhab.binding.tado.internal.api.model.TemperatureUnit.FAHRENHEIT == homeInfo
130 .getTemperatureUnit() ? TemperatureUnit.FAHRENHEIT : TemperatureUnit.CELSIUS;
131 updateProperty(TadoBindingConstants.PROPERTY_HOME_TEMPERATURE_UNIT, temperatureUnit.name());
132 } catch (IOException | ApiException e) {
133 logger.debug("Error accessing tado server: {}", e.getMessage(), e);
134 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
135 "Could not connect to server due to " + e.getMessage());
139 updateStatus(ThingStatus.ONLINE);
143 public void dispose() {
145 ScheduledFuture<?> initializationFuture = this.initializationFuture;
146 if (initializationFuture != null && !initializationFuture.isCancelled()) {
147 initializationFuture.cancel(true);
151 public HomeApi getApi() {
155 public @Nullable Long getHomeId() {
159 public HomeState getHomeState() throws IOException, ApiException {
160 return api.homeState(getHomeId());
163 public void updateHomeState() {
165 updateState(TadoBindingConstants.CHANNEL_HOME_PRESENCE_MODE,
166 getHomeState().getPresence() == PresenceState.HOME ? OnOffType.ON : OnOffType.OFF);
167 } catch (IOException | ApiException e) {
168 logger.debug("Error accessing tado server: {}", e.getMessage(), e);
173 public void handleCommand(ChannelUID channelUID, Command command) {
174 String id = channelUID.getId();
176 if (command == RefreshType.REFRESH) {
182 case TadoBindingConstants.CHANNEL_HOME_PRESENCE_MODE:
183 HomePresence presence = new HomePresence();
184 presence.setHomePresence(command.toFullString().toUpperCase().equals("ON")
185 || command.toFullString().toUpperCase().equals("HOME") ? PresenceState.HOME
186 : PresenceState.AWAY);
188 api.updatePresenceLock(homeId, presence);
189 } catch (IOException | ApiException e) {
190 logger.warn("Error setting home presence: {}", e.getMessage(), e);
198 public State getBatteryLowAlarm(long zoneId) {
199 TadoBatteryChecker batteryChecker = this.batteryChecker;
200 return batteryChecker != null ? batteryChecker.getBatteryLowAlarm(zoneId) : UnDefType.UNDEF;