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.ThingStatus;
38 import org.openhab.core.thing.ThingStatusDetail;
39 import org.openhab.core.thing.binding.BaseBridgeHandler;
40 import org.openhab.core.types.Command;
41 import org.openhab.core.types.RefreshType;
42 import org.openhab.core.types.State;
43 import org.openhab.core.types.UnDefType;
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 @Nullable 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 Bridge bridge = getBridge();
89 if (bridge != null && bridge.getStatus() == ThingStatus.ONLINE) {
94 // Get user info to verify successful authentication and connection to server
95 User user = api.showUser();
97 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
98 "Cannot connect to server. Username and/or password might be invalid");
102 List<UserHomes> homes = user.getHomes();
103 if (homes == null || homes.isEmpty()) {
104 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
105 "User does not have access to any home");
109 Integer firstHomeId = homes.get(0).getId();
110 if (firstHomeId == null) {
111 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, "Missing Home Id");
115 homeId = firstHomeId.longValue();
117 HomeInfo homeInfo = api.showHome(homeId);
118 TemperatureUnit temperatureUnit = org.openhab.binding.tado.internal.api.model.TemperatureUnit.FAHRENHEIT == homeInfo
119 .getTemperatureUnit() ? TemperatureUnit.FAHRENHEIT : TemperatureUnit.CELSIUS;
120 updateProperty(TadoBindingConstants.PROPERTY_HOME_TEMPERATURE_UNIT, temperatureUnit.name());
121 } catch (IOException | ApiException e) {
122 logger.debug("Error accessing tado server: {}", e.getMessage(), e);
123 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
124 "Could not connect to server due to " + e.getMessage());
128 updateStatus(ThingStatus.ONLINE);
132 public void dispose() {
134 ScheduledFuture<?> initializationFuture = this.initializationFuture;
135 if (initializationFuture != null && !initializationFuture.isCancelled()) {
136 initializationFuture.cancel(true);
140 public HomeApi getApi() {
144 public @Nullable Long getHomeId() {
148 public HomeState getHomeState() throws IOException, ApiException {
149 return api.homeState(getHomeId());
152 public void updateHomeState() {
154 updateState(TadoBindingConstants.CHANNEL_HOME_PRESENCE_MODE,
155 getHomeState().getPresence() == PresenceState.HOME ? OnOffType.ON : OnOffType.OFF);
156 } catch (IOException | ApiException e) {
157 logger.debug("Error accessing tado server: {}", e.getMessage(), e);
162 public void handleCommand(ChannelUID channelUID, Command command) {
163 String id = channelUID.getId();
165 if (command == RefreshType.REFRESH) {
171 case TadoBindingConstants.CHANNEL_HOME_PRESENCE_MODE:
172 HomePresence presence = new HomePresence();
173 presence.setHomePresence(command.toFullString().toUpperCase().equals("ON")
174 || command.toFullString().toUpperCase().equals("HOME") ? PresenceState.HOME
175 : PresenceState.AWAY);
177 api.updatePresenceLock(homeId, presence);
178 } catch (IOException | ApiException e) {
179 logger.warn("Error setting home presence: {}", e.getMessage(), e);
187 public State getBatteryLowAlarm(long zoneId) {
188 TadoBatteryChecker batteryChecker = this.batteryChecker;
189 return batteryChecker != null ? batteryChecker.getBatteryLowAlarm(zoneId) : UnDefType.UNDEF;