]> git.basschouten.com Git - openhab-addons.git/commitdiff
[digitalSTROM] Shade angle support for GR things (#10444)
authorardanedh <803221+ardanedh@users.noreply.github.com>
Sat, 1 May 2021 12:20:46 +0000 (14:20 +0200)
committerGitHub <noreply@github.com>
Sat, 1 May 2021 12:20:46 +0000 (14:20 +0200)
Signed-off-by: Rouven Schürch <r.schuerch@gmx.ch>
20 files changed:
bundles/org.openhab.binding.digitalstrom/src/main/java/org/openhab/binding/digitalstrom/internal/discovery/SceneDiscoveryService.java
bundles/org.openhab.binding.digitalstrom/src/main/java/org/openhab/binding/digitalstrom/internal/handler/DeviceHandler.java
bundles/org.openhab.binding.digitalstrom/src/main/java/org/openhab/binding/digitalstrom/internal/handler/ZoneTemperatureControlHandler.java
bundles/org.openhab.binding.digitalstrom/src/main/java/org/openhab/binding/digitalstrom/internal/lib/manager/impl/TemperatureControlManager.java
bundles/org.openhab.binding.digitalstrom/src/main/java/org/openhab/binding/digitalstrom/internal/lib/serverconnection/constants/JSONApiResponseKeysEnum.java
bundles/org.openhab.binding.digitalstrom/src/main/java/org/openhab/binding/digitalstrom/internal/lib/structure/devices/Device.java
bundles/org.openhab.binding.digitalstrom/src/main/java/org/openhab/binding/digitalstrom/internal/lib/structure/devices/deviceparameters/constants/ApplicationGroup.java [new file with mode: 0644]
bundles/org.openhab.binding.digitalstrom/src/main/java/org/openhab/binding/digitalstrom/internal/lib/structure/devices/deviceparameters/constants/FuncNameAndColorGroupEnum.java [deleted file]
bundles/org.openhab.binding.digitalstrom/src/main/java/org/openhab/binding/digitalstrom/internal/lib/structure/devices/deviceparameters/constants/FunctionalColorGroupEnum.java [deleted file]
bundles/org.openhab.binding.digitalstrom/src/main/java/org/openhab/binding/digitalstrom/internal/lib/structure/devices/deviceparameters/constants/OutputChannelEnum.java [new file with mode: 0644]
bundles/org.openhab.binding.digitalstrom/src/main/java/org/openhab/binding/digitalstrom/internal/lib/structure/devices/impl/DeviceImpl.java
bundles/org.openhab.binding.digitalstrom/src/main/java/org/openhab/binding/digitalstrom/internal/lib/structure/scene/SceneDiscovery.java
bundles/org.openhab.binding.digitalstrom/src/main/java/org/openhab/binding/digitalstrom/internal/lib/util/DSJsonParser.java [new file with mode: 0644]
bundles/org.openhab.binding.digitalstrom/src/main/java/org/openhab/binding/digitalstrom/internal/providers/DsChannelTypeProvider.java
bundles/org.openhab.binding.digitalstrom/src/test/java/org/openhab/binding/digitalstrom/internal/lib/structure/devices/deviceparameters/constants/ApplicationGroupTest.java [new file with mode: 0644]
bundles/org.openhab.binding.digitalstrom/src/test/java/org/openhab/binding/digitalstrom/internal/lib/structure/devices/deviceparameters/constants/OutputChannelEnumTest.java [new file with mode: 0644]
bundles/org.openhab.binding.digitalstrom/src/test/java/org/openhab/binding/digitalstrom/internal/lib/structure/devices/impl/DeviceImplTest.java [new file with mode: 0644]
bundles/org.openhab.binding.digitalstrom/src/test/java/org/openhab/binding/digitalstrom/internal/lib/util/DSJsonParserTest.java [new file with mode: 0644]
bundles/org.openhab.binding.digitalstrom/src/test/java/org/openhab/binding/digitalstrom/internal/lib/util/JsonModel.java [new file with mode: 0644]
bundles/org.openhab.binding.digitalstrom/src/test/java/org/openhab/binding/digitalstrom/internal/lib/util/OutputChannel.java [new file with mode: 0644]

index c19557f3cdc16e2fd530671f737895fe2b51310e..61e1ae2b8b21ec82621ec59803ba85188058871c 100644 (file)
  */
 package org.openhab.binding.digitalstrom.internal.discovery;
 
-import static org.openhab.binding.digitalstrom.internal.DigitalSTROMBindingConstants.*;
+import static org.openhab.binding.digitalstrom.internal.DigitalSTROMBindingConstants.BINDING_ID;
+import static org.openhab.binding.digitalstrom.internal.DigitalSTROMBindingConstants.GROUP_ID;
+import static org.openhab.binding.digitalstrom.internal.DigitalSTROMBindingConstants.SCENE_ID;
+import static org.openhab.binding.digitalstrom.internal.DigitalSTROMBindingConstants.ZONE_ID;
 
 import java.util.Arrays;
 import java.util.Date;
@@ -21,7 +24,8 @@ import java.util.HashSet;
 import java.util.Map;
 
 import org.openhab.binding.digitalstrom.internal.handler.BridgeHandler;
-import org.openhab.binding.digitalstrom.internal.lib.structure.devices.deviceparameters.constants.FuncNameAndColorGroupEnum;
+import org.openhab.binding.digitalstrom.internal.handler.SceneHandler;
+import org.openhab.binding.digitalstrom.internal.lib.structure.devices.deviceparameters.constants.ApplicationGroup;
 import org.openhab.binding.digitalstrom.internal.lib.structure.scene.InternalScene;
 import org.openhab.binding.digitalstrom.internal.lib.structure.scene.constants.SceneEnum;
 import org.openhab.core.config.discovery.AbstractDiscoveryService;
@@ -119,9 +123,10 @@ public class SceneDiscoveryService extends AbstractDiscoveryService {
     }
 
     private boolean ignoreGroup(Short groupID) {
-        if (FuncNameAndColorGroupEnum.getMode(groupID) != null) {
-            switch (FuncNameAndColorGroupEnum.getMode(groupID)) {
-                case TEMPERATION_CONTROL:
+        ApplicationGroup group = ApplicationGroup.getGroup(groupID);
+        if (group != null) {
+            switch (group) {
+                case TEMPERATURE_CONTROL:
                     return true;
                 default:
                     return false;
index 2225d95d6d371743c069ca4c8c2b54f6901643e9..6228b2c98cd5b05eef8aa6e82e1dcff794bdae7b 100644 (file)
@@ -458,7 +458,8 @@ public class DeviceHandler extends BaseThingHandler implements DeviceStatusListe
                 } else if (this.device.isBlind()) {
                     // load channel for set the angle of jalousie devices
                     String channelTypeID = DsChannelTypeProvider.getOutputChannelTypeID(
-                            ((Device) device).getFunctionalColorGroup(), ((Device) device).getOutputMode());
+                            ((Device) device).getFunctionalColorGroup().getColor(), ((Device) device).getOutputMode(),
+                            ((Device) device).getOutputChannels());
                     loadOutputChannel(new ChannelTypeUID(BINDING_ID, channelTypeID),
                             DsChannelTypeProvider.getItemType(channelTypeID));
                 }
@@ -712,10 +713,11 @@ public class DeviceHandler extends BaseThingHandler implements DeviceStatusListe
         if (!device.isDeviceWithOutput()) {
             loadOutputChannel(null, null);
         }
-        String channelTypeID = DsChannelTypeProvider.getOutputChannelTypeID(device.getFunctionalColorGroup(),
-                device.getOutputMode());
+        String channelTypeID = DsChannelTypeProvider.getOutputChannelTypeID(device.getFunctionalColorGroup().getColor(),
+                device.getOutputMode(), device.getOutputChannels());
         logger.debug("load channel: typeID={}, itemType={}",
-                DsChannelTypeProvider.getOutputChannelTypeID(device.getFunctionalColorGroup(), device.getOutputMode()),
+                DsChannelTypeProvider.getOutputChannelTypeID(device.getFunctionalColorGroup().getColor(),
+                        device.getOutputMode(), device.getOutputChannels()),
                 DsChannelTypeProvider.getItemType(channelTypeID));
         if (channelTypeID != null && (currentChannel == null || !currentChannel.equals(channelTypeID))) {
             loadOutputChannel(new ChannelTypeUID(BINDING_ID, channelTypeID),
index f5f14771d8c3507099ca385fcc09c64ca2971903..bb1bd17df6ca029154ac84d57bd2031fdd4405a4 100644 (file)
@@ -29,7 +29,8 @@ import org.openhab.binding.digitalstrom.internal.lib.climate.jsonresponsecontain
 import org.openhab.binding.digitalstrom.internal.lib.listener.TemperatureControlStatusListener;
 import org.openhab.binding.digitalstrom.internal.lib.manager.StructureManager;
 import org.openhab.binding.digitalstrom.internal.lib.manager.impl.TemperatureControlManager;
-import org.openhab.binding.digitalstrom.internal.lib.structure.devices.deviceparameters.constants.FunctionalColorGroupEnum;
+import org.openhab.binding.digitalstrom.internal.lib.structure.devices.deviceparameters.constants.ApplicationGroup;
+import org.openhab.binding.digitalstrom.internal.lib.structure.devices.deviceparameters.constants.OutputChannelEnum;
 import org.openhab.binding.digitalstrom.internal.lib.structure.devices.deviceparameters.constants.OutputModeEnum;
 import org.openhab.binding.digitalstrom.internal.providers.DsChannelTypeProvider;
 import org.openhab.core.config.core.Configuration;
@@ -280,14 +281,14 @@ public class ZoneTemperatureControlHandler extends BaseThingHandler implements T
                         && (currentChannelID == null
                                 || !currentChannelID.contains(DsChannelTypeProvider.TEMPERATURE_CONTROLLED))
                         && !controlState.equals(ControlStates.EMERGENCY)) {
-                    currentChannelID = DsChannelTypeProvider.getOutputChannelTypeID(FunctionalColorGroupEnum.BLUE,
-                            OutputModeEnum.TEMPRETURE_PWM);
+                    currentChannelID = DsChannelTypeProvider.getOutputChannelTypeID(ApplicationGroup.Color.BLUE,
+                            OutputModeEnum.TEMPRETURE_PWM, new ArrayList<OutputChannelEnum>());
                     loadChannel();
                     currentValue = tempControlStatus.getNominalValue();
                     updateState(currentChannelID, new DecimalType(currentValue.doubleValue()));
                 } else if (!controlMode.equals(ControlModes.PID_CONTROL) && !controlMode.equals(ControlModes.OFF)) {
-                    currentChannelID = DsChannelTypeProvider.getOutputChannelTypeID(FunctionalColorGroupEnum.BLUE,
-                            OutputModeEnum.HEATING_PWM);
+                    currentChannelID = DsChannelTypeProvider.getOutputChannelTypeID(ApplicationGroup.Color.BLUE,
+                            OutputModeEnum.HEATING_PWM, new ArrayList<OutputChannelEnum>());
                     loadChannel();
                     currentValue = tempControlStatus.getControlValue();
                     updateState(currentChannelID, new PercentType(fixPercent(currentValue.intValue())));
index 64d849d6904c6fe80d17bc56db7870c72d38e5a2..43163e07f3cb4bc741b1cc05ceff161839d04ec9 100644 (file)
@@ -30,7 +30,7 @@ import org.openhab.binding.digitalstrom.internal.lib.listener.SystemStateChangeL
 import org.openhab.binding.digitalstrom.internal.lib.listener.TemperatureControlStatusListener;
 import org.openhab.binding.digitalstrom.internal.lib.manager.ConnectionManager;
 import org.openhab.binding.digitalstrom.internal.lib.serverconnection.DsAPI;
-import org.openhab.binding.digitalstrom.internal.lib.structure.devices.deviceparameters.constants.FuncNameAndColorGroupEnum;
+import org.openhab.binding.digitalstrom.internal.lib.structure.devices.deviceparameters.constants.ApplicationGroup;
 import org.openhab.binding.digitalstrom.internal.lib.structure.devices.deviceparameters.constants.SensorEnum;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -406,7 +406,7 @@ public class TemperatureControlManager implements EventHandler, TemperatureContr
     public boolean pushControlValue(Integer zoneID, Float newValue) {
         if (checkAndGetTemperatureControlStatus(zoneID) != null) {
             if (dSapi.pushZoneSensorValue(connectionMananager.getSessionToken(), zoneID, null,
-                    FuncNameAndColorGroupEnum.TEMPERATION_CONTROL.getFunctionalColorGroup(), null, newValue,
+                    ApplicationGroup.TEMPERATURE_CONTROL.getId(), null, newValue,
                     SensorEnum.ROOM_TEMPERATURE_CONTROL_VARIABLE)) {
                 addEcho(zoneID, SensorEnum.ROOM_TEMPERATURE_CONTROL_VARIABLE, newValue);
                 return true;
index 4823ba27393355b51a4b069603a705ecd61ef9f8..b9687537006342f6b4feb962d47c42ae82ad2eca 100644 (file)
@@ -16,11 +16,14 @@ import java.util.List;
 import java.util.Map;
 
 import org.openhab.binding.digitalstrom.internal.lib.config.Config;
+import org.openhab.binding.digitalstrom.internal.lib.event.constants.EventNames;
 import org.openhab.binding.digitalstrom.internal.lib.event.types.EventItem;
+import org.openhab.binding.digitalstrom.internal.lib.sensorjobexecutor.sensorjob.impl.DeviceConsumptionSensorJob;
 import org.openhab.binding.digitalstrom.internal.lib.structure.devices.deviceparameters.DeviceSceneSpec;
 import org.openhab.binding.digitalstrom.internal.lib.structure.devices.deviceparameters.DeviceStateUpdate;
+import org.openhab.binding.digitalstrom.internal.lib.structure.devices.deviceparameters.constants.ApplicationGroup;
 import org.openhab.binding.digitalstrom.internal.lib.structure.devices.deviceparameters.constants.DeviceBinarayInputEnum;
-import org.openhab.binding.digitalstrom.internal.lib.structure.devices.deviceparameters.constants.FunctionalColorGroupEnum;
+import org.openhab.binding.digitalstrom.internal.lib.structure.devices.deviceparameters.constants.OutputChannelEnum;
 import org.openhab.binding.digitalstrom.internal.lib.structure.devices.deviceparameters.constants.OutputModeEnum;
 import org.openhab.binding.digitalstrom.internal.lib.structure.devices.deviceparameters.constants.SensorEnum;
 import org.openhab.binding.digitalstrom.internal.lib.structure.devices.deviceparameters.impl.DSID;
@@ -133,14 +136,14 @@ public interface Device extends GeneralDeviceInformation {
      *
      * @return current functional color group
      */
-    FunctionalColorGroupEnum getFunctionalColorGroup();
+    ApplicationGroup getFunctionalColorGroup();
 
     /**
      * Sets the functional color group of this device.
      *
      * @param fuctionalColorGroup to set
      */
-    void setFunctionalColorGroup(FunctionalColorGroupEnum fuctionalColorGroup);
+    void setFunctionalColorGroup(ApplicationGroup fuctionalColorGroup);
 
     /**
      * Returns the current output mode of this device.
@@ -152,6 +155,8 @@ public interface Device extends GeneralDeviceInformation {
      */
     OutputModeEnum getOutputMode();
 
+    List<OutputChannelEnum> getOutputChannels();
+
     /**
      * Adds an increase command as {@link DeviceStateUpdate} to the list of outstanding commands.
      */
@@ -215,9 +220,9 @@ public interface Device extends GeneralDeviceInformation {
     short getMaxOutputValue();
 
     /**
-     * Returns a list with group id's in which the device is part of.
+     * Returns a list with group ids which the device is part of.
      *
-     * @return List of group id's
+     * @return List of group ids
      */
     List<Short> getGroups();
 
diff --git a/bundles/org.openhab.binding.digitalstrom/src/main/java/org/openhab/binding/digitalstrom/internal/lib/structure/devices/deviceparameters/constants/ApplicationGroup.java b/bundles/org.openhab.binding.digitalstrom/src/main/java/org/openhab/binding/digitalstrom/internal/lib/structure/devices/deviceparameters/constants/ApplicationGroup.java
new file mode 100644 (file)
index 0000000..2581b35
--- /dev/null
@@ -0,0 +1,113 @@
+/**
+ * Copyright (c) 2010-2021 Contributors to the openHAB project
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ */
+package org.openhab.binding.digitalstrom.internal.lib.structure.devices.deviceparameters.constants;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * digitalSTROM Application Groups.
+ * 
+ * <pre>
+    | Group ID | Name                  | Color   | Application                         |
+    | -------- | --------------------- | ------- | ----------------------------------- |
+    | 1        | Lights                | Yellow  | Room lights                         |
+    | 2        | Blinds                | Gray    | Blinds, curtains, shades, awnings   |
+    | 3        | Heating               | Blue    | Heating                             |
+    | 9        | Cooling               | Blue    | Cooling                             |
+    | 10       | Ventilation           | Blue    | Ventilation                         |
+    | 11       | Window                | Blue    | Windows                             |
+    | 12       | Recirculation         | Blue    | Ceiling fan, Fan coil units         |
+    | 64       | Apartment Ventilation | Blue    | Ventilation system                  |
+    | 48       | Temperature Control   | Blue    | Single room temperature control     |
+    | 4        | Audio                 | Cyan    | Playing music or radio              |
+    | 5        | Video                 | Magenta | TV, Video                           |
+    | 8        | Joker                 | Black   | Configurable                        |
+    | n/a      | Single Device         | White   | Various, individual per device      |
+    | n/a      | Security              | Red     | Security related functions, Alarms  |
+    | n/a      | Access                | Green   | Access related functions, door bell |
+ * </pre>
+ * 
+ * @author Rouven Schürch - Initial contribution
+ * @see <a href="https://developer.digitalstrom.org/Architecture/ds-basics.pdf">ds-basics.pdf</a> (Version 1.4/1.6),
+ *      chapter 3.2 (Group), Table 2.
+ *
+ */
+public enum ApplicationGroup {
+
+    LIGHTS((short) 1, Color.YELLOW),
+    BLINDS((short) 2, Color.GREY),
+    HEATING((short) 3, Color.BLUE),
+    COOLING((short) 9, Color.BLUE),
+    VENTILATION((short) 10, Color.BLUE),
+    WINDOW((short) 11, Color.BLUE),
+    RECIRCULATION((short) 12, Color.BLUE),
+    APARTMENT_VENTILATION((short) 64, Color.BLUE),
+    TEMPERATURE_CONTROL((short) 48, Color.BLUE),
+    AUDIO((short) 4, Color.CYAN),
+    VIDEO((short) 5, Color.MAGENTA),
+    JOKER((short) 8, Color.BLACK),
+    SINGLE_DEVICE((short) -1, Color.WHITE),
+    SECURITY((short) -2, Color.RED),
+    ACCESS((short) -3, Color.GREEN),
+    UNDEFINED(null, Color.UNDEFINED);
+
+    public enum Color {
+        YELLOW,
+        GREY,
+        BLUE,
+        CYAN,
+        MAGENTA,
+        BLACK,
+        WHITE,
+        RED,
+        GREEN,
+        UNDEFINED
+    }
+
+    private Short groupId;
+
+    static final Map<Short, ApplicationGroup> APPLICATION_GROUPS = new HashMap<>();
+
+    private Color color;
+
+    static {
+        for (ApplicationGroup applications : ApplicationGroup.values()) {
+            APPLICATION_GROUPS.put(applications.getId(), applications);
+        }
+    }
+
+    private ApplicationGroup(Short groupId, Color color) {
+        this.groupId = groupId;
+        this.color = color;
+    }
+
+    public Short getId() {
+        return groupId;
+    }
+
+    /**
+     * Returns the corresponding ApplicationGroup or ApplicationGroup.UNDEFINED if
+     * there is no ApplicationGroup for the given groupId.
+     * 
+     * @param groupId
+     * @return ApplicationGroup or ApplicationGroup.UNDEFINED
+     */
+    public static ApplicationGroup getGroup(Short groupId) {
+        return APPLICATION_GROUPS.containsKey(groupId) ? APPLICATION_GROUPS.get(groupId) : ApplicationGroup.UNDEFINED;
+    }
+
+    public Color getColor() {
+        return color;
+    }
+}
diff --git a/bundles/org.openhab.binding.digitalstrom/src/main/java/org/openhab/binding/digitalstrom/internal/lib/structure/devices/deviceparameters/constants/FuncNameAndColorGroupEnum.java b/bundles/org.openhab.binding.digitalstrom/src/main/java/org/openhab/binding/digitalstrom/internal/lib/structure/devices/deviceparameters/constants/FuncNameAndColorGroupEnum.java
deleted file mode 100644 (file)
index e8fb506..0000000
+++ /dev/null
@@ -1,115 +0,0 @@
-/**
- * Copyright (c) 2010-2021 Contributors to the openHAB project
- *
- * See the NOTICE file(s) distributed with this work for additional
- * information.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License 2.0 which is available at
- * http://www.eclipse.org/legal/epl-2.0
- *
- * SPDX-License-Identifier: EPL-2.0
- */
-package org.openhab.binding.digitalstrom.internal.lib.structure.devices.deviceparameters.constants;
-
-import java.util.HashMap;
-import java.util.Map;
-
-/**
- * The {@link FuncNameAndColorGroupEnum} contains all digitalSTROM functional group names and links to their
- * {@link FunctionalColorGroupEnum}.
- *
- * @author Michael Ochel - Initial contribution
- * @author Matthias Siegele - Initial contribution
- * @see <a href="http://developer.digitalstrom.org/Architecture/ds-basics.pdf">ds-basics.pdf
- *      "Table 1: digitalSTROM functional groups and their colors", page 9</a>
- */
-public enum FuncNameAndColorGroupEnum {
-    /*
-     * | Number | Name | Color | Function |
-     * --------------------------------------------------------------------------------------
-     * | 1 | Lights | Yellow | Room lights |
-     * | 2 | Blinds | Gray | Blinds or shades outside |
-     * | 12 | Curtains | Gray | Curtains and blinds inside |
-     * | 3 | Heating | Blue | Heating |
-     * | 9 | Cooling | Blue | Cooling |
-     * | 10 | Ventilation | Blue | Ventilation |
-     * | 11 | Window | Blue | Window |
-     * | 48 | Temperature Control | Blue | Single room temperature control |
-     * | 4 | Audio | Cyan | Playing music or radio |
-     * | 5 | Video | Magenta | TV, Video |
-     * | 8 | Joker | Black | Configurable behaviour |
-     * | n/a | Single Device | White | Various, individual per device |
-     * | n/a | Security | Red | Security related functions, Alarms |
-     * | n/a | Access | Green | Access related functions, door bell |
-     *
-     */
-    LIGHTS((short) 1, FunctionalColorGroupEnum.getColorGroup((short) 1)),
-    BLINDS((short) 2, FunctionalColorGroupEnum.getColorGroup((short) 2)),
-    CURTAINS((short) 12, FunctionalColorGroupEnum.getColorGroup((short) 12)),
-    HEATING((short) 3, FunctionalColorGroupEnum.getColorGroup((short) 3)),
-    COOLING((short) 9, FunctionalColorGroupEnum.getColorGroup((short) 9)),
-    VENTILATION((short) 10, FunctionalColorGroupEnum.getColorGroup((short) 10)),
-    WINDOW((short) 11, FunctionalColorGroupEnum.getColorGroup((short) 11)),
-    TEMPERATION_CONTROL((short) 48, FunctionalColorGroupEnum.getColorGroup((short) 48)),
-    AUDIO((short) 4, FunctionalColorGroupEnum.getColorGroup((short) 4)),
-    VIDEO((short) 5, FunctionalColorGroupEnum.getColorGroup((short) 5)),
-    JOKER((short) 8, FunctionalColorGroupEnum.getColorGroup((short) 8)),
-    SINGLE_DEVICE((short) -1, FunctionalColorGroupEnum.getColorGroup((short) -1)),
-    SECURITY((short) -2, FunctionalColorGroupEnum.getColorGroup((short) -2)),
-    ACCESS((short) -3, FunctionalColorGroupEnum.getColorGroup((short) -3));
-
-    private final short colorGroup;
-    private final FunctionalColorGroupEnum color;
-
-    static final Map<Short, FuncNameAndColorGroupEnum> COLOR_GROUPS = new HashMap<>();
-
-    static {
-        for (FuncNameAndColorGroupEnum colorGroup : FuncNameAndColorGroupEnum.values()) {
-            COLOR_GROUPS.put(colorGroup.getFunctionalColorGroup(), colorGroup);
-        }
-    }
-
-    /**
-     * Returns true, if contains the given output mode id in DigitalSTROM, otherwise false.
-     *
-     * @param functionalNameGroupID to be checked
-     * @return true, if contains
-     */
-    public static boolean containsColorGroup(Short functionalNameGroupID) {
-        return COLOR_GROUPS.keySet().contains(functionalNameGroupID);
-    }
-
-    /**
-     * Returns the {@link FuncNameAndColorGroupEnum} of the given functional name group id.
-     *
-     * @param functionalNameGroupID of the {@link FuncNameAndColorGroupEnum}
-     * @return FunctionalNameAndColorGroupEnum
-     */
-    public static FuncNameAndColorGroupEnum getMode(Short functionalNameGroupID) {
-        return COLOR_GROUPS.get(functionalNameGroupID);
-    }
-
-    private FuncNameAndColorGroupEnum(short functionalColorGroupID, FunctionalColorGroupEnum functionalColorGroup) {
-        this.colorGroup = functionalColorGroupID;
-        this.color = functionalColorGroup;
-    }
-
-    /**
-     * Returns the functional name group id form this Object.
-     *
-     * @return functional name group id
-     */
-    public Short getFunctionalColorGroup() {
-        return colorGroup;
-    }
-
-    /**
-     * Returns the {@link FunctionalColorGroupEnum} form this Object.
-     *
-     * @return FunctionalColorGroupEnum
-     */
-    public FunctionalColorGroupEnum getFunctionalColor() {
-        return color;
-    }
-}
diff --git a/bundles/org.openhab.binding.digitalstrom/src/main/java/org/openhab/binding/digitalstrom/internal/lib/structure/devices/deviceparameters/constants/FunctionalColorGroupEnum.java b/bundles/org.openhab.binding.digitalstrom/src/main/java/org/openhab/binding/digitalstrom/internal/lib/structure/devices/deviceparameters/constants/FunctionalColorGroupEnum.java
deleted file mode 100644 (file)
index b9b6be1..0000000
+++ /dev/null
@@ -1,102 +0,0 @@
-/**
- * Copyright (c) 2010-2021 Contributors to the openHAB project
- *
- * See the NOTICE file(s) distributed with this work for additional
- * information.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License 2.0 which is available at
- * http://www.eclipse.org/legal/epl-2.0
- *
- * SPDX-License-Identifier: EPL-2.0
- */
-package org.openhab.binding.digitalstrom.internal.lib.structure.devices.deviceparameters.constants;
-
-import java.util.Arrays;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-/**
- * The {@link FunctionalColorGroupEnum} contains all digitalSTROM functional color groups.
- *
- * @author Michael Ochel - Initial contribution
- * @author Matthias Siegele - Initial contribution
- * @see <a href="http://developer.digitalstrom.org/Architecture/ds-basics.pdf">ds-basics.pdf,
- *      "Table 1: digitalSTROM functional groups and their colors", page 9 [04.09.2015]</a>
- */
-public enum FunctionalColorGroupEnum {
-    /*
-     * | Number | Name | Color | Function |
-     * --------------------------------------------------------------------------------------
-     * | 1 | Lights | Yellow | Room lights |
-     * | 2 | Blinds | Gray | Blinds or shades outside |
-     * | 12 | Curtains | Gray | Curtains and blinds inside |
-     * | 3 | Heating | Blue | Heating |
-     * | 9 | Cooling | Blue | Cooling |
-     * | 10 | Ventilation | Blue | Ventilation |
-     * | 11 | Window | Blue | Window |
-     * | 48 | Temperature Control | Blue | Single room temperature control |
-     * | 4 | Audio | Cyan | Playing music or radio |
-     * | 5 | Video | Magenta | TV, Video |
-     * | 8 | Joker | Black | Configurable behaviour |
-     * | n/a | Single Device | White | Various, individual per device |
-     * | n/a | Security | Red | Security related functions, Alarms |
-     * | n/a | Access | Green | Access related functions, door bell |
-     *
-     */
-    YELLOW(Arrays.asList((short) 1)),
-    GREY(Arrays.asList((short) 2, (short) 12)),
-    BLUE(Arrays.asList((short) 3, (short) 9, (short) 10, (short) 11, (short) 48)),
-    CYAN(Arrays.asList((short) 4)),
-    MAGENTA(Arrays.asList((short) 5)),
-    BLACK(Arrays.asList((short) 8)),
-    WHITE(Arrays.asList((short) -1)),
-    RED(Arrays.asList((short) -2)),
-    GREEN(Arrays.asList((short) -3));
-
-    private final List<Short> colorGroup;
-
-    static final Map<Short, FunctionalColorGroupEnum> COLOR_GROUPS = new HashMap<>();
-
-    static {
-        for (FunctionalColorGroupEnum colorGroup : FunctionalColorGroupEnum.values()) {
-            for (Short colorGroupID : colorGroup.getFunctionalColorGroup()) {
-                COLOR_GROUPS.put(colorGroupID, colorGroup);
-            }
-        }
-    }
-
-    /**
-     * Returns true, if contains the given functional color group id in digitalSTROM exits, otherwise false.
-     *
-     * @param functionalColorGroupID to be checked
-     * @return true, if contains
-     */
-    public static boolean containsColorGroup(Short functionalColorGroupID) {
-        return COLOR_GROUPS.keySet().contains(functionalColorGroupID);
-    }
-
-    /**
-     * Returns the {@link FunctionalColorGroupEnum} of the given color id.
-     *
-     * @param functionalColorGroupID of the {@link FunctionalColorGroupEnum}
-     * @return {@link FunctionalColorGroupEnum} of the id
-     */
-    public static FunctionalColorGroupEnum getColorGroup(Short functionalColorGroupID) {
-        return COLOR_GROUPS.get(functionalColorGroupID);
-    }
-
-    private FunctionalColorGroupEnum(List<Short> functionalColorGroupID) {
-        this.colorGroup = functionalColorGroupID;
-    }
-
-    /**
-     * Returns the functional color group id's as {@link List} of this {@link FunctionalColorGroupEnum}.
-     *
-     * @return functional color group id's
-     */
-    public List<Short> getFunctionalColorGroup() {
-        return colorGroup;
-    }
-}
diff --git a/bundles/org.openhab.binding.digitalstrom/src/main/java/org/openhab/binding/digitalstrom/internal/lib/structure/devices/deviceparameters/constants/OutputChannelEnum.java b/bundles/org.openhab.binding.digitalstrom/src/main/java/org/openhab/binding/digitalstrom/internal/lib/structure/devices/deviceparameters/constants/OutputChannelEnum.java
new file mode 100644 (file)
index 0000000..c6a6723
--- /dev/null
@@ -0,0 +1,145 @@
+/**
+ * Copyright (c) 2010-2021 Contributors to the openHAB project
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ */
+package org.openhab.binding.digitalstrom.internal.lib.structure.devices.deviceparameters.constants;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * The {@link OutputChannelEnum} lists all available digitalSTROM-device output
+ * channels:
+ * 
+ * <pre>
+     | ID  | Description                           | Channel Name                                                         | Min | Max   | Unit                 |
+     | --- | ------------------------------------- | -------------------------------------------------------------------- | --- | ----- | -------------------- |
+     | 1   | Light Brightness                      | brightness                                                           | 0   | 100   | percent              |
+     | 2   | Colored Light Hue                     | hue                                                                  | 0   | 360   | degrees              |
+     | 3   | Colored Light Saturation              | saturation                                                           | 0   | 100   | percent              |
+     | 4   | Color Temperature                     | colortemp                                                            | 100 | 1000  | mired                |
+     | 5   | Light CIE Color Model x               | x                                                                    | 0   | 10000 | scaled to 0.0 to 1.0 |
+     | 6   | Light CIE Color Model y               | y                                                                    | 0   | 10000 | scaled to 0.0 to 1.0 |
+     | 7   | Shade Position Outside (blinds)       | shadePositionOutside                                                 | 0   | 100   | percent              |
+     | 8   | Shade Position Outside (curtains)     | shadePositionIndoor                                                  | 0   | 100   | percent              |
+     | 9   | Shade Opening Angle Outside (blinds)  | shadeOpeningAngleOutside                                             | 0   | 100   | percent              |
+     | 10  | Shade Opening Angle Indoor (curtains) | shadeOpeningAngleIndoor                                              | 0   | 100   | percent              |
+     | 11  | Transparency (e.g. smart glass)       | transparency                                                         | 0   | 100   | percent              |
+     | 12  | Air Flow Intensity                    | airFlowIntensity                                                     | 0   | 100   | percent              |
+     | 13  | Air Flow Direction                    | airFlowDirection - 0=both(undefined), 1=supply, (in),2=exhaust (out) | 0   | 2     | specific             |
+     | 14  | Flap Opening Angle                    | airFlapPosition                                                      | 0   | 100   | percent              |
+     | 15  | Ventilation Louver Position           | airLouverPosition                                                    | 0   | 100   | percent              |
+     | 16  | Heating Power                         | heatingPower                                                         | 0   | 100   | percent              |
+     | 17  | Cooling Capacity                      | coolingCapacity                                                      | 0   | 100   | percent              |
+     | 18  | Audio Volume (loudness)               | audioVolume                                                          | 0   | 100   | percent              |
+     | 19  | Power State                           | powerState - 0=powerOff, 1=powerOn, 2=forcedOff, 3=standby           | 0   | 2     | specific             |
+     | 20  | Ventilation swing mode                | airLouverAuto - 0=not active, 1=active                               | 0   | 1     | specific             |
+     | 21  | Ventilation auto intensity            | airFlowAuto - 0=not active, 1=active                                 | 0   | 1     | specific             |
+     | 22  | Water Temperature                     | waterTemperature                                                     | 0   | 150   | celsius              |
+     | 23  | Water Flow Rate                       | waterFlow                                                            | 0   | 100   | percent              |
+     | 24  | Power Level                           | powerLevel                                                           | 0   | 100   | percent              |
+ * </pre>
+ *
+ * @author Rouven Schürch - Initial contribution
+ * @see <a href="http://developer.digitalstrom.org/Architecture/ds-basics.pdf">ds-basics.pdf</a> (Version 1.4/1.6),
+ *      chapter
+ *      9.1 (Output Channel Types), Table 6: Output channel types
+ */
+public enum OutputChannelEnum {
+
+    BRIGHTNESS(1, "brightness"),
+    HUE(2, "hue"),
+    SATURATION(3, "saturation"),
+    COLORTEMP(4, "colortemp"),
+    X(5, "x"),
+    Y(6, "y"),
+    SHADE_POSITION_OUTSIDE(7, "shadePositionOutside"),
+    SHADE_POSITION_INDOOR(8, "shadePositionIndoor"),
+    SHADE_OPENING_ANGLE_OUTSIDE(9, "shadeOpeningAngleOutside"),
+    SHADE_OPENING_ANGLE_INDOOR(10, "shadeOpeningAngleIndoor"),
+    TRANSPARENCY(11, "transparency"),
+    AIR_FLOW_INTENSITY(12, "airFlowIntensity"),
+    AIR_FLOW_DIRECTION(13, "airFlowDirection"),
+    AIR_FLAP_POSITION(14, "airFlapPosition"),
+    AIR_LOUVER_POSITION(15, "airLouverPosition"),
+    HEATING_POWER(16, "heatingPower"),
+    COOLING_CAPACITY(17, "coolingCapacity"),
+    AUDIO_VOLUME(18, "audioVolume"),
+    POWER_STATE(19, "powerState"),
+    AIR_LOUVER_AUTO(20, "airLouverAuto"),
+    AIR_FLOW_AUTO(21, "airFlowAuto"),
+    WATER_TEMPERATURE(22, "waterTemperature"),
+    WATER_FLOW(23, "waterFlow"),
+    POWER_LEVEL(24, "powerLevel");
+
+    private final int channelId;
+
+    private final String name;
+
+    static final Map<Integer, OutputChannelEnum> OUTPUT_CHANNELS = new HashMap<>();
+
+    static {
+        for (OutputChannelEnum channels : OutputChannelEnum.values()) {
+            OUTPUT_CHANNELS.put(channels.getChannelId(), channels);
+        }
+    }
+
+    /**
+     * Returns true, if the output channel id is contained in digitalSTROM,
+     * otherwise false.
+     *
+     * @param channelID to be checked
+     * @return true, if contains, otherwise false
+     */
+    public static boolean containsChannel(Integer channelID) {
+        return OUTPUT_CHANNELS.keySet().contains(channelID);
+    }
+
+    /**
+     * Returns the {@link OutputChannelEnum} for the given channelID, otherwise
+     * null.
+     *
+     * @param channelID of the {@link OutputChannelEnum}
+     * @return OutputChannelEnum or null
+     */
+    public static OutputChannelEnum getChannel(Integer channelID) {
+        return OUTPUT_CHANNELS.get(channelID);
+    }
+
+    private OutputChannelEnum(int channelId, String name) {
+        this.channelId = channelId;
+        this.name = name;
+    }
+
+    /**
+     * Returns the id of this {@link OutputChannelEnum} object.
+     *
+     * @return mode id
+     */
+    public int getChannelId() {
+        return channelId;
+    }
+
+    /**
+     * 
+     * @return the name of this {@link OutputChannelEnum} object.
+     */
+    public String getName() {
+        return name;
+    }
+
+    public static boolean isShadeChannel(OutputChannelEnum outputChannelEnum) {
+        return outputChannelEnum == OutputChannelEnum.SHADE_OPENING_ANGLE_INDOOR
+                || outputChannelEnum == OutputChannelEnum.SHADE_OPENING_ANGLE_OUTSIDE
+                || outputChannelEnum == OutputChannelEnum.SHADE_POSITION_INDOOR
+                || outputChannelEnum == OutputChannelEnum.SHADE_POSITION_OUTSIDE;
+    }
+}
index 4f7969ca8d7e3ab589ec0deecaecb05cd71fe63a..5d7f937680807cc13d1f585413bbefd9f9511ea0 100644 (file)
@@ -33,10 +33,10 @@ import org.openhab.binding.digitalstrom.internal.lib.structure.devices.Device;
 import org.openhab.binding.digitalstrom.internal.lib.structure.devices.deviceparameters.DeviceConstants;
 import org.openhab.binding.digitalstrom.internal.lib.structure.devices.deviceparameters.DeviceSceneSpec;
 import org.openhab.binding.digitalstrom.internal.lib.structure.devices.deviceparameters.DeviceStateUpdate;
+import org.openhab.binding.digitalstrom.internal.lib.structure.devices.deviceparameters.constants.ApplicationGroup;
 import org.openhab.binding.digitalstrom.internal.lib.structure.devices.deviceparameters.constants.ChangeableDeviceConfigEnum;
 import org.openhab.binding.digitalstrom.internal.lib.structure.devices.deviceparameters.constants.DeviceBinarayInputEnum;
-import org.openhab.binding.digitalstrom.internal.lib.structure.devices.deviceparameters.constants.FuncNameAndColorGroupEnum;
-import org.openhab.binding.digitalstrom.internal.lib.structure.devices.deviceparameters.constants.FunctionalColorGroupEnum;
+import org.openhab.binding.digitalstrom.internal.lib.structure.devices.deviceparameters.constants.OutputChannelEnum;
 import org.openhab.binding.digitalstrom.internal.lib.structure.devices.deviceparameters.constants.OutputModeEnum;
 import org.openhab.binding.digitalstrom.internal.lib.structure.devices.deviceparameters.constants.SensorEnum;
 import org.openhab.binding.digitalstrom.internal.lib.structure.devices.deviceparameters.impl.DSID;
@@ -46,6 +46,7 @@ import org.openhab.binding.digitalstrom.internal.lib.structure.devices.devicepar
 import org.openhab.binding.digitalstrom.internal.lib.structure.devices.deviceparameters.impl.JSONDeviceSceneSpecImpl;
 import org.openhab.binding.digitalstrom.internal.lib.structure.scene.InternalScene;
 import org.openhab.binding.digitalstrom.internal.lib.structure.scene.constants.SceneEnum;
+import org.openhab.binding.digitalstrom.internal.lib.util.DSJsonParser;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -67,10 +68,8 @@ public class DeviceImpl extends AbstractGeneralDeviceInformations implements Dev
 
     private DSID meterDSID;
     private int zoneId = 0;
-    private List<Short> groupList = new LinkedList<>();
+    private List<ApplicationGroup> groupList = new LinkedList<>();
 
-    private FunctionalColorGroupEnum functionalGroup;
-    private FuncNameAndColorGroupEnum functionalName;
     private String hwInfo;
 
     private OutputModeEnum outputMode;
@@ -93,6 +92,7 @@ public class DeviceImpl extends AbstractGeneralDeviceInformations implements Dev
     private final List<DeviceBinaryInput> deviceBinaryInputs = Collections.synchronizedList(new ArrayList<>());
     private final List<SensorEnum> devicePowerSensorTypes = new ArrayList<>();
     private final List<SensorEnum> deviceClimateSensorTypes = new ArrayList<>();
+    private final List<OutputChannelEnum> outputChannels = Collections.synchronizedList(new ArrayList<>());
 
     // for scenes
     private short activeSceneNumber = -1;
@@ -109,11 +109,11 @@ public class DeviceImpl extends AbstractGeneralDeviceInformations implements Dev
     private final List<DeviceStateUpdate> deviceStateUpdates = Collections.synchronizedList(new LinkedList<>());
 
     /*
-     * Saves the refresh priorities and reading initialized flag of power sensors as an matrix.
-     * The first array fields are 0 = active power, 1 = output current, 2 = electric meter, 3 = power consumption and in
-     * each field is a
-     * string array with the fields 0 = refresh priority 1 = reading initial flag (true = reading is initialized,
-     * otherwise false)
+     * Saves the refresh priorities and reading initialized flag of power sensors as
+     * an matrix. The first array fields are 0 = active power, 1 = output current, 2
+     * = electric meter, 3 = power consumption and in each field is a string array
+     * with the fields 0 = refresh priority 1 = reading initial flag (true = reading
+     * is initialized, otherwise false)
      */
     private final Object[] powerSensorRefresh = new Object[] { new String[] { Config.REFRESH_PRIORITY_NEVER, "false" },
             new String[] { Config.REFRESH_PRIORITY_NEVER, "false" },
@@ -128,9 +128,10 @@ public class DeviceImpl extends AbstractGeneralDeviceInformations implements Dev
     public static final int REFRESH_ELECTRIC_METER_ARRAY_FIELD = 2;
     public static final int REFRESH_POWER_CONSUMPTION_ARRAY_FIELD = 3;
     /*
-     * Cache the last power sensor value to get power sensor value directly
-     * the key is the output value and the value is an Integer array for the sensor values (0 = active power, 1 =
-     * output current, 2 = power consumption, 3 = output current high)
+     * Cache the last power sensor value to get power sensor value directly the key
+     * is the output value and the value is an Integer array for the sensor values
+     * (0 = active power, 1 = output current, 2 = power consumption, 3 = output
+     * current high)
      */
     private final Map<Short, Integer[]> cachedSensorPowerValues = Collections.synchronizedMap(new HashMap<>());
 
@@ -139,14 +140,18 @@ public class DeviceImpl extends AbstractGeneralDeviceInformations implements Dev
     public static final int POWER_CONSUMPTION_ARRAY_FIELD = 2;
     public static final int OUTPUT_CURRENT_HIGH_ARRAY_FIELD = 3;
 
-    // Preparing for the advance device property setting "Turn 'switched' output off if value below:", but the
-    // configuration currently not work in digitalSTROM, because of that the value is fix 1.
+    // Preparing for the advance device property setting "Turn 'switched' output off
+    // if value below:", but the
+    // configuration currently not work in digitalSTROM, because of that the value
+    // is fix 1.
     private final int switchPercentOff = 1;
 
     /**
-     * Creates a new {@link DeviceImpl} from the given DigitalSTROM-Device {@link JsonObject}.
+     * Creates a new {@link DeviceImpl} from the given DigitalSTROM-Device
+     * {@link JsonObject}.
      *
-     * @param deviceJsonObject json response of the digitalSTROM-Server, must not be null
+     * @param deviceJsonObject json response of the digitalSTROM-Server, must not be
+     *            null
      */
     public DeviceImpl(JsonObject deviceJsonObject) {
         super(deviceJsonObject);
@@ -178,13 +183,14 @@ public class DeviceImpl extends AbstractGeneralDeviceInformations implements Dev
             JsonArray array = deviceJsonObject.get(JSONApiResponseKeysEnum.GROUPS.getKey()).getAsJsonArray();
             for (int i = 0; i < array.size(); i++) {
                 if (array.get(i) != null) {
-                    initAddGroup(array.get(i).getAsShort());
+                    addGroupToList(array.get(i).getAsShort());
                 }
             }
         } else if (groups != null && groups.isJsonObject()) {
             for (Entry<String, JsonElement> entry : deviceJsonObject.get(JSONApiResponseKeysEnum.GROUPS.getKey())
                     .getAsJsonObject().entrySet()) {
-                initAddGroup(entry.getValue().getAsJsonObject().get(JSONApiResponseKeysEnum.ID.getKey()).getAsShort());
+                addGroupToList(
+                        entry.getValue().getAsJsonObject().get(JSONApiResponseKeysEnum.ID.getKey()).getAsShort());
             }
         }
         if (deviceJsonObject.get(JSONApiResponseKeysEnum.OUTPUT_MODE.getKey()) != null) {
@@ -220,24 +226,14 @@ public class DeviceImpl extends AbstractGeneralDeviceInformations implements Dev
                 }
             }
         }
-        init();
-    }
 
-    private void initAddGroup(Short groupID) {
-        if (groupID != -1) {
-            this.groupList.add(groupID);
-            if (FuncNameAndColorGroupEnum.containsColorGroup(groupID)) {
-                if (this.functionalName == null
-                        || !FuncNameAndColorGroupEnum.getMode(groupID).equals(FuncNameAndColorGroupEnum.JOKER)) {
-                    this.functionalName = FuncNameAndColorGroupEnum.getMode(groupID);
-                    this.functionalGroup = functionalName.getFunctionalColor();
-                }
-            }
-        }
+        outputChannels.addAll(DSJsonParser.getOutputChannels(deviceJsonObject));
+
+        init();
     }
 
     private void init() {
-        if (groupList.contains((short) 1)) {
+        if (groupList.contains(ApplicationGroup.LIGHTS)) {
             maxOutputValue = DeviceConstants.MAX_OUTPUT_VALUE_LIGHT;
             if (this.isDimmable()) {
                 minOutputValue = DeviceConstants.MIN_DIM_VALUE;
@@ -269,21 +265,41 @@ public class DeviceImpl extends AbstractGeneralDeviceInformations implements Dev
 
     @Override
     public List<Short> getGroups() {
-        return new LinkedList<>(groupList);
+        LinkedList<Short> linkedList = new LinkedList<>();
+        groupList.forEach(group -> linkedList.add(group.getId()));
+        return linkedList;
+    }
+
+    /**
+     * Adds the ApplicationGroup of the given groupId to the internal list
+     * 
+     * @param groupID
+     * @return true if the groupId is a valid ApplicationGroup id, false otherwise
+     */
+    private boolean addGroupToList(Short groupID) {
+        ApplicationGroup group = ApplicationGroup.getGroup(groupID);
+        if (ApplicationGroup.UNDEFINED.equals(group)) {
+            logger.warn("Unknown application group with ID '{}' found! Ignoring group", groupID);
+        } else {
+            if (!this.groupList.contains(group)) {
+                this.groupList.add(group);
+            }
+        }
+
+        return group != null;
     }
 
     @Override
     public void addGroup(Short groupID) {
-        if (!this.groupList.contains(groupID)) {
-            this.groupList.add(groupID);
-        }
+        addGroupToList(groupID);
         informListenerAboutConfigChange(ChangeableDeviceConfigEnum.GROUPS);
     }
 
     @Override
     public void setGroups(List<Short> newGroupList) {
         if (newGroupList != null) {
-            this.groupList = newGroupList;
+            groupList.clear();
+            newGroupList.forEach(groupId -> groupList.add(ApplicationGroup.getGroup(groupId)));
         }
         informListenerAboutConfigChange(ChangeableDeviceConfigEnum.GROUPS);
     }
@@ -369,12 +385,12 @@ public class DeviceImpl extends AbstractGeneralDeviceInformations implements Dev
 
     @Override
     public boolean isHeatingDevice() {
-        return functionalName.equals(FuncNameAndColorGroupEnum.HEATING);
+        return groupList.contains(ApplicationGroup.HEATING);
     }
 
     @Override
     public boolean isTemperatureControlledDevice() {
-        return functionalName.equals(FuncNameAndColorGroupEnum.TEMPERATION_CONTROL);
+        return groupList.contains(ApplicationGroup.TEMPERATURE_CONTROL);
     }
 
     @Override
@@ -384,17 +400,19 @@ public class DeviceImpl extends AbstractGeneralDeviceInformations implements Dev
 
     @Override
     public boolean isBlind() {
-        return outputMode.equals(OutputModeEnum.POSITION_CON_US);
+        return (outputMode == OutputModeEnum.POSITION_CON || outputMode == OutputModeEnum.POSITION_CON_US)
+                && (outputChannels.contains(OutputChannelEnum.SHADE_OPENING_ANGLE_INDOOR)
+                        || outputChannels.contains(OutputChannelEnum.SHADE_OPENING_ANGLE_OUTSIDE));
     }
 
     @Override
-    public synchronized FunctionalColorGroupEnum getFunctionalColorGroup() {
-        return this.functionalGroup;
+    public synchronized ApplicationGroup getFunctionalColorGroup() {
+        return groupList.stream().findFirst().get();
     }
 
     @Override
-    public synchronized void setFunctionalColorGroup(FunctionalColorGroupEnum fuctionalColorGroup) {
-        this.functionalGroup = fuctionalColorGroup;
+    public synchronized void setFunctionalColorGroup(ApplicationGroup functionalColorGroup) {
+        groupList.add(functionalColorGroup);
         informListenerAboutConfigChange(ChangeableDeviceConfigEnum.FUNCTIONAL_GROUP);
     }
 
@@ -403,6 +421,11 @@ public class DeviceImpl extends AbstractGeneralDeviceInformations implements Dev
         return outputMode;
     }
 
+    @Override
+    public List<OutputChannelEnum> getOutputChannels() {
+        return outputChannels;
+    }
+
     @Override
     public synchronized void setOutputMode(OutputModeEnum newOutputMode) {
         this.outputMode = newOutputMode;
@@ -1423,7 +1446,8 @@ public class DeviceImpl extends AbstractGeneralDeviceInformations implements Dev
     }
 
     /**
-     * Checks output current sensor to return automatically high output current sensor, if the sensor exists.
+     * Checks output current sensor to return automatically high output current
+     * sensor, if the sensor exists.
      *
      * @param devSenVal
      * @return output current high DeviceSensorValue or the given DeviceSensorValue
@@ -1655,7 +1679,8 @@ public class DeviceImpl extends AbstractGeneralDeviceInformations implements Dev
     }
 
     /**
-     * if an {@link DeviceStatusListener} is registered inform him about the new state otherwise do nothing.
+     * if an {@link DeviceStatusListener} is registered inform him about the new
+     * state otherwise do nothing.
      *
      * @param deviceStateUpdate
      */
@@ -1868,9 +1893,8 @@ public class DeviceImpl extends AbstractGeneralDeviceInformations implements Dev
 
     @Override
     public String toString() {
-        return "DeviceImpl [meterDSID=" + meterDSID + ", zoneId=" + zoneId + ", groupList=" + groupList
-                + ", functionalGroup=" + functionalGroup + ", functionalName=" + functionalName + ", hwInfo=" + hwInfo
-                + ", getName()=" + getName() + ", getDSID()=" + getDSID() + ", getDSUID()=" + getDSUID()
+        return "DeviceImpl [meterDSID=" + meterDSID + ", zoneId=" + zoneId + ", groupList=" + groupList + ", hwInfo="
+                + hwInfo + ", getName()=" + getName() + ", getDSID()=" + getDSID() + ", getDSUID()=" + getDSUID()
                 + ", isPresent()=" + isPresent() + ", isValide()=" + isValid() + ", getDisplayID()=" + getDisplayID()
                 + ", outputMode=" + outputMode + ", getSensorTypes()=" + getSensorTypes() + ", getDeviceSensorValues()="
                 + getDeviceSensorValues() + ", powerSensorRefresh=" + powerSensorRefreshToString() + "]";
index 480600fef9826cbc30c840523689b3330157cf10..320805008de3aa1b53419c763c28dccc741f039d 100644 (file)
@@ -26,7 +26,7 @@ import org.openhab.binding.digitalstrom.internal.lib.manager.SceneManager;
 import org.openhab.binding.digitalstrom.internal.lib.manager.StructureManager;
 import org.openhab.binding.digitalstrom.internal.lib.serverconnection.constants.JSONApiResponseKeysEnum;
 import org.openhab.binding.digitalstrom.internal.lib.serverconnection.impl.JSONResponseHandler;
-import org.openhab.binding.digitalstrom.internal.lib.structure.devices.deviceparameters.constants.FunctionalColorGroupEnum;
+import org.openhab.binding.digitalstrom.internal.lib.structure.devices.deviceparameters.constants.ApplicationGroup;
 import org.openhab.binding.digitalstrom.internal.lib.structure.scene.constants.ApartmentSceneEnum;
 import org.openhab.binding.digitalstrom.internal.lib.structure.scene.constants.SceneEnum;
 import org.openhab.binding.digitalstrom.internal.lib.structure.scene.constants.ZoneSceneEnum;
@@ -263,8 +263,9 @@ public class SceneDiscovery {
                                             groupIdInter = null;
                                         }
                                         if (groupID != null) {
-                                            if (FunctionalColorGroupEnum.getColorGroup(groupID)
-                                                    .equals(FunctionalColorGroupEnum.YELLOW)) {
+
+                                            if (ApplicationGroup.Color.YELLOW
+                                                    .equals(ApplicationGroup.getGroup(groupID).getColor())) {
                                                 discoverScene(SceneEnum.AUTO_OFF.getSceneNumber(), groupID);
                                             }
                                             String response = connectionManager.getHttpTransport()
diff --git a/bundles/org.openhab.binding.digitalstrom/src/main/java/org/openhab/binding/digitalstrom/internal/lib/util/DSJsonParser.java b/bundles/org.openhab.binding.digitalstrom/src/main/java/org/openhab/binding/digitalstrom/internal/lib/util/DSJsonParser.java
new file mode 100644 (file)
index 0000000..cb5c43a
--- /dev/null
@@ -0,0 +1,61 @@
+/**
+ * Copyright (c) 2010-2021 Contributors to the openHAB project
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ */
+package org.openhab.binding.digitalstrom.internal.lib.util;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map.Entry;
+
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.openhab.binding.digitalstrom.internal.lib.serverconnection.constants.JSONApiResponseKeysEnum;
+import org.openhab.binding.digitalstrom.internal.lib.structure.devices.deviceparameters.constants.OutputChannelEnum;
+import org.openhab.binding.digitalstrom.internal.lib.structure.devices.impl.DeviceImpl;
+
+import com.google.gson.JsonArray;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonObject;
+
+/**
+ * digitalSTROM JSON Parser class. Externalizes code from {@link DeviceImpl}
+ *
+ * @author Rouven Schürch - Initial contribution
+ *
+ */
+@NonNullByDefault
+public final class DSJsonParser {
+
+    private DSJsonParser() {
+    }
+
+    public static List<OutputChannelEnum> getOutputChannels(JsonObject jsonObject) {
+        List<OutputChannelEnum> outputChannels = new ArrayList<>();
+        JsonElement jsonOutputChannels = jsonObject.get(JSONApiResponseKeysEnum.OUTPUT_CHANNELS.getKey());
+        if (jsonOutputChannels != null && jsonOutputChannels.isJsonArray()) {
+            JsonArray array = jsonObject.get(JSONApiResponseKeysEnum.OUTPUT_CHANNELS.getKey()).getAsJsonArray();
+            for (int i = 0; i < array.size(); i++) {
+                if (array.get(i) != null) {
+                    int channelId = array.get(i).getAsJsonObject().get("channelID").getAsInt();
+                    outputChannels.add(OutputChannelEnum.getChannel(channelId));
+                }
+            }
+        } else if (jsonOutputChannels != null && jsonOutputChannels.isJsonObject()) {
+            for (Entry<String, JsonElement> entry : jsonObject.get(JSONApiResponseKeysEnum.OUTPUT_CHANNELS.getKey())
+                    .getAsJsonObject().entrySet()) {
+                int channelId = entry.getValue().getAsJsonObject().get("channelID").getAsInt();
+                outputChannels.add(OutputChannelEnum.getChannel(channelId));
+            }
+        }
+
+        return outputChannels;
+    }
+}
index 15480e7ecf4ab1b95337519ffcb37725020854b9..52bdb315b588d4f6242a143c023ef41728ba473c 100644 (file)
@@ -25,10 +25,11 @@ import java.util.Locale;
 import java.util.Set;
 
 import org.openhab.binding.digitalstrom.internal.DigitalSTROMBindingConstants;
+import org.openhab.binding.digitalstrom.internal.lib.structure.devices.deviceparameters.constants.ApplicationGroup;
 import org.openhab.binding.digitalstrom.internal.lib.structure.devices.deviceparameters.constants.DeviceBinarayInputEnum;
-import org.openhab.binding.digitalstrom.internal.lib.structure.devices.deviceparameters.constants.FunctionalColorGroupEnum;
 import org.openhab.binding.digitalstrom.internal.lib.structure.devices.deviceparameters.constants.MeteringTypeEnum;
 import org.openhab.binding.digitalstrom.internal.lib.structure.devices.deviceparameters.constants.MeteringUnitsEnum;
+import org.openhab.binding.digitalstrom.internal.lib.structure.devices.deviceparameters.constants.OutputChannelEnum;
 import org.openhab.binding.digitalstrom.internal.lib.structure.devices.deviceparameters.constants.OutputModeEnum;
 import org.openhab.binding.digitalstrom.internal.lib.structure.devices.deviceparameters.constants.SensorEnum;
 import org.openhab.core.i18n.TranslationProvider;
@@ -47,8 +48,8 @@ import org.osgi.service.component.annotations.Deactivate;
 import org.osgi.service.component.annotations.Reference;
 
 /**
- * The {@link DsChannelTypeProvider} implements the {@link ChannelTypeProvider} generates all supported
- * {@link Channel}'s for digitalSTROM.
+ * The {@link DsChannelTypeProvider} implements the {@link ChannelTypeProvider}
+ * generates all supported {@link Channel}'s for digitalSTROM.
  *
  * @author Michael Ochel - Initial contribution
  * @author Matthias Siegele - Initial contribution
@@ -57,7 +58,8 @@ import org.osgi.service.component.annotations.Reference;
 @Component(service = ChannelTypeProvider.class)
 public class DsChannelTypeProvider extends BaseDsI18n implements ChannelTypeProvider {
 
-    // channelID building (effect group type + (nothing || SEPERATOR + item type || SEPERATOR + extended item type) e.g.
+    // channelID building (effect group type + (nothing || SEPERATOR + item type ||
+    // SEPERATOR + extended item type) e.g.
     // light_switch, shade or shade_angle
     // channel effect group type
     public static final String LIGHT = "light"; // and tag
@@ -112,34 +114,40 @@ public class DsChannelTypeProvider extends BaseDsI18n implements ChannelTypeProv
     public static final String CATEGORY_MOTION = "Motion";
 
     /**
-     * Returns the output channel type id as {@link String} for the given {@link FunctionalColorGroupEnum} and
-     * {@link OutputModeEnum} or null, if no channel type exists for the given {@link FunctionalColorGroupEnum} and
+     * Returns the output channel type id as {@link String} for the given
+     * {@link ApplicationGroup.Color} and {@link OutputModeEnum} or null, if no
+     * channel type exists for the given {@link ApplicationGroup.Color} and
      * {@link OutputModeEnum}.
      *
      * @param functionalGroup of the {@link Device}
      * @param outputMode of the {@link Device}
      * @return the output channel type id or null
      */
-    public static String getOutputChannelTypeID(FunctionalColorGroupEnum functionalGroup, OutputModeEnum outputMode) {
+    public static String getOutputChannelTypeID(ApplicationGroup.Color functionalGroup, OutputModeEnum outputMode,
+            List<OutputChannelEnum> outputChannels) {
         if (functionalGroup != null && outputMode != null) {
             String channelPreID = GENERAL;
-            if (functionalGroup.equals(FunctionalColorGroupEnum.YELLOW)) {
-                channelPreID = LIGHT;
-            }
-            if (functionalGroup.equals(FunctionalColorGroupEnum.GREY)) {
-                if (outputMode.equals(OutputModeEnum.POSITION_CON)) {
-                    return buildIdentifier(SHADE);
-                }
-                if (outputMode.equals(OutputModeEnum.POSITION_CON_US)) {
-                    return buildIdentifier(SHADE, ANGLE);
-                }
-            }
-            if (functionalGroup.equals(FunctionalColorGroupEnum.BLUE)) {
-                channelPreID = HEATING;
-                if (OutputModeEnum.outputModeIsTemperationControlled(outputMode)) {
-                    return buildIdentifier(channelPreID, TEMPERATURE_CONTROLLED);
-                }
+
+            switch (functionalGroup) {
+                case YELLOW:
+                    channelPreID = LIGHT;
+                    break;
+                case GREY:
+                    if (outputChannels != null && (outputChannels.contains(OutputChannelEnum.SHADE_OPENING_ANGLE_INDOOR)
+                            || outputChannels.contains(OutputChannelEnum.SHADE_OPENING_ANGLE_OUTSIDE))) {
+                        return buildIdentifier(SHADE, ANGLE);
+                    } else {
+                        return buildIdentifier(SHADE);
+                    }
+                case BLUE:
+                    channelPreID = HEATING;
+                    if (OutputModeEnum.outputModeIsTemperationControlled(outputMode)) {
+                        return buildIdentifier(channelPreID, TEMPERATURE_CONTROLLED);
+                    }
+                default:
+                    break;
             }
+
             if (OutputModeEnum.outputModeIsSwitch(outputMode)) {
                 return buildIdentifier(channelPreID, SWITCH);
             }
@@ -324,7 +332,8 @@ public class DsChannelTypeProvider extends BaseDsI18n implements ChannelTypeProv
     }
 
     private StateDescriptionFragment getSensorStateDescription(SensorEnum sensorType) {
-        // the digitalSTROM resolution for temperature in kelvin is not correct but sensor-events and cached values are
+        // the digitalSTROM resolution for temperature in kelvin is not correct but
+        // sensor-events and cached values are
         // shown in °C so we will use this unit for temperature sensors
         String unitShortCut = sensorType.getUnitShortcut();
         if (unitShortCut.equals("%")) {
@@ -424,7 +433,8 @@ public class DsChannelTypeProvider extends BaseDsI18n implements ChannelTypeProv
     }
 
     /**
-     * Returns the supported item type for the given channel type id or null, if the channel type does not exist.
+     * Returns the supported item type for the given channel type id or null, if the
+     * channel type does not exist.
      *
      * @param channelTypeID of the channel
      * @return item type or null
@@ -542,7 +552,8 @@ public class DsChannelTypeProvider extends BaseDsI18n implements ChannelTypeProv
     }
 
     /**
-     * Returns the {@link ChannelGroupTypeUID} for the given {@link DeviceBinarayInputEnum}.
+     * Returns the {@link ChannelGroupTypeUID} for the given
+     * {@link DeviceBinarayInputEnum}.
      *
      * @param binaryInputType (must not be null)
      * @return the channel type uid
diff --git a/bundles/org.openhab.binding.digitalstrom/src/test/java/org/openhab/binding/digitalstrom/internal/lib/structure/devices/deviceparameters/constants/ApplicationGroupTest.java b/bundles/org.openhab.binding.digitalstrom/src/test/java/org/openhab/binding/digitalstrom/internal/lib/structure/devices/deviceparameters/constants/ApplicationGroupTest.java
new file mode 100644 (file)
index 0000000..e5a3540
--- /dev/null
@@ -0,0 +1,157 @@
+/**
+ * Copyright (c) 2010-2021 Contributors to the openHAB project
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ */
+package org.openhab.binding.digitalstrom.internal.lib.structure.devices.deviceparameters.constants;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.core.Is.is;
+
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.junit.jupiter.MockitoExtension;
+
+/**
+ * Test class for {@link ApplicationGroup}
+ *
+ * @author Rouven Schürch - Initial contribution
+ *
+ */
+@ExtendWith(MockitoExtension.class)
+@NonNullByDefault
+class ApplicationGroupTest {
+
+    @Test
+    void test1LightsYellow() {
+        ApplicationGroup group = ApplicationGroup.getGroup((short) 1);
+        assertThat(group.getColor(), is(ApplicationGroup.Color.YELLOW));
+        assertThat(group, is(ApplicationGroup.LIGHTS));
+    }
+
+    @Test
+    void test2BlindsGray() {
+        ApplicationGroup group = ApplicationGroup.getGroup((short) 2);
+        assertThat(group.getColor(), is(ApplicationGroup.Color.GREY));
+        assertThat(group, is(ApplicationGroup.BLINDS));
+    }
+
+    @Test
+    void test3HeatingBlue() {
+        ApplicationGroup group = ApplicationGroup.getGroup((short) 3);
+        assertThat(group.getColor(), is(ApplicationGroup.Color.BLUE));
+        assertThat(group, is(ApplicationGroup.HEATING));
+    }
+
+    @Test
+    void test9CoolingBlue() {
+        ApplicationGroup group = ApplicationGroup.getGroup((short) 9);
+        assertThat(group.getColor(), is(ApplicationGroup.Color.BLUE));
+        assertThat(group, is(ApplicationGroup.COOLING));
+    }
+
+    @Test
+    void test10VentilationBlue() {
+        ApplicationGroup group = ApplicationGroup.getGroup((short) 10);
+        assertThat(group.getColor(), is(ApplicationGroup.Color.BLUE));
+        assertThat(group, is(ApplicationGroup.VENTILATION));
+    }
+
+    @Test
+    void test11WindowBlue() {
+        ApplicationGroup group = ApplicationGroup.getGroup((short) 11);
+        assertThat(group.getColor(), is(ApplicationGroup.Color.BLUE));
+        assertThat(group, is(ApplicationGroup.WINDOW));
+    }
+
+    @Test
+    void test12RecirculationBlue() {
+        ApplicationGroup group = ApplicationGroup.getGroup((short) 12);
+        assertThat(group.getColor(), is(ApplicationGroup.Color.BLUE));
+        assertThat(group, is(ApplicationGroup.RECIRCULATION));
+    }
+
+    @Test
+    void test64ApartmentVentilationBlue() {
+        ApplicationGroup group = ApplicationGroup.getGroup((short) 64);
+        assertThat(group.getColor(), is(ApplicationGroup.Color.BLUE));
+        assertThat(group, is(ApplicationGroup.APARTMENT_VENTILATION));
+    }
+
+    @Test
+    void test48TemperatureControlBlue() {
+        ApplicationGroup group = ApplicationGroup.getGroup((short) 48);
+        assertThat(group.getColor(), is(ApplicationGroup.Color.BLUE));
+        assertThat(group, is(ApplicationGroup.TEMPERATURE_CONTROL));
+    }
+
+    @Test
+    void test4AudioCyan() {
+        ApplicationGroup group = ApplicationGroup.getGroup((short) 4);
+        assertThat(group.getColor(), is(ApplicationGroup.Color.CYAN));
+        assertThat(group, is(ApplicationGroup.AUDIO));
+    }
+
+    @Test
+    void test5VideoMagenta() {
+        ApplicationGroup group = ApplicationGroup.getGroup((short) 5);
+        assertThat(group.getColor(), is(ApplicationGroup.Color.MAGENTA));
+        assertThat(group, is(ApplicationGroup.VIDEO));
+    }
+
+    @Test
+    void test8JokerBlack() {
+        ApplicationGroup group = ApplicationGroup.getGroup((short) 8);
+        assertThat(group.getColor(), is(ApplicationGroup.Color.BLACK));
+        assertThat(group, is(ApplicationGroup.JOKER));
+    }
+
+    @Test
+    void testNASingleDeviceWhite() {
+        ApplicationGroup group = ApplicationGroup.getGroup((short) -1);
+        assertThat(group.getColor(), is(ApplicationGroup.Color.WHITE));
+        assertThat(group, is(ApplicationGroup.SINGLE_DEVICE));
+    }
+
+    @Test
+    void testNASecurityRed() {
+        ApplicationGroup group = ApplicationGroup.getGroup((short) -2);
+        assertThat(group.getColor(), is(ApplicationGroup.Color.RED));
+        assertThat(group, is(ApplicationGroup.SECURITY));
+    }
+
+    @Test
+    void testNAAccessGreen() {
+        ApplicationGroup group = ApplicationGroup.getGroup((short) -3);
+        assertThat(group.getColor(), is(ApplicationGroup.Color.GREEN));
+        assertThat(group, is(ApplicationGroup.ACCESS));
+    }
+
+    @Test
+    void testUndefinedGroup100() {
+        ApplicationGroup group = ApplicationGroup.getGroup((short) 100);
+        assertThat(group.getColor(), is(ApplicationGroup.Color.UNDEFINED));
+        assertThat(group, is(ApplicationGroup.UNDEFINED));
+    }
+
+    @Test
+    void testUndefinedGroupNull() {
+        ApplicationGroup group = ApplicationGroup.getGroup(null);
+        assertThat(group.getColor(), is(ApplicationGroup.Color.UNDEFINED));
+        assertThat(group, is(ApplicationGroup.UNDEFINED));
+    }
+
+    @Test
+    void testGetShortId() {
+        Short id = ApplicationGroup.BLINDS.getId();
+        assertThat(ApplicationGroup.getGroup(id).getId(), is(id));
+    }
+}
diff --git a/bundles/org.openhab.binding.digitalstrom/src/test/java/org/openhab/binding/digitalstrom/internal/lib/structure/devices/deviceparameters/constants/OutputChannelEnumTest.java b/bundles/org.openhab.binding.digitalstrom/src/test/java/org/openhab/binding/digitalstrom/internal/lib/structure/devices/deviceparameters/constants/OutputChannelEnumTest.java
new file mode 100644 (file)
index 0000000..acb73d3
--- /dev/null
@@ -0,0 +1,196 @@
+/**
+ * Copyright (c) 2010-2021 Contributors to the openHAB project
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ */
+package org.openhab.binding.digitalstrom.internal.lib.structure.devices.deviceparameters.constants;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.core.Is.is;
+
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.junit.jupiter.api.Test;
+
+/**
+ * Test class for {@link OutputChannelEnum}
+ *
+ * @author Rouven Schürch - Initial contribution
+ *
+ */
+@NonNullByDefault
+class OutputChannelEnumTest {
+    @Test
+    void test1LightBrightness() {
+        OutputChannelEnum outputChannel = OutputChannelEnum.getChannel(1);
+        assertThat(outputChannel, is(OutputChannelEnum.BRIGHTNESS));
+        assertThat(outputChannel.getName(), is("brightness"));
+    }
+
+    @Test
+    void test2Hue() {
+        OutputChannelEnum outputChannel = OutputChannelEnum.getChannel(2);
+        assertThat(outputChannel, is(OutputChannelEnum.HUE));
+        assertThat(outputChannel.getName(), is("hue"));
+    }
+
+    @Test
+    void test3Saturation() {
+        OutputChannelEnum outputChannel = OutputChannelEnum.getChannel(3);
+        assertThat(outputChannel, is(OutputChannelEnum.SATURATION));
+        assertThat(outputChannel.getName(), is("saturation"));
+    }
+
+    @Test
+    void test4Colortemp() {
+        OutputChannelEnum outputChannel = OutputChannelEnum.getChannel(4);
+        assertThat(outputChannel, is(OutputChannelEnum.COLORTEMP));
+        assertThat(outputChannel.getName(), is("colortemp"));
+    }
+
+    @Test
+    void test5X() {
+        OutputChannelEnum outputChannel = OutputChannelEnum.getChannel(5);
+        assertThat(outputChannel, is(OutputChannelEnum.X));
+        assertThat(outputChannel.getName(), is("x"));
+    }
+
+    @Test
+    void test6Y() {
+        OutputChannelEnum outputChannel = OutputChannelEnum.getChannel(6);
+        assertThat(outputChannel, is(OutputChannelEnum.Y));
+        assertThat(outputChannel.getName(), is("y"));
+    }
+
+    @Test
+    void test7ShadePositionOutside() {
+        OutputChannelEnum outputChannel = OutputChannelEnum.getChannel(7);
+        assertThat(outputChannel, is(OutputChannelEnum.SHADE_POSITION_OUTSIDE));
+        assertThat(outputChannel.getName(), is("shadePositionOutside"));
+    }
+
+    @Test
+    void test8ShadePositionIndoor() {
+        OutputChannelEnum outputChannel = OutputChannelEnum.getChannel(8);
+        assertThat(outputChannel, is(OutputChannelEnum.SHADE_POSITION_INDOOR));
+        assertThat(outputChannel.getName(), is("shadePositionIndoor"));
+    }
+
+    @Test
+    void test9ShadeOpeningAngleOutside() {
+        OutputChannelEnum outputChannel = OutputChannelEnum.getChannel(9);
+        assertThat(outputChannel, is(OutputChannelEnum.SHADE_OPENING_ANGLE_OUTSIDE));
+        assertThat(outputChannel.getName(), is("shadeOpeningAngleOutside"));
+    }
+
+    @Test
+    void test10ShadeOpeningAngleIndoor() {
+        OutputChannelEnum outputChannel = OutputChannelEnum.getChannel(10);
+        assertThat(outputChannel, is(OutputChannelEnum.SHADE_OPENING_ANGLE_INDOOR));
+        assertThat(outputChannel.getName(), is("shadeOpeningAngleIndoor"));
+    }
+
+    @Test
+    void test11Transparency() {
+        OutputChannelEnum outputChannel = OutputChannelEnum.getChannel(11);
+        assertThat(outputChannel, is(OutputChannelEnum.TRANSPARENCY));
+        assertThat(outputChannel.getName(), is("transparency"));
+    }
+
+    @Test
+    void test12AirFlowIntensity() {
+        OutputChannelEnum outputChannel = OutputChannelEnum.getChannel(12);
+        assertThat(outputChannel, is(OutputChannelEnum.AIR_FLOW_INTENSITY));
+        assertThat(outputChannel.getName(), is("airFlowIntensity"));
+    }
+
+    @Test
+    void test13AirFlowDirection() {
+        OutputChannelEnum outputChannel = OutputChannelEnum.getChannel(13);
+        assertThat(outputChannel, is(OutputChannelEnum.AIR_FLOW_DIRECTION));
+        assertThat(outputChannel.getName(), is("airFlowDirection"));
+    }
+
+    @Test
+    void test14AirFlapPosition() {
+        OutputChannelEnum outputChannel = OutputChannelEnum.getChannel(14);
+        assertThat(outputChannel, is(OutputChannelEnum.AIR_FLAP_POSITION));
+        assertThat(outputChannel.getName(), is("airFlapPosition"));
+    }
+
+    @Test
+    void test15AirLouverPosition() {
+        OutputChannelEnum outputChannel = OutputChannelEnum.getChannel(15);
+        assertThat(outputChannel, is(OutputChannelEnum.AIR_LOUVER_POSITION));
+        assertThat(outputChannel.getName(), is("airLouverPosition"));
+    }
+
+    @Test
+    void test16HeatingPower() {
+        OutputChannelEnum outputChannel = OutputChannelEnum.getChannel(16);
+        assertThat(outputChannel, is(OutputChannelEnum.HEATING_POWER));
+        assertThat(outputChannel.getName(), is("heatingPower"));
+    }
+
+    @Test
+    void test17CoolingCapacity() {
+        OutputChannelEnum outputChannel = OutputChannelEnum.getChannel(17);
+        assertThat(outputChannel, is(OutputChannelEnum.COOLING_CAPACITY));
+        assertThat(outputChannel.getName(), is("coolingCapacity"));
+    }
+
+    @Test
+    void test18AudioVolume() {
+        OutputChannelEnum outputChannel = OutputChannelEnum.getChannel(18);
+        assertThat(outputChannel, is(OutputChannelEnum.AUDIO_VOLUME));
+        assertThat(outputChannel.getName(), is("audioVolume"));
+    }
+
+    @Test
+    void test19PowerState() {
+        OutputChannelEnum outputChannel = OutputChannelEnum.getChannel(19);
+        assertThat(outputChannel, is(OutputChannelEnum.POWER_STATE));
+        assertThat(outputChannel.getName(), is("powerState"));
+    }
+
+    @Test
+    void test20AirLouverAuto() {
+        OutputChannelEnum outputChannel = OutputChannelEnum.getChannel(20);
+        assertThat(outputChannel, is(OutputChannelEnum.AIR_LOUVER_AUTO));
+        assertThat(outputChannel.getName(), is("airLouverAuto"));
+    }
+
+    @Test
+    void test21AirFlowAuto() {
+        OutputChannelEnum outputChannel = OutputChannelEnum.getChannel(21);
+        assertThat(outputChannel, is(OutputChannelEnum.AIR_FLOW_AUTO));
+        assertThat(outputChannel.getName(), is("airFlowAuto"));
+    }
+
+    @Test
+    void test22WaterTemperature() {
+        OutputChannelEnum outputChannel = OutputChannelEnum.getChannel(22);
+        assertThat(outputChannel, is(OutputChannelEnum.WATER_TEMPERATURE));
+        assertThat(outputChannel.getName(), is("waterTemperature"));
+    }
+
+    @Test
+    void test23WaterFlow() {
+        OutputChannelEnum outputChannel = OutputChannelEnum.getChannel(23);
+        assertThat(outputChannel, is(OutputChannelEnum.WATER_FLOW));
+        assertThat(outputChannel.getName(), is("waterFlow"));
+    }
+
+    @Test
+    void test24PowerLevel() {
+        OutputChannelEnum outputChannel = OutputChannelEnum.getChannel(24);
+        assertThat(outputChannel, is(OutputChannelEnum.POWER_LEVEL));
+        assertThat(outputChannel.getName(), is("powerLevel"));
+    }
+}
diff --git a/bundles/org.openhab.binding.digitalstrom/src/test/java/org/openhab/binding/digitalstrom/internal/lib/structure/devices/impl/DeviceImplTest.java b/bundles/org.openhab.binding.digitalstrom/src/test/java/org/openhab/binding/digitalstrom/internal/lib/structure/devices/impl/DeviceImplTest.java
new file mode 100644 (file)
index 0000000..b3ea80a
--- /dev/null
@@ -0,0 +1,161 @@
+/**
+ * Copyright (c) 2010-2021 Contributors to the openHAB project
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ */
+package org.openhab.binding.digitalstrom.internal.lib.structure.devices.impl;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.core.Is.*;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.junit.jupiter.MockitoExtension;
+import org.openhab.binding.digitalstrom.internal.lib.structure.devices.deviceparameters.constants.OutputChannelEnum;
+import org.openhab.binding.digitalstrom.internal.lib.structure.devices.deviceparameters.constants.OutputModeEnum;
+import org.openhab.binding.digitalstrom.internal.lib.util.JsonModel;
+import org.openhab.binding.digitalstrom.internal.lib.util.OutputChannel;
+
+import com.google.gson.Gson;
+import com.google.gson.JsonObject;
+import com.google.gson.JsonParser;
+
+/**
+ * Test class for certain code in {@link DeviceImpl}
+ *
+ * @author Rouven Schürch - Initial contribution
+ *
+ */
+@ExtendWith(MockitoExtension.class)
+@NonNullByDefault
+class DeviceImplTest {
+
+    private static final List<OutputChannel> EMPTY_CHANNEL = new ArrayList<>();
+
+    private static final List<OutputChannel> SHADE_ANGLE_CHANNELS = Arrays.asList(
+            new OutputChannel(OutputChannelEnum.SHADE_OPENING_ANGLE_OUTSIDE),
+            new OutputChannel(OutputChannelEnum.SHADE_OPENING_ANGLE_INDOOR));
+
+    private static final List<OutputChannel> SHADE_POSITION_CHANNELS = Arrays.asList(
+            new OutputChannel(OutputChannelEnum.SHADE_POSITION_INDOOR),
+            new OutputChannel(OutputChannelEnum.SHADE_POSITION_OUTSIDE));
+
+    private static final List<OutputChannel> NON_SHADE_CHANNEL = Arrays
+            .asList(new OutputChannel(OutputChannelEnum.BRIGHTNESS));
+
+    private static final List<OutputChannel> MIXED_SHADE_CHANNEL = Arrays.asList(
+            new OutputChannel(OutputChannelEnum.BRIGHTNESS),
+            new OutputChannel(OutputChannelEnum.SHADE_OPENING_ANGLE_OUTSIDE));
+
+    @Test
+    void isBlindSwitchShadeChannel() {
+        JsonObject jsonObject = createJsonObject(OutputModeEnum.SINGLE_SWITCH, SHADE_ANGLE_CHANNELS);
+        DeviceImpl deviceImpl = new DeviceImpl(jsonObject);
+        assertThat(deviceImpl.isBlind(), is(false));
+    }
+
+    @Test
+    void isBlindSwitchNoShadeChannel() {
+        JsonObject jsonObject = createJsonObject(OutputModeEnum.SINGLE_SWITCH, NON_SHADE_CHANNEL);
+        DeviceImpl deviceImpl = new DeviceImpl(jsonObject);
+        assertThat(deviceImpl.isBlind(), is(false));
+    }
+
+    @Test
+    void isBlindSwitchMixedShadeChannel() {
+        JsonObject jsonObject = createJsonObject(OutputModeEnum.SINGLE_SWITCH, MIXED_SHADE_CHANNEL);
+        DeviceImpl deviceImpl = new DeviceImpl(jsonObject);
+        assertThat(deviceImpl.isBlind(), is(false));
+    }
+
+    @Test
+    void isBlindPositionConUsNoChannel() {
+        JsonObject jsonObject = createJsonObject(OutputModeEnum.POSITION_CON_US, EMPTY_CHANNEL);
+        DeviceImpl deviceImpl = new DeviceImpl(jsonObject);
+        assertThat(deviceImpl.isBlind(), is(false));
+    }
+
+    @Test
+    void isBlindPositionConUsNonShadeChannel() {
+        JsonObject jsonObject = createJsonObject(OutputModeEnum.POSITION_CON_US, NON_SHADE_CHANNEL);
+        DeviceImpl deviceImpl = new DeviceImpl(jsonObject);
+        assertThat(deviceImpl.isBlind(), is(false));
+    }
+
+    @Test
+    void isBlindPositionConUsShadePositionChannels() {
+        JsonObject jsonObject = createJsonObject(OutputModeEnum.POSITION_CON_US, SHADE_POSITION_CHANNELS);
+        DeviceImpl deviceImpl = new DeviceImpl(jsonObject);
+        assertThat(deviceImpl.isBlind(), is(false));
+    }
+
+    @Test
+    void isBlindPositionConUsShadeAngleChannels() {
+        JsonObject jsonObject = createJsonObject(OutputModeEnum.POSITION_CON_US, SHADE_ANGLE_CHANNELS);
+        DeviceImpl deviceImpl = new DeviceImpl(jsonObject);
+        assertThat(deviceImpl.isBlind(), is(true));
+    }
+
+    @Test
+    void isBlindPositionConUsMixedChannels() {
+        JsonObject jsonObject = createJsonObject(OutputModeEnum.POSITION_CON_US, MIXED_SHADE_CHANNEL);
+        DeviceImpl deviceImpl = new DeviceImpl(jsonObject);
+        assertThat(deviceImpl.isBlind(), is(true));
+    }
+
+    @Test
+    void isBlindPositionConNoChannel() {
+        JsonObject jsonObject = createJsonObject(OutputModeEnum.POSITION_CON, EMPTY_CHANNEL);
+        DeviceImpl deviceImpl = new DeviceImpl(jsonObject);
+        assertThat(deviceImpl.isBlind(), is(false));
+    }
+
+    @Test
+    void isBlindPositionConNonShadeChannel() {
+        JsonObject jsonObject = createJsonObject(OutputModeEnum.POSITION_CON, NON_SHADE_CHANNEL);
+        DeviceImpl deviceImpl = new DeviceImpl(jsonObject);
+        assertThat(deviceImpl.isBlind(), is(false));
+    }
+
+    @Test
+    void isBlindPositionConShadePositionChannels() {
+        JsonObject jsonObject = createJsonObject(OutputModeEnum.POSITION_CON, SHADE_POSITION_CHANNELS);
+        DeviceImpl deviceImpl = new DeviceImpl(jsonObject);
+        assertThat(deviceImpl.isBlind(), is(false));
+    }
+
+    @Test
+    void isBlindPositionConShadeAngleChannels() {
+        JsonObject jsonObject = createJsonObject(OutputModeEnum.POSITION_CON, SHADE_ANGLE_CHANNELS);
+        DeviceImpl deviceImpl = new DeviceImpl(jsonObject);
+        assertThat(deviceImpl.isBlind(), is(true));
+    }
+
+    @Test
+    void isBlindPositionConMixedChannels() {
+        JsonObject jsonObject = createJsonObject(OutputModeEnum.POSITION_CON, MIXED_SHADE_CHANNEL);
+        DeviceImpl deviceImpl = new DeviceImpl(jsonObject);
+        assertThat(deviceImpl.isBlind(), is(true));
+    }
+
+    private static JsonObject createJsonObject(OutputModeEnum outputMode, List<OutputChannel> channels) {
+        JsonModel model = new JsonModel(outputMode.getMode(), channels);
+
+        Gson gson = new Gson();
+        String json = gson.toJson(model);
+
+        return JsonParser.parseString(json).getAsJsonObject();
+    }
+}
diff --git a/bundles/org.openhab.binding.digitalstrom/src/test/java/org/openhab/binding/digitalstrom/internal/lib/util/DSJsonParserTest.java b/bundles/org.openhab.binding.digitalstrom/src/test/java/org/openhab/binding/digitalstrom/internal/lib/util/DSJsonParserTest.java
new file mode 100644 (file)
index 0000000..57ec109
--- /dev/null
@@ -0,0 +1,72 @@
+/**
+ * Copyright (c) 2010-2021 Contributors to the openHAB project
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ */
+package org.openhab.binding.digitalstrom.internal.lib.util;
+
+import static org.hamcrest.MatcherAssert.*;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.contains;
+import static org.hamcrest.collection.IsCollectionWithSize.hasSize;
+
+import java.util.Arrays;
+import java.util.List;
+
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.junit.jupiter.api.Test;
+import org.openhab.binding.digitalstrom.internal.lib.structure.devices.deviceparameters.constants.OutputChannelEnum;
+
+import com.google.gson.Gson;
+import com.google.gson.JsonObject;
+import com.google.gson.JsonParser;
+
+/**
+ * Test class for {@link DSJsonParser}
+ *
+ * @author Rouven Schürch - Initial contribution
+ *
+ */
+@NonNullByDefault
+class DSJsonParserTest {
+
+    @Test
+    void testParseSingleOutputchannels() {
+        JsonObject jsonObject = createJsonObject(Arrays.asList(new OutputChannel(OutputChannelEnum.BRIGHTNESS)));
+
+        List<OutputChannelEnum> channels = DSJsonParser.getOutputChannels(jsonObject);
+        assertThat(channels, contains(OutputChannelEnum.BRIGHTNESS));
+    }
+
+    @Test
+    void testParseMultipleOutputchannels() {
+        JsonObject jsonObject = createJsonObject(Arrays.asList(new OutputChannel(OutputChannelEnum.BRIGHTNESS),
+                new OutputChannel(OutputChannelEnum.AIR_FLAP_POSITION)));
+
+        List<OutputChannelEnum> channels = DSJsonParser.getOutputChannels(jsonObject);
+        assertThat(channels, contains(OutputChannelEnum.BRIGHTNESS, OutputChannelEnum.AIR_FLAP_POSITION));
+    }
+
+    @Test
+    void testParseNoOutputchannels() {
+        JsonObject jsonObject = createJsonObject(Arrays.asList());
+        List<OutputChannelEnum> channels = DSJsonParser.getOutputChannels(jsonObject);
+        assertThat(channels, hasSize(0));
+    }
+
+    private static JsonObject createJsonObject(List<OutputChannel> channels) {
+        JsonModel model = new JsonModel(channels);
+
+        Gson gson = new Gson();
+        String json = gson.toJson(model);
+
+        return JsonParser.parseString(json).getAsJsonObject();
+    }
+}
diff --git a/bundles/org.openhab.binding.digitalstrom/src/test/java/org/openhab/binding/digitalstrom/internal/lib/util/JsonModel.java b/bundles/org.openhab.binding.digitalstrom/src/test/java/org/openhab/binding/digitalstrom/internal/lib/util/JsonModel.java
new file mode 100644 (file)
index 0000000..b0a4592
--- /dev/null
@@ -0,0 +1,43 @@
+/**
+ * Copyright (c) 2010-2021 Contributors to the openHAB project
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ */
+package org.openhab.binding.digitalstrom.internal.lib.util;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.jdt.annotation.NonNullByDefault;
+
+/**
+ * Model used in test cases.
+ *
+ * @author Rouven Schürch - Initial contribution
+ *
+ */
+@NonNullByDefault
+public class JsonModel {
+    public JsonModel(List<OutputChannel> outputChannels) {
+        this(-1, outputChannels);
+    }
+
+    public JsonModel(int outputMode, List<OutputChannel> outputChannels) {
+        this.outputMode = outputMode;
+        this.outputChannels = new ArrayList<>();
+        if (outputChannels != null) {
+            this.outputChannels = outputChannels;
+        }
+    }
+
+    int outputMode;
+
+    List<OutputChannel> outputChannels;
+}
diff --git a/bundles/org.openhab.binding.digitalstrom/src/test/java/org/openhab/binding/digitalstrom/internal/lib/util/OutputChannel.java b/bundles/org.openhab.binding.digitalstrom/src/test/java/org/openhab/binding/digitalstrom/internal/lib/util/OutputChannel.java
new file mode 100644 (file)
index 0000000..4b07de5
--- /dev/null
@@ -0,0 +1,38 @@
+/**
+ * Copyright (c) 2010-2021 Contributors to the openHAB project
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ */
+package org.openhab.binding.digitalstrom.internal.lib.util;
+
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.openhab.binding.digitalstrom.internal.lib.structure.devices.deviceparameters.constants.OutputChannelEnum;
+
+/**
+ * Model used in test cases.
+ *
+ * @author Rouven Schürch - Initial contribution
+ *
+ */
+@NonNullByDefault
+public class OutputChannel {
+    public OutputChannel(OutputChannelEnum outputChannel) {
+        super();
+        this.channelID = outputChannel.getChannelId();
+        this.name = outputChannel.getName();
+        this.id = outputChannel.getName();
+        this.index = outputChannel.getChannelId();
+    }
+
+    int channelID;
+    String name;
+    String id;
+    int index;
+}