]> git.basschouten.com Git - openhab-addons.git/blob
cdfbb43db1bc9ce01747f18e80d1e3e67d88ab9c
[openhab-addons.git] /
1 /**
2  * Copyright (c) 2010-2020 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.digitalstrom.internal.lib.structure.scene;
14
15 import java.util.Collections;
16 import java.util.LinkedList;
17 import java.util.List;
18
19 import org.apache.commons.lang.StringUtils;
20 import org.openhab.binding.digitalstrom.internal.lib.listener.SceneStatusListener;
21 import org.openhab.binding.digitalstrom.internal.lib.structure.devices.Device;
22 import org.openhab.binding.digitalstrom.internal.lib.structure.scene.constants.SceneTypes;
23 import org.slf4j.Logger;
24 import org.slf4j.LoggerFactory;
25
26 /**
27  * The {@link InternalScene} represents a digitalSTROM-Scene for the internal model.
28  *
29  * @author Michael Ochel - Initial contribution
30  * @author Matthias Siegele - Initial contribution
31  */
32 public class InternalScene {
33     private final Logger logger = LoggerFactory.getLogger(InternalScene.class);
34
35     private final Short sceneID;
36     private final Short groupID;
37     private final Integer zoneID;
38     private String sceneName;
39     private final String internalSceneID;
40     private boolean active = false;
41     private boolean deviceHasChanged = false;
42     private String sceneType = SceneTypes.GROUP_SCENE;
43
44     private List<Device> devices = Collections.synchronizedList(new LinkedList<>());
45     private SceneStatusListener listener;
46
47     /**
48      * Creates a new {@link InternalScene} with the given parameters. Only the <i>sceneID</i> must not be null. If the
49      * <i>sceneName</i> is null, the internal scene id will be set as name in format "[zoneID]-[groupID]-[sceneID]". If
50      * the
51      * <i>zoneID</i> and/or the <i> groupID</i> is null, the broadcast address 0 will be set.
52      *
53      * @param zoneID can be null
54      * @param groupID can be null
55      * @param sceneID must not be null
56      * @param sceneName can be null
57      */
58     public InternalScene(Integer zoneID, Short groupID, Short sceneID, String sceneName) {
59         if (sceneID == null) {
60             throw new IllegalArgumentException("The parameter sceneID can't be null!");
61         }
62         this.sceneID = sceneID;
63         if (groupID == null) {
64             this.groupID = 0;
65         } else {
66             this.groupID = groupID;
67         }
68         if (zoneID == null) {
69             this.zoneID = 0;
70         } else {
71             this.zoneID = zoneID;
72         }
73         this.internalSceneID = this.zoneID + "-" + this.groupID + "-" + this.sceneID;
74         if (StringUtils.isBlank(sceneName)) {
75             this.sceneName = this.internalSceneID;
76         } else {
77             this.sceneName = sceneName;
78         }
79         setSceneType();
80     }
81
82     private void setSceneType() {
83         if ((sceneName != null) && !sceneName.contains("Apartment-Scene: ") && !sceneName.contains("Zone-Scene: Zone:")
84                 && !(sceneName.contains("Zone: ") && sceneName.contains("Group: ") && sceneName.contains("Scene: "))) {
85             sceneType = SceneTypes.NAMED_SCENE;
86         } else if (this.zoneID == 0) {
87             sceneType = SceneTypes.APARTMENT_SCENE;
88         } else if (this.groupID == 0) {
89             sceneType = SceneTypes.ZONE_SCENE;
90         }
91     }
92
93     /**
94      * Activates this Scene.
95      */
96     public void activateScene() {
97         logger.debug("activate scene: {}", this.getSceneName());
98         this.active = true;
99         deviceHasChanged = false;
100         informListener();
101         if (this.devices != null) {
102             for (Device device : this.devices) {
103                 device.callInternalScene(this);
104             }
105         }
106     }
107
108     /**
109      * Deactivates this Scene.
110      */
111     public void deactivateScene() {
112         logger.debug("deactivate scene: {}", this.getSceneName());
113         if (active) {
114             this.active = false;
115             deviceHasChanged = false;
116             informListener();
117             if (this.devices != null) {
118                 for (Device device : this.devices) {
119                     device.undoInternalScene(this);
120                 }
121             }
122         }
123     }
124
125     /**
126      * Will be called by a device, if an undo call of an other scene activated this scene.
127      */
128     public void activateSceneByDevice() {
129         logger.debug("activate scene by device: {}", this.getSceneName());
130         if (!active && !deviceHasChanged) {
131             this.active = true;
132             deviceHasChanged = false;
133             informListener();
134         }
135     }
136
137     /**
138      * Will be called by a device, if an call of an other scene deactivated this scene.
139      */
140     public void deactivateSceneByDevice() {
141         logger.debug("deactivate scene by device: {}", this.getSceneName());
142         if (active) {
143             this.active = false;
144             deviceHasChanged = false;
145             informListener();
146         }
147     }
148
149     /**
150      * This method has a device to call, if this scene was activated and the device state has changed.
151      *
152      * @param sceneNumber new scene number
153      */
154     public void deviceSceneChanged(short sceneNumber) {
155         if (this.sceneID != sceneNumber) {
156             if (active) {
157                 deviceHasChanged = true;
158                 active = false;
159                 informListener();
160             }
161         }
162     }
163
164     private void informListener() {
165         logger.debug("inform listener: {}", this.getSceneName());
166         if (this.listener != null) {
167             listener.onSceneStateChanged(this.active);
168         } else {
169             logger.debug("no listener found for scene: {}", this.getSceneName());
170         }
171     }
172
173     /**
174      * Returns true, if this scene is active, otherwise false.
175      *
176      * @return Scene is active? (true = yes | false = no)
177      */
178     public boolean isActive() {
179         return this.active;
180     }
181
182     /**
183      * Adds an affected {@link Device} to this {@link InternalScene} device list.
184      *
185      * @param device to add
186      */
187     public void addDevice(Device device) {
188         if (!this.devices.contains(device)) {
189             this.devices.add(device);
190         }
191         short prio = 0;
192         if (this.listener != null) {
193             prio = 1;
194         } else {
195             prio = 2;
196         }
197         device.checkSceneConfig(sceneID, prio);
198     }
199
200     /**
201      * Overrides the existing device list of this {@link InternalScene} with a new reference to a {@link List} of
202      * affected {@link Device}'s.
203      *
204      * @param deviceList to add
205      */
206     public void addReferenceDevices(List<Device> deviceList) {
207         this.devices = deviceList;
208         checkDeviceSceneConfig();
209     }
210
211     /**
212      * Proves, if the scene configuration is saved to all {@link Device}'s. If not, the device initials the reading out
213      * of the missing configuration in the following priority steps:
214      * <ul>
215      * <li>low priority, if no listener is added.</li>
216      * <li>medium priority, if a listener is added.</li>
217      * <li>high priority, if this scene has been activated.</li>
218      * </ul>
219      */
220     public void checkDeviceSceneConfig() {
221         short prio = 0;
222         if (this.listener != null) {
223             prio = 1;
224         } else {
225             prio = 2;
226         }
227         if (devices != null) {
228             for (Device device : devices) {
229                 device.checkSceneConfig(sceneID, prio);
230             }
231         }
232     }
233
234     /**
235      * Returns the list of the affected {@link Device}'s.
236      *
237      * @return device list
238      */
239     public List<Device> getDeviceList() {
240         return this.devices;
241     }
242
243     /**
244      * Adds a {@link List} of affected {@link Device}'s.
245      *
246      * @param deviceList to add
247      */
248     public void addDevices(List<Device> deviceList) {
249         for (Device device : deviceList) {
250             addDevice(device);
251         }
252     }
253
254     /**
255      * Removes a not anymore affected {@link Device} from the device list.
256      *
257      * @param device to remove
258      */
259     public void removeDevice(Device device) {
260         this.devices.remove(device);
261     }
262
263     /**
264      * Updates the affected {@link Device}'s with the given deviceList.
265      *
266      * @param deviceList to update
267      */
268     public void updateDeviceList(List<Device> deviceList) {
269         if (!this.devices.equals(deviceList)) {
270             this.devices.clear();
271             addDevices(deviceList);
272         }
273     }
274
275     /**
276      * Returns the Scene name.
277      *
278      * @return scene name
279      */
280     public String getSceneName() {
281         return sceneName;
282     }
283
284     /**
285      * Sets the scene name.
286      *
287      * @param sceneName to set
288      */
289     public void setSceneName(String sceneName) {
290         this.sceneName = sceneName;
291         setSceneType();
292     }
293
294     /**
295      * Returns the Scene id of this scene call.
296      *
297      * @return scene id
298      */
299     public Short getSceneID() {
300         return sceneID;
301     }
302
303     /**
304      * Returns the group id of this scene call.
305      *
306      * @return group id
307      */
308     public Short getGroupID() {
309         return groupID;
310     }
311
312     /**
313      * Returns the zone id of this scene call.
314      *
315      * @return zone id
316      */
317     public Integer getZoneID() {
318         return zoneID;
319     }
320
321     /**
322      * Returns the id of this scene call.
323      *
324      * @return scene call id
325      */
326     public String getID() {
327         return internalSceneID;
328     }
329
330     /**
331      * Registers a {@link SceneStatusListener} to this {@link InternalScene}.
332      *
333      * @param listener to register
334      */
335     public synchronized void registerSceneListener(SceneStatusListener listener) {
336         this.listener = listener;
337         this.listener.onSceneAdded(this);
338         checkDeviceSceneConfig();
339     }
340
341     /**
342      * Unregisters the {@link SceneStatusListener} from this {@link InternalScene}.
343      */
344     public synchronized void unregisterSceneListener() {
345         if (listener != null) {
346             this.listener = null;
347         }
348     }
349
350     /**
351      * Returns the scene type.
352      * <br>
353      * <b>Note:</b>
354      * The valid Scene types can be found at {@link SceneTypes}.
355      *
356      * @return sceneType
357      */
358     public String getSceneType() {
359         return this.sceneType;
360     }
361
362     @Override
363     public String toString() {
364         return "NamedScene [SceneName=" + sceneName + ", NAMED_SCENE_ID=" + internalSceneID + "]";
365     }
366
367     @Override
368     public int hashCode() {
369         final int prime = 31;
370         int result = 1;
371         result = prime * result + ((internalSceneID == null) ? 0 : internalSceneID.hashCode());
372         return result;
373     }
374
375     @Override
376     public boolean equals(Object obj) {
377         if (this == obj) {
378             return true;
379         }
380         if (obj == null) {
381             return false;
382         }
383         if (!(obj instanceof InternalScene)) {
384             return false;
385         }
386         InternalScene other = (InternalScene) obj;
387         if (internalSceneID == null) {
388             if (other.getID() != null) {
389                 return false;
390             }
391         } else if (!internalSceneID.equals(other.getID())) {
392             return false;
393         }
394         return true;
395     }
396 }