2 * Copyright (c) 2010-2021 Contributors to the openHAB project
4 * See the NOTICE file(s) distributed with this work for additional
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
11 * SPDX-License-Identifier: EPL-2.0
13 package org.openhab.binding.digitalstrom.internal.lib.structure.scene;
15 import java.util.Collections;
16 import java.util.LinkedList;
17 import java.util.List;
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;
27 * The {@link InternalScene} represents a digitalSTROM-Scene for the internal model.
29 * @author Michael Ochel - Initial contribution
30 * @author Matthias Siegele - Initial contribution
32 public class InternalScene {
33 private final Logger logger = LoggerFactory.getLogger(InternalScene.class);
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;
44 private List<Device> devices = Collections.synchronizedList(new LinkedList<>());
45 private SceneStatusListener listener;
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
51 * <i>zoneID</i> and/or the <i> groupID</i> is null, the broadcast address 0 will be set.
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
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!");
62 this.sceneID = sceneID;
63 if (groupID == null) {
66 this.groupID = groupID;
73 this.internalSceneID = this.zoneID + "-" + this.groupID + "-" + this.sceneID;
74 if (StringUtils.isBlank(sceneName)) {
75 this.sceneName = this.internalSceneID;
77 this.sceneName = sceneName;
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;
94 * Activates this Scene.
96 public void activateScene() {
97 logger.debug("activate scene: {}", this.getSceneName());
99 deviceHasChanged = false;
101 if (this.devices != null) {
102 for (Device device : this.devices) {
103 device.callInternalScene(this);
109 * Deactivates this Scene.
111 public void deactivateScene() {
112 logger.debug("deactivate scene: {}", this.getSceneName());
115 deviceHasChanged = false;
117 if (this.devices != null) {
118 for (Device device : this.devices) {
119 device.undoInternalScene(this);
126 * Will be called by a device, if an undo call of an other scene activated this scene.
128 public void activateSceneByDevice() {
129 logger.debug("activate scene by device: {}", this.getSceneName());
130 if (!active && !deviceHasChanged) {
132 deviceHasChanged = false;
138 * Will be called by a device, if an call of an other scene deactivated this scene.
140 public void deactivateSceneByDevice() {
141 logger.debug("deactivate scene by device: {}", this.getSceneName());
144 deviceHasChanged = false;
150 * This method has a device to call, if this scene was activated and the device state has changed.
152 * @param sceneNumber new scene number
154 public void deviceSceneChanged(short sceneNumber) {
155 if (this.sceneID != sceneNumber) {
157 deviceHasChanged = true;
164 private void informListener() {
165 logger.debug("inform listener: {}", this.getSceneName());
166 if (this.listener != null) {
167 listener.onSceneStateChanged(this.active);
169 logger.debug("no listener found for scene: {}", this.getSceneName());
174 * Returns true, if this scene is active, otherwise false.
176 * @return Scene is active? (true = yes | false = no)
178 public boolean isActive() {
183 * Adds an affected {@link Device} to this {@link InternalScene} device list.
185 * @param device to add
187 public void addDevice(Device device) {
188 if (!this.devices.contains(device)) {
189 this.devices.add(device);
192 if (this.listener != null) {
197 device.checkSceneConfig(sceneID, prio);
201 * Overrides the existing device list of this {@link InternalScene} with a new reference to a {@link List} of
202 * affected {@link Device}'s.
204 * @param deviceList to add
206 public void addReferenceDevices(List<Device> deviceList) {
207 this.devices = deviceList;
208 checkDeviceSceneConfig();
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:
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>
220 public void checkDeviceSceneConfig() {
222 if (this.listener != null) {
227 if (devices != null) {
228 for (Device device : devices) {
229 device.checkSceneConfig(sceneID, prio);
235 * Returns the list of the affected {@link Device}'s.
237 * @return device list
239 public List<Device> getDeviceList() {
244 * Adds a {@link List} of affected {@link Device}'s.
246 * @param deviceList to add
248 public void addDevices(List<Device> deviceList) {
249 for (Device device : deviceList) {
255 * Removes a not anymore affected {@link Device} from the device list.
257 * @param device to remove
259 public void removeDevice(Device device) {
260 this.devices.remove(device);
264 * Updates the affected {@link Device}'s with the given deviceList.
266 * @param deviceList to update
268 public void updateDeviceList(List<Device> deviceList) {
269 if (!this.devices.equals(deviceList)) {
270 this.devices.clear();
271 addDevices(deviceList);
276 * Returns the Scene name.
280 public String getSceneName() {
285 * Sets the scene name.
287 * @param sceneName to set
289 public void setSceneName(String sceneName) {
290 this.sceneName = sceneName;
295 * Returns the Scene id of this scene call.
299 public Short getSceneID() {
304 * Returns the group id of this scene call.
308 public Short getGroupID() {
313 * Returns the zone id of this scene call.
317 public Integer getZoneID() {
322 * Returns the id of this scene call.
324 * @return scene call id
326 public String getID() {
327 return internalSceneID;
331 * Registers a {@link SceneStatusListener} to this {@link InternalScene}.
333 * @param listener to register
335 public synchronized void registerSceneListener(SceneStatusListener listener) {
336 this.listener = listener;
337 this.listener.onSceneAdded(this);
338 checkDeviceSceneConfig();
342 * Unregisters the {@link SceneStatusListener} from this {@link InternalScene}.
344 public synchronized void unregisterSceneListener() {
345 if (listener != null) {
346 this.listener = null;
351 * Returns the scene type.
354 * The valid Scene types can be found at {@link SceneTypes}.
358 public String getSceneType() {
359 return this.sceneType;
363 public String toString() {
364 return "NamedScene [SceneName=" + sceneName + ", NAMED_SCENE_ID=" + internalSceneID + "]";
368 public int hashCode() {
369 final int prime = 31;
371 result = prime * result + ((internalSceneID == null) ? 0 : internalSceneID.hashCode());
376 public boolean equals(Object obj) {
383 if (!(obj instanceof InternalScene)) {
386 InternalScene other = (InternalScene) obj;
387 if (internalSceneID == null) {
388 if (other.getID() != null) {
391 } else if (!internalSceneID.equals(other.getID())) {