]> git.basschouten.com Git - openhab-addons.git/blob
620861fbf87e02a9dacf26864b0d72366c277209
[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.mybmw.internal.utils;
14
15 import static org.openhab.binding.mybmw.internal.utils.ChargeProfileWrapper.ProfileKey.*;
16 import static org.openhab.binding.mybmw.internal.utils.Constants.*;
17
18 import java.time.DayOfWeek;
19 import java.time.LocalTime;
20 import java.time.format.DateTimeParseException;
21 import java.util.ArrayList;
22 import java.util.EnumSet;
23 import java.util.HashMap;
24 import java.util.Map;
25 import java.util.Optional;
26 import java.util.Set;
27
28 import org.eclipse.jdt.annotation.NonNullByDefault;
29 import org.eclipse.jdt.annotation.Nullable;
30 import org.openhab.binding.mybmw.internal.MyBMWConstants.ChargingMode;
31 import org.openhab.binding.mybmw.internal.MyBMWConstants.ChargingPreference;
32 import org.openhab.binding.mybmw.internal.dto.charge.ChargeProfile;
33 import org.openhab.binding.mybmw.internal.dto.charge.ChargingSettings;
34 import org.openhab.binding.mybmw.internal.dto.charge.ChargingWindow;
35 import org.openhab.binding.mybmw.internal.dto.charge.Time;
36 import org.openhab.binding.mybmw.internal.dto.charge.Timer;
37 import org.slf4j.Logger;
38 import org.slf4j.LoggerFactory;
39
40 /**
41  * The {@link ChargeProfileWrapper} Wrapper for ChargeProfiles
42  *
43  * @author Bernd Weymann - Initial contribution
44  * @author Norbert Truchsess - add ChargeProfileActions
45  */
46 @NonNullByDefault
47 public class ChargeProfileWrapper {
48     private static final Logger LOGGER = LoggerFactory.getLogger(ChargeProfileWrapper.class);
49
50     private static final String CHARGING_WINDOW = "chargingWindow";
51     private static final String WEEKLY_PLANNER = "weeklyPlanner";
52     private static final String ACTIVATE = "activate";
53     private static final String DEACTIVATE = "deactivate";
54
55     public enum ProfileKey {
56         CLIMATE,
57         TIMER1,
58         TIMER2,
59         TIMER3,
60         TIMER4,
61         WINDOWSTART,
62         WINDOWEND
63     }
64
65     private Optional<ChargingMode> mode = Optional.empty();
66     private Optional<ChargingPreference> preference = Optional.empty();
67     private Optional<String> controlType = Optional.empty();
68     private Optional<ChargingSettings> chargeSettings = Optional.empty();
69
70     private final Map<ProfileKey, Boolean> enabled = new HashMap<>();
71     private final Map<ProfileKey, LocalTime> times = new HashMap<>();
72     private final Map<ProfileKey, Set<DayOfWeek>> daysOfWeek = new HashMap<>();
73
74     public ChargeProfileWrapper(final ChargeProfile profile) {
75         setPreference(profile.chargingPreference);
76         setMode(profile.chargingMode);
77         controlType = Optional.of(profile.chargingControlType);
78         chargeSettings = Optional.of(profile.chargingSettings);
79         setEnabled(CLIMATE, profile.climatisationOn);
80
81         addTimer(TIMER1, profile.getTimerId(1));
82         addTimer(TIMER2, profile.getTimerId(2));
83         if (profile.chargingControlType.equals(WEEKLY_PLANNER)) {
84             addTimer(TIMER3, profile.getTimerId(3));
85             addTimer(TIMER4, profile.getTimerId(4));
86         }
87
88         if (CHARGING_WINDOW.equals(profile.chargingPreference)) {
89             addTime(WINDOWSTART, profile.reductionOfChargeCurrent.start);
90             addTime(WINDOWEND, profile.reductionOfChargeCurrent.end);
91         } else {
92             preference.ifPresent(pref -> {
93                 if (ChargingPreference.chargingWindow.equals(pref)) {
94                     addTime(WINDOWSTART, null);
95                     addTime(WINDOWEND, null);
96                 }
97             });
98         }
99     }
100
101     public @Nullable Boolean isEnabled(final ProfileKey key) {
102         return enabled.get(key);
103     }
104
105     public void setEnabled(final ProfileKey key, @Nullable final Boolean enabled) {
106         if (enabled == null) {
107             this.enabled.remove(key);
108         } else {
109             this.enabled.put(key, enabled);
110         }
111     }
112
113     public @Nullable String getMode() {
114         return mode.map(m -> m.name()).orElse(null);
115     }
116
117     public @Nullable String getControlType() {
118         return controlType.get();
119     }
120
121     public @Nullable ChargingSettings getChargeSettings() {
122         return chargeSettings.get();
123     }
124
125     public void setMode(final @Nullable String mode) {
126         if (mode != null) {
127             try {
128                 this.mode = Optional.of(ChargingMode.valueOf(mode));
129                 return;
130             } catch (IllegalArgumentException iae) {
131                 LOGGER.warn("unexpected value for chargingMode: {}", mode);
132             }
133         }
134         this.mode = Optional.empty();
135     }
136
137     public @Nullable String getPreference() {
138         return preference.map(pref -> pref.name()).orElse(null);
139     }
140
141     public void setPreference(final @Nullable String preference) {
142         if (preference != null) {
143             try {
144                 this.preference = Optional.of(ChargingPreference.valueOf(preference));
145                 return;
146             } catch (IllegalArgumentException iae) {
147                 LOGGER.warn("unexpected value for chargingPreference: {}", preference);
148             }
149         }
150         this.preference = Optional.empty();
151     }
152
153     public @Nullable Set<DayOfWeek> getDays(final ProfileKey key) {
154         return daysOfWeek.get(key);
155     }
156
157     public void setDays(final ProfileKey key, final @Nullable Set<DayOfWeek> days) {
158         if (days == null) {
159             daysOfWeek.remove(key);
160         } else {
161             daysOfWeek.put(key, days);
162         }
163     }
164
165     public void setDayEnabled(final ProfileKey key, final DayOfWeek day, final boolean enabled) {
166         final Set<DayOfWeek> days = daysOfWeek.get(key);
167         if (days == null) {
168             daysOfWeek.put(key, enabled ? EnumSet.of(day) : EnumSet.noneOf(DayOfWeek.class));
169         } else {
170             if (enabled) {
171                 days.add(day);
172             } else {
173                 days.remove(day);
174             }
175         }
176     }
177
178     public LocalTime getTime(final ProfileKey key) {
179         LocalTime t = times.get(key);
180         if (t != null) {
181             return t;
182         } else {
183             LOGGER.debug("Profile not valid - Key {} doesn't contain boolean value", key);
184             return Constants.NULL_LOCAL_TIME;
185         }
186     }
187
188     public void setTime(final ProfileKey key, @Nullable LocalTime time) {
189         if (time == null) {
190             times.remove(key);
191         } else {
192             times.put(key, time);
193         }
194     }
195
196     public String getJson() {
197         final ChargeProfile profile = new ChargeProfile();
198
199         preference.ifPresent(pref -> profile.chargingPreference = pref.name());
200         profile.chargingControlType = controlType.get();
201         Boolean enabledBool = isEnabled(CLIMATE);
202         profile.climatisationOn = enabledBool == null ? false : enabledBool;
203         preference.ifPresent(pref -> {
204             if (ChargingPreference.chargingWindow.equals(pref)) {
205                 profile.chargingMode = getMode();
206                 final LocalTime start = getTime(WINDOWSTART);
207                 final LocalTime end = getTime(WINDOWEND);
208                 if (!start.equals(Constants.NULL_LOCAL_TIME) && !end.equals(Constants.NULL_LOCAL_TIME)) {
209                     ChargingWindow cw = new ChargingWindow();
210                     profile.reductionOfChargeCurrent = cw;
211                     cw.start = new Time();
212                     cw.start.hour = start.getHour();
213                     cw.start.minute = start.getMinute();
214                     cw.end = new Time();
215                     cw.end.hour = end.getHour();
216                     cw.end.minute = end.getMinute();
217                 }
218             }
219         });
220         profile.departureTimes = new ArrayList<Timer>();
221         profile.departureTimes.add(getTimer(TIMER1));
222         profile.departureTimes.add(getTimer(TIMER2));
223         if (profile.chargingControlType.equals(WEEKLY_PLANNER)) {
224             profile.departureTimes.add(getTimer(TIMER3));
225             profile.departureTimes.add(getTimer(TIMER4));
226         }
227
228         profile.chargingSettings = chargeSettings.get();
229         return Converter.getGson().toJson(profile);
230     }
231
232     private void addTime(final ProfileKey key, @Nullable final Time time) {
233         try {
234             times.put(key, time == null ? NULL_LOCAL_TIME : LocalTime.parse(Converter.getTime(time), TIME_FORMATER));
235         } catch (DateTimeParseException dtpe) {
236             LOGGER.warn("unexpected value for {} time: {}", key.name(), time);
237         }
238     }
239
240     private void addTimer(final ProfileKey key, @Nullable final Timer timer) {
241         if (timer == null) {
242             enabled.put(key, false);
243             addTime(key, null);
244             daysOfWeek.put(key, EnumSet.noneOf(DayOfWeek.class));
245         } else {
246             enabled.put(key, ACTIVATE.equals(timer.action));
247             addTime(key, timer.timeStamp);
248             final EnumSet<DayOfWeek> daySet = EnumSet.noneOf(DayOfWeek.class);
249             if (timer.timerWeekDays != null) {
250                 daysOfWeek.put(key, EnumSet.noneOf(DayOfWeek.class));
251                 for (String day : timer.timerWeekDays) {
252                     try {
253                         daySet.add(DayOfWeek.valueOf(day.toUpperCase()));
254                     } catch (IllegalArgumentException iae) {
255                         LOGGER.warn("unexpected value for {} day: {}", key.name(), day);
256                     }
257                     daysOfWeek.put(key, daySet);
258                 }
259             }
260         }
261     }
262
263     private Timer getTimer(final ProfileKey key) {
264         final Timer timer = new Timer();
265         switch (key) {
266             case TIMER1:
267                 timer.id = 1;
268                 break;
269             case TIMER2:
270                 timer.id = 2;
271                 break;
272             case TIMER3:
273                 timer.id = 3;
274                 break;
275             case TIMER4:
276                 timer.id = 4;
277                 break;
278             default:
279                 // timer id stays -1
280                 break;
281         }
282         Boolean enabledBool = isEnabled(key);
283         if (enabledBool != null) {
284             timer.action = enabledBool ? ACTIVATE : DEACTIVATE;
285         } else {
286             timer.action = DEACTIVATE;
287         }
288         final LocalTime time = getTime(key);
289         if (!time.equals(Constants.NULL_LOCAL_TIME)) {
290             timer.timeStamp = new Time();
291             timer.timeStamp.hour = time.getHour();
292             timer.timeStamp.minute = time.getMinute();
293         }
294         final Set<DayOfWeek> days = daysOfWeek.get(key);
295         if (days != null) {
296             timer.timerWeekDays = new ArrayList<>();
297             for (DayOfWeek day : days) {
298                 timer.timerWeekDays.add(day.name().toLowerCase());
299             }
300         }
301         return timer;
302     }
303 }