]> git.basschouten.com Git - openhab-addons.git/blob
ec69c146e34db01a7f0dcdc4036d4d92d36ab876
[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.homeconnect.internal.handler;
14
15 import static org.openhab.binding.homeconnect.internal.HomeConnectBindingConstants.*;
16 import static org.openhab.core.library.unit.Units.SECOND;
17
18 import java.util.Arrays;
19 import java.util.List;
20 import java.util.Map;
21 import java.util.Optional;
22 import java.util.concurrent.ScheduledFuture;
23 import java.util.concurrent.TimeUnit;
24
25 import javax.measure.IncommensurableException;
26 import javax.measure.UnconvertibleException;
27 import javax.measure.quantity.Time;
28
29 import org.eclipse.jdt.annotation.NonNullByDefault;
30 import org.eclipse.jdt.annotation.Nullable;
31 import org.openhab.binding.homeconnect.internal.client.HomeConnectApiClient;
32 import org.openhab.binding.homeconnect.internal.client.exception.ApplianceOfflineException;
33 import org.openhab.binding.homeconnect.internal.client.exception.AuthorizationException;
34 import org.openhab.binding.homeconnect.internal.client.exception.CommunicationException;
35 import org.openhab.binding.homeconnect.internal.client.model.Data;
36 import org.openhab.binding.homeconnect.internal.type.HomeConnectDynamicStateDescriptionProvider;
37 import org.openhab.core.library.types.OnOffType;
38 import org.openhab.core.library.types.QuantityType;
39 import org.openhab.core.thing.Channel;
40 import org.openhab.core.thing.ChannelUID;
41 import org.openhab.core.thing.Thing;
42 import org.openhab.core.types.Command;
43 import org.openhab.core.types.UnDefType;
44 import org.slf4j.Logger;
45 import org.slf4j.LoggerFactory;
46
47 /**
48  * The {@link HomeConnectOvenHandler} is responsible for handling commands, which are
49  * sent to one of the channels of a oven.
50  *
51  * @author Jonas BrĂ¼stel - Initial contribution
52  */
53 @NonNullByDefault
54 public class HomeConnectOvenHandler extends AbstractHomeConnectThingHandler {
55
56     private static final List<String> INACTIVE_STATE = Arrays.asList(OPERATION_STATE_INACTIVE, OPERATION_STATE_READY);
57     private static final int CAVITY_TEMPERATURE_SCHEDULER_INITIAL_DELAY = 30;
58     private static final int CAVITY_TEMPERATURE_SCHEDULER_PERIOD = 90;
59
60     private final Logger logger = LoggerFactory.getLogger(HomeConnectOvenHandler.class);
61
62     private @Nullable ScheduledFuture<?> cavityTemperatureFuture;
63     private boolean manuallyUpdateCavityTemperature;
64
65     public HomeConnectOvenHandler(Thing thing,
66             HomeConnectDynamicStateDescriptionProvider dynamicStateDescriptionProvider) {
67         super(thing, dynamicStateDescriptionProvider);
68         manuallyUpdateCavityTemperature = true;
69     }
70
71     @Override
72     protected void configureChannelUpdateHandlers(Map<String, ChannelUpdateHandler> handlers) {
73         // register default update handlers
74         handlers.put(CHANNEL_OPERATION_STATE, defaultOperationStateChannelUpdateHandler());
75         handlers.put(CHANNEL_POWER_STATE, defaultPowerStateChannelUpdateHandler());
76         handlers.put(CHANNEL_DOOR_STATE, defaultDoorStateChannelUpdateHandler());
77         handlers.put(CHANNEL_REMOTE_CONTROL_ACTIVE_STATE, defaultRemoteControlActiveStateChannelUpdateHandler());
78         handlers.put(CHANNEL_REMOTE_START_ALLOWANCE_STATE, defaultRemoteStartAllowanceChannelUpdateHandler());
79         handlers.put(CHANNEL_SELECTED_PROGRAM_STATE, defaultSelectedProgramStateUpdateHandler());
80         handlers.put(CHANNEL_ACTIVE_PROGRAM_STATE, defaultActiveProgramStateUpdateHandler());
81
82         // register oven specific update handlers
83         handlers.put(CHANNEL_OVEN_CURRENT_CAVITY_TEMPERATURE,
84                 (channelUID, cache) -> updateState(channelUID, cache.putIfAbsentAndGet(channelUID, () -> {
85                     Optional<HomeConnectApiClient> apiClient = getApiClient();
86                     if (apiClient.isPresent()) {
87                         Data data = apiClient.get().getCurrentCavityTemperature(getThingHaId());
88                         return new QuantityType<>(data.getValueAsInt(), mapTemperature(data.getUnit()));
89                     }
90                     return UnDefType.UNDEF;
91                 })));
92         handlers.put(CHANNEL_SETPOINT_TEMPERATURE, (channelUID, cache) -> {
93             Optional<Channel> channel = getThingChannel(CHANNEL_SELECTED_PROGRAM_STATE);
94             if (channel.isPresent()) {
95                 defaultSelectedProgramStateUpdateHandler().handle(channel.get().getUID(), cache);
96             }
97         });
98         handlers.put(CHANNEL_DURATION, (channelUID, cache) -> {
99             Optional<Channel> channel = getThingChannel(CHANNEL_SELECTED_PROGRAM_STATE);
100             if (channel.isPresent()) {
101                 defaultSelectedProgramStateUpdateHandler().handle(channel.get().getUID(), cache);
102             }
103         });
104     }
105
106     @Override
107     protected void configureEventHandlers(Map<String, EventHandler> handlers) {
108         // register default SSE event handlers
109         handlers.put(EVENT_DOOR_STATE, defaultDoorStateEventHandler());
110         handlers.put(EVENT_REMOTE_CONTROL_ACTIVE, defaultBooleanEventHandler(CHANNEL_REMOTE_CONTROL_ACTIVE_STATE));
111         handlers.put(EVENT_REMOTE_CONTROL_START_ALLOWED,
112                 defaultBooleanEventHandler(CHANNEL_REMOTE_START_ALLOWANCE_STATE));
113         handlers.put(EVENT_SELECTED_PROGRAM, defaultSelectedProgramStateEventHandler());
114         handlers.put(EVENT_FINISH_IN_RELATIVE, defaultRemainingProgramTimeEventHandler());
115         handlers.put(EVENT_REMAINING_PROGRAM_TIME, defaultRemainingProgramTimeEventHandler());
116         handlers.put(EVENT_PROGRAM_PROGRESS, defaultPercentQuantityTypeEventHandler(CHANNEL_PROGRAM_PROGRESS_STATE));
117         handlers.put(EVENT_ELAPSED_PROGRAM_TIME, defaultElapsedProgramTimeEventHandler());
118         handlers.put(EVENT_ACTIVE_PROGRAM, defaultActiveProgramEventHandler());
119
120         // register oven specific SSE event handlers
121         handlers.put(EVENT_OPERATION_STATE, event -> {
122             defaultOperationStateEventHandler().handle(event);
123             if (STATE_OPERATION_RUN.equals(event.getValue())) {
124                 manuallyUpdateCavityTemperature = true;
125             }
126         });
127         handlers.put(EVENT_POWER_STATE, event -> {
128             getThingChannel(CHANNEL_POWER_STATE).ifPresent(
129                     channel -> updateState(channel.getUID(), OnOffType.from(STATE_POWER_ON.equals(event.getValue()))));
130
131             if (STATE_POWER_ON.equals(event.getValue())) {
132                 updateChannels();
133             } else {
134                 resetProgramStateChannels(true);
135                 getThingChannel(CHANNEL_SELECTED_PROGRAM_STATE)
136                         .ifPresent(c -> updateState(c.getUID(), UnDefType.UNDEF));
137                 getThingChannel(CHANNEL_ACTIVE_PROGRAM_STATE).ifPresent(c -> updateState(c.getUID(), UnDefType.UNDEF));
138                 getThingChannel(CHANNEL_SETPOINT_TEMPERATURE).ifPresent(c -> updateState(c.getUID(), UnDefType.UNDEF));
139                 getThingChannel(CHANNEL_DURATION).ifPresent(c -> updateState(c.getUID(), UnDefType.UNDEF));
140             }
141         });
142
143         handlers.put(EVENT_OVEN_CAVITY_TEMPERATURE, event -> {
144             manuallyUpdateCavityTemperature = false;
145             getThingChannel(CHANNEL_OVEN_CURRENT_CAVITY_TEMPERATURE).ifPresent(channel -> updateState(channel.getUID(),
146                     new QuantityType<>(event.getValueAsInt(), mapTemperature(event.getUnit()))));
147         });
148
149         handlers.put(EVENT_SETPOINT_TEMPERATURE,
150                 event -> getThingChannel(CHANNEL_SETPOINT_TEMPERATURE)
151                         .ifPresent(channel -> updateState(channel.getUID(),
152                                 new QuantityType<>(event.getValueAsInt(), mapTemperature(event.getUnit())))));
153         handlers.put(EVENT_DURATION, event -> getThingChannel(CHANNEL_DURATION).ifPresent(
154                 channel -> updateState(channel.getUID(), new QuantityType<>(event.getValueAsInt(), SECOND))));
155     }
156
157     @Override
158     protected void handleCommand(final ChannelUID channelUID, final Command command,
159             final HomeConnectApiClient apiClient)
160             throws CommunicationException, AuthorizationException, ApplianceOfflineException {
161         super.handleCommand(channelUID, command, apiClient);
162
163         handlePowerCommand(channelUID, command, apiClient, STATE_POWER_STANDBY);
164
165         String operationState = getOperationState();
166         if (operationState != null && INACTIVE_STATE.contains(operationState) && command instanceof QuantityType) {
167             // set setpoint temperature
168             if (CHANNEL_SETPOINT_TEMPERATURE.equals(channelUID.getId())) {
169                 handleTemperatureCommand(channelUID, command, apiClient);
170             } else if (CHANNEL_DURATION.equals(channelUID.getId())) {
171                 @SuppressWarnings("unchecked")
172                 QuantityType<Time> quantity = ((QuantityType<Time>) command);
173
174                 try {
175                     String value = String
176                             .valueOf(quantity.getUnit().getConverterToAny(SECOND).convert(quantity).intValue());
177                     logger.debug("Set duration to {} seconds. haId={}", value, getThingHaId());
178
179                     apiClient.setProgramOptions(getThingHaId(), OPTION_DURATION, value, "seconds", true, false);
180                 } catch (IncommensurableException | UnconvertibleException e) {
181                     logger.warn("Could not set duration! haId={}, error={}", getThingHaId(), e.getMessage());
182                 }
183             }
184         } else {
185             logger.debug("Device can not handle command {} in current operation state ({}). haId={}", command,
186                     operationState, getThingHaId());
187         }
188     }
189
190     @Override
191     public void initialize() {
192         super.initialize();
193         cavityTemperatureFuture = scheduler.scheduleWithFixedDelay(() -> {
194             String operationState = getOperationState();
195             boolean manuallyUpdateCavityTemperature = this.manuallyUpdateCavityTemperature;
196
197             if (STATE_OPERATION_RUN.equals(operationState)) {
198                 getThingChannel(CHANNEL_OVEN_CURRENT_CAVITY_TEMPERATURE).ifPresent(c -> {
199                     if (manuallyUpdateCavityTemperature) {
200                         logger.debug("Update cavity temperature manually via API. haId={}", getThingHaId());
201                         updateChannel(c.getUID());
202                     } else {
203                         logger.debug("Update cavity temperature via SSE, don't need to fetch manually. haId={}",
204                                 getThingHaId());
205                     }
206                 });
207             }
208         }, CAVITY_TEMPERATURE_SCHEDULER_INITIAL_DELAY, CAVITY_TEMPERATURE_SCHEDULER_PERIOD, TimeUnit.SECONDS);
209     }
210
211     @Override
212     public void dispose() {
213         ScheduledFuture<?> cavityTemperatureFuture = this.cavityTemperatureFuture;
214         if (cavityTemperatureFuture != null) {
215             cavityTemperatureFuture.cancel(true);
216         }
217         super.dispose();
218     }
219
220     @Override
221     public String toString() {
222         return "HomeConnectOvenHandler [haId: " + getThingHaId() + "]";
223     }
224
225     @Override
226     protected void resetProgramStateChannels(boolean offline) {
227         super.resetProgramStateChannels(offline);
228         getThingChannel(CHANNEL_REMAINING_PROGRAM_TIME_STATE).ifPresent(c -> updateState(c.getUID(), UnDefType.UNDEF));
229         getThingChannel(CHANNEL_PROGRAM_PROGRESS_STATE).ifPresent(c -> updateState(c.getUID(), UnDefType.UNDEF));
230         getThingChannel(CHANNEL_ELAPSED_PROGRAM_TIME).ifPresent(c -> updateState(c.getUID(), UnDefType.UNDEF));
231     }
232 }