]> git.basschouten.com Git - openhab-addons.git/blob
8b54bb9d3aa21e68e7f313b35598e5a38e2daeb8
[openhab-addons.git] /
1 /**
2  * Copyright (c) 2010-2023 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.mielecloud.internal.webservice.api;
14
15 import java.util.Optional;
16
17 import org.eclipse.jdt.annotation.NonNullByDefault;
18 import org.eclipse.jdt.annotation.Nullable;
19 import org.openhab.binding.mielecloud.internal.webservice.api.json.StateType;
20
21 /**
22  * This immutable class provides methods to extract the state information related to state transitions in a comfortable
23  * way.
24  *
25  * @author Björn Lange - Initial contribution
26  */
27 @NonNullByDefault
28 public class TransitionState {
29     private final boolean remainingTimeWasSetInCurrentProgram;
30     private final Optional<DeviceState> previousState;
31     private final DeviceState nextState;
32
33     /**
34      * Creates a new {@link TransitionState}.
35      *
36      * Note: {@code previousState} <b>must not</b> be saved in a field in this class as this will create a linked list
37      * and cause memory issues. The constructor only serves the purpose of unpacking state that must be carried on.
38      *
39      * @param previousTransitionState The previous transition state if it exists.
40      * @param nextState The device state which the device is transitioning to.
41      */
42     public TransitionState(@Nullable TransitionState previousTransitionState, DeviceState nextState) {
43         this.remainingTimeWasSetInCurrentProgram = wasRemainingTimeSetInCurrentProgram(previousTransitionState,
44                 nextState);
45         this.previousState = Optional.ofNullable(previousTransitionState).map(it -> it.nextState);
46         this.nextState = nextState;
47     }
48
49     /**
50      * Gets whether the finish state changed due to the transition form the previous to the current state.
51      *
52      * @return Whether the finish state changed due to the transition form the previous to the current state.
53      */
54     public boolean hasFinishedChanged() {
55         return previousState.map(this::hasFinishedChangedFromPreviousState).orElse(true);
56     }
57
58     private boolean hasFinishedChangedFromPreviousState(DeviceState previous) {
59         if (previous.getStateType().equals(nextState.getStateType())) {
60             return false;
61         }
62
63         if (isInRunningState(previous) && nextState.isInState(StateType.FAILURE)) {
64             return false;
65         }
66
67         if (isInRunningState(previous) != isInRunningState(nextState)) {
68             return true;
69         }
70
71         if (nextState.isInState(StateType.OFF)) {
72             return true;
73         }
74
75         return false;
76     }
77
78     /**
79      * Gets whether a program finished.
80      *
81      * @return Whether a program finished.
82      */
83     public Optional<Boolean> isFinished() {
84         return previousState.flatMap(this::hasFinishedFromPreviousState);
85     }
86
87     private Optional<Boolean> hasFinishedFromPreviousState(DeviceState prevState) {
88         if (!prevState.getStateType().isPresent()) {
89             return Optional.empty();
90         }
91
92         if (nextState.isInState(StateType.OFF)) {
93             return Optional.of(false);
94         }
95
96         if (nextState.isInState(StateType.FAILURE)) {
97             return Optional.of(false);
98         }
99
100         return Optional.of(!isInRunningState(nextState));
101     }
102
103     /**
104      * Gets the remaining time of the active program.
105      *
106      * Note: Tracking changes in the remaining time is a workaround for the Miele API not properly distinguishing
107      * between "there is no remaining time set" and "the remaining time is zero". If the remaining time is zero when a
108      * program is started then we assume that no timer was set / program with remaining time is active. This may be
109      * changed later by the user which is detected by the remaining time changing from 0 to some larger value.
110      *
111      * @return The remaining time in seconds.
112      */
113     public Optional<Integer> getRemainingTime() {
114         if (!remainingTimeWasSetInCurrentProgram && isInRunningState(nextState)) {
115             return nextState.getRemainingTime().filter(it -> it != 0);
116         } else {
117             return nextState.getRemainingTime();
118         }
119     }
120
121     /**
122      * Gets the program progress.
123      *
124      * @return The progress of the active program in percent.
125      */
126     public Optional<Integer> getProgress() {
127         if (getRemainingTime().isPresent()) {
128             return nextState.getProgress();
129         } else {
130             return Optional.empty();
131         }
132     }
133
134     private static boolean wasRemainingTimeSetInCurrentProgram(@Nullable TransitionState previousTransitionState,
135             DeviceState nextState) {
136         if (previousTransitionState != null && isInRunningState(previousTransitionState.nextState)) {
137             return previousTransitionState.remainingTimeWasSetInCurrentProgram
138                     || previousTransitionState.getRemainingTime().isPresent();
139         } else {
140             return false;
141         }
142     }
143
144     private static boolean isInRunningState(DeviceState device) {
145         return device.isInState(StateType.RUNNING) || device.isInState(StateType.PAUSE);
146     }
147 }