]> git.basschouten.com Git - openhab-addons.git/blob
47a3b1ed9425278c2a5024f39cba9eca3a00d53e
[openhab-addons.git] /
1 /**
2  * Copyright (c) 2010-2022 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.hdpowerview.internal.database;
14
15 import java.util.Arrays;
16 import java.util.Map;
17 import java.util.function.Function;
18 import java.util.stream.Collectors;
19
20 import org.eclipse.jdt.annotation.NonNullByDefault;
21 import org.slf4j.Logger;
22 import org.slf4j.LoggerFactory;
23
24 /**
25  * Class containing the database of all known shade 'types' and their respective 'capabilities'.
26  *
27  * If user systems detect shade types that are not in the database, then this class can issue logger warning messages
28  * indicating such absence, and prompting the user to report it to developers so that the database and the respective
29  * binding functionality can (hopefully) be extended over time.
30  *
31  * @author Andrew Fiddian-Green - Initial Contribution
32  */
33 @NonNullByDefault
34 public class ShadeCapabilitiesDatabase {
35
36     private final Logger logger = LoggerFactory.getLogger(ShadeCapabilitiesDatabase.class);
37
38     /*
39      * Database of known shade capabilities.
40      */
41     private static final Map<Integer, Capabilities> CAPABILITIES_DATABASE = Arrays.asList(
42     // @formatter:off
43             new Capabilities(0).primary()        .tiltOnClosed()                                .text("Bottom Up"),
44             new Capabilities(1).primary()        .tiltOnClosed()                                .text("Bottom Up Tilt 90°"),
45             new Capabilities(2).primary()        .tiltAnywhere().tilt180()                      .text("Bottom Up Tilt 180°"),
46             new Capabilities(3).primary()        .tiltOnClosed()                                .text("Vertical"),
47             new Capabilities(4).primary()        .tiltAnywhere().tilt180()                      .text("Vertical Tilt 180°"),
48             new Capabilities(5)                  .tiltAnywhere().tilt180()                      .text("Tilt Only 180°"),
49             new Capabilities(6).primaryInverted()                                               .text("Top Down"),
50             new Capabilities(7).primary()                                 .secondary()          .text("Top Down Bottom Up"),
51             new Capabilities(8).primary()                                 .secondaryOverlapped().text("Dual Overlapped"),
52             new Capabilities(9).primary()        .tiltAnywhere()          .secondaryOverlapped().text("Dual Overlapped Tilt 90°"),
53     // @formatter:on
54             new Capabilities()).stream().collect(Collectors.toMap(Capabilities::getValue, Function.identity()));
55
56     /*
57      * Database of known shade types and corresponding capabilities.
58      */
59     private static final Map<Integer, Type> TYPE_DATABASE = Arrays.asList(
60     // @formatter:off
61             new Type( 4).capabilities(0).text("Roman"),
62             new Type( 5).capabilities(0).text("Bottom Up"),
63             new Type( 6).capabilities(0).text("Duette"),
64             new Type( 7).capabilities(6).text("Top Down"),
65             new Type( 8).capabilities(7).text("Duette Top Down Bottom Up"),
66             new Type( 9).capabilities(7).text("Duette DuoLite Top Down Bottom Up"),
67             new Type(18).capabilities(1).text("Silhouette"),
68             new Type(23).capabilities(1).text("Silhouette"),
69             new Type(38).capabilities(9).text("Silhouette Duolite"),
70             new Type(42).capabilities(0).text("M25T Roller Blind"),
71             new Type(43).capabilities(1).text("Facette"),
72             new Type(44).capabilities(0).text("Twist"),
73             new Type(47).capabilities(7).text("Pleated Top Down Bottom Up"),
74             new Type(49).capabilities(0).text("AC Roller"),
75             new Type(51).capabilities(2).text("Venetian"),
76             new Type(54).capabilities(3).text("Vertical Slats Left Stack"),
77             new Type(55).capabilities(3).text("Vertical Slats Right Stack"),
78             new Type(56).capabilities(3).text("Vertical Slats Split Stack"),
79             new Type(62).capabilities(2).text("Venetian"),
80             new Type(65).capabilities(8).text("Vignette Duolite"),
81             new Type(66).capabilities(5).text("Shutter"),
82             new Type(69).capabilities(3).text("Curtain Left Stack"),
83             new Type(70).capabilities(3).text("Curtain Right Stack"),
84             new Type(71).capabilities(3).text("Curtain Split Stack"),
85             new Type(79).capabilities(8).text("Duolite Lift"),
86     // @formatter:on
87             new Type()).stream().collect(Collectors.toMap(Type::getValue, Function.identity()));
88
89     /**
90      * Base class that is extended by Type and Capabilities classes.
91      *
92      * @author Andrew Fiddian-Green - Initial Contribution
93      */
94     private static class Base {
95         protected int intValue = -1;
96         protected String text = "-- not in database --";
97
98         public Integer getValue() {
99             return intValue;
100         }
101
102         @Override
103         public String toString() {
104             return String.format("%s (%d)", text, intValue);
105         }
106     }
107
108     /**
109      * Describes a shade type entry in the database; implements 'capabilities' parameter.
110      *
111      * @author Andrew Fiddian-Green - Initial Contribution
112      */
113     public static class Type extends Base {
114         private int capabilities = -1;
115
116         protected Type() {
117         }
118
119         protected Type(int type) {
120             intValue = type;
121         }
122
123         protected Type text(String text) {
124             this.text = text;
125             return this;
126         }
127
128         protected Type capabilities(int capabilities) {
129             this.capabilities = capabilities;
130             return this;
131         }
132
133         /**
134          * Get shade types's 'capabilities'.
135          *
136          * @return 'capabilities'.
137          */
138         public int getCapabilities() {
139             return capabilities;
140         }
141     }
142
143     /**
144      * Describes a shade 'capabilities' entry in the database; adds properties indicating its supported functionality.
145      *
146      * @author Andrew Fiddian-Green - Initial Contribution
147      */
148     public static class Capabilities extends Base {
149         private boolean supportsPrimary;
150         private boolean supportsSecondary;
151         private boolean supportsTiltOnClosed;
152         private boolean supportsTiltAnywhere;
153         private boolean supportsSecondaryOverlapped;
154         private boolean primaryInverted;
155         private boolean tilt180Degrees;
156
157         public Capabilities() {
158         }
159
160         protected Capabilities secondaryOverlapped() {
161             supportsSecondaryOverlapped = true;
162             return this;
163         }
164
165         protected Capabilities(int capabilities) {
166             intValue = capabilities;
167         }
168
169         protected Capabilities text(String text) {
170             this.text = text;
171             return this;
172         }
173
174         protected Capabilities primary() {
175             supportsPrimary = true;
176             return this;
177         }
178
179         protected Capabilities tiltOnClosed() {
180             supportsTiltOnClosed = true;
181             return this;
182         }
183
184         protected Capabilities secondary() {
185             supportsSecondary = true;
186             return this;
187         }
188
189         protected Capabilities tiltAnywhere() {
190             supportsTiltAnywhere = true;
191             return this;
192         }
193
194         protected Capabilities primaryInverted() {
195             supportsPrimary = true;
196             primaryInverted = true;
197             return this;
198         }
199
200         protected Capabilities tilt180() {
201             tilt180Degrees = true;
202             return this;
203         }
204
205         /**
206          * Check if the Capabilities class instance supports a primary shade.
207          *
208          * @return true if it supports a primary shade.
209          */
210         public boolean supportsPrimary() {
211             return supportsPrimary;
212         }
213
214         /**
215          * Check if the Capabilities class instance supports a vane/tilt function (by means of a second motor).
216          *
217          * @return true if it supports a vane/tilt function (by means of a second motor).
218          */
219         public boolean supportsTiltAnywhere() {
220             return supportsTiltAnywhere;
221         }
222
223         /**
224          * Check if the Capabilities class instance supports a secondary shade.
225          *
226          * @return true if it supports a secondary shade.
227          */
228         public boolean supportsSecondary() {
229             return supportsSecondary;
230         }
231
232         /**
233          * Check if the Capabilities class instance if the primary shade is inverted.
234          *
235          * @return true if the primary shade is inverted.
236          */
237         public boolean isPrimaryInverted() {
238             return primaryInverted;
239         }
240
241         /**
242          * Check if the Capabilities class instance supports 'tilt on closed'.
243          *
244          * Note: Simple bottom up or vertical shades that do not have independent vane controls, can be tilted in a
245          * simple way, only when they are fully closed, by moving the shade motor a bit further.
246          *
247          * @return true if the it supports tilt on closed.
248          */
249         public boolean supportsTiltOnClosed() {
250             return supportsTiltOnClosed && !supportsTiltAnywhere;
251         }
252
253         /**
254          * Check if the Capabilities class instance supports 180 degrees tilt.
255          *
256          * @return true if the tilt range is 180 degrees.
257          */
258         public boolean supportsTilt180() {
259             return tilt180Degrees;
260         }
261
262         /**
263          * Check if the Capabilities class instance supports an overlapped secondary shade.
264          * e.g. a 'DuoLite' or blackout shade.
265          *
266          * @return true if the shade supports a secondary overlapped shade.
267          */
268         public boolean supportsSecondaryOverlapped() {
269             return supportsSecondaryOverlapped;
270         }
271     }
272
273     /**
274      * Determines if a given shade 'type' is in the database.
275      *
276      * @param type the shade 'type' parameter.
277      * @return true if the shade 'type' is known.
278      */
279     public boolean isTypeInDatabase(int type) {
280         return TYPE_DATABASE.containsKey(type);
281     }
282
283     /**
284      * Determines if a given 'capabilities' value is in the database.
285      *
286      * @param capabilities the shade 'capabilities' parameter
287      * @return true if the 'capabilities' value is known
288      */
289     public boolean isCapabilitiesInDatabase(int capabilities) {
290         return CAPABILITIES_DATABASE.containsKey(capabilities);
291     }
292
293     /**
294      * Return a Type class instance that corresponds to the given 'type' parameter.
295      *
296      * @param type the shade 'type' parameter.
297      * @return corresponding instance of Type class.
298      */
299     public Type getType(int type) {
300         return TYPE_DATABASE.getOrDefault(type, new Type());
301     }
302
303     /**
304      * Return a Capabilities class instance that corresponds to the given 'capabilities' parameter.
305      *
306      * @param capabilities the shade 'capabilities' parameter.
307      * @return corresponding instance of Capabilities class.
308      */
309     public Capabilities getCapabilities(int capabilities) {
310         return CAPABILITIES_DATABASE.getOrDefault(capabilities, new Capabilities());
311     }
312
313     private static final String REQUEST_DEVELOPERS_TO_UPDATE = " => Please request developers to update the database!";
314
315     /**
316      * Log a message indicating that 'type' is not in database.
317      *
318      * @param type
319      */
320     public void logTypeNotInDatabase(int type) {
321         logger.warn("The shade 'type:{}' is not in the database!{}", type, REQUEST_DEVELOPERS_TO_UPDATE);
322     }
323
324     /**
325      * Log a message indicating that 'capabilities' is not in database.
326      *
327      * @param capabilities
328      */
329     public void logCapabilitiesNotInDatabase(int type, int capabilities) {
330         logger.warn("The 'capabilities:{}' for shade 'type:{}' are not in the database!{}", capabilities, type,
331                 REQUEST_DEVELOPERS_TO_UPDATE);
332     }
333
334     /**
335      * Log a message indicating the type's capabilities and the passed capabilities are not equal.
336      *
337      * @param type
338      * @param capabilities
339      */
340     public void logCapabilitiesMismatch(int type, int capabilities) {
341         logger.warn("The 'capabilities:{}' reported by shade 'type:{}' don't match the database!{}", capabilities, type,
342                 REQUEST_DEVELOPERS_TO_UPDATE);
343     }
344
345     /**
346      * Log a message indicating that a shade's secondary/vanes support, as observed via its actual JSON payload, does
347      * not match the expected value as declared in its 'type' and 'capabilities'.
348      *
349      * @param propertyKey
350      * @param type
351      * @param capabilities
352      * @param propertyValue
353      */
354     public void logPropertyMismatch(String propertyKey, int type, int capabilities, boolean propertyValue) {
355         logger.warn(
356                 "The '{}:{}' property actually reported by shade 'type:{}' is different "
357                         + "than expected from its 'capabilities:{}' in the database!{}",
358                 propertyKey, propertyValue, type, capabilities, REQUEST_DEVELOPERS_TO_UPDATE);
359     }
360 }