2 * Copyright (c) 2010-2023 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.slf4j.Logger;
45 import org.slf4j.LoggerFactory;
48 * The {@link TadoHomeHandler} is the bridge of all home-based things.
50 * @author Dennis Frommknecht - Initial contribution
53 public class TadoHomeHandler extends BaseBridgeHandler {
55 private Logger logger = LoggerFactory.getLogger(TadoHomeHandler.class);
57 private TadoHomeConfig configuration;
58 private final HomeApi api;
60 private @Nullable Long homeId;
61 private final TadoBatteryChecker batteryChecker;
62 private @Nullable ScheduledFuture<?> initializationFuture;
64 public TadoHomeHandler(Bridge bridge) {
66 batteryChecker = new TadoBatteryChecker(this);
67 configuration = getConfigAs(TadoHomeConfig.class);
68 api = new HomeApiFactory().create(configuration.username, configuration.password);
71 public TemperatureUnit getTemperatureUnit() {
72 String temperatureUnitStr = this.thing.getProperties()
73 .getOrDefault(TadoBindingConstants.PROPERTY_HOME_TEMPERATURE_UNIT, "CELSIUS");
74 return TemperatureUnit.valueOf(temperatureUnitStr);
78 public void initialize() {
79 configuration = getConfigAs(TadoHomeConfig.class);
80 ScheduledFuture<?> initializationFuture = this.initializationFuture;
81 if (initializationFuture == null || initializationFuture.isDone()) {
82 this.initializationFuture = scheduler.scheduleWithFixedDelay(
83 this::initializeBridgeStatusAndPropertiesIfOffline, 0, 300, TimeUnit.SECONDS);
87 private void initializeBridgeStatusAndPropertiesIfOffline() {
88 if (getThing().getStatus() == ThingStatus.ONLINE) {
89 for (Thing thing : getThing().getThings()) {
90 ThingHandler handler = thing.getHandler();
91 if ((handler instanceof BaseHomeThingHandler) && (thing.getStatus() == ThingStatus.OFFLINE)
92 && (thing.getStatusInfo().getStatusDetail() == ThingStatusDetail.COMMUNICATION_ERROR)) {
93 scheduler.submit(() -> handler.bridgeStatusChanged(getThing().getStatusInfo()));
99 // if we are already online, don't make unnecessary calls on the server
100 if (getThing().getStatus() != ThingStatus.ONLINE) {
101 // Get user info to verify successful authentication and connection to server
102 User user = api.showUser();
104 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
105 "Cannot connect to server. Username and/or password might be invalid");
109 List<UserHomes> homes = user.getHomes();
110 if (homes == null || homes.isEmpty()) {
111 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
112 "User does not have access to any home");
116 Integer firstHomeId = homes.get(0).getId();
117 if (firstHomeId == null) {
118 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, "Missing Home Id");
122 homeId = firstHomeId.longValue();
125 // but always make one server call as a 'ping' to confirm we are really still online
126 HomeInfo homeInfo = api.showHome(homeId);
127 TemperatureUnit temperatureUnit = org.openhab.binding.tado.internal.api.model.TemperatureUnit.FAHRENHEIT == homeInfo
128 .getTemperatureUnit() ? TemperatureUnit.FAHRENHEIT : TemperatureUnit.CELSIUS;
129 updateProperty(TadoBindingConstants.PROPERTY_HOME_TEMPERATURE_UNIT, temperatureUnit.name());
130 } catch (IOException | ApiException e) {
131 logger.debug("Error accessing tado server: {}", e.getMessage(), e);
132 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
133 "Could not connect to server due to " + e.getMessage());
137 updateStatus(ThingStatus.ONLINE);
141 public void dispose() {
143 ScheduledFuture<?> initializationFuture = this.initializationFuture;
144 if (initializationFuture != null && !initializationFuture.isCancelled()) {
145 initializationFuture.cancel(true);
149 public HomeApi getApi() {
153 public @Nullable Long getHomeId() {
157 public HomeState getHomeState() throws IOException, ApiException {
158 return api.homeState(getHomeId());
161 public void updateHomeState() {
163 updateState(TadoBindingConstants.CHANNEL_HOME_PRESENCE_MODE,
164 getHomeState().getPresence() == PresenceState.HOME ? OnOffType.ON : OnOffType.OFF);
165 } catch (IOException | ApiException e) {
166 logger.debug("Error accessing tado server: {}", e.getMessage(), e);
171 public void handleCommand(ChannelUID channelUID, Command command) {
172 String id = channelUID.getId();
174 if (command == RefreshType.REFRESH) {
180 case TadoBindingConstants.CHANNEL_HOME_PRESENCE_MODE:
181 HomePresence presence = new HomePresence();
182 presence.setHomePresence("ON".equals(command.toFullString().toUpperCase())
183 || "HOME".equals(command.toFullString().toUpperCase()) ? PresenceState.HOME
184 : PresenceState.AWAY);
186 api.updatePresenceLock(homeId, presence);
187 } catch (IOException | ApiException e) {
188 logger.warn("Error setting home presence: {}", e.getMessage(), e);
195 public TadoBatteryChecker getBatteryChecker() {
196 return this.batteryChecker;