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.apache.commons.lang.StringUtils;
26 import org.openhab.binding.digitalstrom.internal.DigitalSTROMBindingConstants;
27 import org.openhab.binding.digitalstrom.internal.lib.GeneralLibConstance;
28 import org.openhab.binding.digitalstrom.internal.lib.config.Config;
29 import org.openhab.binding.digitalstrom.internal.lib.event.types.EventItem;
30 import org.openhab.binding.digitalstrom.internal.lib.listener.DeviceStatusListener;
31 import org.openhab.binding.digitalstrom.internal.lib.serverconnection.constants.JSONApiResponseKeysEnum;
32 import org.openhab.binding.digitalstrom.internal.lib.structure.devices.AbstractGeneralDeviceInformations;
33 import org.openhab.binding.digitalstrom.internal.lib.structure.devices.Device;
34 import org.openhab.binding.digitalstrom.internal.lib.structure.devices.deviceparameters.DeviceConstants;
35 import org.openhab.binding.digitalstrom.internal.lib.structure.devices.deviceparameters.DeviceSceneSpec;
36 import org.openhab.binding.digitalstrom.internal.lib.structure.devices.deviceparameters.DeviceStateUpdate;
37 import org.openhab.binding.digitalstrom.internal.lib.structure.devices.deviceparameters.constants.ChangeableDeviceConfigEnum;
38 import org.openhab.binding.digitalstrom.internal.lib.structure.devices.deviceparameters.constants.DeviceBinarayInputEnum;
39 import org.openhab.binding.digitalstrom.internal.lib.structure.devices.deviceparameters.constants.FuncNameAndColorGroupEnum;
40 import org.openhab.binding.digitalstrom.internal.lib.structure.devices.deviceparameters.constants.FunctionalColorGroupEnum;
41 import org.openhab.binding.digitalstrom.internal.lib.structure.devices.deviceparameters.constants.OutputModeEnum;
42 import org.openhab.binding.digitalstrom.internal.lib.structure.devices.deviceparameters.constants.SensorEnum;
43 import org.openhab.binding.digitalstrom.internal.lib.structure.devices.deviceparameters.impl.DSID;
44 import org.openhab.binding.digitalstrom.internal.lib.structure.devices.deviceparameters.impl.DeviceBinaryInput;
45 import org.openhab.binding.digitalstrom.internal.lib.structure.devices.deviceparameters.impl.DeviceSensorValue;
46 import org.openhab.binding.digitalstrom.internal.lib.structure.devices.deviceparameters.impl.DeviceStateUpdateImpl;
47 import org.openhab.binding.digitalstrom.internal.lib.structure.devices.deviceparameters.impl.JSONDeviceSceneSpecImpl;
48 import org.openhab.binding.digitalstrom.internal.lib.structure.scene.InternalScene;
49 import org.openhab.binding.digitalstrom.internal.lib.structure.scene.constants.SceneEnum;
50 import org.slf4j.Logger;
51 import org.slf4j.LoggerFactory;
53 import com.google.gson.JsonArray;
54 import com.google.gson.JsonElement;
55 import com.google.gson.JsonObject;
58 * The {@link DeviceImpl} is the implementation of the {@link Device}.
60 * @author Michael Ochel - Initial contribution
61 * @author Matthias Siegele - Initial contribution
63 public class DeviceImpl extends AbstractGeneralDeviceInformations implements Device {
65 private final Logger logger = LoggerFactory.getLogger(DeviceImpl.class);
67 private Config config;
69 private DSID meterDSID;
70 private int zoneId = 0;
71 private List<Short> groupList = new LinkedList<>();
73 private FunctionalColorGroupEnum functionalGroup;
74 private FuncNameAndColorGroupEnum functionalName;
75 private String hwInfo;
77 private OutputModeEnum outputMode;
79 private boolean isOn = false;
80 private boolean isOpen = true;
81 private short outputValue = 0;
82 private short maxOutputValue = DeviceConstants.DEFAULT_MAX_OUTPUTVALUE;
83 private short minOutputValue = 0;
85 private short slatAngle = 0;
86 private final short maxSlatAngle = DeviceConstants.MAX_SLAT_ANGLE;
87 private final short minSlatAngle = DeviceConstants.MIN_SLAT_ANGLE;
89 private int slatPosition = 0;
90 private final int maxSlatPosition = DeviceConstants.MAX_ROLLERSHUTTER;
91 private final int minSlatPosition = DeviceConstants.MIN_ROLLERSHUTTER;
93 private final List<DeviceSensorValue> deviceSensorValues = Collections.synchronizedList(new ArrayList<>());
94 private final List<DeviceBinaryInput> deviceBinaryInputs = Collections.synchronizedList(new ArrayList<>());
95 private final List<SensorEnum> devicePowerSensorTypes = new ArrayList<>();
96 private final List<SensorEnum> deviceClimateSensorTypes = new ArrayList<>();
99 private short activeSceneNumber = -1;
100 private InternalScene activeScene;
101 private InternalScene lastScene;
102 private int outputValueBeforeSceneCall = 0;
103 private short slatAngleBeforeSceneCall = 0;
104 private boolean lastCallWasUndo = false;
106 private final Map<Short, DeviceSceneSpec> sceneConfigMap = Collections.synchronizedMap(new HashMap<>());
107 private final Map<Short, Integer[]> sceneOutputMap = Collections.synchronizedMap(new HashMap<>());
109 // saves outstanding commands
110 private final List<DeviceStateUpdate> deviceStateUpdates = Collections.synchronizedList(new LinkedList<>());
113 * Saves the refresh priorities and reading initialized flag of power sensors as an matrix.
114 * The first array fields are 0 = active power, 1 = output current, 2 = electric meter, 3 = power consumption and in
116 * string array with the fields 0 = refresh priority 1 = reading initial flag (true = reading is initialized,
119 private final Object[] powerSensorRefresh = new Object[] { new String[] { Config.REFRESH_PRIORITY_NEVER, "false" },
120 new String[] { Config.REFRESH_PRIORITY_NEVER, "false" },
121 new String[] { Config.REFRESH_PRIORITY_NEVER, "false" },
122 new String[] { Config.REFRESH_PRIORITY_NEVER, "false" } };
124 public static final int REFRESH_PRIORITY_ARRAY_FIELD = 0;
125 public static final int READING_INITIALIZED_ARRAY_FIELD = 1;
127 public static final int REFRESH_ACTIVE_POWER_ARRAY_FIELD = 0;
128 public static final int REFRESH_OUTPUT_CURRENT_ARRAY_FIELD = 1;
129 public static final int REFRESH_ELECTRIC_METER_ARRAY_FIELD = 2;
130 public static final int REFRESH_POWER_CONSUMPTION_ARRAY_FIELD = 3;
132 * Cache the last power sensor value to get power sensor value directly
133 * the key is the output value and the value is an Integer array for the sensor values (0 = active power, 1 =
134 * output current, 2 = power consumption, 3 = output current high)
136 private final Map<Short, Integer[]> cachedSensorPowerValues = Collections.synchronizedMap(new HashMap<>());
138 public static final int ACTIVE_POWER_ARRAY_FIELD = 0;
139 public static final int OUTPUT_CURRENT_ARRAY_FIELD = 1;
140 public static final int POWER_CONSUMPTION_ARRAY_FIELD = 2;
141 public static final int OUTPUT_CURRENT_HIGH_ARRAY_FIELD = 3;
143 // Preparing for the advance device property setting "Turn 'switched' output off if value below:", but the
144 // configuration currently not work in digitalSTROM, because of that the value is fix 1.
145 private final int switchPercentOff = 1;
148 * Creates a new {@link DeviceImpl} from the given DigitalSTROM-Device {@link JsonObject}.
150 * @param deviceJsonObject json response of the digitalSTROM-Server, must not be null
152 public DeviceImpl(JsonObject deviceJsonObject) {
153 super(deviceJsonObject);
154 if (deviceJsonObject.get(JSONApiResponseKeysEnum.METER_DSID.getKey()) != null) {
155 this.meterDSID = new DSID(deviceJsonObject.get(JSONApiResponseKeysEnum.METER_DSID.getKey()).getAsString());
156 } else if (deviceJsonObject.get(JSONApiResponseKeysEnum.DS_METER_DSID.getKey()) != null) {
157 this.meterDSID = new DSID(
158 deviceJsonObject.get(JSONApiResponseKeysEnum.DS_METER_DSID.getKey()).getAsString());
160 if (deviceJsonObject.get(JSONApiResponseKeysEnum.HW_INFO.getKey()) != null) {
161 this.hwInfo = deviceJsonObject.get(JSONApiResponseKeysEnum.HW_INFO.getKey()).getAsString();
162 } else if (deviceJsonObject.get(JSONApiResponseKeysEnum.HW_INFO_UPPER_HW.getKey()) != null) {
163 this.hwInfo = deviceJsonObject.get(JSONApiResponseKeysEnum.HW_INFO_UPPER_HW.getKey()).getAsString();
165 if (deviceJsonObject.get(JSONApiResponseKeysEnum.ON.getKey()) != null) {
167 this.isOn = deviceJsonObject.get(JSONApiResponseKeysEnum.ON.getKey()).getAsBoolean();
169 this.isOpen = deviceJsonObject.get(JSONApiResponseKeysEnum.ON.getKey()).getAsBoolean();
172 if (deviceJsonObject.get(JSONApiResponseKeysEnum.ZONE_ID.getKey()) != null) {
173 zoneId = deviceJsonObject.get(JSONApiResponseKeysEnum.ZONE_ID.getKey()).getAsInt();
174 } else if (deviceJsonObject.get(JSONApiResponseKeysEnum.ZONE_ID_Lower_Z.getKey()) != null) {
175 zoneId = deviceJsonObject.get(JSONApiResponseKeysEnum.ZONE_ID_Lower_Z.getKey()).getAsInt();
177 JsonElement groups = deviceJsonObject.get(JSONApiResponseKeysEnum.GROUPS.getKey());
178 if (groups != null && groups.isJsonArray()) {
179 JsonArray array = deviceJsonObject.get(JSONApiResponseKeysEnum.GROUPS.getKey()).getAsJsonArray();
180 for (int i = 0; i < array.size(); i++) {
181 if (array.get(i) != null) {
182 initAddGroup(array.get(i).getAsShort());
185 } else if (groups != null && groups.isJsonObject()) {
186 for (Entry<String, JsonElement> entry : deviceJsonObject.get(JSONApiResponseKeysEnum.GROUPS.getKey())
187 .getAsJsonObject().entrySet()) {
188 initAddGroup(entry.getValue().getAsJsonObject().get(JSONApiResponseKeysEnum.ID.getKey()).getAsShort());
191 if (deviceJsonObject.get(JSONApiResponseKeysEnum.OUTPUT_MODE.getKey()) != null) {
192 int tmp = deviceJsonObject.get(JSONApiResponseKeysEnum.OUTPUT_MODE.getKey()).getAsInt();
194 if (OutputModeEnum.containsMode(tmp)) {
195 outputMode = OutputModeEnum.getMode(tmp);
199 if (deviceJsonObject.get(JSONApiResponseKeysEnum.SENSOR_INPUTS.getKey()) != null
200 && deviceJsonObject.get(JSONApiResponseKeysEnum.SENSOR_INPUTS.getKey()).isJsonObject()) {
201 JsonObject jObj = deviceJsonObject.get(JSONApiResponseKeysEnum.SENSOR_INPUTS.getKey()).getAsJsonObject();
202 for (Entry<String, JsonElement> entry : jObj.entrySet()) {
203 if (entry.getValue().isJsonObject()) {
204 JsonObject sensorType = entry.getValue().getAsJsonObject();
205 if (sensorType.get(JSONApiResponseKeysEnum.TYPE.getKey()) != null) {
207 .containsSensor(sensorType.get(JSONApiResponseKeysEnum.TYPE.getKey()).getAsShort())) {
208 setDeviceSensorValue(new DeviceSensorValue(entry.getValue().getAsJsonObject()));
214 if (deviceJsonObject.get(JSONApiResponseKeysEnum.BINARY_INPUTS.getKey()) != null
215 && deviceJsonObject.get(JSONApiResponseKeysEnum.BINARY_INPUTS.getKey()).isJsonObject()) {
216 JsonObject jObj = deviceJsonObject.get(JSONApiResponseKeysEnum.BINARY_INPUTS.getKey()).getAsJsonObject();
217 for (Entry<String, JsonElement> entry : jObj.entrySet()) {
218 if (entry.getValue().isJsonObject()) {
219 JsonObject binaryInput = entry.getValue().getAsJsonObject();
220 deviceBinaryInputs.add(new DeviceBinaryInput(binaryInput));
227 private void initAddGroup(Short groupID) {
229 this.groupList.add(groupID);
230 if (FuncNameAndColorGroupEnum.containsColorGroup(groupID)) {
231 if (this.functionalName == null
232 || !FuncNameAndColorGroupEnum.getMode(groupID).equals(FuncNameAndColorGroupEnum.JOKER)) {
233 this.functionalName = FuncNameAndColorGroupEnum.getMode(groupID);
234 this.functionalGroup = functionalName.getFunctionalColor();
240 private void init() {
241 if (groupList.contains((short) 1)) {
242 maxOutputValue = DeviceConstants.MAX_OUTPUT_VALUE_LIGHT;
243 if (this.isDimmable()) {
244 minOutputValue = DeviceConstants.MIN_DIM_VALUE;
247 maxOutputValue = DeviceConstants.DEFAULT_MAX_OUTPUTVALUE;
251 outputValue = DeviceConstants.DEFAULT_MAX_OUTPUTVALUE;
256 public synchronized DSID getMeterDSID() {
257 return this.meterDSID;
261 public synchronized void setMeterDSID(String meterDSID) {
262 this.meterDSID = new DSID(meterDSID);
263 informListenerAboutConfigChange(ChangeableDeviceConfigEnum.METER_DSID);
267 public String getHWinfo() {
272 public List<Short> getGroups() {
273 return new LinkedList<>(groupList);
277 public void addGroup(Short groupID) {
278 if (!this.groupList.contains(groupID)) {
279 this.groupList.add(groupID);
281 informListenerAboutConfigChange(ChangeableDeviceConfigEnum.GROUPS);
285 public void setGroups(List<Short> newGroupList) {
286 if (newGroupList != null) {
287 this.groupList = newGroupList;
289 informListenerAboutConfigChange(ChangeableDeviceConfigEnum.GROUPS);
293 public synchronized int getZoneId() {
298 public synchronized void setZoneId(int zoneID) {
299 this.zoneId = zoneID;
300 informListenerAboutConfigChange(ChangeableDeviceConfigEnum.ZONE_ID);
304 public synchronized boolean isOn() {
309 public synchronized void setIsOn(boolean flag) {
311 this.deviceStateUpdates.add(new DeviceStateUpdateImpl(DeviceStateUpdate.ON_OFF, 1));
313 this.deviceStateUpdates.add(new DeviceStateUpdateImpl(DeviceStateUpdate.ON_OFF, -1));
318 public synchronized boolean isOpen() {
323 public synchronized void setIsOpen(boolean flag) {
325 this.deviceStateUpdates.add(new DeviceStateUpdateImpl(DeviceStateUpdate.OPEN_CLOSE, 1));
327 this.deviceStateUpdates.add(new DeviceStateUpdateImpl(DeviceStateUpdate.OPEN_CLOSE_ANGLE, 1));
330 this.deviceStateUpdates.add(new DeviceStateUpdateImpl(DeviceStateUpdate.OPEN_CLOSE, -1));
332 this.deviceStateUpdates.add(new DeviceStateUpdateImpl(DeviceStateUpdate.OPEN_CLOSE_ANGLE, -1));
338 public synchronized void setOutputValue(short value) {
341 this.deviceStateUpdates.add(new DeviceStateUpdateImpl(DeviceStateUpdate.ON_OFF, -1));
343 } else if (value > maxOutputValue) {
344 this.deviceStateUpdates.add(new DeviceStateUpdateImpl(DeviceStateUpdate.ON_OFF, 1));
346 this.deviceStateUpdates.add(new DeviceStateUpdateImpl(DeviceStateUpdate.OUTPUT, value));
352 public synchronized boolean isDimmable() {
353 return OutputModeEnum.outputModeIsDimmable(outputMode);
357 public synchronized boolean isSwitch() {
358 return OutputModeEnum.outputModeIsSwitch(outputMode);
362 public synchronized boolean isDeviceWithOutput() {
363 return this.outputMode != null && !this.outputMode.equals(OutputModeEnum.DISABLED);
367 public boolean isSensorDevice() {
368 return !isDeviceWithOutput() && !deviceClimateSensorTypes.isEmpty();
372 public boolean isHeatingDevice() {
373 return functionalName.equals(FuncNameAndColorGroupEnum.HEATING);
377 public boolean isTemperatureControlledDevice() {
378 return functionalName.equals(FuncNameAndColorGroupEnum.TEMPERATION_CONTROL);
382 public boolean isShade() {
383 return OutputModeEnum.outputModeIsShade(outputMode);
387 public boolean isBlind() {
388 return outputMode.equals(OutputModeEnum.POSITION_CON_US);
392 public synchronized FunctionalColorGroupEnum getFunctionalColorGroup() {
393 return this.functionalGroup;
397 public synchronized void setFunctionalColorGroup(FunctionalColorGroupEnum fuctionalColorGroup) {
398 this.functionalGroup = fuctionalColorGroup;
399 informListenerAboutConfigChange(ChangeableDeviceConfigEnum.FUNCTIONAL_GROUP);
403 public OutputModeEnum getOutputMode() {
408 public synchronized void setOutputMode(OutputModeEnum newOutputMode) {
409 this.outputMode = newOutputMode;
410 informListenerAboutConfigChange(ChangeableDeviceConfigEnum.OUTPUT_MODE);
414 public synchronized void increase() {
416 deviceStateUpdates.add(new DeviceStateUpdateImpl(DeviceStateUpdate.OUTPUT_INCREASE, 0));
419 this.deviceStateUpdates.add(new DeviceStateUpdateImpl(DeviceStateUpdate.SLAT_INCREASE, 0));
421 this.deviceStateUpdates.add(new DeviceStateUpdateImpl(DeviceStateUpdate.SLAT_ANGLE_DECREASE, 0));
427 public synchronized void decrease() {
429 this.deviceStateUpdates.add(new DeviceStateUpdateImpl(DeviceStateUpdate.OUTPUT_DECREASE, 0));
432 this.deviceStateUpdates.add(new DeviceStateUpdateImpl(DeviceStateUpdate.SLAT_DECREASE, 0));
434 this.deviceStateUpdates.add(new DeviceStateUpdateImpl(DeviceStateUpdate.SLAT_ANGLE_DECREASE, 0));
440 public synchronized void increaseSlatAngle() {
442 this.deviceStateUpdates.add(new DeviceStateUpdateImpl(DeviceStateUpdate.SLAT_ANGLE_DECREASE, 1));
447 public synchronized void decreaseSlatAngle() {
449 this.deviceStateUpdates.add(new DeviceStateUpdateImpl(DeviceStateUpdate.SLAT_ANGLE_DECREASE, 1));
454 public synchronized short getOutputValue() {
459 public short getMaxOutputValue() {
460 return maxOutputValue;
464 public short getMinOutputValue() {
465 return minOutputValue;
469 public synchronized int getSlatPosition() {
474 public synchronized short getAnglePosition() {
479 public synchronized void setAnglePosition(int angle) {
480 if (angle == slatAngle) {
483 if (angle < minSlatAngle) {
484 this.deviceStateUpdates.add(new DeviceStateUpdateImpl(DeviceStateUpdate.SLAT_ANGLE, minSlatAngle));
485 } else if (angle > this.maxSlatPosition) {
486 this.deviceStateUpdates.add(new DeviceStateUpdateImpl(DeviceStateUpdate.SLAT_ANGLE, maxSlatAngle));
488 this.deviceStateUpdates.add(new DeviceStateUpdateImpl(DeviceStateUpdate.SLAT_ANGLE, angle));
493 public synchronized void setSlatPosition(int position) {
494 if (position == this.slatPosition) {
497 if (position < minSlatPosition) {
498 this.deviceStateUpdates.add(new DeviceStateUpdateImpl(DeviceStateUpdate.SLATPOSITION, minSlatPosition));
499 } else if (position > this.maxSlatPosition) {
500 this.deviceStateUpdates.add(new DeviceStateUpdateImpl(DeviceStateUpdate.SLATPOSITION, maxSlatPosition));
502 this.deviceStateUpdates.add(new DeviceStateUpdateImpl(DeviceStateUpdate.SLATPOSITION, position));
506 private short getDimmStep() {
508 return DeviceConstants.DIM_STEP_LIGHT;
509 } else if (isShade()) {
510 return DeviceConstants.MOVE_STEP_ROLLERSHUTTER;
512 return DeviceConstants.DEFAULT_MOVE_STEP;
517 public int getMaxSlatPosition() {
518 return maxSlatPosition;
522 public int getMinSlatPosition() {
523 return minSlatPosition;
527 public int getMaxSlatAngle() {
532 public int getMinSlatAngle() {
539 public synchronized void callInternalScene(InternalScene scene) {
540 if (lastCallWasUndo) {
542 if (activeScene != null) {
543 activeScene.deactivateSceneByDevice();
547 internalCallScene(scene.getSceneID());
549 lastCallWasUndo = false;
553 public void checkSceneConfig(Short sceneNumber, short prio) {
554 if (isDeviceWithOutput()) {
555 if (!containsSceneConfig(sceneNumber)) {
556 deviceStateUpdates.add(new DeviceStateUpdateImpl(DeviceStateUpdate.UPDATE_SCENE_CONFIG,
557 new Short[] { sceneNumber, prio }));
560 if (sceneOutputMap.get(sceneNumber) == null) {
561 deviceStateUpdates.add(new DeviceStateUpdateImpl(DeviceStateUpdate.UPDATE_SCENE_OUTPUT,
562 new Short[] { sceneNumber, prio }));
568 public synchronized void undoInternalScene(InternalScene scene) {
569 logger.debug("undo Scene {} dSID {}", scene.getSceneID(), dsid.getValue());
570 if (activeScene != null && activeScene.equals(scene)) {
571 if (lastCallWasUndo) {
575 if (this.lastScene != null && !lastScene.equals(activeScene)) {
576 activeScene = lastScene;
578 activeScene.activateSceneByDevice();
581 logger.debug("internalUndo Scene dSID {}", dsid.getValue());
582 this.activeScene = null;
585 lastCallWasUndo = true;
590 public synchronized void callScene(Short sceneNumber) {
591 this.deviceStateUpdates.add(new DeviceStateUpdateImpl(DeviceStateUpdate.UPDATE_CALL_SCENE, sceneNumber));
595 public synchronized void internalCallScene(Short sceneNumber) {
596 logger.debug("call Scene id {} dSID {}", sceneNumber, dsid.getValue());
597 if (isDeviceWithOutput()) {
598 activeSceneNumber = sceneNumber;
599 informLastSceneAboutSceneCall(sceneNumber);
601 outputValueBeforeSceneCall = this.outputValue;
603 outputValueBeforeSceneCall = this.slatPosition;
605 slatAngleBeforeSceneCall = this.slatAngle;
608 if (!checkSceneNumber(sceneNumber)) {
609 if (containsSceneConfig(sceneNumber)) {
610 if (doIgnoreScene(sceneNumber)) {
614 this.deviceStateUpdates.add(new DeviceStateUpdateImpl(DeviceStateUpdate.UPDATE_SCENE_CONFIG,
615 new Short[] { sceneNumber, GeneralLibConstance.HIGHEST_READ_OUT_PRIORITY }));
617 if (sceneOutputMap.get(sceneNumber) != null) {
619 updateInternalDeviceState(new DeviceStateUpdateImpl(DeviceStateUpdate.OUTPUT,
620 sceneOutputMap.get(sceneNumber)[GeneralLibConstance.SCENE_ARRAY_INDEX_VALUE]));
622 updateInternalDeviceState(new DeviceStateUpdateImpl(DeviceStateUpdate.SLATPOSITION,
623 sceneOutputMap.get(sceneNumber)[GeneralLibConstance.SCENE_ARRAY_INDEX_VALUE]));
625 updateInternalDeviceState(new DeviceStateUpdateImpl(DeviceStateUpdate.SLAT_ANGLE,
626 sceneOutputMap.get(sceneNumber)[GeneralLibConstance.SCENE_ARRAY_INDEX_ANGLE]));
630 this.deviceStateUpdates.add(new DeviceStateUpdateImpl(DeviceStateUpdate.UPDATE_SCENE_OUTPUT,
631 new Short[] { sceneNumber, GeneralLibConstance.HIGHEST_READ_OUT_PRIORITY }));
638 private boolean checkSceneNumber(Short sceneNumber) {
639 if (SceneEnum.containsScene(sceneNumber)) {
640 if (this.outputMode.equals(OutputModeEnum.POWERSAVE)) {
641 switch (SceneEnum.getScene(sceneNumber)) {
645 this.updateInternalDeviceState(new DeviceStateUpdateImpl(DeviceStateUpdate.ON_OFF, -1));
661 if (this.outputMode.equals(OutputModeEnum.WIPE)) {
662 switch (SceneEnum.getScene(sceneNumber)) {
674 this.updateInternalDeviceState(new DeviceStateUpdateImpl(DeviceStateUpdate.ON_OFF, -1));
680 switch (SceneEnum.getScene(sceneNumber)) {
685 this.updateInternalDeviceState(new DeviceStateUpdateImpl(DeviceStateUpdate.ON_OFF, 1));
687 this.updateInternalDeviceState(new DeviceStateUpdateImpl(DeviceStateUpdate.OPEN_CLOSE, 1));
689 this.updateInternalDeviceState(
690 new DeviceStateUpdateImpl(DeviceStateUpdate.OPEN_CLOSE_ANGLE, 1));
699 this.updateInternalDeviceState(new DeviceStateUpdateImpl(DeviceStateUpdate.ON_OFF, -1));
701 this.updateInternalDeviceState(new DeviceStateUpdateImpl(DeviceStateUpdate.OPEN_CLOSE, -1));
703 this.updateInternalDeviceState(
704 new DeviceStateUpdateImpl(DeviceStateUpdate.OPEN_CLOSE_ANGLE, -1));
710 case AREA_1_INCREMENT:
711 case AREA_2_INCREMENT:
712 case AREA_3_INCREMENT:
713 case AREA_4_INCREMENT:
715 if (outputValue == maxOutputValue) {
718 this.updateInternalDeviceState(new DeviceStateUpdateImpl(DeviceStateUpdate.OUTPUT_INCREASE, 0));
721 if (slatPosition == maxSlatPosition) {
724 this.updateInternalDeviceState(new DeviceStateUpdateImpl(DeviceStateUpdate.SLAT_INCREASE, 0));
726 if (slatAngle == maxSlatAngle) {
729 updateInternalDeviceState(
730 new DeviceStateUpdateImpl(DeviceStateUpdate.SLAT_ANGLE_INCREASE, 0));
736 case AREA_1_DECREMENT:
737 case AREA_2_DECREMENT:
738 case AREA_3_DECREMENT:
739 case AREA_4_DECREMENT:
741 if (outputValue == minOutputValue) {
744 updateInternalDeviceState(new DeviceStateUpdateImpl(DeviceStateUpdate.OUTPUT_DECREASE, 0));
747 if (slatPosition == minSlatPosition) {
750 updateInternalDeviceState(new DeviceStateUpdateImpl(DeviceStateUpdate.SLAT_DECREASE, 0));
752 if (slatAngle == minSlatAngle) {
755 this.updateInternalDeviceState(
756 new DeviceStateUpdateImpl(DeviceStateUpdate.SLAT_ANGLE_INCREASE, 0));
767 this.deviceStateUpdates.add(new DeviceStateUpdateImpl(DeviceStateUpdate.UPDATE_OUTPUT_VALUE, 0));
769 // Area Stepping continue scenes
770 case AREA_STEPPING_CONTINUE:
779 private Integer[] getStandartSceneOutput(short sceneNumber) {
780 if (SceneEnum.getScene(sceneNumber) != null) {
781 switch (SceneEnum.getScene(sceneNumber)) {
785 return new Integer[] { (int) maxOutputValue, -1 };
788 return new Integer[] { (int) maxSlatPosition, (int) maxSlatAngle };
790 return new Integer[] { (int) maxSlatPosition, -1 };
798 return new Integer[] { (int) 0, -1 };
801 return new Integer[] { (int) 0, 0 };
803 return new Integer[] { (int) 0, -1 };
813 private void informLastSceneAboutSceneCall(short sceneNumber) {
814 if (this.activeScene != null && this.activeScene.getSceneID() != sceneNumber) {
815 this.activeScene.deactivateSceneByDevice();
816 this.lastScene = this.activeScene;
817 this.activeScene = null;
822 public synchronized void undoScene() {
823 this.deviceStateUpdates
824 .add(new DeviceStateUpdateImpl(DeviceStateUpdate.UPDATE_UNDO_SCENE, this.activeSceneNumber));
828 public synchronized void internalUndoScene() {
830 updateInternalDeviceState(
831 new DeviceStateUpdateImpl(DeviceStateUpdate.OUTPUT, this.outputValueBeforeSceneCall));
833 updateInternalDeviceState(
834 new DeviceStateUpdateImpl(DeviceStateUpdate.SLATPOSITION, this.outputValueBeforeSceneCall));
836 updateInternalDeviceState(
837 new DeviceStateUpdateImpl(DeviceStateUpdate.SLAT_ANGLE, this.slatAngleBeforeSceneCall));
841 if (activeSceneNumber != -1) {
842 activeSceneNumber = -1;
847 public InternalScene getAcitiveScene() {
848 return this.activeScene;
852 public Integer[] getSceneOutputValue(short sceneId) {
853 synchronized (sceneOutputMap) {
854 if (sceneOutputMap.containsKey(sceneId)) {
855 return sceneOutputMap.get(sceneId);
858 return new Integer[] { -1, -1 };
862 public void setSceneOutputValue(short sceneId, int value) {
863 internalSetSceneOutputValue(sceneId, value, -1);
864 if (listener != null) {
865 listener.onSceneConfigAdded(sceneId);
870 public void setSceneOutputValue(short sceneId, int value, int angle) {
871 internalSetSceneOutputValue(sceneId, value, angle);
872 if (listener != null) {
873 listener.onSceneConfigAdded(sceneId);
877 private void internalSetSceneOutputValue(short sceneId, int value, int angle) {
878 synchronized (sceneOutputMap) {
879 sceneOutputMap.put(sceneId, new Integer[] { value, angle });
881 if (activeSceneNumber == sceneId) {
882 internalCallScene(sceneId);
887 public List<Short> getSavedScenes() {
888 Set<Short> bothKeySet = new HashSet<>(sceneOutputMap.keySet());
889 bothKeySet.addAll(sceneConfigMap.keySet());
890 return new LinkedList<>(bothKeySet);
894 public void addSceneConfig(short sceneId, DeviceSceneSpec sceneSpec) {
895 if (sceneSpec != null) {
896 synchronized (sceneConfigMap) {
897 sceneConfigMap.put(sceneId, sceneSpec);
898 if (listener != null) {
899 listener.onSceneConfigAdded(sceneId);
906 public DeviceSceneSpec getSceneConfig(short sceneId) {
907 synchronized (sceneConfigMap) {
908 return sceneConfigMap.get(sceneId);
913 public boolean doIgnoreScene(short sceneId) {
914 synchronized (sceneConfigMap) {
915 if (this.sceneConfigMap.containsKey(sceneId)) {
916 return this.sceneConfigMap.get(sceneId).isDontCare();
923 public boolean containsSceneConfig(short sceneId) {
924 synchronized (sceneConfigMap) {
925 return sceneConfigMap.containsKey(sceneId);
932 public boolean equals(Object obj) {
933 if (obj instanceof Device) {
934 Device device = (Device) obj;
935 return device.getDSID().equals(this.getDSID());
941 public int hashCode() {
942 return this.getDSID().hashCode();
946 public boolean isPowerSensorUpToDate(SensorEnum powerSensorType) {
947 if (powerSensorType != null && SensorEnum.isPowerSensor(powerSensorType)) {
948 boolean isUpToDate = true;
949 if (powerSensorType.equals(SensorEnum.ACTIVE_POWER)) {
950 isUpToDate = (outputMode != null && outputMode.equals(OutputModeEnum.WIPE) && !isOn)
951 || (isOn && !isShade()) && !checkPowerSensorRefreshPriorityNever(powerSensorType)
952 ? checkSensorRefreshTime(powerSensorType)
955 if (powerSensorType.equals(SensorEnum.ELECTRIC_METER)) {
956 isUpToDate = (isOn || getDeviceSensorValue(powerSensorType).getDsValue() == 0) && !isShade()
957 && !checkPowerSensorRefreshPriorityNever(powerSensorType)
958 ? checkSensorRefreshTime(powerSensorType)
961 isUpToDate = isOn && !isShade() && !checkPowerSensorRefreshPriorityNever(powerSensorType)
962 ? checkSensorRefreshTime(powerSensorType)
965 if (!getSensorDataReadingInitialized(powerSensorType)) {
966 deviceStateUpdates.add(new DeviceStateUpdateImpl(powerSensorType, 0));
967 setSensorDataReadingInitialized(powerSensorType, true);
973 throw new IllegalArgumentException("powerSensorType is null or not a power sensor type.");
976 private boolean checkSensorRefreshTime(SensorEnum sensorType) {
977 if (sensorType != null) {
978 DeviceSensorValue devSenVal = getDeviceSensorValue(sensorType);
979 if (devSenVal.getValid()) {
980 int refresh = Config.DEFAULT_SENSORDATA_REFRESH_INTERVAL;
981 if (config != null) {
982 refresh = config.getSensordataRefreshInterval();
984 return (devSenVal.getTimestamp().getTime() + refresh) > System.currentTimeMillis();
991 public boolean isSensorDataUpToDate() {
992 boolean isUpToDate = true;
993 for (SensorEnum sensorType : devicePowerSensorTypes) {
994 isUpToDate = isPowerSensorUpToDate(sensorType);
1000 public void setSensorDataRefreshPriority(String activePowerRefreshPriority, String electricMeterRefreshPriority,
1001 String outputCurrentRefreshPriority) {
1002 if (checkPriority(activePowerRefreshPriority)) {
1003 ((String[]) powerSensorRefresh[REFRESH_ACTIVE_POWER_ARRAY_FIELD])[REFRESH_PRIORITY_ARRAY_FIELD] = activePowerRefreshPriority;
1005 if (checkPriority(outputCurrentRefreshPriority)) {
1006 ((String[]) powerSensorRefresh[REFRESH_OUTPUT_CURRENT_ARRAY_FIELD])[REFRESH_PRIORITY_ARRAY_FIELD] = outputCurrentRefreshPriority;
1008 if (checkPriority(electricMeterRefreshPriority)) {
1009 ((String[]) powerSensorRefresh[REFRESH_ELECTRIC_METER_ARRAY_FIELD])[REFRESH_PRIORITY_ARRAY_FIELD] = electricMeterRefreshPriority;
1014 public void setSensorDataRefreshPriority(SensorEnum powerSensorType, String refreshPriority) {
1015 if (checkPriority(refreshPriority)) {
1016 String[] powerSensorRefresh = getPowerSensorRefresh(powerSensorType);
1017 if (powerSensorRefresh != null) {
1018 powerSensorRefresh[REFRESH_ACTIVE_POWER_ARRAY_FIELD] = refreshPriority;
1024 public String getPowerSensorRefreshPriority(SensorEnum powerSensorType) {
1025 if (powerSensorType.equals(SensorEnum.ACTIVE_POWER) && outputMode.equals(OutputModeEnum.WIPE) && !isOn) {
1026 return Config.REFRESH_PRIORITY_LOW;
1028 String[] powerSensorRefresh = getPowerSensorRefresh(powerSensorType);
1029 if (powerSensorRefresh != null) {
1030 return powerSensorRefresh[REFRESH_PRIORITY_ARRAY_FIELD];
1036 public boolean checkPowerSensorRefreshPriorityNever(SensorEnum powerSensorType) {
1037 if (getPowerSensorRefreshPriority(powerSensorType) != null) {
1038 return getPowerSensorRefreshPriority(powerSensorType).equals(Config.REFRESH_PRIORITY_NEVER);
1043 private void setAllSensorDataRefreshPrioritiesToNever() {
1044 for (short i = 0; i < powerSensorRefresh.length; i++) {
1045 ((String[]) powerSensorRefresh[i])[REFRESH_PRIORITY_ARRAY_FIELD] = Config.REFRESH_PRIORITY_NEVER;
1049 private void setSensorDataReadingInitialized(SensorEnum powerSensorType, Boolean flag) {
1050 String[] powerSensorRefresh = getPowerSensorRefresh(powerSensorType);
1051 if (powerSensorRefresh != null) {
1052 powerSensorRefresh[READING_INITIALIZED_ARRAY_FIELD] = flag.toString();
1056 private boolean getSensorDataReadingInitialized(SensorEnum powerSensorType) {
1057 String[] powerSensorRefresh = getPowerSensorRefresh(powerSensorType);
1058 if (powerSensorRefresh != null) {
1059 return Boolean.valueOf(powerSensorRefresh[READING_INITIALIZED_ARRAY_FIELD]);
1064 private String[] getPowerSensorRefresh(SensorEnum powerSensorType) {
1065 switch (powerSensorType) {
1067 return (String[]) powerSensorRefresh[REFRESH_ACTIVE_POWER_ARRAY_FIELD];
1068 case OUTPUT_CURRENT:
1069 return (String[]) powerSensorRefresh[REFRESH_OUTPUT_CURRENT_ARRAY_FIELD];
1070 case ELECTRIC_METER:
1071 return (String[]) powerSensorRefresh[REFRESH_ELECTRIC_METER_ARRAY_FIELD];
1072 case POWER_CONSUMPTION:
1073 return (String[]) powerSensorRefresh[REFRESH_POWER_CONSUMPTION_ARRAY_FIELD];
1079 private boolean checkPriority(String priority) {
1081 case Config.REFRESH_PRIORITY_HIGH:
1082 case Config.REFRESH_PRIORITY_MEDIUM:
1083 case Config.REFRESH_PRIORITY_LOW:
1084 case Config.REFRESH_PRIORITY_NEVER:
1087 logger.error("Sensor data update priority do not exist! Please check the input!");
1093 public boolean isDeviceUpToDate() {
1094 isSensorDataUpToDate();
1095 return this.deviceStateUpdates.isEmpty();
1099 public DeviceStateUpdate getNextDeviceUpdateState() {
1100 return !this.deviceStateUpdates.isEmpty() ? this.deviceStateUpdates.remove(0) : null;
1103 private int internalSetOutputValue(int value) {
1105 slatPosition = value;
1106 if (slatPosition <= 0) {
1112 return slatPosition;
1114 outputValue = (short) value;
1115 if (outputValue <= 0) {
1119 if (outputValue < switchPercentOff) {
1124 setCachedMeterData();
1128 setCachedMeterData();
1135 private void internalSetOff() {
1137 logger.debug("internal set OFF ");
1138 if (!checkPowerSensorRefreshPriorityNever(SensorEnum.ACTIVE_POWER)) {
1139 if (getSensorDataReadingInitialized(SensorEnum.ACTIVE_POWER)) {
1140 deviceStateUpdates.add(new DeviceStateUpdateImpl(SensorEnum.ACTIVE_POWER, -1));
1141 logger.debug("internal set sensor to 0");
1143 setDsSensorValue(SensorEnum.ACTIVE_POWER, 0);
1145 if (!checkPowerSensorRefreshPriorityNever(SensorEnum.OUTPUT_CURRENT)) {
1146 if (getSensorDataReadingInitialized(SensorEnum.OUTPUT_CURRENT)) {
1147 deviceStateUpdates.add(new DeviceStateUpdateImpl(SensorEnum.OUTPUT_CURRENT, -1));
1149 setDsSensorValue(SensorEnum.OUTPUT_CURRENT, 0);
1151 if (!checkPowerSensorRefreshPriorityNever(SensorEnum.POWER_CONSUMPTION)) {
1152 if (getSensorDataReadingInitialized(SensorEnum.POWER_CONSUMPTION)) {
1153 deviceStateUpdates.add(new DeviceStateUpdateImpl(SensorEnum.POWER_CONSUMPTION, -1));
1155 setDsSensorValue(SensorEnum.POWER_CONSUMPTION, 0);
1159 private short internalSetAngleValue(int value) {
1163 if (value > maxSlatAngle) {
1164 slatAngle = maxSlatAngle;
1166 slatAngle = (short) value;
1173 public List<SensorEnum> getSensorTypes() {
1174 List<SensorEnum> list = new ArrayList<>(devicePowerSensorTypes);
1175 list.addAll(deviceClimateSensorTypes);
1180 public List<SensorEnum> getPowerSensorTypes() {
1181 return devicePowerSensorTypes;
1185 public List<SensorEnum> getClimateSensorTypes() {
1186 return deviceClimateSensorTypes;
1190 public List<DeviceSensorValue> getDeviceSensorValues() {
1191 return deviceSensorValues;
1195 public boolean supportsSensorType(SensorEnum sensorType) {
1196 if (sensorType != null) {
1197 return getSensorTypes().contains(sensorType);
1203 public void setDeviceSensorValue(DeviceSensorValue deviceSensorValue) {
1204 if (deviceSensorValue != null) {
1205 int index = deviceSensorValues.indexOf(deviceSensorValue);
1207 deviceSensorValues.add(deviceSensorValue);
1208 if (SensorEnum.isPowerSensor(deviceSensorValue.getSensorType())) {
1209 devicePowerSensorTypes.add(deviceSensorValue.getSensorType());
1211 deviceClimateSensorTypes.add(deviceSensorValue.getSensorType());
1214 if (deviceSensorValue.getTimestamp().after(deviceSensorValues.get(index).getTimestamp())) {
1215 logger.debug("set deviceSeneorValue, new deviceSensorValue is: {}", deviceSensorValue.toString());
1216 deviceSensorValues.set(index, deviceSensorValue);
1217 checkSensorValueSet(deviceSensorValue, true);
1224 public void setDeviceSensorByEvent(EventItem event) {
1225 DeviceSensorValue devSenVal = new DeviceSensorValue(event.getProperties());
1226 SensorEnum sensorType = devSenVal.getSensorType();
1227 if (!isEchoSensor(sensorType)) {
1228 logger.debug("Event is no echo, set values {} for sensorType {}", devSenVal, devSenVal.getSensorType());
1229 if (SensorEnum.isPowerSensor(sensorType) && getSensorDataReadingInitialized(sensorType)) {
1230 logger.debug("SensorJob was initialized, remove sensorjob for sensorType: {}",
1231 devSenVal.getSensorType());
1232 deviceStateUpdates.add(new DeviceStateUpdateImpl(sensorType, -1));
1234 setDeviceSensorValue(devSenVal);
1236 logger.debug("Event is echo remove sensorType {} from echoBox", devSenVal.getSensorType());
1237 sensorEchoBox.remove(devSenVal.getSensorType());
1241 private boolean isEchoSensor(SensorEnum sensorType) {
1242 return sensorEchoBox != null ? sensorEchoBox.contains(sensorType) : false;
1245 private List<SensorEnum> sensorEchoBox = Collections.synchronizedList(new LinkedList<>());
1248 public void setDeviceSensorDsValueBySensorJob(SensorEnum sensorType, Integer value) {
1249 logger.debug("sensorJob for device {} is executet", dsid.getValue());
1250 if (isSensorEchoBoxEnabled()) {
1251 // temperature resolution is not correct, so waiting for device sensor-event
1252 if (!sensorType.toString().contains("TEMPERATURE")) {
1253 logger.debug("echoBox is enabled, add sensorType {} to echoBox", sensorType);
1254 sensorEchoBox.add(sensorType);
1256 logger.debug("echoBox is enabled, ignoring temperation update and wait for sensor Event");
1260 setDsSensorValue(sensorType, value);
1264 public void enableSensorEchoBox() {
1265 if (sensorEchoBox == null) {
1266 sensorEchoBox = Collections.synchronizedList(new LinkedList<>());
1271 public void disableSensorEchoBox() {
1272 sensorEchoBox = null;
1276 public boolean isSensorEchoBoxEnabled() {
1277 return sensorEchoBox != null;
1281 public DeviceSensorValue getDeviceSensorValue(SensorEnum sensorType) {
1282 if (sensorType != null) {
1283 for (DeviceSensorValue devSenVal : deviceSensorValues) {
1284 if (devSenVal.getSensorType().equals(sensorType)) {
1293 public DeviceSensorValue getDeviceSensorValue(Short sensorIndex) {
1294 if (sensorIndex != null) {
1295 for (DeviceSensorValue devSenVal : deviceSensorValues) {
1296 if (devSenVal.getSensorIndex().equals(sensorIndex)) {
1305 public Short getSensorIndex(SensorEnum sensorType) {
1306 if (sensorType != null) {
1307 DeviceSensorValue devSenVal = getDeviceSensorValue(sensorType);
1308 return devSenVal != null ? devSenVal.getSensorIndex() : null;
1314 public SensorEnum getSensorType(Short sensorIndex) {
1315 if (sensorIndex != null) {
1316 DeviceSensorValue devSenVal = getDeviceSensorValue(sensorIndex);
1317 return devSenVal != null ? devSenVal.getSensorType() : null;
1323 public Integer getDsSensorValue(SensorEnum sensorType) {
1324 return getDsSensorValue((Object) sensorType);
1328 public Integer getDsSensorValue(Short sensorIndex) {
1329 return getDsSensorValue((Object) sensorIndex);
1333 public Float getFloatSensorValue(Short sensorIndex) {
1334 return getFloatSensorValue((Object) sensorIndex);
1338 public Float getFloatSensorValue(SensorEnum sensorType) {
1339 return getFloatSensorValue((Object) sensorType);
1343 public boolean setFloatSensorValue(SensorEnum sensorType, Float floatSensorValue) {
1344 return checkAndSetSensorValue(sensorType, null, floatSensorValue);
1348 public boolean setFloatSensorValue(Short sensorIndex, Float floatSensorValue) {
1349 return checkAndSetSensorValue(sensorIndex, null, floatSensorValue);
1353 public boolean setDsSensorValue(Short sensorIndex, Integer dSSensorValue) {
1354 return checkAndSetSensorValue(sensorIndex, dSSensorValue, null);
1358 public boolean setDsSensorValue(SensorEnum sensorType, Integer dSSensorValue) {
1359 return checkAndSetSensorValue(sensorType, dSSensorValue, null);
1363 public boolean setDsSensorValue(Short sensorIndex, Integer dSSensorValue, Float floatSensorValue) {
1364 return checkAndSetSensorValue(sensorIndex, dSSensorValue, floatSensorValue);
1368 public boolean setDsSensorValue(SensorEnum sensorType, Integer dSSensorValue, Float floatSensorValue) {
1369 return checkAndSetSensorValue(sensorType, dSSensorValue, floatSensorValue);
1373 public boolean hasSensors() {
1374 return hasClimateSensors() || hasPowerSensors();
1378 public boolean hasClimateSensors() {
1379 return !deviceClimateSensorTypes.isEmpty();
1383 public boolean hasPowerSensors() {
1384 return !devicePowerSensorTypes.isEmpty();
1387 // Sensor get/set helper methods
1388 private DeviceSensorValue getDeviceSensorValueForGet(Object obj) {
1389 return checkHighOutputCurrent(getDeviceSensorValueForSet(obj));
1392 private DeviceSensorValue getDeviceSensorValueForSet(Object obj) {
1393 if (obj instanceof Short) {
1394 return getDeviceSensorValue((Short) obj);
1396 return getDeviceSensorValue((SensorEnum) obj);
1400 private Integer getDsSensorValue(Object obj) {
1402 DeviceSensorValue devSenVal = checkPowerSensor(getDeviceSensorValueForGet(obj));
1403 return devSenVal != null && devSenVal.getValid() ? devSenVal.getDsValue() : null;
1408 private Float getFloatSensorValue(Object obj) {
1410 DeviceSensorValue devSenVal = checkPowerSensor(getDeviceSensorValueForGet(obj));
1411 return devSenVal != null && devSenVal.getValid() ? devSenVal.getFloatValue() : null;
1416 private DeviceSensorValue checkPowerSensor(DeviceSensorValue devSenVal) {
1417 if (devSenVal != null && SensorEnum.isPowerSensor(devSenVal.getSensorType())) {
1418 if (!devSenVal.getSensorType().equals(SensorEnum.ELECTRIC_METER)
1419 && !(SensorEnum.isPowerSensor(devSenVal.getSensorType()) && isOn)) {
1420 devSenVal.setDsValue(0);
1427 * Checks output current sensor to return automatically high output current sensor, if the sensor exists.
1430 * @return output current high DeviceSensorValue or the given DeviceSensorValue
1432 private DeviceSensorValue checkHighOutputCurrent(DeviceSensorValue devSenVal) {
1433 if (devSenVal != null && devSenVal.getSensorType().equals(SensorEnum.OUTPUT_CURRENT)
1434 && devSenVal.getDsValue() == SensorEnum.OUTPUT_CURRENT.getMax().intValue()
1435 && devicePowerSensorTypes.contains(SensorEnum.OUTPUT_CURRENT_H)) {
1436 return getDeviceSensorValue(SensorEnum.OUTPUT_CURRENT_H);
1441 private boolean checkAndSetSensorValue(Object obj, Integer dsValue, Float floatValue) {
1442 boolean isSet = false;
1444 DeviceSensorValue devSenVal = getDeviceSensorValueForSet(obj);
1445 if (devSenVal != null) {
1446 if (dsValue != null && floatValue != null) {
1447 isSet = devSenVal.setValues(floatValue, dsValue);
1448 } else if (dsValue != null) {
1449 isSet = devSenVal.setDsValue(dsValue);
1450 } else if (floatValue != null) {
1451 isSet = devSenVal.setFloatValue(floatValue);
1453 logger.debug("check devSenVal {} isSet={}", devSenVal.toString(), isSet);
1454 checkSensorValueSet(devSenVal, isSet);
1460 private void checkSensorValueSet(DeviceSensorValue devSenVal, boolean isSet) {
1461 if (devSenVal != null) {
1463 if (outputMode.equals(OutputModeEnum.WIPE) && !isOn
1464 && devSenVal.getSensorType().equals(SensorEnum.ACTIVE_POWER)) {
1465 int standby = Config.DEFAULT_STANDBY_ACTIVE_POWER;
1466 if (config != null) {
1467 standby = config.getStandbyActivePower();
1469 if (devSenVal.getDsValue() > standby) {
1470 this.updateInternalDeviceState(new DeviceStateUpdateImpl(DeviceStateUpdate.ON_OFF, 1));
1473 if (SensorEnum.isPowerSensor(devSenVal.getSensorType())) {
1474 addPowerSensorCache(devSenVal);
1476 informListenerAboutStateUpdate(
1477 new DeviceStateUpdateImpl(devSenVal.getSensorType(), devSenVal.getFloatValue()));
1479 setSensorDataReadingInitialized(devSenVal.getSensorType(), false);
1483 private void addPowerSensorCache(DeviceSensorValue newDevSenVal) {
1484 Integer[] cachedPowerValues = cachedSensorPowerValues.get(outputValue);
1485 if (cachedPowerValues == null) {
1486 cachedPowerValues = new Integer[4];
1488 switch (newDevSenVal.getSensorType()) {
1490 cachedPowerValues[ACTIVE_POWER_ARRAY_FIELD] = newDevSenVal.getDsValue();
1492 case OUTPUT_CURRENT:
1493 cachedPowerValues[OUTPUT_CURRENT_ARRAY_FIELD] = newDevSenVal.getDsValue();
1495 case OUTPUT_CURRENT_H:
1496 cachedPowerValues[OUTPUT_CURRENT_HIGH_ARRAY_FIELD] = newDevSenVal.getDsValue();
1498 case POWER_CONSUMPTION:
1499 cachedPowerValues[POWER_CONSUMPTION_ARRAY_FIELD] = newDevSenVal.getDsValue();
1504 this.cachedSensorPowerValues.put(outputValue, cachedPowerValues);
1508 public synchronized void updateInternalDeviceState(DeviceStateUpdate deviceStateUpdate) {
1509 DeviceStateUpdate deviceStateUpdateInt = internalSetOutputValue(deviceStateUpdate);
1510 if (deviceStateUpdateInt != null) {
1511 validateActiveScene();
1512 informListenerAboutStateUpdate(deviceStateUpdate);
1516 private DeviceStateUpdate internalSetOutputValue(DeviceStateUpdate deviceStateUpdate) {
1517 if (deviceStateUpdate == null) {
1520 logger.debug("internal set outputvalue");
1521 switch (deviceStateUpdate.getType()) {
1522 case DeviceStateUpdate.OUTPUT_DECREASE:
1523 return new DeviceStateUpdateImpl(DeviceStateUpdate.OUTPUT_DECREASE,
1524 internalSetOutputValue(outputValue - getDimmStep()));
1525 case DeviceStateUpdate.OUTPUT_INCREASE:
1526 return new DeviceStateUpdateImpl(DeviceStateUpdate.OUTPUT_INCREASE,
1527 internalSetOutputValue(outputValue + getDimmStep()));
1528 case DeviceStateUpdate.OUTPUT:
1529 internalSetOutputValue(deviceStateUpdate.getValueAsInteger());
1531 case DeviceStateUpdate.ON_OFF:
1532 if (deviceStateUpdate.getValueAsInteger() < 0) {
1533 internalSetOutputValue(0);
1535 internalSetOutputValue(maxOutputValue);
1538 case DeviceStateUpdate.OPEN_CLOSE:
1539 if (deviceStateUpdate.getValueAsInteger() < 0) {
1540 internalSetOutputValue(0);
1542 internalSetOutputValue(maxSlatPosition);
1545 case DeviceStateUpdate.OPEN_CLOSE_ANGLE:
1546 if (deviceStateUpdate.getValueAsInteger() < 0) {
1547 internalSetAngleValue(0);
1549 internalSetAngleValue(maxSlatAngle);
1552 case DeviceStateUpdate.SLAT_DECREASE:
1553 return new DeviceStateUpdateImpl(DeviceStateUpdate.SLAT_DECREASE,
1554 internalSetOutputValue(slatPosition - getDimmStep()));
1555 case DeviceStateUpdate.SLAT_INCREASE:
1556 return new DeviceStateUpdateImpl(DeviceStateUpdate.SLAT_INCREASE,
1557 internalSetOutputValue(slatPosition + getDimmStep()));
1558 case DeviceStateUpdate.SLATPOSITION:
1559 internalSetOutputValue(deviceStateUpdate.getValueAsInteger());
1561 case DeviceStateUpdate.SLAT_ANGLE_DECREASE:
1562 return new DeviceStateUpdateImpl(DeviceStateUpdate.SLAT_ANGLE_DECREASE,
1563 internalSetAngleValue(slatAngle - DeviceConstants.ANGLE_STEP_SLAT));
1564 case DeviceStateUpdate.SLAT_ANGLE_INCREASE:
1565 return new DeviceStateUpdateImpl(DeviceStateUpdate.SLAT_ANGLE_INCREASE,
1566 internalSetAngleValue(slatAngle + DeviceConstants.ANGLE_STEP_SLAT));
1567 case DeviceStateUpdate.SLAT_ANGLE:
1568 internalSetAngleValue(deviceStateUpdate.getValueAsInteger());
1570 case DeviceStateUpdate.UPDATE_CALL_SCENE:
1571 this.internalCallScene(deviceStateUpdate.getValueAsShort());
1573 case DeviceStateUpdate.UPDATE_UNDO_SCENE:
1574 this.internalUndoScene();
1577 if (deviceStateUpdate.isSensorUpdateType()) {
1578 SensorEnum sensorType = deviceStateUpdate.getTypeAsSensorEnum();
1579 setFloatSensorValue(sensorType, deviceStateUpdate.getValueAsFloat());
1583 return deviceStateUpdate;
1586 private void validateActiveScene() {
1587 if (activeScene == null) {
1590 Integer[] sceneOutput = getStandartSceneOutput(activeScene.getSceneID());
1591 if (sceneOutput == null) {
1592 sceneOutput = sceneOutputMap.get(activeScene.getSceneID());
1594 if (sceneOutput != null) {
1595 boolean outputChanged = false;
1597 if (isBlind() && sceneOutput[1] != slatAngle) {
1598 logger.debug("Scene output angle: {} setted output value {}", sceneOutput[1], slatAngle);
1599 outputChanged = true;
1601 if (sceneOutput[0] != slatPosition) {
1602 logger.debug("Scene output value: {} setted output value {}", sceneOutput[0], slatPosition);
1603 outputChanged = true;
1606 if (sceneOutput[0] != outputValue) {
1607 logger.debug("Scene output value: {} setted output value {}", sceneOutput[0], outputValue);
1608 outputChanged = true;
1611 if (outputChanged) {
1612 logger.debug("Device output from Device with dSID {} changed deactivate scene {}", dsid.getValue(),
1613 activeScene.getID());
1614 activeScene.deviceSceneChanged((short) -1);
1624 public DeviceStatusListener unregisterDeviceStatusListener() {
1625 setAllSensorDataRefreshPrioritiesToNever();
1626 return super.unregisterDeviceStatusListener();
1629 private void setCachedMeterData() {
1630 logger.debug("load cached sensor data device with dsid {}", dsid.getValue());
1631 Integer[] cachedSensorData = this.cachedSensorPowerValues.get(this.getOutputValue());
1632 if (cachedSensorData != null) {
1633 if (cachedSensorData[ACTIVE_POWER_ARRAY_FIELD] != null
1634 && !checkPowerSensorRefreshPriorityNever(SensorEnum.ACTIVE_POWER)) {
1635 informListenerAboutStateUpdate(new DeviceStateUpdateImpl(SensorEnum.ACTIVE_POWER,
1636 (float) cachedSensorData[ACTIVE_POWER_ARRAY_FIELD]));
1639 if (cachedSensorData[OUTPUT_CURRENT_ARRAY_FIELD] != null
1640 && !checkPowerSensorRefreshPriorityNever(SensorEnum.OUTPUT_CURRENT)) {
1641 if (cachedSensorData[OUTPUT_CURRENT_ARRAY_FIELD] == SensorEnum.OUTPUT_CURRENT.getMax().intValue()
1642 && devicePowerSensorTypes.contains(SensorEnum.OUTPUT_CURRENT_H)) {
1643 informListenerAboutStateUpdate(new DeviceStateUpdateImpl(SensorEnum.OUTPUT_CURRENT,
1644 cachedSensorData[OUTPUT_CURRENT_HIGH_ARRAY_FIELD]));
1646 informListenerAboutStateUpdate(new DeviceStateUpdateImpl(SensorEnum.OUTPUT_CURRENT,
1647 cachedSensorData[OUTPUT_CURRENT_ARRAY_FIELD]));
1650 if (cachedSensorData[ACTIVE_POWER_ARRAY_FIELD] != null
1651 && !checkPowerSensorRefreshPriorityNever(SensorEnum.POWER_CONSUMPTION)) {
1652 informListenerAboutStateUpdate(
1653 new DeviceStateUpdateImpl(SensorEnum.ACTIVE_POWER, cachedSensorData[ACTIVE_POWER_ARRAY_FIELD]));
1659 * if an {@link DeviceStatusListener} is registered inform him about the new state otherwise do nothing.
1661 * @param deviceStateUpdate
1663 private void informListenerAboutStateUpdate(DeviceStateUpdate deviceStateUpdate) {
1664 if (listener != null) {
1665 listener.onDeviceStateChanged(correctDeviceStatusUpdate(deviceStateUpdate));
1669 private DeviceStateUpdate correctDeviceStatusUpdate(DeviceStateUpdate deviceStateUpdate) {
1670 if (isSwitch() && deviceStateUpdate.getType().equals(DeviceStateUpdate.OUTPUT)) {
1671 if (deviceStateUpdate.getValueAsInteger() >= switchPercentOff) {
1672 return new DeviceStateUpdateImpl(DeviceStateUpdate.ON_OFF, DeviceStateUpdate.ON_VALUE);
1674 return new DeviceStateUpdateImpl(DeviceStateUpdate.ON_OFF, DeviceStateUpdate.OFF_VALUE);
1677 return deviceStateUpdate;
1680 private void informListenerAboutConfigChange(ChangeableDeviceConfigEnum changedConfig) {
1681 if (listener != null) {
1682 listener.onDeviceConfigChanged(changedConfig);
1683 logger.debug("Inform listener about device config {} changed", changedConfig.toString());
1687 @SuppressWarnings("null")
1689 public void saveConfigSceneSpecificationIntoDevice(Map<String, String> propertries) {
1690 if (propertries != null) {
1692 for (String key : propertries.keySet()) {
1693 if (key.startsWith(DigitalSTROMBindingConstants.DEVICE_SCENE)) {
1695 short sceneID = Short.parseShort((String) key
1696 .subSequence(DigitalSTROMBindingConstants.DEVICE_SCENE.length(), key.length()));
1697 sceneSave = propertries.get(key);
1698 if (StringUtils.isNotBlank(sceneSave)) {
1699 logger.debug("Find saved scene configuration for device with dSID {} and sceneID {}", dsid,
1701 String[] sceneParm = sceneSave.replace(" ", "").split(",");
1702 JSONDeviceSceneSpecImpl sceneSpecNew = null;
1703 int sceneValue = -1;
1704 int sceneAngle = -1;
1705 for (int j = 0; j < sceneParm.length; j++) {
1706 String[] sceneParmSplit = sceneParm[j].split(":");
1707 switch (sceneParmSplit[0]) {
1709 sceneSpecNew = new JSONDeviceSceneSpecImpl(sceneParmSplit[1]);
1712 sceneSpecNew.setDontcare(Boolean.parseBoolean(sceneParmSplit[1]));
1715 sceneSpecNew.setLocalPrio(Boolean.parseBoolean(sceneParmSplit[1]));
1718 sceneSpecNew.setSpecialMode(Boolean.parseBoolean(sceneParmSplit[1]));
1721 sceneValue = Integer.parseInt(sceneParmSplit[1]);
1724 sceneAngle = Integer.parseInt(sceneParmSplit[1]);
1728 if (sceneValue > -1) {
1730 "Saved sceneValue {}, sceneAngle {} for scene id {} into device with dsid {}",
1731 sceneValue, sceneAngle, sceneID, getDSID().getValue());
1732 internalSetSceneOutputValue(sceneID, sceneValue, sceneAngle);
1733 deviceStateUpdates.add(new DeviceStateUpdateImpl(DeviceStateUpdate.UPDATE_SCENE_OUTPUT,
1734 new Short[] { sceneID, (short) -1 }));
1736 if (sceneSpecNew != null) {
1737 logger.debug("Saved sceneConfig: [{}] for scene id {} into device with dsid {}",
1738 sceneSpecNew.toString(), sceneID, getDSID().getValue());
1739 synchronized (sceneConfigMap) {
1740 sceneConfigMap.put(sceneID, sceneSpecNew);
1742 deviceStateUpdates.add(new DeviceStateUpdateImpl(DeviceStateUpdate.UPDATE_SCENE_CONFIG,
1743 new Short[] { sceneID, (short) -1 }));
1746 } catch (NumberFormatException e) {
1754 @SuppressWarnings("null")
1756 public void saveConfigSceneSpecificationIntoDevice(String propertries) {
1757 String[] scenes = propertries.split("\n");
1758 for (int i = 0; i < scenes.length; i++) {
1759 logger.debug("Find saved scene configuration for device with dSID {} and sceneID {}", dsid, i);
1760 String[] sceneIdToConfig = scenes[i].replaceAll(" ", "").split("=");
1761 String[] sceneParm = sceneIdToConfig[1].split(",");
1762 JSONDeviceSceneSpecImpl sceneSpecNew = null;
1763 int sceneValue = -1;
1764 int sceneAngle = -1;
1765 for (int j = 0; j < sceneParm.length; j++) {
1766 String[] sceneParmSplit = sceneParm[j].split(":");
1767 switch (sceneParmSplit[0]) {
1769 sceneSpecNew = new JSONDeviceSceneSpecImpl(sceneParmSplit[1]);
1772 sceneSpecNew.setDontcare(Boolean.parseBoolean(sceneParmSplit[1]));
1775 sceneSpecNew.setLocalPrio(Boolean.parseBoolean(sceneParmSplit[1]));
1778 sceneSpecNew.setSpecialMode(Boolean.parseBoolean(sceneParmSplit[1]));
1781 sceneValue = Integer.parseInt(sceneParmSplit[1]);
1784 sceneAngle = Integer.parseInt(sceneParmSplit[1]);
1788 if (sceneValue > -1) {
1789 logger.debug("Saved sceneValue {}, sceneAngle {} for scene id {} into device with dsid {}", sceneValue,
1790 sceneAngle, i, getDSID().getValue());
1791 synchronized (sceneOutputMap) {
1792 sceneOutputMap.put(sceneSpecNew.getScene().getSceneNumber(),
1793 new Integer[] { sceneValue, sceneAngle });
1796 if (sceneSpecNew != null) {
1797 logger.debug("Saved sceneConfig: [{}] for scene id {} into device with dsid {}",
1798 sceneSpecNew.toString(), i, getDSID().getValue());
1799 synchronized (sceneConfigMap) {
1800 sceneConfigMap.put(sceneSpecNew.getScene().getSceneNumber(), sceneSpecNew);
1807 public void setConfig(Config config) {
1808 this.config = config;
1811 private String powerSensorRefreshToString() {
1812 String powSenRef = "";
1813 for (int i = 0; i < powerSensorRefresh.length; i++) {
1814 powSenRef = powSenRef + " [" + i + "]=Prio: "
1815 + ((String[]) powerSensorRefresh[i])[REFRESH_PRIORITY_ARRAY_FIELD] + ", Initialized: "
1816 + ((String[]) powerSensorRefresh[i])[READING_INITIALIZED_ARRAY_FIELD] + " ";
1822 public boolean isBinaryInputDevice() {
1823 return !deviceBinaryInputs.isEmpty();
1827 public List<DeviceBinaryInput> getBinaryInputs() {
1828 return deviceBinaryInputs;
1832 public DeviceBinaryInput getBinaryInput(DeviceBinarayInputEnum binaryInputType) {
1833 if (binaryInputType != null) {
1834 for (DeviceBinaryInput binInput : deviceBinaryInputs) {
1835 if (binaryInputType.getBinaryInputType().equals(binInput.getInputType())) {
1844 public Short getBinaryInputState(DeviceBinarayInputEnum binaryInputType) {
1845 DeviceBinaryInput devBinInput = getBinaryInput(binaryInputType);
1846 if (devBinInput != null) {
1847 return devBinInput.getState();
1853 public boolean setBinaryInputState(DeviceBinarayInputEnum binaryInputType, Short newState) {
1854 DeviceBinaryInput devBinInput = getBinaryInput(binaryInputType);
1855 if (devBinInput != null) {
1856 devBinInput.setState(newState);
1857 informListenerAboutStateUpdate(new DeviceStateUpdateImpl(binaryInputType, newState));
1864 public void setBinaryInputs(List<DeviceBinaryInput> newBinaryInputs) {
1865 this.deviceBinaryInputs.clear();
1866 this.deviceBinaryInputs.addAll(newBinaryInputs);
1867 informListenerAboutConfigChange(ChangeableDeviceConfigEnum.BINARY_INPUTS);
1871 public String toString() {
1872 return "DeviceImpl [meterDSID=" + meterDSID + ", zoneId=" + zoneId + ", groupList=" + groupList
1873 + ", functionalGroup=" + functionalGroup + ", functionalName=" + functionalName + ", hwInfo=" + hwInfo
1874 + ", getName()=" + getName() + ", getDSID()=" + getDSID() + ", getDSUID()=" + getDSUID()
1875 + ", isPresent()=" + isPresent() + ", isValide()=" + isValid() + ", getDisplayID()=" + getDisplayID()
1876 + ", outputMode=" + outputMode + ", getSensorTypes()=" + getSensorTypes() + ", getDeviceSensorValues()="
1877 + getDeviceSensorValues() + ", powerSensorRefresh=" + powerSensorRefreshToString() + "]";