2 * Copyright (c) 2010-2023 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.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;
26 * The {@link InternalScene} represents a digitalSTROM-Scene for the internal model.
28 * @author Michael Ochel - Initial contribution
29 * @author Matthias Siegele - Initial contribution
31 public class InternalScene {
32 private final Logger logger = LoggerFactory.getLogger(InternalScene.class);
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;
43 private List<Device> devices = Collections.synchronizedList(new LinkedList<>());
44 private SceneStatusListener listener;
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
50 * <i>zoneID</i> and/or the <i> groupID</i> is null, the broadcast address 0 will be set.
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
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!");
61 this.sceneID = sceneID;
62 if (groupID == null) {
65 this.groupID = groupID;
72 this.internalSceneID = this.zoneID + "-" + this.groupID + "-" + this.sceneID;
73 if (sceneName == null || sceneName.isBlank()) {
74 this.sceneName = this.internalSceneID;
76 this.sceneName = sceneName;
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;
93 * Activates this Scene.
95 public void activateScene() {
96 logger.debug("activate scene: {}", this.getSceneName());
98 deviceHasChanged = false;
100 if (this.devices != null) {
101 for (Device device : this.devices) {
102 device.callInternalScene(this);
108 * Deactivates this Scene.
110 public void deactivateScene() {
111 logger.debug("deactivate scene: {}", this.getSceneName());
114 deviceHasChanged = false;
116 if (this.devices != null) {
117 for (Device device : this.devices) {
118 device.undoInternalScene(this);
125 * Will be called by a device, if an undo call of another scene activated this scene.
127 public void activateSceneByDevice() {
128 logger.debug("activate scene by device: {}", this.getSceneName());
129 if (!active && !deviceHasChanged) {
131 deviceHasChanged = false;
137 * Will be called by a device, if a call of another scene deactivated this scene.
139 public void deactivateSceneByDevice() {
140 logger.debug("deactivate scene by device: {}", this.getSceneName());
143 deviceHasChanged = false;
149 * This method has a device to call, if this scene was activated and the device state has changed.
151 * @param sceneNumber new scene number
153 public void deviceSceneChanged(short sceneNumber) {
154 if (this.sceneID != sceneNumber) {
156 deviceHasChanged = true;
163 private void informListener() {
164 logger.debug("inform listener: {}", this.getSceneName());
165 if (this.listener != null) {
166 listener.onSceneStateChanged(this.active);
168 logger.debug("no listener found for scene: {}", this.getSceneName());
173 * Returns true, if this scene is active, otherwise false.
175 * @return Scene is active? (true = yes | false = no)
177 public boolean isActive() {
182 * Adds an affected {@link Device} to this {@link InternalScene} device list.
184 * @param device to add
186 public void addDevice(Device device) {
187 if (!this.devices.contains(device)) {
188 this.devices.add(device);
191 if (this.listener != null) {
196 device.checkSceneConfig(sceneID, prio);
200 * Overrides the existing device list of this {@link InternalScene} with a new reference to a {@link List} of
201 * affected {@link Device}'s.
203 * @param deviceList to add
205 public void addReferenceDevices(List<Device> deviceList) {
206 this.devices = deviceList;
207 checkDeviceSceneConfig();
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:
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>
219 public void checkDeviceSceneConfig() {
221 if (this.listener != null) {
226 if (devices != null) {
227 for (Device device : devices) {
228 device.checkSceneConfig(sceneID, prio);
234 * Returns the list of the affected {@link Device}'s.
236 * @return device list
238 public List<Device> getDeviceList() {
243 * Adds a {@link List} of affected {@link Device}'s.
245 * @param deviceList to add
247 public void addDevices(List<Device> deviceList) {
248 for (Device device : deviceList) {
254 * Removes a not anymore affected {@link Device} from the device list.
256 * @param device to remove
258 public void removeDevice(Device device) {
259 this.devices.remove(device);
263 * Updates the affected {@link Device}'s with the given deviceList.
265 * @param deviceList to update
267 public void updateDeviceList(List<Device> deviceList) {
268 if (!this.devices.equals(deviceList)) {
269 this.devices.clear();
270 addDevices(deviceList);
275 * Returns the Scene name.
279 public String getSceneName() {
284 * Sets the scene name.
286 * @param sceneName to set
288 public void setSceneName(String sceneName) {
289 this.sceneName = sceneName;
294 * Returns the Scene id of this scene call.
298 public Short getSceneID() {
303 * Returns the group id of this scene call.
307 public Short getGroupID() {
312 * Returns the zone id of this scene call.
316 public Integer getZoneID() {
321 * Returns the id of this scene call.
323 * @return scene call id
325 public String getID() {
326 return internalSceneID;
330 * Registers a {@link SceneStatusListener} to this {@link InternalScene}.
332 * @param listener to register
334 public synchronized void registerSceneListener(SceneStatusListener listener) {
335 this.listener = listener;
336 this.listener.onSceneAdded(this);
337 checkDeviceSceneConfig();
341 * Unregisters the {@link SceneStatusListener} from this {@link InternalScene}.
343 public synchronized void unregisterSceneListener() {
344 if (listener != null) {
345 this.listener = null;
350 * Returns the scene type.
353 * The valid Scene types can be found at {@link SceneTypes}.
357 public String getSceneType() {
358 return this.sceneType;
362 public String toString() {
363 return "NamedScene [SceneName=" + sceneName + ", NAMED_SCENE_ID=" + internalSceneID + "]";
367 public int hashCode() {
368 final int prime = 31;
370 result = prime * result + ((internalSceneID == null) ? 0 : internalSceneID.hashCode());
375 public boolean equals(Object obj) {
382 if (!(obj instanceof InternalScene)) {
385 InternalScene other = (InternalScene) obj;
386 if (internalSceneID == null) {
387 if (other.getID() != null) {
390 } else if (!internalSceneID.equals(other.getID())) {