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