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.devices.impl;
15 import java.util.ArrayList;
16 import java.util.Collections;
17 import java.util.HashMap;
18 import java.util.HashSet;
19 import java.util.LinkedList;
20 import java.util.List;
22 import java.util.Map.Entry;
25 import org.openhab.binding.digitalstrom.internal.DigitalSTROMBindingConstants;
26 import org.openhab.binding.digitalstrom.internal.lib.GeneralLibConstance;
27 import org.openhab.binding.digitalstrom.internal.lib.config.Config;
28 import org.openhab.binding.digitalstrom.internal.lib.event.types.EventItem;
29 import org.openhab.binding.digitalstrom.internal.lib.listener.DeviceStatusListener;
30 import org.openhab.binding.digitalstrom.internal.lib.serverconnection.constants.JSONApiResponseKeysEnum;
31 import org.openhab.binding.digitalstrom.internal.lib.structure.devices.AbstractGeneralDeviceInformations;
32 import org.openhab.binding.digitalstrom.internal.lib.structure.devices.Device;
33 import org.openhab.binding.digitalstrom.internal.lib.structure.devices.deviceparameters.DeviceConstants;
34 import org.openhab.binding.digitalstrom.internal.lib.structure.devices.deviceparameters.DeviceSceneSpec;
35 import org.openhab.binding.digitalstrom.internal.lib.structure.devices.deviceparameters.DeviceStateUpdate;
36 import org.openhab.binding.digitalstrom.internal.lib.structure.devices.deviceparameters.constants.ChangeableDeviceConfigEnum;
37 import org.openhab.binding.digitalstrom.internal.lib.structure.devices.deviceparameters.constants.DeviceBinarayInputEnum;
38 import org.openhab.binding.digitalstrom.internal.lib.structure.devices.deviceparameters.constants.FuncNameAndColorGroupEnum;
39 import org.openhab.binding.digitalstrom.internal.lib.structure.devices.deviceparameters.constants.FunctionalColorGroupEnum;
40 import org.openhab.binding.digitalstrom.internal.lib.structure.devices.deviceparameters.constants.OutputModeEnum;
41 import org.openhab.binding.digitalstrom.internal.lib.structure.devices.deviceparameters.constants.SensorEnum;
42 import org.openhab.binding.digitalstrom.internal.lib.structure.devices.deviceparameters.impl.DSID;
43 import org.openhab.binding.digitalstrom.internal.lib.structure.devices.deviceparameters.impl.DeviceBinaryInput;
44 import org.openhab.binding.digitalstrom.internal.lib.structure.devices.deviceparameters.impl.DeviceSensorValue;
45 import org.openhab.binding.digitalstrom.internal.lib.structure.devices.deviceparameters.impl.DeviceStateUpdateImpl;
46 import org.openhab.binding.digitalstrom.internal.lib.structure.devices.deviceparameters.impl.JSONDeviceSceneSpecImpl;
47 import org.openhab.binding.digitalstrom.internal.lib.structure.scene.InternalScene;
48 import org.openhab.binding.digitalstrom.internal.lib.structure.scene.constants.SceneEnum;
49 import org.slf4j.Logger;
50 import org.slf4j.LoggerFactory;
52 import com.google.gson.JsonArray;
53 import com.google.gson.JsonElement;
54 import com.google.gson.JsonObject;
57 * The {@link DeviceImpl} is the implementation of the {@link Device}.
59 * @author Michael Ochel - Initial contribution
60 * @author Matthias Siegele - Initial contribution
62 public class DeviceImpl extends AbstractGeneralDeviceInformations implements Device {
64 private final Logger logger = LoggerFactory.getLogger(DeviceImpl.class);
66 private Config config;
68 private DSID meterDSID;
69 private int zoneId = 0;
70 private List<Short> groupList = new LinkedList<>();
72 private FunctionalColorGroupEnum functionalGroup;
73 private FuncNameAndColorGroupEnum functionalName;
74 private String hwInfo;
76 private OutputModeEnum outputMode;
78 private boolean isOn = false;
79 private boolean isOpen = true;
80 private short outputValue = 0;
81 private short maxOutputValue = DeviceConstants.DEFAULT_MAX_OUTPUTVALUE;
82 private short minOutputValue = 0;
84 private short slatAngle = 0;
85 private final short maxSlatAngle = DeviceConstants.MAX_SLAT_ANGLE;
86 private final short minSlatAngle = DeviceConstants.MIN_SLAT_ANGLE;
88 private int slatPosition = 0;
89 private final int maxSlatPosition = DeviceConstants.MAX_ROLLERSHUTTER;
90 private final int minSlatPosition = DeviceConstants.MIN_ROLLERSHUTTER;
92 private final List<DeviceSensorValue> deviceSensorValues = Collections.synchronizedList(new ArrayList<>());
93 private final List<DeviceBinaryInput> deviceBinaryInputs = Collections.synchronizedList(new ArrayList<>());
94 private final List<SensorEnum> devicePowerSensorTypes = new ArrayList<>();
95 private final List<SensorEnum> deviceClimateSensorTypes = new ArrayList<>();
98 private short activeSceneNumber = -1;
99 private InternalScene activeScene;
100 private InternalScene lastScene;
101 private int outputValueBeforeSceneCall = 0;
102 private short slatAngleBeforeSceneCall = 0;
103 private boolean lastCallWasUndo = false;
105 private final Map<Short, DeviceSceneSpec> sceneConfigMap = Collections.synchronizedMap(new HashMap<>());
106 private final Map<Short, Integer[]> sceneOutputMap = Collections.synchronizedMap(new HashMap<>());
108 // saves outstanding commands
109 private final List<DeviceStateUpdate> deviceStateUpdates = Collections.synchronizedList(new LinkedList<>());
112 * Saves the refresh priorities and reading initialized flag of power sensors as an matrix.
113 * The first array fields are 0 = active power, 1 = output current, 2 = electric meter, 3 = power consumption and in
115 * string array with the fields 0 = refresh priority 1 = reading initial flag (true = reading is initialized,
118 private final Object[] powerSensorRefresh = new Object[] { new String[] { Config.REFRESH_PRIORITY_NEVER, "false" },
119 new String[] { Config.REFRESH_PRIORITY_NEVER, "false" },
120 new String[] { Config.REFRESH_PRIORITY_NEVER, "false" },
121 new String[] { Config.REFRESH_PRIORITY_NEVER, "false" } };
123 public static final int REFRESH_PRIORITY_ARRAY_FIELD = 0;
124 public static final int READING_INITIALIZED_ARRAY_FIELD = 1;
126 public static final int REFRESH_ACTIVE_POWER_ARRAY_FIELD = 0;
127 public static final int REFRESH_OUTPUT_CURRENT_ARRAY_FIELD = 1;
128 public static final int REFRESH_ELECTRIC_METER_ARRAY_FIELD = 2;
129 public static final int REFRESH_POWER_CONSUMPTION_ARRAY_FIELD = 3;
131 * Cache the last power sensor value to get power sensor value directly
132 * the key is the output value and the value is an Integer array for the sensor values (0 = active power, 1 =
133 * output current, 2 = power consumption, 3 = output current high)
135 private final Map<Short, Integer[]> cachedSensorPowerValues = Collections.synchronizedMap(new HashMap<>());
137 public static final int ACTIVE_POWER_ARRAY_FIELD = 0;
138 public static final int OUTPUT_CURRENT_ARRAY_FIELD = 1;
139 public static final int POWER_CONSUMPTION_ARRAY_FIELD = 2;
140 public static final int OUTPUT_CURRENT_HIGH_ARRAY_FIELD = 3;
142 // Preparing for the advance device property setting "Turn 'switched' output off if value below:", but the
143 // configuration currently not work in digitalSTROM, because of that the value is fix 1.
144 private final int switchPercentOff = 1;
147 * Creates a new {@link DeviceImpl} from the given DigitalSTROM-Device {@link JsonObject}.
149 * @param deviceJsonObject json response of the digitalSTROM-Server, must not be null
151 public DeviceImpl(JsonObject deviceJsonObject) {
152 super(deviceJsonObject);
153 if (deviceJsonObject.get(JSONApiResponseKeysEnum.METER_DSID.getKey()) != null) {
154 this.meterDSID = new DSID(deviceJsonObject.get(JSONApiResponseKeysEnum.METER_DSID.getKey()).getAsString());
155 } else if (deviceJsonObject.get(JSONApiResponseKeysEnum.DS_METER_DSID.getKey()) != null) {
156 this.meterDSID = new DSID(
157 deviceJsonObject.get(JSONApiResponseKeysEnum.DS_METER_DSID.getKey()).getAsString());
159 if (deviceJsonObject.get(JSONApiResponseKeysEnum.HW_INFO.getKey()) != null) {
160 this.hwInfo = deviceJsonObject.get(JSONApiResponseKeysEnum.HW_INFO.getKey()).getAsString();
161 } else if (deviceJsonObject.get(JSONApiResponseKeysEnum.HW_INFO_UPPER_HW.getKey()) != null) {
162 this.hwInfo = deviceJsonObject.get(JSONApiResponseKeysEnum.HW_INFO_UPPER_HW.getKey()).getAsString();
164 if (deviceJsonObject.get(JSONApiResponseKeysEnum.ON.getKey()) != null) {
166 this.isOn = deviceJsonObject.get(JSONApiResponseKeysEnum.ON.getKey()).getAsBoolean();
168 this.isOpen = deviceJsonObject.get(JSONApiResponseKeysEnum.ON.getKey()).getAsBoolean();
171 if (deviceJsonObject.get(JSONApiResponseKeysEnum.ZONE_ID.getKey()) != null) {
172 zoneId = deviceJsonObject.get(JSONApiResponseKeysEnum.ZONE_ID.getKey()).getAsInt();
173 } else if (deviceJsonObject.get(JSONApiResponseKeysEnum.ZONE_ID_Lower_Z.getKey()) != null) {
174 zoneId = deviceJsonObject.get(JSONApiResponseKeysEnum.ZONE_ID_Lower_Z.getKey()).getAsInt();
176 JsonElement groups = deviceJsonObject.get(JSONApiResponseKeysEnum.GROUPS.getKey());
177 if (groups != null && groups.isJsonArray()) {
178 JsonArray array = deviceJsonObject.get(JSONApiResponseKeysEnum.GROUPS.getKey()).getAsJsonArray();
179 for (int i = 0; i < array.size(); i++) {
180 if (array.get(i) != null) {
181 initAddGroup(array.get(i).getAsShort());
184 } else if (groups != null && groups.isJsonObject()) {
185 for (Entry<String, JsonElement> entry : deviceJsonObject.get(JSONApiResponseKeysEnum.GROUPS.getKey())
186 .getAsJsonObject().entrySet()) {
187 initAddGroup(entry.getValue().getAsJsonObject().get(JSONApiResponseKeysEnum.ID.getKey()).getAsShort());
190 if (deviceJsonObject.get(JSONApiResponseKeysEnum.OUTPUT_MODE.getKey()) != null) {
191 int tmp = deviceJsonObject.get(JSONApiResponseKeysEnum.OUTPUT_MODE.getKey()).getAsInt();
193 if (OutputModeEnum.containsMode(tmp)) {
194 outputMode = OutputModeEnum.getMode(tmp);
198 if (deviceJsonObject.get(JSONApiResponseKeysEnum.SENSOR_INPUTS.getKey()) != null
199 && deviceJsonObject.get(JSONApiResponseKeysEnum.SENSOR_INPUTS.getKey()).isJsonObject()) {
200 JsonObject jObj = deviceJsonObject.get(JSONApiResponseKeysEnum.SENSOR_INPUTS.getKey()).getAsJsonObject();
201 for (Entry<String, JsonElement> entry : jObj.entrySet()) {
202 if (entry.getValue().isJsonObject()) {
203 JsonObject sensorType = entry.getValue().getAsJsonObject();
204 if (sensorType.get(JSONApiResponseKeysEnum.TYPE.getKey()) != null) {
206 .containsSensor(sensorType.get(JSONApiResponseKeysEnum.TYPE.getKey()).getAsShort())) {
207 setDeviceSensorValue(new DeviceSensorValue(entry.getValue().getAsJsonObject()));
213 if (deviceJsonObject.get(JSONApiResponseKeysEnum.BINARY_INPUTS.getKey()) != null
214 && deviceJsonObject.get(JSONApiResponseKeysEnum.BINARY_INPUTS.getKey()).isJsonObject()) {
215 JsonObject jObj = deviceJsonObject.get(JSONApiResponseKeysEnum.BINARY_INPUTS.getKey()).getAsJsonObject();
216 for (Entry<String, JsonElement> entry : jObj.entrySet()) {
217 if (entry.getValue().isJsonObject()) {
218 JsonObject binaryInput = entry.getValue().getAsJsonObject();
219 deviceBinaryInputs.add(new DeviceBinaryInput(binaryInput));
226 private void initAddGroup(Short groupID) {
228 this.groupList.add(groupID);
229 if (FuncNameAndColorGroupEnum.containsColorGroup(groupID)) {
230 if (this.functionalName == null
231 || !FuncNameAndColorGroupEnum.getMode(groupID).equals(FuncNameAndColorGroupEnum.JOKER)) {
232 this.functionalName = FuncNameAndColorGroupEnum.getMode(groupID);
233 this.functionalGroup = functionalName.getFunctionalColor();
239 private void init() {
240 if (groupList.contains((short) 1)) {
241 maxOutputValue = DeviceConstants.MAX_OUTPUT_VALUE_LIGHT;
242 if (this.isDimmable()) {
243 minOutputValue = DeviceConstants.MIN_DIM_VALUE;
246 maxOutputValue = DeviceConstants.DEFAULT_MAX_OUTPUTVALUE;
250 outputValue = DeviceConstants.DEFAULT_MAX_OUTPUTVALUE;
255 public synchronized DSID getMeterDSID() {
256 return this.meterDSID;
260 public synchronized void setMeterDSID(String meterDSID) {
261 this.meterDSID = new DSID(meterDSID);
262 informListenerAboutConfigChange(ChangeableDeviceConfigEnum.METER_DSID);
266 public String getHWinfo() {
271 public List<Short> getGroups() {
272 return new LinkedList<>(groupList);
276 public void addGroup(Short groupID) {
277 if (!this.groupList.contains(groupID)) {
278 this.groupList.add(groupID);
280 informListenerAboutConfigChange(ChangeableDeviceConfigEnum.GROUPS);
284 public void setGroups(List<Short> newGroupList) {
285 if (newGroupList != null) {
286 this.groupList = newGroupList;
288 informListenerAboutConfigChange(ChangeableDeviceConfigEnum.GROUPS);
292 public synchronized int getZoneId() {
297 public synchronized void setZoneId(int zoneID) {
298 this.zoneId = zoneID;
299 informListenerAboutConfigChange(ChangeableDeviceConfigEnum.ZONE_ID);
303 public synchronized boolean isOn() {
308 public synchronized void setIsOn(boolean flag) {
310 this.deviceStateUpdates.add(new DeviceStateUpdateImpl(DeviceStateUpdate.ON_OFF, 1));
312 this.deviceStateUpdates.add(new DeviceStateUpdateImpl(DeviceStateUpdate.ON_OFF, -1));
317 public synchronized boolean isOpen() {
322 public synchronized void setIsOpen(boolean flag) {
324 this.deviceStateUpdates.add(new DeviceStateUpdateImpl(DeviceStateUpdate.OPEN_CLOSE, 1));
326 this.deviceStateUpdates.add(new DeviceStateUpdateImpl(DeviceStateUpdate.OPEN_CLOSE_ANGLE, 1));
329 this.deviceStateUpdates.add(new DeviceStateUpdateImpl(DeviceStateUpdate.OPEN_CLOSE, -1));
331 this.deviceStateUpdates.add(new DeviceStateUpdateImpl(DeviceStateUpdate.OPEN_CLOSE_ANGLE, -1));
337 public synchronized void setOutputValue(short value) {
340 this.deviceStateUpdates.add(new DeviceStateUpdateImpl(DeviceStateUpdate.ON_OFF, -1));
342 } else if (value > maxOutputValue) {
343 this.deviceStateUpdates.add(new DeviceStateUpdateImpl(DeviceStateUpdate.ON_OFF, 1));
345 this.deviceStateUpdates.add(new DeviceStateUpdateImpl(DeviceStateUpdate.OUTPUT, value));
351 public synchronized boolean isDimmable() {
352 return OutputModeEnum.outputModeIsDimmable(outputMode);
356 public synchronized boolean isSwitch() {
357 return OutputModeEnum.outputModeIsSwitch(outputMode);
361 public synchronized boolean isDeviceWithOutput() {
362 return this.outputMode != null && !this.outputMode.equals(OutputModeEnum.DISABLED);
366 public boolean isSensorDevice() {
367 return !isDeviceWithOutput() && !deviceClimateSensorTypes.isEmpty();
371 public boolean isHeatingDevice() {
372 return functionalName.equals(FuncNameAndColorGroupEnum.HEATING);
376 public boolean isTemperatureControlledDevice() {
377 return functionalName.equals(FuncNameAndColorGroupEnum.TEMPERATION_CONTROL);
381 public boolean isShade() {
382 return OutputModeEnum.outputModeIsShade(outputMode);
386 public boolean isBlind() {
387 return outputMode.equals(OutputModeEnum.POSITION_CON_US);
391 public synchronized FunctionalColorGroupEnum getFunctionalColorGroup() {
392 return this.functionalGroup;
396 public synchronized void setFunctionalColorGroup(FunctionalColorGroupEnum fuctionalColorGroup) {
397 this.functionalGroup = fuctionalColorGroup;
398 informListenerAboutConfigChange(ChangeableDeviceConfigEnum.FUNCTIONAL_GROUP);
402 public OutputModeEnum getOutputMode() {
407 public synchronized void setOutputMode(OutputModeEnum newOutputMode) {
408 this.outputMode = newOutputMode;
409 informListenerAboutConfigChange(ChangeableDeviceConfigEnum.OUTPUT_MODE);
413 public synchronized void increase() {
415 deviceStateUpdates.add(new DeviceStateUpdateImpl(DeviceStateUpdate.OUTPUT_INCREASE, 0));
418 this.deviceStateUpdates.add(new DeviceStateUpdateImpl(DeviceStateUpdate.SLAT_INCREASE, 0));
420 this.deviceStateUpdates.add(new DeviceStateUpdateImpl(DeviceStateUpdate.SLAT_ANGLE_DECREASE, 0));
426 public synchronized void decrease() {
428 this.deviceStateUpdates.add(new DeviceStateUpdateImpl(DeviceStateUpdate.OUTPUT_DECREASE, 0));
431 this.deviceStateUpdates.add(new DeviceStateUpdateImpl(DeviceStateUpdate.SLAT_DECREASE, 0));
433 this.deviceStateUpdates.add(new DeviceStateUpdateImpl(DeviceStateUpdate.SLAT_ANGLE_DECREASE, 0));
439 public synchronized void increaseSlatAngle() {
441 this.deviceStateUpdates.add(new DeviceStateUpdateImpl(DeviceStateUpdate.SLAT_ANGLE_DECREASE, 1));
446 public synchronized void decreaseSlatAngle() {
448 this.deviceStateUpdates.add(new DeviceStateUpdateImpl(DeviceStateUpdate.SLAT_ANGLE_DECREASE, 1));
453 public synchronized short getOutputValue() {
458 public short getMaxOutputValue() {
459 return maxOutputValue;
463 public short getMinOutputValue() {
464 return minOutputValue;
468 public synchronized int getSlatPosition() {
473 public synchronized short getAnglePosition() {
478 public synchronized void setAnglePosition(int angle) {
479 if (angle == slatAngle) {
482 if (angle < minSlatAngle) {
483 this.deviceStateUpdates.add(new DeviceStateUpdateImpl(DeviceStateUpdate.SLAT_ANGLE, minSlatAngle));
484 } else if (angle > this.maxSlatPosition) {
485 this.deviceStateUpdates.add(new DeviceStateUpdateImpl(DeviceStateUpdate.SLAT_ANGLE, maxSlatAngle));
487 this.deviceStateUpdates.add(new DeviceStateUpdateImpl(DeviceStateUpdate.SLAT_ANGLE, angle));
492 public synchronized void setSlatPosition(int position) {
493 if (position == this.slatPosition) {
496 if (position < minSlatPosition) {
497 this.deviceStateUpdates.add(new DeviceStateUpdateImpl(DeviceStateUpdate.SLATPOSITION, minSlatPosition));
498 } else if (position > this.maxSlatPosition) {
499 this.deviceStateUpdates.add(new DeviceStateUpdateImpl(DeviceStateUpdate.SLATPOSITION, maxSlatPosition));
501 this.deviceStateUpdates.add(new DeviceStateUpdateImpl(DeviceStateUpdate.SLATPOSITION, position));
505 private short getDimmStep() {
507 return DeviceConstants.DIM_STEP_LIGHT;
508 } else if (isShade()) {
509 return DeviceConstants.MOVE_STEP_ROLLERSHUTTER;
511 return DeviceConstants.DEFAULT_MOVE_STEP;
516 public int getMaxSlatPosition() {
517 return maxSlatPosition;
521 public int getMinSlatPosition() {
522 return minSlatPosition;
526 public int getMaxSlatAngle() {
531 public int getMinSlatAngle() {
538 public synchronized void callInternalScene(InternalScene scene) {
539 if (lastCallWasUndo) {
541 if (activeScene != null) {
542 activeScene.deactivateSceneByDevice();
546 internalCallScene(scene.getSceneID());
548 lastCallWasUndo = false;
552 public void checkSceneConfig(Short sceneNumber, short prio) {
553 if (isDeviceWithOutput()) {
554 if (!containsSceneConfig(sceneNumber)) {
555 deviceStateUpdates.add(new DeviceStateUpdateImpl(DeviceStateUpdate.UPDATE_SCENE_CONFIG,
556 new Short[] { sceneNumber, prio }));
559 if (sceneOutputMap.get(sceneNumber) == null) {
560 deviceStateUpdates.add(new DeviceStateUpdateImpl(DeviceStateUpdate.UPDATE_SCENE_OUTPUT,
561 new Short[] { sceneNumber, prio }));
567 public synchronized void undoInternalScene(InternalScene scene) {
568 logger.debug("undo Scene {} dSID {}", scene.getSceneID(), dsid.getValue());
569 if (activeScene != null && activeScene.equals(scene)) {
570 if (lastCallWasUndo) {
574 if (this.lastScene != null && !lastScene.equals(activeScene)) {
575 activeScene = lastScene;
577 activeScene.activateSceneByDevice();
580 logger.debug("internalUndo Scene dSID {}", dsid.getValue());
581 this.activeScene = null;
584 lastCallWasUndo = true;
589 public synchronized void callScene(Short sceneNumber) {
590 this.deviceStateUpdates.add(new DeviceStateUpdateImpl(DeviceStateUpdate.UPDATE_CALL_SCENE, sceneNumber));
594 public synchronized void internalCallScene(Short sceneNumber) {
595 logger.debug("call Scene id {} dSID {}", sceneNumber, dsid.getValue());
596 if (isDeviceWithOutput()) {
597 activeSceneNumber = sceneNumber;
598 informLastSceneAboutSceneCall(sceneNumber);
600 outputValueBeforeSceneCall = this.outputValue;
602 outputValueBeforeSceneCall = this.slatPosition;
604 slatAngleBeforeSceneCall = this.slatAngle;
607 if (!checkSceneNumber(sceneNumber)) {
608 if (containsSceneConfig(sceneNumber)) {
609 if (doIgnoreScene(sceneNumber)) {
613 this.deviceStateUpdates.add(new DeviceStateUpdateImpl(DeviceStateUpdate.UPDATE_SCENE_CONFIG,
614 new Short[] { sceneNumber, GeneralLibConstance.HIGHEST_READ_OUT_PRIORITY }));
616 if (sceneOutputMap.get(sceneNumber) != null) {
618 updateInternalDeviceState(new DeviceStateUpdateImpl(DeviceStateUpdate.OUTPUT,
619 sceneOutputMap.get(sceneNumber)[GeneralLibConstance.SCENE_ARRAY_INDEX_VALUE]));
621 updateInternalDeviceState(new DeviceStateUpdateImpl(DeviceStateUpdate.SLATPOSITION,
622 sceneOutputMap.get(sceneNumber)[GeneralLibConstance.SCENE_ARRAY_INDEX_VALUE]));
624 updateInternalDeviceState(new DeviceStateUpdateImpl(DeviceStateUpdate.SLAT_ANGLE,
625 sceneOutputMap.get(sceneNumber)[GeneralLibConstance.SCENE_ARRAY_INDEX_ANGLE]));
629 this.deviceStateUpdates.add(new DeviceStateUpdateImpl(DeviceStateUpdate.UPDATE_SCENE_OUTPUT,
630 new Short[] { sceneNumber, GeneralLibConstance.HIGHEST_READ_OUT_PRIORITY }));
637 private boolean checkSceneNumber(Short sceneNumber) {
638 if (SceneEnum.containsScene(sceneNumber)) {
639 if (this.outputMode.equals(OutputModeEnum.POWERSAVE)) {
640 switch (SceneEnum.getScene(sceneNumber)) {
644 this.updateInternalDeviceState(new DeviceStateUpdateImpl(DeviceStateUpdate.ON_OFF, -1));
660 if (this.outputMode.equals(OutputModeEnum.WIPE)) {
661 switch (SceneEnum.getScene(sceneNumber)) {
673 this.updateInternalDeviceState(new DeviceStateUpdateImpl(DeviceStateUpdate.ON_OFF, -1));
679 switch (SceneEnum.getScene(sceneNumber)) {
684 this.updateInternalDeviceState(new DeviceStateUpdateImpl(DeviceStateUpdate.ON_OFF, 1));
686 this.updateInternalDeviceState(new DeviceStateUpdateImpl(DeviceStateUpdate.OPEN_CLOSE, 1));
688 this.updateInternalDeviceState(
689 new DeviceStateUpdateImpl(DeviceStateUpdate.OPEN_CLOSE_ANGLE, 1));
698 this.updateInternalDeviceState(new DeviceStateUpdateImpl(DeviceStateUpdate.ON_OFF, -1));
700 this.updateInternalDeviceState(new DeviceStateUpdateImpl(DeviceStateUpdate.OPEN_CLOSE, -1));
702 this.updateInternalDeviceState(
703 new DeviceStateUpdateImpl(DeviceStateUpdate.OPEN_CLOSE_ANGLE, -1));
709 case AREA_1_INCREMENT:
710 case AREA_2_INCREMENT:
711 case AREA_3_INCREMENT:
712 case AREA_4_INCREMENT:
714 if (outputValue == maxOutputValue) {
717 this.updateInternalDeviceState(new DeviceStateUpdateImpl(DeviceStateUpdate.OUTPUT_INCREASE, 0));
720 if (slatPosition == maxSlatPosition) {
723 this.updateInternalDeviceState(new DeviceStateUpdateImpl(DeviceStateUpdate.SLAT_INCREASE, 0));
725 if (slatAngle == maxSlatAngle) {
728 updateInternalDeviceState(
729 new DeviceStateUpdateImpl(DeviceStateUpdate.SLAT_ANGLE_INCREASE, 0));
735 case AREA_1_DECREMENT:
736 case AREA_2_DECREMENT:
737 case AREA_3_DECREMENT:
738 case AREA_4_DECREMENT:
740 if (outputValue == minOutputValue) {
743 updateInternalDeviceState(new DeviceStateUpdateImpl(DeviceStateUpdate.OUTPUT_DECREASE, 0));
746 if (slatPosition == minSlatPosition) {
749 updateInternalDeviceState(new DeviceStateUpdateImpl(DeviceStateUpdate.SLAT_DECREASE, 0));
751 if (slatAngle == minSlatAngle) {
754 this.updateInternalDeviceState(
755 new DeviceStateUpdateImpl(DeviceStateUpdate.SLAT_ANGLE_INCREASE, 0));
766 this.deviceStateUpdates.add(new DeviceStateUpdateImpl(DeviceStateUpdate.UPDATE_OUTPUT_VALUE, 0));
768 // Area Stepping continue scenes
769 case AREA_STEPPING_CONTINUE:
778 private Integer[] getStandartSceneOutput(short sceneNumber) {
779 if (SceneEnum.getScene(sceneNumber) != null) {
780 switch (SceneEnum.getScene(sceneNumber)) {
784 return new Integer[] { (int) maxOutputValue, -1 };
787 return new Integer[] { (int) maxSlatPosition, (int) maxSlatAngle };
789 return new Integer[] { (int) maxSlatPosition, -1 };
797 return new Integer[] { (int) 0, -1 };
800 return new Integer[] { (int) 0, 0 };
802 return new Integer[] { (int) 0, -1 };
812 private void informLastSceneAboutSceneCall(short sceneNumber) {
813 if (this.activeScene != null && this.activeScene.getSceneID() != sceneNumber) {
814 this.activeScene.deactivateSceneByDevice();
815 this.lastScene = this.activeScene;
816 this.activeScene = null;
821 public synchronized void undoScene() {
822 this.deviceStateUpdates
823 .add(new DeviceStateUpdateImpl(DeviceStateUpdate.UPDATE_UNDO_SCENE, this.activeSceneNumber));
827 public synchronized void internalUndoScene() {
829 updateInternalDeviceState(
830 new DeviceStateUpdateImpl(DeviceStateUpdate.OUTPUT, this.outputValueBeforeSceneCall));
832 updateInternalDeviceState(
833 new DeviceStateUpdateImpl(DeviceStateUpdate.SLATPOSITION, this.outputValueBeforeSceneCall));
835 updateInternalDeviceState(
836 new DeviceStateUpdateImpl(DeviceStateUpdate.SLAT_ANGLE, this.slatAngleBeforeSceneCall));
840 if (activeSceneNumber != -1) {
841 activeSceneNumber = -1;
846 public InternalScene getAcitiveScene() {
847 return this.activeScene;
851 public Integer[] getSceneOutputValue(short sceneId) {
852 synchronized (sceneOutputMap) {
853 if (sceneOutputMap.containsKey(sceneId)) {
854 return sceneOutputMap.get(sceneId);
857 return new Integer[] { -1, -1 };
861 public void setSceneOutputValue(short sceneId, int value) {
862 internalSetSceneOutputValue(sceneId, value, -1);
863 if (listener != null) {
864 listener.onSceneConfigAdded(sceneId);
869 public void setSceneOutputValue(short sceneId, int value, int angle) {
870 internalSetSceneOutputValue(sceneId, value, angle);
871 if (listener != null) {
872 listener.onSceneConfigAdded(sceneId);
876 private void internalSetSceneOutputValue(short sceneId, int value, int angle) {
877 synchronized (sceneOutputMap) {
878 sceneOutputMap.put(sceneId, new Integer[] { value, angle });
880 if (activeSceneNumber == sceneId) {
881 internalCallScene(sceneId);
886 public List<Short> getSavedScenes() {
887 Set<Short> bothKeySet = new HashSet<>(sceneOutputMap.keySet());
888 bothKeySet.addAll(sceneConfigMap.keySet());
889 return new LinkedList<>(bothKeySet);
893 public void addSceneConfig(short sceneId, DeviceSceneSpec sceneSpec) {
894 if (sceneSpec != null) {
895 synchronized (sceneConfigMap) {
896 sceneConfigMap.put(sceneId, sceneSpec);
897 if (listener != null) {
898 listener.onSceneConfigAdded(sceneId);
905 public DeviceSceneSpec getSceneConfig(short sceneId) {
906 synchronized (sceneConfigMap) {
907 return sceneConfigMap.get(sceneId);
912 public boolean doIgnoreScene(short sceneId) {
913 synchronized (sceneConfigMap) {
914 if (this.sceneConfigMap.containsKey(sceneId)) {
915 return this.sceneConfigMap.get(sceneId).isDontCare();
922 public boolean containsSceneConfig(short sceneId) {
923 synchronized (sceneConfigMap) {
924 return sceneConfigMap.containsKey(sceneId);
931 public boolean equals(Object obj) {
932 if (obj instanceof Device) {
933 Device device = (Device) obj;
934 return device.getDSID().equals(this.getDSID());
940 public int hashCode() {
941 return this.getDSID().hashCode();
945 public boolean isPowerSensorUpToDate(SensorEnum powerSensorType) {
946 if (powerSensorType != null && SensorEnum.isPowerSensor(powerSensorType)) {
947 boolean isUpToDate = true;
948 if (powerSensorType.equals(SensorEnum.ACTIVE_POWER)) {
949 isUpToDate = (outputMode != null && outputMode.equals(OutputModeEnum.WIPE) && !isOn)
950 || (isOn && !isShade()) && !checkPowerSensorRefreshPriorityNever(powerSensorType)
951 ? checkSensorRefreshTime(powerSensorType)
954 if (powerSensorType.equals(SensorEnum.ELECTRIC_METER)) {
955 isUpToDate = (isOn || getDeviceSensorValue(powerSensorType).getDsValue() == 0) && !isShade()
956 && !checkPowerSensorRefreshPriorityNever(powerSensorType)
957 ? checkSensorRefreshTime(powerSensorType)
960 isUpToDate = isOn && !isShade() && !checkPowerSensorRefreshPriorityNever(powerSensorType)
961 ? checkSensorRefreshTime(powerSensorType)
964 if (!getSensorDataReadingInitialized(powerSensorType)) {
965 deviceStateUpdates.add(new DeviceStateUpdateImpl(powerSensorType, 0));
966 setSensorDataReadingInitialized(powerSensorType, true);
972 throw new IllegalArgumentException("powerSensorType is null or not a power sensor type.");
975 private boolean checkSensorRefreshTime(SensorEnum sensorType) {
976 if (sensorType != null) {
977 DeviceSensorValue devSenVal = getDeviceSensorValue(sensorType);
978 if (devSenVal.getValid()) {
979 int refresh = Config.DEFAULT_SENSORDATA_REFRESH_INTERVAL;
980 if (config != null) {
981 refresh = config.getSensordataRefreshInterval();
983 return (devSenVal.getTimestamp().getTime() + refresh) > System.currentTimeMillis();
990 public boolean isSensorDataUpToDate() {
991 boolean isUpToDate = true;
992 for (SensorEnum sensorType : devicePowerSensorTypes) {
993 isUpToDate = isPowerSensorUpToDate(sensorType);
999 public void setSensorDataRefreshPriority(String activePowerRefreshPriority, String electricMeterRefreshPriority,
1000 String outputCurrentRefreshPriority) {
1001 if (checkPriority(activePowerRefreshPriority)) {
1002 ((String[]) powerSensorRefresh[REFRESH_ACTIVE_POWER_ARRAY_FIELD])[REFRESH_PRIORITY_ARRAY_FIELD] = activePowerRefreshPriority;
1004 if (checkPriority(outputCurrentRefreshPriority)) {
1005 ((String[]) powerSensorRefresh[REFRESH_OUTPUT_CURRENT_ARRAY_FIELD])[REFRESH_PRIORITY_ARRAY_FIELD] = outputCurrentRefreshPriority;
1007 if (checkPriority(electricMeterRefreshPriority)) {
1008 ((String[]) powerSensorRefresh[REFRESH_ELECTRIC_METER_ARRAY_FIELD])[REFRESH_PRIORITY_ARRAY_FIELD] = electricMeterRefreshPriority;
1013 public void setSensorDataRefreshPriority(SensorEnum powerSensorType, String refreshPriority) {
1014 if (checkPriority(refreshPriority)) {
1015 String[] powerSensorRefresh = getPowerSensorRefresh(powerSensorType);
1016 if (powerSensorRefresh != null) {
1017 powerSensorRefresh[REFRESH_ACTIVE_POWER_ARRAY_FIELD] = refreshPriority;
1023 public String getPowerSensorRefreshPriority(SensorEnum powerSensorType) {
1024 if (powerSensorType.equals(SensorEnum.ACTIVE_POWER) && outputMode.equals(OutputModeEnum.WIPE) && !isOn) {
1025 return Config.REFRESH_PRIORITY_LOW;
1027 String[] powerSensorRefresh = getPowerSensorRefresh(powerSensorType);
1028 if (powerSensorRefresh != null) {
1029 return powerSensorRefresh[REFRESH_PRIORITY_ARRAY_FIELD];
1035 public boolean checkPowerSensorRefreshPriorityNever(SensorEnum powerSensorType) {
1036 if (getPowerSensorRefreshPriority(powerSensorType) != null) {
1037 return getPowerSensorRefreshPriority(powerSensorType).equals(Config.REFRESH_PRIORITY_NEVER);
1042 private void setAllSensorDataRefreshPrioritiesToNever() {
1043 for (short i = 0; i < powerSensorRefresh.length; i++) {
1044 ((String[]) powerSensorRefresh[i])[REFRESH_PRIORITY_ARRAY_FIELD] = Config.REFRESH_PRIORITY_NEVER;
1048 private void setSensorDataReadingInitialized(SensorEnum powerSensorType, Boolean flag) {
1049 String[] powerSensorRefresh = getPowerSensorRefresh(powerSensorType);
1050 if (powerSensorRefresh != null) {
1051 powerSensorRefresh[READING_INITIALIZED_ARRAY_FIELD] = flag.toString();
1055 private boolean getSensorDataReadingInitialized(SensorEnum powerSensorType) {
1056 String[] powerSensorRefresh = getPowerSensorRefresh(powerSensorType);
1057 if (powerSensorRefresh != null) {
1058 return Boolean.valueOf(powerSensorRefresh[READING_INITIALIZED_ARRAY_FIELD]);
1063 private String[] getPowerSensorRefresh(SensorEnum powerSensorType) {
1064 switch (powerSensorType) {
1066 return (String[]) powerSensorRefresh[REFRESH_ACTIVE_POWER_ARRAY_FIELD];
1067 case OUTPUT_CURRENT:
1068 return (String[]) powerSensorRefresh[REFRESH_OUTPUT_CURRENT_ARRAY_FIELD];
1069 case ELECTRIC_METER:
1070 return (String[]) powerSensorRefresh[REFRESH_ELECTRIC_METER_ARRAY_FIELD];
1071 case POWER_CONSUMPTION:
1072 return (String[]) powerSensorRefresh[REFRESH_POWER_CONSUMPTION_ARRAY_FIELD];
1078 private boolean checkPriority(String priority) {
1080 case Config.REFRESH_PRIORITY_HIGH:
1081 case Config.REFRESH_PRIORITY_MEDIUM:
1082 case Config.REFRESH_PRIORITY_LOW:
1083 case Config.REFRESH_PRIORITY_NEVER:
1086 logger.error("Sensor data update priority do not exist! Please check the input!");
1092 public boolean isDeviceUpToDate() {
1093 isSensorDataUpToDate();
1094 return this.deviceStateUpdates.isEmpty();
1098 public DeviceStateUpdate getNextDeviceUpdateState() {
1099 return !this.deviceStateUpdates.isEmpty() ? this.deviceStateUpdates.remove(0) : null;
1102 private int internalSetOutputValue(int value) {
1104 slatPosition = value;
1105 if (slatPosition <= 0) {
1111 return slatPosition;
1113 outputValue = (short) value;
1114 if (outputValue <= 0) {
1118 if (outputValue < switchPercentOff) {
1123 setCachedMeterData();
1127 setCachedMeterData();
1134 private void internalSetOff() {
1136 logger.debug("internal set OFF ");
1137 if (!checkPowerSensorRefreshPriorityNever(SensorEnum.ACTIVE_POWER)) {
1138 if (getSensorDataReadingInitialized(SensorEnum.ACTIVE_POWER)) {
1139 deviceStateUpdates.add(new DeviceStateUpdateImpl(SensorEnum.ACTIVE_POWER, -1));
1140 logger.debug("internal set sensor to 0");
1142 setDsSensorValue(SensorEnum.ACTIVE_POWER, 0);
1144 if (!checkPowerSensorRefreshPriorityNever(SensorEnum.OUTPUT_CURRENT)) {
1145 if (getSensorDataReadingInitialized(SensorEnum.OUTPUT_CURRENT)) {
1146 deviceStateUpdates.add(new DeviceStateUpdateImpl(SensorEnum.OUTPUT_CURRENT, -1));
1148 setDsSensorValue(SensorEnum.OUTPUT_CURRENT, 0);
1150 if (!checkPowerSensorRefreshPriorityNever(SensorEnum.POWER_CONSUMPTION)) {
1151 if (getSensorDataReadingInitialized(SensorEnum.POWER_CONSUMPTION)) {
1152 deviceStateUpdates.add(new DeviceStateUpdateImpl(SensorEnum.POWER_CONSUMPTION, -1));
1154 setDsSensorValue(SensorEnum.POWER_CONSUMPTION, 0);
1158 private short internalSetAngleValue(int value) {
1162 if (value > maxSlatAngle) {
1163 slatAngle = maxSlatAngle;
1165 slatAngle = (short) value;
1172 public List<SensorEnum> getSensorTypes() {
1173 List<SensorEnum> list = new ArrayList<>(devicePowerSensorTypes);
1174 list.addAll(deviceClimateSensorTypes);
1179 public List<SensorEnum> getPowerSensorTypes() {
1180 return devicePowerSensorTypes;
1184 public List<SensorEnum> getClimateSensorTypes() {
1185 return deviceClimateSensorTypes;
1189 public List<DeviceSensorValue> getDeviceSensorValues() {
1190 return deviceSensorValues;
1194 public boolean supportsSensorType(SensorEnum sensorType) {
1195 if (sensorType != null) {
1196 return getSensorTypes().contains(sensorType);
1202 public void setDeviceSensorValue(DeviceSensorValue deviceSensorValue) {
1203 if (deviceSensorValue != null) {
1204 int index = deviceSensorValues.indexOf(deviceSensorValue);
1206 deviceSensorValues.add(deviceSensorValue);
1207 if (SensorEnum.isPowerSensor(deviceSensorValue.getSensorType())) {
1208 devicePowerSensorTypes.add(deviceSensorValue.getSensorType());
1210 deviceClimateSensorTypes.add(deviceSensorValue.getSensorType());
1213 if (deviceSensorValue.getTimestamp().after(deviceSensorValues.get(index).getTimestamp())) {
1214 logger.debug("set deviceSeneorValue, new deviceSensorValue is: {}", deviceSensorValue.toString());
1215 deviceSensorValues.set(index, deviceSensorValue);
1216 checkSensorValueSet(deviceSensorValue, true);
1223 public void setDeviceSensorByEvent(EventItem event) {
1224 DeviceSensorValue devSenVal = new DeviceSensorValue(event.getProperties());
1225 SensorEnum sensorType = devSenVal.getSensorType();
1226 if (!isEchoSensor(sensorType)) {
1227 logger.debug("Event is no echo, set values {} for sensorType {}", devSenVal, devSenVal.getSensorType());
1228 if (SensorEnum.isPowerSensor(sensorType) && getSensorDataReadingInitialized(sensorType)) {
1229 logger.debug("SensorJob was initialized, remove sensorjob for sensorType: {}",
1230 devSenVal.getSensorType());
1231 deviceStateUpdates.add(new DeviceStateUpdateImpl(sensorType, -1));
1233 setDeviceSensorValue(devSenVal);
1235 logger.debug("Event is echo remove sensorType {} from echoBox", devSenVal.getSensorType());
1236 sensorEchoBox.remove(devSenVal.getSensorType());
1240 private boolean isEchoSensor(SensorEnum sensorType) {
1241 return sensorEchoBox != null ? sensorEchoBox.contains(sensorType) : false;
1244 private List<SensorEnum> sensorEchoBox = Collections.synchronizedList(new LinkedList<>());
1247 public void setDeviceSensorDsValueBySensorJob(SensorEnum sensorType, Integer value) {
1248 logger.debug("sensorJob for device {} is executet", dsid.getValue());
1249 if (isSensorEchoBoxEnabled()) {
1250 // temperature resolution is not correct, so waiting for device sensor-event
1251 if (!sensorType.toString().contains("TEMPERATURE")) {
1252 logger.debug("echoBox is enabled, add sensorType {} to echoBox", sensorType);
1253 sensorEchoBox.add(sensorType);
1255 logger.debug("echoBox is enabled, ignoring temperation update and wait for sensor Event");
1259 setDsSensorValue(sensorType, value);
1263 public void enableSensorEchoBox() {
1264 if (sensorEchoBox == null) {
1265 sensorEchoBox = Collections.synchronizedList(new LinkedList<>());
1270 public void disableSensorEchoBox() {
1271 sensorEchoBox = null;
1275 public boolean isSensorEchoBoxEnabled() {
1276 return sensorEchoBox != null;
1280 public DeviceSensorValue getDeviceSensorValue(SensorEnum sensorType) {
1281 if (sensorType != null) {
1282 for (DeviceSensorValue devSenVal : deviceSensorValues) {
1283 if (devSenVal.getSensorType().equals(sensorType)) {
1292 public DeviceSensorValue getDeviceSensorValue(Short sensorIndex) {
1293 if (sensorIndex != null) {
1294 for (DeviceSensorValue devSenVal : deviceSensorValues) {
1295 if (devSenVal.getSensorIndex().equals(sensorIndex)) {
1304 public Short getSensorIndex(SensorEnum sensorType) {
1305 if (sensorType != null) {
1306 DeviceSensorValue devSenVal = getDeviceSensorValue(sensorType);
1307 return devSenVal != null ? devSenVal.getSensorIndex() : null;
1313 public SensorEnum getSensorType(Short sensorIndex) {
1314 if (sensorIndex != null) {
1315 DeviceSensorValue devSenVal = getDeviceSensorValue(sensorIndex);
1316 return devSenVal != null ? devSenVal.getSensorType() : null;
1322 public Integer getDsSensorValue(SensorEnum sensorType) {
1323 return getDsSensorValue((Object) sensorType);
1327 public Integer getDsSensorValue(Short sensorIndex) {
1328 return getDsSensorValue((Object) sensorIndex);
1332 public Float getFloatSensorValue(Short sensorIndex) {
1333 return getFloatSensorValue((Object) sensorIndex);
1337 public Float getFloatSensorValue(SensorEnum sensorType) {
1338 return getFloatSensorValue((Object) sensorType);
1342 public boolean setFloatSensorValue(SensorEnum sensorType, Float floatSensorValue) {
1343 return checkAndSetSensorValue(sensorType, null, floatSensorValue);
1347 public boolean setFloatSensorValue(Short sensorIndex, Float floatSensorValue) {
1348 return checkAndSetSensorValue(sensorIndex, null, floatSensorValue);
1352 public boolean setDsSensorValue(Short sensorIndex, Integer dSSensorValue) {
1353 return checkAndSetSensorValue(sensorIndex, dSSensorValue, null);
1357 public boolean setDsSensorValue(SensorEnum sensorType, Integer dSSensorValue) {
1358 return checkAndSetSensorValue(sensorType, dSSensorValue, null);
1362 public boolean setDsSensorValue(Short sensorIndex, Integer dSSensorValue, Float floatSensorValue) {
1363 return checkAndSetSensorValue(sensorIndex, dSSensorValue, floatSensorValue);
1367 public boolean setDsSensorValue(SensorEnum sensorType, Integer dSSensorValue, Float floatSensorValue) {
1368 return checkAndSetSensorValue(sensorType, dSSensorValue, floatSensorValue);
1372 public boolean hasSensors() {
1373 return hasClimateSensors() || hasPowerSensors();
1377 public boolean hasClimateSensors() {
1378 return !deviceClimateSensorTypes.isEmpty();
1382 public boolean hasPowerSensors() {
1383 return !devicePowerSensorTypes.isEmpty();
1386 // Sensor get/set helper methods
1387 private DeviceSensorValue getDeviceSensorValueForGet(Object obj) {
1388 return checkHighOutputCurrent(getDeviceSensorValueForSet(obj));
1391 private DeviceSensorValue getDeviceSensorValueForSet(Object obj) {
1392 if (obj instanceof Short) {
1393 return getDeviceSensorValue((Short) obj);
1395 return getDeviceSensorValue((SensorEnum) obj);
1399 private Integer getDsSensorValue(Object obj) {
1401 DeviceSensorValue devSenVal = checkPowerSensor(getDeviceSensorValueForGet(obj));
1402 return devSenVal != null && devSenVal.getValid() ? devSenVal.getDsValue() : null;
1407 private Float getFloatSensorValue(Object obj) {
1409 DeviceSensorValue devSenVal = checkPowerSensor(getDeviceSensorValueForGet(obj));
1410 return devSenVal != null && devSenVal.getValid() ? devSenVal.getFloatValue() : null;
1415 private DeviceSensorValue checkPowerSensor(DeviceSensorValue devSenVal) {
1416 if (devSenVal != null && SensorEnum.isPowerSensor(devSenVal.getSensorType())) {
1417 if (!devSenVal.getSensorType().equals(SensorEnum.ELECTRIC_METER)
1418 && !(SensorEnum.isPowerSensor(devSenVal.getSensorType()) && isOn)) {
1419 devSenVal.setDsValue(0);
1426 * Checks output current sensor to return automatically high output current sensor, if the sensor exists.
1429 * @return output current high DeviceSensorValue or the given DeviceSensorValue
1431 private DeviceSensorValue checkHighOutputCurrent(DeviceSensorValue devSenVal) {
1432 if (devSenVal != null && devSenVal.getSensorType().equals(SensorEnum.OUTPUT_CURRENT)
1433 && devSenVal.getDsValue() == SensorEnum.OUTPUT_CURRENT.getMax().intValue()
1434 && devicePowerSensorTypes.contains(SensorEnum.OUTPUT_CURRENT_H)) {
1435 return getDeviceSensorValue(SensorEnum.OUTPUT_CURRENT_H);
1440 private boolean checkAndSetSensorValue(Object obj, Integer dsValue, Float floatValue) {
1441 boolean isSet = false;
1443 DeviceSensorValue devSenVal = getDeviceSensorValueForSet(obj);
1444 if (devSenVal != null) {
1445 if (dsValue != null && floatValue != null) {
1446 isSet = devSenVal.setValues(floatValue, dsValue);
1447 } else if (dsValue != null) {
1448 isSet = devSenVal.setDsValue(dsValue);
1449 } else if (floatValue != null) {
1450 isSet = devSenVal.setFloatValue(floatValue);
1452 logger.debug("check devSenVal {} isSet={}", devSenVal.toString(), isSet);
1453 checkSensorValueSet(devSenVal, isSet);
1459 private void checkSensorValueSet(DeviceSensorValue devSenVal, boolean isSet) {
1460 if (devSenVal != null) {
1462 if (outputMode.equals(OutputModeEnum.WIPE) && !isOn
1463 && devSenVal.getSensorType().equals(SensorEnum.ACTIVE_POWER)) {
1464 int standby = Config.DEFAULT_STANDBY_ACTIVE_POWER;
1465 if (config != null) {
1466 standby = config.getStandbyActivePower();
1468 if (devSenVal.getDsValue() > standby) {
1469 this.updateInternalDeviceState(new DeviceStateUpdateImpl(DeviceStateUpdate.ON_OFF, 1));
1472 if (SensorEnum.isPowerSensor(devSenVal.getSensorType())) {
1473 addPowerSensorCache(devSenVal);
1475 informListenerAboutStateUpdate(
1476 new DeviceStateUpdateImpl(devSenVal.getSensorType(), devSenVal.getFloatValue()));
1478 setSensorDataReadingInitialized(devSenVal.getSensorType(), false);
1482 private void addPowerSensorCache(DeviceSensorValue newDevSenVal) {
1483 Integer[] cachedPowerValues = cachedSensorPowerValues.get(outputValue);
1484 if (cachedPowerValues == null) {
1485 cachedPowerValues = new Integer[4];
1487 switch (newDevSenVal.getSensorType()) {
1489 cachedPowerValues[ACTIVE_POWER_ARRAY_FIELD] = newDevSenVal.getDsValue();
1491 case OUTPUT_CURRENT:
1492 cachedPowerValues[OUTPUT_CURRENT_ARRAY_FIELD] = newDevSenVal.getDsValue();
1494 case OUTPUT_CURRENT_H:
1495 cachedPowerValues[OUTPUT_CURRENT_HIGH_ARRAY_FIELD] = newDevSenVal.getDsValue();
1497 case POWER_CONSUMPTION:
1498 cachedPowerValues[POWER_CONSUMPTION_ARRAY_FIELD] = newDevSenVal.getDsValue();
1503 this.cachedSensorPowerValues.put(outputValue, cachedPowerValues);
1507 public synchronized void updateInternalDeviceState(DeviceStateUpdate deviceStateUpdate) {
1508 DeviceStateUpdate deviceStateUpdateInt = internalSetOutputValue(deviceStateUpdate);
1509 if (deviceStateUpdateInt != null) {
1510 validateActiveScene();
1511 informListenerAboutStateUpdate(deviceStateUpdate);
1515 private DeviceStateUpdate internalSetOutputValue(DeviceStateUpdate deviceStateUpdate) {
1516 if (deviceStateUpdate == null) {
1519 logger.debug("internal set outputvalue");
1520 switch (deviceStateUpdate.getType()) {
1521 case DeviceStateUpdate.OUTPUT_DECREASE:
1522 return new DeviceStateUpdateImpl(DeviceStateUpdate.OUTPUT_DECREASE,
1523 internalSetOutputValue(outputValue - getDimmStep()));
1524 case DeviceStateUpdate.OUTPUT_INCREASE:
1525 return new DeviceStateUpdateImpl(DeviceStateUpdate.OUTPUT_INCREASE,
1526 internalSetOutputValue(outputValue + getDimmStep()));
1527 case DeviceStateUpdate.OUTPUT:
1528 internalSetOutputValue(deviceStateUpdate.getValueAsInteger());
1530 case DeviceStateUpdate.ON_OFF:
1531 if (deviceStateUpdate.getValueAsInteger() < 0) {
1532 internalSetOutputValue(0);
1534 internalSetOutputValue(maxOutputValue);
1537 case DeviceStateUpdate.OPEN_CLOSE:
1538 if (deviceStateUpdate.getValueAsInteger() < 0) {
1539 internalSetOutputValue(0);
1541 internalSetOutputValue(maxSlatPosition);
1544 case DeviceStateUpdate.OPEN_CLOSE_ANGLE:
1545 if (deviceStateUpdate.getValueAsInteger() < 0) {
1546 internalSetAngleValue(0);
1548 internalSetAngleValue(maxSlatAngle);
1551 case DeviceStateUpdate.SLAT_DECREASE:
1552 return new DeviceStateUpdateImpl(DeviceStateUpdate.SLAT_DECREASE,
1553 internalSetOutputValue(slatPosition - getDimmStep()));
1554 case DeviceStateUpdate.SLAT_INCREASE:
1555 return new DeviceStateUpdateImpl(DeviceStateUpdate.SLAT_INCREASE,
1556 internalSetOutputValue(slatPosition + getDimmStep()));
1557 case DeviceStateUpdate.SLATPOSITION:
1558 internalSetOutputValue(deviceStateUpdate.getValueAsInteger());
1560 case DeviceStateUpdate.SLAT_ANGLE_DECREASE:
1561 return new DeviceStateUpdateImpl(DeviceStateUpdate.SLAT_ANGLE_DECREASE,
1562 internalSetAngleValue(slatAngle - DeviceConstants.ANGLE_STEP_SLAT));
1563 case DeviceStateUpdate.SLAT_ANGLE_INCREASE:
1564 return new DeviceStateUpdateImpl(DeviceStateUpdate.SLAT_ANGLE_INCREASE,
1565 internalSetAngleValue(slatAngle + DeviceConstants.ANGLE_STEP_SLAT));
1566 case DeviceStateUpdate.SLAT_ANGLE:
1567 internalSetAngleValue(deviceStateUpdate.getValueAsInteger());
1569 case DeviceStateUpdate.UPDATE_CALL_SCENE:
1570 this.internalCallScene(deviceStateUpdate.getValueAsShort());
1572 case DeviceStateUpdate.UPDATE_UNDO_SCENE:
1573 this.internalUndoScene();
1576 if (deviceStateUpdate.isSensorUpdateType()) {
1577 SensorEnum sensorType = deviceStateUpdate.getTypeAsSensorEnum();
1578 setFloatSensorValue(sensorType, deviceStateUpdate.getValueAsFloat());
1582 return deviceStateUpdate;
1585 private void validateActiveScene() {
1586 if (activeScene == null) {
1589 Integer[] sceneOutput = getStandartSceneOutput(activeScene.getSceneID());
1590 if (sceneOutput == null) {
1591 sceneOutput = sceneOutputMap.get(activeScene.getSceneID());
1593 if (sceneOutput != null) {
1594 boolean outputChanged = false;
1596 if (isBlind() && sceneOutput[1] != slatAngle) {
1597 logger.debug("Scene output angle: {} setted output value {}", sceneOutput[1], slatAngle);
1598 outputChanged = true;
1600 if (sceneOutput[0] != slatPosition) {
1601 logger.debug("Scene output value: {} setted output value {}", sceneOutput[0], slatPosition);
1602 outputChanged = true;
1605 if (sceneOutput[0] != outputValue) {
1606 logger.debug("Scene output value: {} setted output value {}", sceneOutput[0], outputValue);
1607 outputChanged = true;
1610 if (outputChanged) {
1611 logger.debug("Device output from Device with dSID {} changed deactivate scene {}", dsid.getValue(),
1612 activeScene.getID());
1613 activeScene.deviceSceneChanged((short) -1);
1623 public DeviceStatusListener unregisterDeviceStatusListener() {
1624 setAllSensorDataRefreshPrioritiesToNever();
1625 return super.unregisterDeviceStatusListener();
1628 private void setCachedMeterData() {
1629 logger.debug("load cached sensor data device with dsid {}", dsid.getValue());
1630 Integer[] cachedSensorData = this.cachedSensorPowerValues.get(this.getOutputValue());
1631 if (cachedSensorData != null) {
1632 if (cachedSensorData[ACTIVE_POWER_ARRAY_FIELD] != null
1633 && !checkPowerSensorRefreshPriorityNever(SensorEnum.ACTIVE_POWER)) {
1634 informListenerAboutStateUpdate(new DeviceStateUpdateImpl(SensorEnum.ACTIVE_POWER,
1635 (float) cachedSensorData[ACTIVE_POWER_ARRAY_FIELD]));
1638 if (cachedSensorData[OUTPUT_CURRENT_ARRAY_FIELD] != null
1639 && !checkPowerSensorRefreshPriorityNever(SensorEnum.OUTPUT_CURRENT)) {
1640 if (cachedSensorData[OUTPUT_CURRENT_ARRAY_FIELD] == SensorEnum.OUTPUT_CURRENT.getMax().intValue()
1641 && devicePowerSensorTypes.contains(SensorEnum.OUTPUT_CURRENT_H)) {
1642 informListenerAboutStateUpdate(new DeviceStateUpdateImpl(SensorEnum.OUTPUT_CURRENT,
1643 cachedSensorData[OUTPUT_CURRENT_HIGH_ARRAY_FIELD]));
1645 informListenerAboutStateUpdate(new DeviceStateUpdateImpl(SensorEnum.OUTPUT_CURRENT,
1646 cachedSensorData[OUTPUT_CURRENT_ARRAY_FIELD]));
1649 if (cachedSensorData[ACTIVE_POWER_ARRAY_FIELD] != null
1650 && !checkPowerSensorRefreshPriorityNever(SensorEnum.POWER_CONSUMPTION)) {
1651 informListenerAboutStateUpdate(
1652 new DeviceStateUpdateImpl(SensorEnum.ACTIVE_POWER, cachedSensorData[ACTIVE_POWER_ARRAY_FIELD]));
1658 * if an {@link DeviceStatusListener} is registered inform him about the new state otherwise do nothing.
1660 * @param deviceStateUpdate
1662 private void informListenerAboutStateUpdate(DeviceStateUpdate deviceStateUpdate) {
1663 if (listener != null) {
1664 listener.onDeviceStateChanged(correctDeviceStatusUpdate(deviceStateUpdate));
1668 private DeviceStateUpdate correctDeviceStatusUpdate(DeviceStateUpdate deviceStateUpdate) {
1669 if (isSwitch() && deviceStateUpdate.getType().equals(DeviceStateUpdate.OUTPUT)) {
1670 if (deviceStateUpdate.getValueAsInteger() >= switchPercentOff) {
1671 return new DeviceStateUpdateImpl(DeviceStateUpdate.ON_OFF, DeviceStateUpdate.ON_VALUE);
1673 return new DeviceStateUpdateImpl(DeviceStateUpdate.ON_OFF, DeviceStateUpdate.OFF_VALUE);
1676 return deviceStateUpdate;
1679 private void informListenerAboutConfigChange(ChangeableDeviceConfigEnum changedConfig) {
1680 if (listener != null) {
1681 listener.onDeviceConfigChanged(changedConfig);
1682 logger.debug("Inform listener about device config {} changed", changedConfig.toString());
1686 @SuppressWarnings("null")
1688 public void saveConfigSceneSpecificationIntoDevice(Map<String, String> propertries) {
1689 if (propertries != null) {
1691 for (String key : propertries.keySet()) {
1692 if (key.startsWith(DigitalSTROMBindingConstants.DEVICE_SCENE)) {
1694 short sceneID = Short.parseShort((String) key
1695 .subSequence(DigitalSTROMBindingConstants.DEVICE_SCENE.length(), key.length()));
1696 sceneSave = propertries.get(key);
1697 if (sceneSave != null && !sceneSave.isBlank()) {
1698 logger.debug("Find saved scene configuration for device with dSID {} and sceneID {}", dsid,
1700 String[] sceneParm = sceneSave.replace(" ", "").split(",");
1701 JSONDeviceSceneSpecImpl sceneSpecNew = null;
1702 int sceneValue = -1;
1703 int sceneAngle = -1;
1704 for (int j = 0; j < sceneParm.length; j++) {
1705 String[] sceneParmSplit = sceneParm[j].split(":");
1706 switch (sceneParmSplit[0]) {
1708 sceneSpecNew = new JSONDeviceSceneSpecImpl(sceneParmSplit[1]);
1711 sceneSpecNew.setDontcare(Boolean.parseBoolean(sceneParmSplit[1]));
1714 sceneSpecNew.setLocalPrio(Boolean.parseBoolean(sceneParmSplit[1]));
1717 sceneSpecNew.setSpecialMode(Boolean.parseBoolean(sceneParmSplit[1]));
1720 sceneValue = Integer.parseInt(sceneParmSplit[1]);
1723 sceneAngle = Integer.parseInt(sceneParmSplit[1]);
1727 if (sceneValue > -1) {
1729 "Saved sceneValue {}, sceneAngle {} for scene id {} into device with dsid {}",
1730 sceneValue, sceneAngle, sceneID, getDSID().getValue());
1731 internalSetSceneOutputValue(sceneID, sceneValue, sceneAngle);
1732 deviceStateUpdates.add(new DeviceStateUpdateImpl(DeviceStateUpdate.UPDATE_SCENE_OUTPUT,
1733 new Short[] { sceneID, (short) -1 }));
1735 if (sceneSpecNew != null) {
1736 logger.debug("Saved sceneConfig: [{}] for scene id {} into device with dsid {}",
1737 sceneSpecNew.toString(), sceneID, getDSID().getValue());
1738 synchronized (sceneConfigMap) {
1739 sceneConfigMap.put(sceneID, sceneSpecNew);
1741 deviceStateUpdates.add(new DeviceStateUpdateImpl(DeviceStateUpdate.UPDATE_SCENE_CONFIG,
1742 new Short[] { sceneID, (short) -1 }));
1745 } catch (NumberFormatException e) {
1753 @SuppressWarnings("null")
1755 public void saveConfigSceneSpecificationIntoDevice(String propertries) {
1756 String[] scenes = propertries.split("\n");
1757 for (int i = 0; i < scenes.length; i++) {
1758 logger.debug("Find saved scene configuration for device with dSID {} and sceneID {}", dsid, i);
1759 String[] sceneIdToConfig = scenes[i].replaceAll(" ", "").split("=");
1760 String[] sceneParm = sceneIdToConfig[1].split(",");
1761 JSONDeviceSceneSpecImpl sceneSpecNew = null;
1762 int sceneValue = -1;
1763 int sceneAngle = -1;
1764 for (int j = 0; j < sceneParm.length; j++) {
1765 String[] sceneParmSplit = sceneParm[j].split(":");
1766 switch (sceneParmSplit[0]) {
1768 sceneSpecNew = new JSONDeviceSceneSpecImpl(sceneParmSplit[1]);
1771 sceneSpecNew.setDontcare(Boolean.parseBoolean(sceneParmSplit[1]));
1774 sceneSpecNew.setLocalPrio(Boolean.parseBoolean(sceneParmSplit[1]));
1777 sceneSpecNew.setSpecialMode(Boolean.parseBoolean(sceneParmSplit[1]));
1780 sceneValue = Integer.parseInt(sceneParmSplit[1]);
1783 sceneAngle = Integer.parseInt(sceneParmSplit[1]);
1787 if (sceneValue > -1) {
1788 logger.debug("Saved sceneValue {}, sceneAngle {} for scene id {} into device with dsid {}", sceneValue,
1789 sceneAngle, i, getDSID().getValue());
1790 synchronized (sceneOutputMap) {
1791 sceneOutputMap.put(sceneSpecNew.getScene().getSceneNumber(),
1792 new Integer[] { sceneValue, sceneAngle });
1795 if (sceneSpecNew != null) {
1796 logger.debug("Saved sceneConfig: [{}] for scene id {} into device with dsid {}",
1797 sceneSpecNew.toString(), i, getDSID().getValue());
1798 synchronized (sceneConfigMap) {
1799 sceneConfigMap.put(sceneSpecNew.getScene().getSceneNumber(), sceneSpecNew);
1806 public void setConfig(Config config) {
1807 this.config = config;
1810 private String powerSensorRefreshToString() {
1811 String powSenRef = "";
1812 for (int i = 0; i < powerSensorRefresh.length; i++) {
1813 powSenRef = powSenRef + " [" + i + "]=Prio: "
1814 + ((String[]) powerSensorRefresh[i])[REFRESH_PRIORITY_ARRAY_FIELD] + ", Initialized: "
1815 + ((String[]) powerSensorRefresh[i])[READING_INITIALIZED_ARRAY_FIELD] + " ";
1821 public boolean isBinaryInputDevice() {
1822 return !deviceBinaryInputs.isEmpty();
1826 public List<DeviceBinaryInput> getBinaryInputs() {
1827 return deviceBinaryInputs;
1831 public DeviceBinaryInput getBinaryInput(DeviceBinarayInputEnum binaryInputType) {
1832 if (binaryInputType != null) {
1833 for (DeviceBinaryInput binInput : deviceBinaryInputs) {
1834 if (binaryInputType.getBinaryInputType().equals(binInput.getInputType())) {
1843 public Short getBinaryInputState(DeviceBinarayInputEnum binaryInputType) {
1844 DeviceBinaryInput devBinInput = getBinaryInput(binaryInputType);
1845 if (devBinInput != null) {
1846 return devBinInput.getState();
1852 public boolean setBinaryInputState(DeviceBinarayInputEnum binaryInputType, Short newState) {
1853 DeviceBinaryInput devBinInput = getBinaryInput(binaryInputType);
1854 if (devBinInput != null) {
1855 devBinInput.setState(newState);
1856 informListenerAboutStateUpdate(new DeviceStateUpdateImpl(binaryInputType, newState));
1863 public void setBinaryInputs(List<DeviceBinaryInput> newBinaryInputs) {
1864 this.deviceBinaryInputs.clear();
1865 this.deviceBinaryInputs.addAll(newBinaryInputs);
1866 informListenerAboutConfigChange(ChangeableDeviceConfigEnum.BINARY_INPUTS);
1870 public String toString() {
1871 return "DeviceImpl [meterDSID=" + meterDSID + ", zoneId=" + zoneId + ", groupList=" + groupList
1872 + ", functionalGroup=" + functionalGroup + ", functionalName=" + functionalName + ", hwInfo=" + hwInfo
1873 + ", getName()=" + getName() + ", getDSID()=" + getDSID() + ", getDSUID()=" + getDSUID()
1874 + ", isPresent()=" + isPresent() + ", isValide()=" + isValid() + ", getDisplayID()=" + getDisplayID()
1875 + ", outputMode=" + outputMode + ", getSensorTypes()=" + getSensorTypes() + ", getDeviceSensorValues()="
1876 + getDeviceSensorValues() + ", powerSensorRefresh=" + powerSensorRefreshToString() + "]";