]> git.basschouten.com Git - openhab-addons.git/commitdiff
[comfoair] extend UoM support, add semantic tags & update state descriptions (#15167)
authorHans Böhm <boehan@users.noreply.github.com>
Mon, 3 Jul 2023 15:45:45 +0000 (17:45 +0200)
committerGitHub <noreply@github.com>
Mon, 3 Jul 2023 15:45:45 +0000 (17:45 +0200)
* enable UoM for rpm values
* support uom for non-hour time channels
* add state options for frost setting
* add data type for percentage
* support DecimalType for QuantityType channels
* support rfc2217
* improve state description for time channels
* improve code style in DataTypes
* remove unnecessary command type check
* enable UoM for enthalpy timer

Signed-off-by: Hans Böhm <h.boehm@gmx.at>
bundles/org.openhab.binding.comfoair/README.md
bundles/org.openhab.binding.comfoair/src/main/java/org/openhab/binding/comfoair/internal/ComfoAirCommandType.java
bundles/org.openhab.binding.comfoair/src/main/java/org/openhab/binding/comfoair/internal/ComfoAirSerialConnector.java
bundles/org.openhab.binding.comfoair/src/main/java/org/openhab/binding/comfoair/internal/datatypes/DataTypeRPM.java
bundles/org.openhab.binding.comfoair/src/main/java/org/openhab/binding/comfoair/internal/datatypes/DataTypeTemperature.java
bundles/org.openhab.binding.comfoair/src/main/java/org/openhab/binding/comfoair/internal/datatypes/DataTypeTime.java
bundles/org.openhab.binding.comfoair/src/main/java/org/openhab/binding/comfoair/internal/datatypes/DataTypeVolt.java
bundles/org.openhab.binding.comfoair/src/main/resources/OH-INF/i18n/comfoair.properties
bundles/org.openhab.binding.comfoair/src/main/resources/OH-INF/thing/thing-types.xml
bundles/org.openhab.binding.comfoair/src/main/resources/OH-INF/update/instructions.xml [new file with mode: 0644]

index 2baa6b2ac59d879e395e2f87da5b76694bce3ecb..1b20b8ba8404b882e4837c429629cbb8a5e10e7b 100644 (file)
@@ -69,8 +69,8 @@ The ComfoAir binding supports the following channels.
 | ventilation#fanIn3                 | Number                   | Fan In Level 3                  | Fan level 3 performance (%) of incoming fan                                                 | false     | yes      |
 | ventilation#fanInPercent           | Number                   | Fan In (%)                      | Current relative speed (%) of incoming fan                                                  | false     | yes      |
 | ventilation#fanOutPercent          | Number                   | Fan Out (%)                     | Current relative speed (%) of outgoing fan                                                  | true      | yes      |
-| ventilation#fanInRPM               | Number                   | Fan In (rpm)                    | Current absolute speed (rpm) of incoming fan                                                | true      | yes      |
-| ventilation#fanOutRPM              | Number                   | Fan Out (rpm)                   | Current absolute speed (rpm) of outgoing fan                                                | true      | yes      |
+| ventilation#fanInRPM               | Number:Frequency         | Fan In (rpm)                    | Current absolute speed (rpm) of incoming fan                                                | true      | yes      |
+| ventilation#fanOutRPM              | Number:Frequency         | Fan Out (rpm)                   | Current absolute speed (rpm) of outgoing fan                                                | true      | yes      |
 | **Temperature Values**             |                          |                                 |                                                                                             |           |          |
 | temperatures#targetTemperature     | Number:Temperature       | Target Temperature              | Target (comfort) temperature                                                                | false     | no       |
 | temperatures#outdoorTemperatureIn  | Number:Temperature       | Outdoor Temperature Incoming    | Intake air temperature (outside)                                                            | true      | yes      |
@@ -108,14 +108,14 @@ The ComfoAir binding supports the following channels.
 | menuP1#menu28Mode                  | Switch                   | Menu 28 Mode (P18)              | State of menu 28 mode (P18)                                                                 | true      | yes      |
 | menuP1#menu29Mode                  | Switch                   | Menu 29 Mode (P19)              | State of menu 29 mode (P19)                                                                 | true      | yes      |
 | **Menu P2: Delay Settings**        |                          |                                 |                                                                                             |           |          |
-| menuP2#bathroomStartDelay          | Number                   | Menu P21                        | Start delay for bathroom switch (min)                                                       | false     | yes      |
-| menuP2#bathroomEndDelay            | Number                   | Menu P22                        | End delay for bathroom switch (min)                                                         | false     | yes      |
-| menuP2#L1EndDelay                  | Number                   | Menu P23                        | End delay for L1 switch (min)                                                               | false     | yes      |
-| menuP2#pulseVentilation            | Number                   | Menu P27                        | Period for pulse ventilation (min)                                                          | false     | yes      |
-| menuP2#filterWeeks                 | Number                   | Menu P24                        | Usage period until filter pollution message (weeks)                                         | false     | yes      |
-| menuP2#RFShortDelay                | Number                   | Menu P25                        | End delay (RF short actuation) for ventilation level 3 (min)                                | false     | yes      |
-| menuP2#RFLongDelay                 | Number                   | Menu P26                        | End delay (RF long actuation) for ventilation level 3 (min)                                 | false     | yes      |
-| menuP2#cookerhoodDelay             | Number                   | Menu P20                        | End delay for cooker hood control (min)                                                     | false     | yes      |
+| menuP2#bathroomStartDelay          | Number:Time              | Menu P21                        | Start delay for bathroom switch (uses minutes internally)                                   | false     | yes      |
+| menuP2#bathroomEndDelay            | Number:Time              | Menu P22                        | End delay for bathroom switch (uses minutes internally)                                     | false     | yes      |
+| menuP2#L1EndDelay                  | Number:Time              | Menu P23                        | End delay for L1 switch (uses minutes internally)                                           | false     | yes      |
+| menuP2#pulseVentilation            | Number:Time              | Menu P27                        | Period for pulse ventilation (uses minutes internally)                                      | false     | yes      |
+| menuP2#filterWeeks                 | Number:Time              | Menu P24                        | Usage period until filter pollution message (uses weeks internally)                         | false     | yes      |
+| menuP2#RFShortDelay                | Number:Time              | Menu P25                        | End delay (RF short actuation) for ventilation level 3 (uses minutes internally)            | false     | yes      |
+| menuP2#RFLongDelay                 | Number:Time              | Menu P26                        | End delay (RF long actuation) for ventilation level 3 (uses minutes internally)             | false     | yes      |
+| menuP2#cookerhoodDelay             | Number:Time              | Menu P20                        | End delay for cooker hood control (uses minutes internally)                                 | false     | yes      |
 | **Menu P9: Option States**         |                          |                                 |                                                                                             |           |          |
 | menuP9#chimneyState                | Switch                   | Chimney Control State           | State of the chimney control                                                                | true      | yes      |
 | menuP9#bypassState                 | Switch                   | Bypass State                    | State of the bypass (ON = open / OFF = closed)                                              | true      | yes      |
@@ -140,7 +140,7 @@ The ComfoAir binding supports the following channels.
 | preheater#preheaterValve           | Number                   | Preheater Valve                 | State of the preheater valve                                                                | true      | yes      |
 | preheater#preheaterFrostProtect    | Switch                   | Frost Protection                | State of the frost protection                                                               | true      | yes      |
 | preheater#preheaterHeating         | Switch                   | Preheater                       | State of the preheater                                                                      | true      | yes      |
-| preheater#preheaterFrostTime       | Number                   | Preheater Frost Time            | Frost minutes                                                                               | true      | yes      |
+| preheater#preheaterFrostTime       | Number:Time              | Preheater Frost Time            | Frost minutes                                                                               | true      | yes      |
 | preheater#preheaterSafety          | Number                   | Preheater Frost Safety          | Frost safety setting                                                                        | true      | yes      |
 | **GHX Values**                     |                          |                                 |                                                                                             |           |          |
 | ewt#ewtTemperatureLow              | Number:Temperature       | GHX Temperature (low)           | Lower temperature of the geothermal heat exchanger                                          | true      | yes      |
@@ -156,7 +156,7 @@ The ComfoAir binding supports the following channels.
 | enthalpy#enthalpyTemperature       | Number:Temperature       | Enthalpy Sensor Temperature     | Temperature of the enthalpy sensor                                                          | true      | yes      |
 | enthalpy#enthalpyHumidity          | Number                   | Enthalpy Sensor Humidity        | Humidity of the enthalpy sensor                                                             | true      | yes      |
 | enthalpy#enthalpyLevel             | Number                   | Enthalpy Sensor Level           | Level of the enthalpy sensor                                                                | true      | yes      |
-| enthalpy#enthalpyTime              | Number                   | Enthalpy Sensor Timer           | Timer state of the enthalpy sensor                                                          | true      | yes      |
+| enthalpy#enthalpyTime              | Number:Time              | Enthalpy Sensor Timer           | Timer state of the enthalpy sensor                                                          | true      | yes      |
 | **Option Settings**                |                          |                                 |                                                                                             |           |          |
 | options#isPreheater                | Switch                   | Preheater                       | Preheater option installed                                                                  | true      | yes      |
 | options#isBypass                   | Switch                   | Bypass                          | Bypass option installed                                                                     | true      | yes      |
index efd0b4494e1bc74fa09ffb17d6edda5ff86a6379..0735c6f472abffaf686f186e5885ee43d2ba2c84 100644 (file)
@@ -30,10 +30,8 @@ import org.openhab.binding.comfoair.internal.datatypes.DataTypeTemperature;
 import org.openhab.binding.comfoair.internal.datatypes.DataTypeTime;
 import org.openhab.binding.comfoair.internal.datatypes.DataTypeVolt;
 import org.openhab.core.library.types.DecimalType;
-import org.openhab.core.library.types.QuantityType;
 import org.openhab.core.types.Command;
 import org.openhab.core.types.State;
-import org.openhab.core.types.UnDefType;
 
 /**
  * Represents all valid commands which could be processed by this binding
@@ -107,28 +105,28 @@ public enum ComfoAirCommandType {
             DataTypeBoolean.getInstance(), Constants.REQUEST_GET_STATES, Constants.REPLY_GET_STATES, new int[] { 7 },
             0x02),
     BATHROOM_START_DELAY(ComfoAirBindingConstants.CG_MENUP2_PREFIX + ComfoAirBindingConstants.CHANNEL_BR_START_DELAY,
-            DataTypeNumber.getInstance(), Constants.REQUEST_SET_DELAYS, 8, 0, new ComfoAirCommandType[] { MENU21_MODE },
+            DataTypeTime.getInstance(), Constants.REQUEST_SET_DELAYS, 8, 0, new ComfoAirCommandType[] { MENU21_MODE },
             Constants.REQUEST_GET_DELAYS, Constants.REPLY_GET_DELAYS, new int[] { 0 }),
     BATHROOM_END_DELAY(ComfoAirBindingConstants.CG_MENUP2_PREFIX + ComfoAirBindingConstants.CHANNEL_BR_END_DELAY,
-            DataTypeNumber.getInstance(), Constants.REQUEST_SET_DELAYS, 8, 1, new ComfoAirCommandType[] { MENU22_MODE },
+            DataTypeTime.getInstance(), Constants.REQUEST_SET_DELAYS, 8, 1, new ComfoAirCommandType[] { MENU22_MODE },
             Constants.REQUEST_GET_DELAYS, Constants.REPLY_GET_DELAYS, new int[] { 1 }),
     L1_END_DELAY(ComfoAirBindingConstants.CG_MENUP2_PREFIX + ComfoAirBindingConstants.CHANNEL_L1_END_DELAY,
-            DataTypeNumber.getInstance(), Constants.REQUEST_SET_DELAYS, 8, 2, new ComfoAirCommandType[] { MENU27_MODE },
+            DataTypeTime.getInstance(), Constants.REQUEST_SET_DELAYS, 8, 2, new ComfoAirCommandType[] { MENU27_MODE },
             Constants.REQUEST_GET_DELAYS, Constants.REPLY_GET_DELAYS, new int[] { 2 }),
     PULSE_VENTILATION(ComfoAirBindingConstants.CG_MENUP2_PREFIX + ComfoAirBindingConstants.CHANNEL_PULSE_VENTILATION,
-            DataTypeNumber.getInstance(), Constants.REQUEST_SET_DELAYS, 8, 3, new ComfoAirCommandType[] { MENU23_MODE },
+            DataTypeTime.getInstance(), Constants.REQUEST_SET_DELAYS, 8, 3, new ComfoAirCommandType[] { MENU23_MODE },
             Constants.REQUEST_GET_DELAYS, Constants.REPLY_GET_DELAYS, new int[] { 3 }),
     FILTER_WEEKS(ComfoAirBindingConstants.CG_MENUP2_PREFIX + ComfoAirBindingConstants.CHANNEL_FILTER_WEEKS,
-            DataTypeNumber.getInstance(), Constants.REQUEST_SET_DELAYS, 8, 4, new ComfoAirCommandType[] { MENU24_MODE },
+            DataTypeTime.getInstance(), Constants.REQUEST_SET_DELAYS, 8, 4, new ComfoAirCommandType[] { MENU24_MODE },
             Constants.REQUEST_GET_DELAYS, Constants.REPLY_GET_DELAYS, new int[] { 4 }),
     RF_SHORT_DELAY(ComfoAirBindingConstants.CG_MENUP2_PREFIX + ComfoAirBindingConstants.CHANNEL_RF_SHORT_DELAY,
-            DataTypeNumber.getInstance(), Constants.REQUEST_SET_DELAYS, 8, 5, new ComfoAirCommandType[] { MENU25_MODE },
+            DataTypeTime.getInstance(), Constants.REQUEST_SET_DELAYS, 8, 5, new ComfoAirCommandType[] { MENU25_MODE },
             Constants.REQUEST_GET_DELAYS, Constants.REPLY_GET_DELAYS, new int[] { 5 }),
     RF_LONG_DELAY(ComfoAirBindingConstants.CG_MENUP2_PREFIX + ComfoAirBindingConstants.CHANNEL_RF_LONG_DELAY,
-            DataTypeNumber.getInstance(), Constants.REQUEST_SET_DELAYS, 8, 6, new ComfoAirCommandType[] { MENU26_MODE },
+            DataTypeTime.getInstance(), Constants.REQUEST_SET_DELAYS, 8, 6, new ComfoAirCommandType[] { MENU26_MODE },
             Constants.REQUEST_GET_DELAYS, Constants.REPLY_GET_DELAYS, new int[] { 6 }),
     COOKERHOOD_DELAY(ComfoAirBindingConstants.CG_MENUP2_PREFIX + ComfoAirBindingConstants.CHANNEL_COOKERHOOD_DELAY,
-            DataTypeNumber.getInstance(), Constants.REQUEST_SET_DELAYS, 8, 7, new ComfoAirCommandType[] { MENU20_MODE },
+            DataTypeTime.getInstance(), Constants.REQUEST_SET_DELAYS, 8, 7, new ComfoAirCommandType[] { MENU20_MODE },
             Constants.REQUEST_GET_DELAYS, Constants.REPLY_GET_DELAYS, new int[] { 7 }),
     CHIMNEY_STATE(ComfoAirBindingConstants.CG_MENUP9_PREFIX + ComfoAirBindingConstants.CHANNEL_CHIMNEY_STATE,
             DataTypeBoolean.getInstance(), Constants.REQUEST_GET_STATES, Constants.REPLY_GET_STATES, new int[] { 8 },
@@ -229,7 +227,7 @@ public enum ComfoAirCommandType {
     ENTHALPY_LEVEL(ComfoAirBindingConstants.CG_ENTHALPY_PREFIX + ComfoAirBindingConstants.CHANNEL_ENTHALPY_LEVEL,
             DataTypeNumber.getInstance(), Constants.REQUEST_GET_SENSORS, Constants.REPLY_GET_SENSORS, new int[] { 4 }),
     ENTHALPY_TIME(ComfoAirBindingConstants.CG_ENTHALPY_PREFIX + ComfoAirBindingConstants.CHANNEL_ENTHALPY_TIME,
-            DataTypeNumber.getInstance(), Constants.REQUEST_GET_SENSORS, Constants.REPLY_GET_SENSORS, new int[] { 5 }),
+            DataTypeTime.getInstance(), Constants.REQUEST_GET_SENSORS, Constants.REPLY_GET_SENSORS, new int[] { 5 }),
     PREHEATER_VALVE(ComfoAirBindingConstants.CG_PREHEATER_PREFIX + ComfoAirBindingConstants.CHANNEL_PREHEATER_VALVE,
             DataTypeNumber.getInstance(), Constants.REQUEST_GET_PREHEATER, Constants.REPLY_GET_PREHEATER,
             new int[] { 0 }),
@@ -242,7 +240,7 @@ public enum ComfoAirCommandType {
             new int[] { 2 }),
     PREHEATER_FROST_TIME(
             ComfoAirBindingConstants.CG_PREHEATER_PREFIX + ComfoAirBindingConstants.CHANNEL_PREHEATER_FROST_TIME,
-            DataTypeNumber.getInstance(), Constants.REQUEST_GET_PREHEATER, Constants.REPLY_GET_PREHEATER,
+            DataTypeTime.getInstance(), Constants.REQUEST_GET_PREHEATER, Constants.REPLY_GET_PREHEATER,
             new int[] { 3, 4 }),
     PREHEATER_OPTION(ComfoAirBindingConstants.CG_PREHEATER_PREFIX + ComfoAirBindingConstants.CHANNEL_PREHEATER_SAFETY,
             DataTypeNumber.getInstance(), Constants.REQUEST_GET_PREHEATER, Constants.REPLY_GET_PREHEATER,
@@ -786,29 +784,22 @@ public enum ComfoAirCommandType {
      *            new state
      * @return initialized ComfoAirCommand
      */
-    @SuppressWarnings("PMD.CompareObjectsWithEquals")
     public static @Nullable ComfoAirCommand getChangeCommand(String key, Command command) {
         ComfoAirCommandType commandType = getCommandTypeByKey(key);
-        State value = UnDefType.NULL;
 
         if (commandType != null) {
             ComfoAirDataType dataType = commandType.getDataType();
-            if (dataType == DataTypeBoolean.getInstance() || dataType == DataTypeNumber.getInstance()
-                    || dataType == DataTypeRPM.getInstance() || command instanceof QuantityType<?>) {
-                value = (State) command;
-            }
-            if (value instanceof UnDefType) {
-                return null;
-            } else {
-                int[] data = dataType.convertFromState(value, commandType);
-                DecimalType decimalValue = value.as(DecimalType.class);
-                if (decimalValue != null) {
-                    int intValue = decimalValue.intValue();
-
-                    if (data != null) {
-                        int dataPosition = commandType.getChangeDataPos();
-                        return new ComfoAirCommand(key, commandType.changeCommand, null, data, dataPosition, intValue);
-                    }
+
+            State value = (State) command;
+
+            int[] data = dataType.convertFromState(value, commandType);
+            DecimalType decimalValue = value.as(DecimalType.class);
+            if (decimalValue != null) {
+                int intValue = decimalValue.intValue();
+
+                if (data != null) {
+                    int dataPosition = commandType.getChangeDataPos();
+                    return new ComfoAirCommand(key, commandType.changeCommand, null, data, dataPosition, intValue);
                 }
             }
         }
index 1d02cfaddcc0279955fdc107a34b3eddea57304c..4faf375b2b3dab390c69597ea2107d84973ec992 100644 (file)
@@ -79,9 +79,19 @@ public class ComfoAirSerialConnector {
                 SerialPort serialPort = portIdentifier.open(this.getClass().getName(), 3000);
                 serialPort.setSerialPortParams(baudRate, SerialPort.DATABITS_8, SerialPort.STOPBITS_1,
                         SerialPort.PARITY_NONE);
-                serialPort.enableReceiveThreshold(1);
-                serialPort.enableReceiveTimeout(1000);
                 serialPort.notifyOnDataAvailable(true);
+
+                try {
+                    serialPort.enableReceiveThreshold(1);
+                } catch (UnsupportedCommOperationException e) {
+                    logger.debug("Enable receive threshold is unsupported");
+                }
+                try {
+                    serialPort.enableReceiveTimeout(1000);
+                } catch (UnsupportedCommOperationException e) {
+                    logger.debug("Enable receive timeout is unsupported");
+                }
+
                 this.serialPort = serialPort;
 
                 inputStream = new DataInputStream(new BufferedInputStream(serialPort.getInputStream()));
index ba26711a0ecf95836a33178439b95060fcf3205e..ed097402f1a9dccda2e72212d37a08d1b76e3a7e 100644 (file)
@@ -16,6 +16,8 @@ import org.eclipse.jdt.annotation.NonNullByDefault;
 import org.eclipse.jdt.annotation.Nullable;
 import org.openhab.binding.comfoair.internal.ComfoAirCommandType;
 import org.openhab.core.library.types.DecimalType;
+import org.openhab.core.library.types.QuantityType;
+import org.openhab.core.library.unit.Units;
 import org.openhab.core.types.State;
 import org.openhab.core.types.UnDefType;
 import org.slf4j.Logger;
@@ -52,20 +54,32 @@ public class DataTypeRPM implements ComfoAirDataType {
                 return UnDefType.NULL;
             }
             // transferred value is (1875000 / rpm) per protocol
-            return new DecimalType((int) (1875000.0 / value));
+            return new QuantityType<>((int) (1875000.0 / value), Units.RPM);
         }
     }
 
     @Override
     public int @Nullable [] convertFromState(State value, ComfoAirCommandType commandType) {
-        if (value instanceof UnDefType) {
+        int[] template = commandType.getChangeDataTemplate();
+        float rpm;
+
+        if (value instanceof QuantityType<?> qt) {
+            QuantityType<?> qtRpm = ((QuantityType<?>) value).toUnit(Units.RPM);
+
+            if (qtRpm != null) {
+                rpm = qtRpm.floatValue();
+            } else {
+                return null;
+            }
+        } else if (value instanceof DecimalType dt) {
+            rpm = dt.floatValue();
+        } else {
             logger.trace("\"DataTypeRPM\" class \"convertFromState\" undefined state");
             return null;
-        } else {
-            int[] template = commandType.getChangeDataTemplate();
-            // transferred value is (1875000 / rpm) per protocol
-            template[commandType.getChangeDataPos()] = (int) (1875000 / ((DecimalType) value).doubleValue());
-            return template;
         }
+
+        // transferred value is (1875000 / rpm) per protocol
+        template[commandType.getChangeDataPos()] = (int) (1875000 / rpm);
+        return template;
     }
 }
index cd4cd3c407937aa0a58f63a36493b6a783df55eb..f0a49be11f963891eb0ae894f21632454442788a 100644 (file)
@@ -15,6 +15,7 @@ package org.openhab.binding.comfoair.internal.datatypes;
 import org.eclipse.jdt.annotation.NonNullByDefault;
 import org.eclipse.jdt.annotation.Nullable;
 import org.openhab.binding.comfoair.internal.ComfoAirCommandType;
+import org.openhab.core.library.types.DecimalType;
 import org.openhab.core.library.types.QuantityType;
 import org.openhab.core.library.unit.SIUnits;
 import org.openhab.core.types.State;
@@ -63,18 +64,28 @@ public class DataTypeTemperature implements ComfoAirDataType {
     @Override
     public int @Nullable [] convertFromState(State value, ComfoAirCommandType commandType) {
         int[] template = commandType.getChangeDataTemplate();
-        QuantityType<?> celsius = ((QuantityType<?>) value).toUnit(SIUnits.CELSIUS);
+        float celsius;
 
-        if (celsius != null) {
-            if (commandType.getReadCommand() == ComfoAirCommandType.Constants.REQUEST_GET_GHX) {
-                template[commandType.getChangeDataPos()] = celsius.intValue();
+        if (value instanceof QuantityType<?> qt) {
+            QuantityType<?> qtCelsius = qt.toUnit(SIUnits.CELSIUS);
+
+            if (qtCelsius != null) {
+                celsius = qtCelsius.floatValue();
             } else {
-                template[commandType.getChangeDataPos()] = (int) (celsius.doubleValue() + 20) * 2;
+                return null;
             }
-            return template;
+        } else if (value instanceof DecimalType dt) {
+            celsius = dt.floatValue();
         } else {
             logger.trace("\"DataTypeTemperature\" class \"convertFromState\" undefined state");
             return null;
         }
+
+        if (commandType.getReadCommand() == ComfoAirCommandType.Constants.REQUEST_GET_GHX) {
+            template[commandType.getChangeDataPos()] = (int) celsius;
+        } else {
+            template[commandType.getChangeDataPos()] = (int) (celsius + 20) * 2;
+        }
+        return template;
     }
 }
index cf2cde002b11c4a5f391fab915896f5702b5c946..d8d1d7294fb71c4e574d3b91a131ebf42977af52 100644 (file)
@@ -15,6 +15,7 @@ package org.openhab.binding.comfoair.internal.datatypes;
 import org.eclipse.jdt.annotation.NonNullByDefault;
 import org.eclipse.jdt.annotation.Nullable;
 import org.openhab.binding.comfoair.internal.ComfoAirCommandType;
+import org.openhab.core.library.types.DecimalType;
 import org.openhab.core.library.types.QuantityType;
 import org.openhab.core.library.unit.Units;
 import org.openhab.core.types.State;
@@ -52,6 +53,16 @@ public class DataTypeTime implements ComfoAirDataType {
                 return UnDefType.NULL;
             }
 
+            if (commandType.getReadCommand() == ComfoAirCommandType.Constants.REQUEST_GET_DELAYS
+                    || commandType.getReadCommand() == ComfoAirCommandType.Constants.REQUEST_GET_PREHEATER) {
+                if (commandType == ComfoAirCommandType.FILTER_WEEKS) {
+                    return new QuantityType<>(value, Units.WEEK);
+                } else {
+                    return new QuantityType<>(value, Units.MINUTE);
+                }
+            } else if (commandType == ComfoAirCommandType.ENTHALPY_TIME) {
+                return new QuantityType<>(value * 12, Units.MINUTE);
+            }
             return new QuantityType<>(value, Units.HOUR);
         }
     }
@@ -61,25 +72,44 @@ public class DataTypeTime implements ComfoAirDataType {
         int[] template = commandType.getChangeDataTemplate();
         int[] possibleValues = commandType.getPossibleValues();
         int position = commandType.getChangeDataPos();
-        QuantityType<?> hours = ((QuantityType<?>) value).toUnit(Units.HOUR);
+        int intValue;
 
-        if (hours != null) {
-            int intValue = hours.intValue();
+        if (value instanceof QuantityType<?> qt) {
+            QuantityType<?> internalQuantity = new QuantityType<>();
 
-            if (possibleValues == null) {
-                template[position] = intValue;
-            } else {
-                for (int i = 0; i < possibleValues.length; i++) {
-                    if (possibleValues[i] == intValue) {
-                        template[position] = intValue;
-                        break;
-                    }
+            if (commandType.getReadCommand() == ComfoAirCommandType.Constants.REQUEST_GET_DELAYS
+                    || commandType.getReadCommand() == ComfoAirCommandType.Constants.REQUEST_GET_PREHEATER) {
+                if (commandType == ComfoAirCommandType.FILTER_WEEKS) {
+                    internalQuantity = qt.toUnit(Units.WEEK);
+                } else {
+                    internalQuantity = qt.toUnit(Units.MINUTE);
                 }
+            } else {
+                internalQuantity = qt.toUnit(Units.HOUR);
+            }
+
+            if (internalQuantity != null) {
+                intValue = internalQuantity.intValue();
+            } else {
+                return null;
             }
-            return template;
+        } else if (value instanceof DecimalType dt) {
+            intValue = dt.intValue();
         } else {
             logger.trace("\"DataTypeTime\" class \"convertFromState\" undefined state");
             return null;
         }
+
+        if (possibleValues == null) {
+            template[position] = intValue;
+        } else {
+            for (int i = 0; i < possibleValues.length; i++) {
+                if (possibleValues[i] == intValue) {
+                    template[position] = intValue;
+                    break;
+                }
+            }
+        }
+        return template;
     }
 }
index e325a1f689a9f07faf61506c6422b08c7e3bf9fb..6af621995b2840cf4acda75d405f8f41fbb4f315 100644 (file)
@@ -15,6 +15,7 @@ package org.openhab.binding.comfoair.internal.datatypes;
 import org.eclipse.jdt.annotation.NonNullByDefault;
 import org.eclipse.jdt.annotation.Nullable;
 import org.openhab.binding.comfoair.internal.ComfoAirCommandType;
+import org.openhab.core.library.types.DecimalType;
 import org.openhab.core.library.types.QuantityType;
 import org.openhab.core.library.unit.Units;
 import org.openhab.core.types.State;
@@ -44,7 +45,7 @@ public class DataTypeVolt implements ComfoAirDataType {
     @Override
     public State convertToState(int @Nullable [] data, ComfoAirCommandType commandType) {
         if (data == null) {
-            logger.trace("\"DataTypeVolt\" class \"convertToState\" method parameter: null");
+            logger.trace("\"DataTypeVoltage\" class \"convertToState\" method parameter: null");
             return UnDefType.NULL;
         } else {
             int[] readReplyDataPos = commandType.getReadReplyDataPos();
@@ -59,14 +60,24 @@ public class DataTypeVolt implements ComfoAirDataType {
     @Override
     public int @Nullable [] convertFromState(State value, ComfoAirCommandType commandType) {
         int[] template = commandType.getChangeDataTemplate();
-        QuantityType<?> volts = ((QuantityType<?>) value).toUnit(Units.VOLT);
+        float volt;
 
-        if (volts != null) {
-            template[commandType.getChangeDataPos()] = (int) (volts.doubleValue() * 255 / 10);
-            return template;
+        if (value instanceof QuantityType<?> qt) {
+            QuantityType<?> qtVolt = qt.toUnit(Units.VOLT);
+
+            if (qtVolt != null) {
+                volt = qtVolt.floatValue();
+            } else {
+                return null;
+            }
+        } else if (value instanceof DecimalType dt) {
+            volt = dt.floatValue();
         } else {
             logger.trace("\"DataTypeVolt\" class \"convertFromState\" undefined state");
             return null;
         }
+
+        template[commandType.getChangeDataPos()] = (int) (volt * 255 / 10);
+        return template;
     }
 }
index bdd739193f9261a6cca75e8309f23e54146c69a4..83c3b00971d93344049bbcc4a987234aa2fd7d98 100644 (file)
@@ -53,19 +53,23 @@ channel-group-type.comfoair.ventilation_WHR930.label = Ventilation Values
 # channel types
 
 channel-type.comfoair.L1_end_delay.label = L1 Switch End Delay (P23)
-channel-type.comfoair.L1_end_delay.description = End delay for L1 switch (min)
+channel-type.comfoair.L1_end_delay.description = End delay for L1 switch (uses minutes internally)
 channel-type.comfoair.RF_long_delay.label = RF Long Delay (P26)
-channel-type.comfoair.RF_long_delay.description = End delay (RF long actuation) for ventilation level 3 (min)
+channel-type.comfoair.RF_long_delay.description = End delay (RF long actuation) for ventilation level 3 (uses minutes internally)
 channel-type.comfoair.RF_max.label = RF Input Max
 channel-type.comfoair.RF_max.description = Maximum setting for RF input
 channel-type.comfoair.RF_min.label = RF Input Min
 channel-type.comfoair.RF_min.description = Minimum setting for RF input
 channel-type.comfoair.RF_mode.label = RF Input State
 channel-type.comfoair.RF_mode.description = State of RF input
+channel-type.comfoair.RF_mode.state.option.OFF = Controlling
+channel-type.comfoair.RF_mode.state.option.ON = Programming
 channel-type.comfoair.RF_negative.label = RF Input Postive/Negative
 channel-type.comfoair.RF_negative.description = Postive/Negative state of RF input
+channel-type.comfoair.RF_negative.state.option.OFF = Positive
+channel-type.comfoair.RF_negative.state.option.ON = Negative
 channel-type.comfoair.RF_short_delay.label = RF Short Delay (P25)
-channel-type.comfoair.RF_short_delay.description = End delay (RF short actuation) for ventilation level 3 (min)
+channel-type.comfoair.RF_short_delay.description = End delay (RF short actuation) for ventilation level 3 (uses minutes internally)
 channel-type.comfoair.RF_value.label = RF Input Target
 channel-type.comfoair.RF_value.description = Target setting for RF input
 channel-type.comfoair.activate.label = Activate Binding Control
@@ -76,8 +80,12 @@ channel-type.comfoair.analog_min.label = Analog Input Min
 channel-type.comfoair.analog_min.description = Minimum setting for analog input
 channel-type.comfoair.analog_mode.label = Analog Input State
 channel-type.comfoair.analog_mode.description = State of analog input
+channel-type.comfoair.analog_mode.state.option.OFF = Controlling
+channel-type.comfoair.analog_mode.state.option.ON = Programming
 channel-type.comfoair.analog_negative.label = Analog Input Postive/Negative
 channel-type.comfoair.analog_negative.description = Postive/Negative state of analog input
+channel-type.comfoair.analog_negative.state.option.OFF = Positive
+channel-type.comfoair.analog_negative.state.option.ON = Negative
 channel-type.comfoair.analog_priority.label = Analog Priority
 channel-type.comfoair.analog_priority.description = Priority of analog inputs for highest fan level
 channel-type.comfoair.analog_priority.state.option.0 = Analog inputs
@@ -87,9 +95,9 @@ channel-type.comfoair.analog_value.description = Target setting for analog input
 channel-type.comfoair.analog_volt.label = Analog Input Voltage Level
 channel-type.comfoair.analog_volt.description = Voltage level of analog input
 channel-type.comfoair.bathroom_end_delay.label = Bathroom Switch End Delay (P22)
-channel-type.comfoair.bathroom_end_delay.description = End delay for bathroom switch (min)
+channel-type.comfoair.bathroom_end_delay.description = End delay for bathroom switch (uses minutes internally)
 channel-type.comfoair.bathroom_start_delay.label = Bathroom Switch Start Delay (P21)
-channel-type.comfoair.bathroom_start_delay.description = Start delay for bathroom switch (min)
+channel-type.comfoair.bathroom_start_delay.description = Start delay for bathroom switch (uses minutes internally)
 channel-type.comfoair.bypass_correction.label = Bypass Correction
 channel-type.comfoair.bypass_correction.description = Bypass correction state
 channel-type.comfoair.bypass_factor.label = Bypass Factor
@@ -98,18 +106,24 @@ channel-type.comfoair.bypass_level.label = Bypass Level
 channel-type.comfoair.bypass_level.description = Bypass level state
 channel-type.comfoair.bypass_state.label = Bypass State
 channel-type.comfoair.bypass_state.description = State of the bypass (ON = open / OFF = closed)
+channel-type.comfoair.bypass_state.state.option.ON = Open
+channel-type.comfoair.bypass_state.state.option.OFF = Closed
 channel-type.comfoair.bypass_summer.label = Bypass Summer Mode
 channel-type.comfoair.bypass_summer.description = Bypass summer mode
 channel-type.comfoair.bypass_time.label = Bypass Duration
 channel-type.comfoair.bypass_time.description = Hours of bypass open
 channel-type.comfoair.chimney_state.label = Chimney Control State
 channel-type.comfoair.chimney_state.description = State of the chimney control
+channel-type.comfoair.chimney_state.state.option.ON = Active
+channel-type.comfoair.chimney_state.state.option.OFF = Inactive
 channel-type.comfoair.cookerhood_delay.label = Cookerhood Delay (P20)
-channel-type.comfoair.cookerhood_delay.description = End delay for cooker hood control (min)
+channel-type.comfoair.cookerhood_delay.description = End delay for cooker hood control (uses minutes internally)
 channel-type.comfoair.cookerhood_speed.label = Cookerhood Speed Up (%)
 channel-type.comfoair.cookerhood_speed.description = Speed up of the cookerhood
 channel-type.comfoair.cookerhood_state.label = Cookerhood State
 channel-type.comfoair.cookerhood_state.description = State of the cookerhood control
+channel-type.comfoair.cookerhood_state.state.option.ON = Active
+channel-type.comfoair.cookerhood_state.state.option.OFF = Inactive
 channel-type.comfoair.cookerhood_temperature.label = Cookerhood Temperature
 channel-type.comfoair.cookerhood_temperature.description = Temperature of cookerhood sensor
 channel-type.comfoair.enthalpy_humidity.label = Enthalpy Sensor Humidity
@@ -118,6 +132,8 @@ channel-type.comfoair.enthalpy_level.label = Enthalpy Sensor Level
 channel-type.comfoair.enthalpy_level.description = Level of the enthalpy sensor
 channel-type.comfoair.enthalpy_state.label = Enthalpy State
 channel-type.comfoair.enthalpy_state.description = State of the enthalpy module
+channel-type.comfoair.enthalpy_state.state.option.ON = Active
+channel-type.comfoair.enthalpy_state.state.option.OFF = Inactive
 channel-type.comfoair.enthalpy_temperature.label = Enthalpy Sensor Temperature
 channel-type.comfoair.enthalpy_temperature.description = Temperature of the enthalpy sensor
 channel-type.comfoair.enthalpy_time.label = Enthalpy Sensor Timer
@@ -148,7 +164,7 @@ channel-type.comfoair.fan_in_2.description = Fan level 2 performance (%) of inco
 channel-type.comfoair.fan_in_3.label = Fan In Level 3
 channel-type.comfoair.fan_in_3.description = Fan level 3 performance (%) of incoming fan
 channel-type.comfoair.fan_in_RPM.label = Fan In (rpm)
-channel-type.comfoair.fan_in_RPM.description = Current absolute speed (rpm) of incoming fan
+channel-type.comfoair.fan_in_RPM.description = Current rotational speed of incoming fan
 channel-type.comfoair.fan_in_percent.label = Fan In (%)
 channel-type.comfoair.fan_in_percent.description = Current relative speed (%) of incoming fan
 channel-type.comfoair.fan_out_0.label = Fan Out Level 0 (away)
@@ -160,7 +176,7 @@ channel-type.comfoair.fan_out_2.description = Fan level 2 performance (%) of out
 channel-type.comfoair.fan_out_3.label = Fan Out Level 3
 channel-type.comfoair.fan_out_3.description = Fan level 3 performance (%) of outgoing fan
 channel-type.comfoair.fan_out_RPM.label = Fan Out (rpm)
-channel-type.comfoair.fan_out_RPM.description = Current absolute speed (rpm) of outgoing fan
+channel-type.comfoair.fan_out_RPM.description = Current rotational speed of outgoing fan
 channel-type.comfoair.fan_out_percent.label = Fan Out (%)
 channel-type.comfoair.fan_out_percent.description = Current relative speed (%) of outgoing fan
 channel-type.comfoair.filter_error.label = Filter Error
@@ -171,15 +187,19 @@ channel-type.comfoair.filter_reset.label = Filter Reset
 channel-type.comfoair.filter_reset.description = Reset filter uptime
 channel-type.comfoair.filter_reset.command.option.1 = Reset
 channel-type.comfoair.filter_weeks.label = Filter Period (P24)
-channel-type.comfoair.filter_weeks.description = Usage period until filter pollution message (weeks)
+channel-type.comfoair.filter_weeks.description = Usage period until filter pollution message (uses full weeks internally)
 channel-type.comfoair.freeze_time.label = Antifrost Duration
 channel-type.comfoair.freeze_time.description = Uptime of antifrost
 channel-type.comfoair.frost_state.label = Antifrost State
 channel-type.comfoair.frost_state.description = State of the antifrost control
+channel-type.comfoair.frost_state.state.option.ON = Active
+channel-type.comfoair.frost_state.state.option.OFF = Inactive
 channel-type.comfoair.ghx_speed.label = GHX Speed Up (%)
 channel-type.comfoair.ghx_speed.description = Speed up of the geothermal heat exchanger
 channel-type.comfoair.ghx_state.label = Geothermal Heat exchanger State
 channel-type.comfoair.ghx_state.description = State of the geothermal heat exchanger valve (ON = open / OFF = closed)
+channel-type.comfoair.ghx_state.state.option.ON = Open
+channel-type.comfoair.ghx_state.state.option.OFF = Closed
 channel-type.comfoair.ghx_temperature.label = GHX Temperature
 channel-type.comfoair.ghx_temperature.description = Temperature of geothermal heat exchanger sensor
 channel-type.comfoair.ghx_temperature_high.label = GHX Temperature (high)
@@ -192,6 +212,8 @@ channel-type.comfoair.heater_power_I.label = Heater Power I-Parameter
 channel-type.comfoair.heater_power_I.description = Heater power I-parameter value
 channel-type.comfoair.heater_state.label = Heater State
 channel-type.comfoair.heater_state.description = State of the heater
+channel-type.comfoair.heater_state.state.option.ON = Active
+channel-type.comfoair.heater_state.state.option.OFF = Inactive
 channel-type.comfoair.heater_target_temperature.label = Heater Target Temperature
 channel-type.comfoair.heater_target_temperature.description = Target temperature of the heater
 channel-type.comfoair.heater_temperature.label = Heater Temperature
@@ -286,18 +308,29 @@ channel-type.comfoair.outdoor_temperature_out.label = Outdoor Temperature Outgoi
 channel-type.comfoair.outdoor_temperature_out.description = Outlet air temperature (outside)
 channel-type.comfoair.preheater_frost_protect.label = Frost Protection
 channel-type.comfoair.preheater_frost_protect.description = State of the frost protection
+channel-type.comfoair.preheater_frost_protect.state.option.ON = Active
+channel-type.comfoair.preheater_frost_protect.state.option.OFF = Inactive
 channel-type.comfoair.preheater_frost_time.label = Preheater Frost Time
-channel-type.comfoair.preheater_frost_time.description = Frost minutes
+channel-type.comfoair.preheater_frost_time.description = Frost time
 channel-type.comfoair.preheater_heating.label = Preheater
 channel-type.comfoair.preheater_heating.description = State of the preheater
+channel-type.comfoair.preheater_heating.state.option.ON = Active
+channel-type.comfoair.preheater_heating.state.option.OFF = Inactive
 channel-type.comfoair.preheater_safety.label = Preheater Frost Safety
 channel-type.comfoair.preheater_safety.description = Frost safety setting
+channel-type.comfoair.preheater_safety.state.option.0 = Extra-safe setting
+channel-type.comfoair.preheater_safety.state.option.1 = Safe setting
+channel-type.comfoair.preheater_safety.state.option.2 = Normal setting
+channel-type.comfoair.preheater_safety.state.option.3 = Economy setting
 channel-type.comfoair.preheater_time.label = Preheater Duration
 channel-type.comfoair.preheater_time.description = Uptime of preheater
 channel-type.comfoair.preheater_valve.label = Preheater Valve
 channel-type.comfoair.preheater_valve.description = State of the preheater valve
+channel-type.comfoair.preheater_valve.state.option.0 = Closed
+channel-type.comfoair.preheater_valve.state.option.1 = Open
+channel-type.comfoair.preheater_valve.state.option.2 = Unknown
 channel-type.comfoair.pulse_ventilation.label = Pulse Ventilation Period (P27)
-channel-type.comfoair.pulse_ventilation.description = Period for pulse ventilation (min)
+channel-type.comfoair.pulse_ventilation.description = Period for pulse ventilation (uses minutes internally)
 channel-type.comfoair.recu_size.label = Comfoair Size
 channel-type.comfoair.recu_size.description = Size of the ComfoAir (1 = big / 2 = small)
 channel-type.comfoair.recu_size.state.option.1 = Big
@@ -310,3 +343,5 @@ channel-type.comfoair.target_temperature.label = Target Temperature
 channel-type.comfoair.target_temperature.description = Target (comfort) temperature
 channel-type.comfoair.v_control_state.label = 0-10V Control State
 channel-type.comfoair.v_control_state.description = State of the 0-10V control
+channel-type.comfoair.v_control_state.state.option.ON = Active
+channel-type.comfoair.v_control_state.state.option.OFF = Inactive
index ec2b1203dbca64ec945297ed2bf30a5f69d65324..804b4840473c9077db4082963afdc414e81709b8 100644 (file)
                        <channel-group id="resets" typeId="resets"/>
                </channel-groups>
 
+               <properties>
+                       <property name="thingTypeVersion">1</property>
+               </properties>
+
                <config-description-ref uri="thing-type:comfoair:serial"/>
 
        </thing-type>
                        <channel-group id="resets" typeId="resets"/>
                </channel-groups>
 
+               <properties>
+                       <property name="vendor">Zehnder</property>
+                       <property name="thingTypeVersion">1</property>
+               </properties>
+
                <config-description-ref uri="thing-type:comfoair:serial"/>
 
        </thing-type>
                <label>Fan Level</label>
                <description>Fan level</description>
                <category>Number</category>
+               <tags>
+                       <tag>Control</tag>
+                       <tag>Level</tag>
+               </tags>
                <state readOnly="false">
                        <options>
                                <option value="1">Away</option>
                <label>Target Temperature</label>
                <description>Target (comfort) temperature</description>
                <category>Temperature</category>
+               <tags>
+                       <tag>Setpoint</tag>
+                       <tag>Temperature</tag>
+               </tags>
                <state min="12" max="28" step="0.5" pattern="%.1f %unit%" readOnly="false"/>
        </channel-type>
 
        </channel-type>
 
        <channel-type id="fan_in_RPM" advanced="true">
-               <item-type>Number</item-type>
+               <item-type>Number:Frequency</item-type>
                <label>Fan In (rpm)</label>
-               <description>Current absolute speed (rpm) of incoming fan</description>
+               <description>Current rotational speed of incoming fan</description>
                <category>Number</category>
-               <state readOnly="true"/>
+               <state readOnly="true" pattern="%.0f rpm"/>
        </channel-type>
 
        <channel-type id="fan_out_RPM" advanced="true">
-               <item-type>Number</item-type>
+               <item-type>Number:Frequency</item-type>
                <label>Fan Out (rpm)</label>
-               <description>Current absolute speed (rpm) of outgoing fan</description>
+               <description>Current rotational speed of outgoing fan</description>
                <category>Number</category>
-               <state readOnly="true"/>
+               <state readOnly="true" pattern="%.0f rpm"/>
        </channel-type>
 
        <channel-type id="outdoor_temperature_in">
                <label>Outdoor Temperature Incoming</label>
                <description>Intake air temperature (outside)</description>
                <category>Temperature</category>
+               <tags>
+                       <tag>Measurement</tag>
+                       <tag>Temperature</tag>
+               </tags>
                <state readOnly="true" pattern="%.1f %unit%"/>
        </channel-type>
 
                <label>Outdoor Temperature Outgoing</label>
                <description>Outlet air temperature (outside)</description>
                <category>Temperature</category>
+               <tags>
+                       <tag>Measurement</tag>
+                       <tag>Temperature</tag>
+               </tags>
                <state readOnly="true" pattern="%.1f %unit%"/>
        </channel-type>
 
                <label>Indoor Temperature Incoming</label>
                <description>Inlet air temperature (inside)</description>
                <category>Temperature</category>
+               <tags>
+                       <tag>Measurement</tag>
+                       <tag>Temperature</tag>
+               </tags>
                <state readOnly="true" pattern="%.1f %unit%"/>
        </channel-type>
 
                <label>Indoor Temperature Outgoing</label>
                <description>Uptake air temperature (inside)</description>
                <category>Temperature</category>
+               <tags>
+                       <tag>Measurement</tag>
+                       <tag>Temperature</tag>
+               </tags>
                <state readOnly="true" pattern="%.1f %unit%"/>
        </channel-type>
 
                <label>Chimney Control State</label>
                <description>State of the chimney control</description>
                <category>Switch</category>
-               <state readOnly="true"/>
+               <tags>
+                       <tag>Status</tag>
+               </tags>
+               <state readOnly="true">
+                       <options>
+                               <option value="ON">Active</option>
+                               <option value="OFF">Inactive</option>
+                       </options>
+               </state>
        </channel-type>
 
        <channel-type id="bypass_state" advanced="true">
                <label>Bypass State</label>
                <description>State of the bypass (ON = open / OFF = closed)</description>
                <category>Switch</category>
-               <state readOnly="true"/>
+               <tags>
+                       <tag>Status</tag>
+               </tags>
+               <state readOnly="true">
+                       <options>
+                               <option value="ON">Open</option>
+                               <option value="OFF">Closed</option>
+                       </options>
+               </state>
        </channel-type>
 
        <channel-type id="ghx_state" advanced="true">
                <label>Geothermal Heat exchanger State</label>
                <description>State of the geothermal heat exchanger valve (ON = open / OFF = closed)</description>
                <category>Switch</category>
-               <state readOnly="true"/>
+               <tags>
+                       <tag>Status</tag>
+               </tags>
+               <state readOnly="true">
+                       <options>
+                               <option value="ON">Open</option>
+                               <option value="OFF">Closed</option>
+                       </options>
+               </state>
        </channel-type>
 
        <channel-type id="heater_state" advanced="true">
                <label>Heater State</label>
                <description>State of the heater</description>
                <category>Switch</category>
-               <state readOnly="true"/>
+               <tags>
+                       <tag>Status</tag>
+               </tags>
+               <state readOnly="true">
+                       <options>
+                               <option value="ON">Active</option>
+                               <option value="OFF">Inactive</option>
+                       </options>
+               </state>
        </channel-type>
 
        <channel-type id="v_control_state" advanced="true">
                <label>0-10V Control State</label>
                <description>State of the 0-10V control</description>
                <category>Switch</category>
-               <state readOnly="true"/>
+               <tags>
+                       <tag>Status</tag>
+               </tags>
+               <state readOnly="true">
+                       <options>
+                               <option value="ON">Active</option>
+                               <option value="OFF">Inactive</option>
+                       </options>
+               </state>
        </channel-type>
 
        <channel-type id="frost_state" advanced="true">
                <label>Antifrost State</label>
                <description>State of the antifrost control</description>
                <category>Switch</category>
-               <state readOnly="true"/>
+               <tags>
+                       <tag>Status</tag>
+               </tags>
+               <state readOnly="true">
+                       <options>
+                               <option value="ON">Active</option>
+                               <option value="OFF">Inactive</option>
+                       </options>
+               </state>
        </channel-type>
 
        <channel-type id="cookerhood_state" advanced="true">
                <label>Cookerhood State</label>
                <description>State of the cookerhood control</description>
                <category>Switch</category>
-               <state readOnly="true"/>
+               <tags>
+                       <tag>Status</tag>
+               </tags>
+               <state readOnly="true">
+                       <options>
+                               <option value="ON">Active</option>
+                               <option value="OFF">Inactive</option>
+                       </options>
+               </state>
        </channel-type>
 
        <channel-type id="enthalpy_state" advanced="true">
                <label>Enthalpy State</label>
                <description>State of the enthalpy module</description>
                <category>Switch</category>
-               <state readOnly="true"/>
+               <tags>
+                       <tag>Status</tag>
+               </tags>
+               <state readOnly="true">
+                       <options>
+                               <option value="ON">Active</option>
+                               <option value="OFF">Inactive</option>
+                       </options>
+               </state>
        </channel-type>
 
        <channel-type id="ghx_temperature" advanced="true">
                <label>GHX Temperature</label>
                <description>Temperature of geothermal heat exchanger sensor</description>
                <category>Temperature</category>
+               <tags>
+                       <tag>Measurement</tag>
+                       <tag>Temperature</tag>
+               </tags>
                <state readOnly="true" pattern="%.1f %unit%"/>
        </channel-type>
 
                <label>Heater Temperature</label>
                <description>Temperature of heater sensor</description>
                <category>Temperature</category>
+               <tags>
+                       <tag>Measurement</tag>
+                       <tag>Temperature</tag>
+               </tags>
                <state readOnly="true" pattern="%.1f %unit%"/>
        </channel-type>
 
                <label>Cookerhood Temperature</label>
                <description>Temperature of cookerhood sensor</description>
                <category>Temperature</category>
+               <tags>
+                       <tag>Measurement</tag>
+                       <tag>Temperature</tag>
+               </tags>
                <state readOnly="true" pattern="%.1f %unit%"/>
        </channel-type>
 
                <label>Level 0 Duration</label>
                <description>Uptime at level 0 (away)</description>
                <category>Time</category>
-               <state readOnly="true" pattern="%.0f %unit%"/>
+               <state readOnly="true" pattern="%.0f h"/>
        </channel-type>
 
        <channel-type id="level1_time" advanced="true">
                <label>Level 1 Duration</label>
                <description>Uptime at level 1</description>
                <category>Time</category>
-               <state readOnly="true" pattern="%.0f %unit%"/>
+               <state readOnly="true" pattern="%.0f h"/>
        </channel-type>
 
        <channel-type id="level2_time" advanced="true">
                <label>Level 2 Duration</label>
                <description>Uptime at level 2</description>
                <category>Time</category>
-               <state readOnly="true" pattern="%.0f %unit%"/>
+               <state readOnly="true" pattern="%.0f h"/>
        </channel-type>
 
        <channel-type id="level3_time" advanced="true">
                <label>Level 3 Duration</label>
                <description>Uptime at level 3</description>
                <category>Time</category>
-               <state readOnly="true" pattern="%.0f %unit%"/>
+               <state readOnly="true" pattern="%.0f h"/>
        </channel-type>
 
        <channel-type id="freeze_time" advanced="true">
                <label>Antifrost Duration</label>
                <description>Uptime of antifrost</description>
                <category>Time</category>
-               <state readOnly="true" pattern="%.0f %unit%"/>
+               <state readOnly="true" pattern="%.0f h"/>
        </channel-type>
 
        <channel-type id="preheater_time" advanced="true">
                <label>Preheater Duration</label>
                <description>Uptime of preheater</description>
                <category>Time</category>
-               <state readOnly="true" pattern="%.0f %unit%"/>
+               <state readOnly="true" pattern="%.0f h"/>
        </channel-type>
 
        <channel-type id="bypass_time" advanced="true">
                <label>Bypass Duration</label>
                <description>Hours of bypass open</description>
                <category>Time</category>
-               <state readOnly="true" pattern="%.0f %unit%"/>
+               <state readOnly="true" pattern="%.0f h"/>
        </channel-type>
 
        <channel-type id="filter_hours">
                <label>Filter Duration</label>
                <description>Uptime of the filter</description>
                <category>Time</category>
-               <state readOnly="true" pattern="%.0f %unit%"/>
+               <state readOnly="true" pattern="%.0f h"/>
        </channel-type>
 
        <channel-type id="bypass_factor" advanced="true">
                <label>Preheater Valve</label>
                <description>State of the preheater valve</description>
                <category>Number</category>
-               <state readOnly="true"/>
+               <tags>
+                       <tag>Status</tag>
+               </tags>
+               <state readOnly="true">
+                       <options>
+                               <option value="0">Closed</option>
+                               <option value="1">Open</option>
+                               <option value="2">Unknown</option>
+                       </options>
+               </state>
        </channel-type>
 
        <channel-type id="preheater_frost_protect" advanced="true">
                <label>Frost Protection</label>
                <description>State of the frost protection</description>
                <category>Switch</category>
-               <state readOnly="true"/>
+               <tags>
+                       <tag>Status</tag>
+               </tags>
+               <state readOnly="true">
+                       <options>
+                               <option value="ON">Active</option>
+                               <option value="OFF">Inactive</option>
+                       </options>
+               </state>
        </channel-type>
 
        <channel-type id="preheater_heating" advanced="true">
                <label>Preheater</label>
                <description>State of the preheater</description>
                <category>Switch</category>
-               <state readOnly="true"/>
+               <tags>
+                       <tag>Status</tag>
+               </tags>
+               <state readOnly="true">
+                       <options>
+                               <option value="ON">Active</option>
+                               <option value="OFF">Inactive</option>
+                       </options>
+               </state>
        </channel-type>
 
        <channel-type id="preheater_frost_time" advanced="true">
-               <item-type>Number</item-type>
+               <item-type>Number:Time</item-type>
                <label>Preheater Frost Time</label>
-               <description>Frost minutes</description>
-               <category>Number</category>
-               <state readOnly="true"/>
+               <description>Frost time</description>
+               <category>Time</category>
+               <state readOnly="true" pattern="%.0f min"/>
        </channel-type>
 
        <channel-type id="preheater_safety" advanced="true">
                <label>Preheater Frost Safety</label>
                <description>Frost safety setting</description>
                <category>Number</category>
-               <state readOnly="true"/>
+               <tags>
+                       <tag>Status</tag>
+               </tags>
+               <state readOnly="true">
+                       <options>
+                               <option value="0">Extra-safe setting</option>
+                               <option value="1">Safe setting</option>
+                               <option value="2">Normal setting</option>
+                               <option value="3">Economy setting</option>
+                       </options>
+               </state>
        </channel-type>
 
        <channel-type id="ghx_temperature_low" advanced="true">
                <label>GHX Temperature (low)</label>
                <description>Lower temperature of the geothermal heat exchanger</description>
                <category>Temperature</category>
-               <state readOnly="true" pattern="%.1f %unit%"/>
+               <tags>
+                       <tag>Setpoint</tag>
+                       <tag>Temperature</tag>
+               </tags>
+               <state min="0" max="15" step="1" pattern="%.1f %unit%" readOnly="false"/>
        </channel-type>
 
        <channel-type id="ghx_temperature_high" advanced="true">
                <label>GHX Temperature (high)</label>
                <description>Upper temperature of the geothermal heat exchanger</description>
                <category>Temperature</category>
-               <state readOnly="true" pattern="%.1f %unit%"/>
+               <tags>
+                       <tag>Setpoint</tag>
+                       <tag>Temperature</tag>
+               </tags>
+               <state min="10" max="25" step="1" pattern="%.1f %unit%" readOnly="false"/>
        </channel-type>
 
        <channel-type id="ghx_speed" advanced="true">
                <label>GHX Speed Up (%)</label>
                <description>Speed up of the geothermal heat exchanger</description>
                <category>Number</category>
-               <state readOnly="true"/>
+               <state min="0" max="99" step="1" pattern="%.0f %%" readOnly="false"/>
        </channel-type>
 
        <channel-type id="heater_power" advanced="true">
                <label>Heater Target Temperature</label>
                <description>Target temperature of the heater</description>
                <category>Temperature</category>
-               <state readOnly="true" pattern="%.1f %unit%"/>
+               <tags>
+                       <tag>Setpoint</tag>
+                       <tag>Temperature</tag>
+               </tags>
+               <state min="5" max="40" step="1" pattern="%.1f %unit%" readOnly="false"/>
        </channel-type>
 
        <channel-type id="cookerhood_speed" advanced="true">
                <label>Enthalpy Sensor Temperature</label>
                <description>Temperature of the enthalpy sensor</description>
                <category>Temperature</category>
+               <tags>
+                       <tag>Measurement</tag>
+                       <tag>Temperature</tag>
+               </tags>
                <state readOnly="true" pattern="%.1f %unit%"/>
        </channel-type>
 
                <label>Enthalpy Sensor Humidity</label>
                <description>Humidity of the enthalpy sensor</description>
                <category>Humidity</category>
+               <tags>
+                       <tag>Measurement</tag>
+                       <tag>Humidity</tag>
+               </tags>
                <state readOnly="true"/>
        </channel-type>
 
        </channel-type>
 
        <channel-type id="enthalpy_time" advanced="true">
-               <item-type>Number</item-type>
+               <item-type>Number:Time</item-type>
                <label>Enthalpy Sensor Timer</label>
                <description>Timer state of the enthalpy sensor</description>
                <category>Time</category>
-               <state readOnly="true"/>
+               <state readOnly="true" pattern="%.0f min"/>
        </channel-type>
 
        <channel-type id="is_preheater" advanced="true">
        </channel-type>
 
        <channel-type id="cookerhood_delay" advanced="true">
-               <item-type>Number</item-type>
+               <item-type>Number:Time</item-type>
                <label>Cookerhood Delay (P20)</label>
-               <description>End delay for cooker hood control (min)</description>
+               <description>End delay for cooker hood control (uses minutes internally)</description>
                <category>Time</category>
-               <state min="0" max="180" step="1" readOnly="false"/>
+               <tags>
+                       <tag>Setpoint</tag>
+                       <tag>Duration</tag>
+               </tags>
+               <state min="0" max="180" step="1" readOnly="false" pattern="%.0f min"/>
        </channel-type>
 
        <channel-type id="bathroom_start_delay" advanced="true">
-               <item-type>Number</item-type>
+               <item-type>Number:Time</item-type>
                <label>Bathroom Switch Start Delay (P21)</label>
-               <description>Start delay for bathroom switch (min)</description>
+               <description>Start delay for bathroom switch (uses minutes internally)</description>
                <category>Time</category>
-               <state min="0" max="120" step="1" readOnly="false"/>
+               <tags>
+                       <tag>Setpoint</tag>
+                       <tag>Duration</tag>
+               </tags>
+               <state min="0" max="120" step="1" readOnly="false" pattern="%.0f min"/>
        </channel-type>
 
        <channel-type id="bathroom_end_delay" advanced="true">
-               <item-type>Number</item-type>
+               <item-type>Number:Time</item-type>
                <label>Bathroom Switch End Delay (P22)</label>
-               <description>End delay for bathroom switch (min)</description>
+               <description>End delay for bathroom switch (uses minutes internally)</description>
                <category>Time</category>
-               <state min="0" max="120" step="1" readOnly="false"/>
+               <tags>
+                       <tag>Setpoint</tag>
+                       <tag>Duration</tag>
+               </tags>
+               <state min="0" max="120" step="1" readOnly="false" pattern="%.0f min"/>
        </channel-type>
 
        <channel-type id="L1_end_delay" advanced="true">
-               <item-type>Number</item-type>
+               <item-type>Number:Time</item-type>
                <label>L1 Switch End Delay (P23)</label>
-               <description>End delay for L1 switch (min)</description>
+               <description>End delay for L1 switch (uses minutes internally)</description>
                <category>Time</category>
-               <state min="0" max="120" step="1" readOnly="false"/>
+               <tags>
+                       <tag>Setpoint</tag>
+                       <tag>Duration</tag>
+               </tags>
+               <state min="0" max="120" step="1" readOnly="false" pattern="%.0f min"/>
        </channel-type>
 
        <channel-type id="filter_weeks" advanced="true">
-               <item-type>Number</item-type>
+               <item-type>Number:Time</item-type>
                <label>Filter Period (P24)</label>
-               <description>Usage period until filter pollution message (weeks)</description>
+               <description>Usage period until filter pollution message (uses full weeks internally)</description>
                <category>Time</category>
-               <state min="10" max="26" step="1" readOnly="false"/>
+               <tags>
+                       <tag>Setpoint</tag>
+                       <tag>Duration</tag>
+               </tags>
+               <state min="10" max="26" step="1" readOnly="false" pattern="%.0f week"/>
        </channel-type>
 
        <channel-type id="RF_short_delay" advanced="true">
-               <item-type>Number</item-type>
+               <item-type>Number:Time</item-type>
                <label>RF Short Delay (P25)</label>
-               <description>End delay (RF short actuation) for ventilation level 3 (min)</description>
+               <description>End delay (RF short actuation) for ventilation level 3 (uses minutes internally)</description>
                <category>Time</category>
-               <state min="1" max="20" step="1" readOnly="false"/>
+               <tags>
+                       <tag>Setpoint</tag>
+                       <tag>Duration</tag>
+               </tags>
+               <state min="1" max="20" step="1" readOnly="false" pattern="%.0f min"/>
        </channel-type>
 
        <channel-type id="RF_long_delay" advanced="true">
-               <item-type>Number</item-type>
+               <item-type>Number:Time</item-type>
                <label>RF Long Delay (P26)</label>
-               <description>End delay (RF long actuation) for ventilation level 3 (min)</description>
+               <description>End delay (RF long actuation) for ventilation level 3 (uses minutes internally)</description>
                <category>Time</category>
-               <state min="1" max="120" step="1" readOnly="false"/>
+               <state min="1" max="120" step="1" readOnly="false" pattern="%.0f min"/>
        </channel-type>
 
        <channel-type id="pulse_ventilation" advanced="true">
-               <item-type>Number</item-type>
+               <item-type>Number:Time</item-type>
                <label>Pulse Ventilation Period (P27)</label>
-               <description>Period for pulse ventilation (min)</description>
+               <description>Period for pulse ventilation (uses minutes internally)</description>
                <category>Time</category>
-               <state min="0" max="120" step="1" readOnly="false"/>
+               <tags>
+                       <tag>Setpoint</tag>
+                       <tag>Duration</tag>
+               </tags>
+               <state min="0" max="120" step="1" readOnly="false" pattern="%.0f min"/>
        </channel-type>
 
        <channel-type id="is_analog" advanced="true">
                <label>Analog Input State</label>
                <description>State of analog input</description>
                <category>Switch</category>
-               <state readOnly="false"/>
+               <state readOnly="false">
+                       <options>
+                               <option value="OFF">Controlling</option>
+                               <option value="ON">Programming</option>
+                       </options>
+               </state>
        </channel-type>
 
        <channel-type id="RF_mode" advanced="true">
                <label>RF Input State</label>
                <description>State of RF input</description>
                <category>Switch</category>
-               <state readOnly="false"/>
+               <state readOnly="false">
+                       <options>
+                               <option value="OFF">Controlling</option>
+                               <option value="ON">Programming</option>
+                       </options>
+               </state>
        </channel-type>
 
        <channel-type id="analog_negative" advanced="true">
                <label>Analog Input Postive/Negative</label>
                <description>Postive/Negative state of analog input</description>
                <category>Switch</category>
-               <state readOnly="false"/>
+               <state readOnly="false">
+                       <options>
+                               <option value="OFF">Positive</option>
+                               <option value="ON">Negative</option>
+                       </options>
+               </state>
        </channel-type>
 
        <channel-type id="RF_negative" advanced="true">
                <label>RF Input Postive/Negative</label>
                <description>Postive/Negative state of RF input</description>
                <category>Switch</category>
-               <state readOnly="false"/>
+               <state readOnly="false">
+                       <options>
+                               <option value="OFF">Positive</option>
+                               <option value="ON">Negative</option>
+                       </options>
+               </state>
        </channel-type>
 
        <channel-type id="analog_volt" advanced="true">
                <label>Analog Input Voltage Level</label>
                <description>Voltage level of analog input</description>
                <category>Number</category>
+               <tags>
+                       <tag>Measurement</tag>
+                       <tag>Voltage</tag>
+               </tags>
                <state readOnly="true"/>
        </channel-type>
 
diff --git a/bundles/org.openhab.binding.comfoair/src/main/resources/OH-INF/update/instructions.xml b/bundles/org.openhab.binding.comfoair/src/main/resources/OH-INF/update/instructions.xml
new file mode 100644 (file)
index 0000000..c6b6847
--- /dev/null
@@ -0,0 +1,126 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
+<update:update-descriptions xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+       xmlns:update="https://openhab.org/schemas/update-description/v1.0.0"
+       xsi:schemaLocation="https://openhab.org/schemas/update-description/v1.0.0 https://openhab.org/schemas/update-description-1.0.0.xsd">
+
+       <thing-type uid="comfoair:comfoair">
+
+               <instruction-set targetVersion="1">
+                       <update-channel id="fanInRPM" groupIds="ventilation">
+                               <type>comfoair:fan_in_RPM</type>
+                       </update-channel>
+
+                       <update-channel id="fanOutRPM" groupIds="ventilation">
+                               <type>comfoair:fan_out_RPM</type>
+                       </update-channel>
+
+                       <update-channel id="bathroomStartDelay" groupIds="menuP2">
+                               <type>comfoair:bathroom_start_delay</type>
+                       </update-channel>
+
+                       <update-channel id="bathroomEndDelay" groupIds="menuP2">
+                               <type>comfoair:bathroom_end_delay</type>
+                       </update-channel>
+
+                       <update-channel id="L1EndDelay" groupIds="menuP2">
+                               <type>comfoair:L1_end_delay</type>
+                       </update-channel>
+
+                       <update-channel id="pulseVentilation" groupIds="menuP2">
+                               <type>comfoair:pulse_ventilation</type>
+                       </update-channel>
+
+                       <update-channel id="filterWeeks" groupIds="menuP2">
+                               <type>comfoair:filter_weeks</type>
+                       </update-channel>
+
+                       <update-channel id="RFShortDelay" groupIds="menuP2">
+                               <type>comfoair:RF_short_delay</type>
+                       </update-channel>
+
+                       <update-channel id="RFLongDelay" groupIds="menuP2">
+                               <type>comfoair:RF_long_delay</type>
+                       </update-channel>
+
+                       <update-channel id="cookerhoodDelay" groupIds="menuP2">
+                               <type>comfoair:cookerhood_delay</type>
+                       </update-channel>
+
+                       <update-channel id="enthalpyTime" groupIds="enthalpy">
+                               <type>comfoair:enthalpy_time</type>
+                       </update-channel>
+
+                       <update-channel id="preheaterFrostTime" groupIds="preheater">
+                               <type>comfoair:preheater_frost_time</type>
+                       </update-channel>
+
+                       <update-channel id="preheaterSafety" groupIds="preheater">
+                               <type>comfoair:preheater_safety</type>
+                       </update-channel>
+
+                       <update-channel id="ewtTemperatureLow" groupIds="ghx">
+                               <type>comfoair:ghx_temperature_low</type>
+                       </update-channel>
+
+                       <update-channel id="ewtTemperatureHigh" groupIds="ghx">
+                               <type>comfoair:ghx_temperature_high</type>
+                       </update-channel>
+
+                       <update-channel id="ewtSpeed" groupIds="ghx">
+                               <type>comfoair:ghx_speed</type>
+                       </update-channel>
+
+                       <update-channel id="heaterTargetTemperature" groupIds="heater">
+                               <type>comfoair:heater_target_temperature</type>
+                       </update-channel>
+               </instruction-set>
+
+       </thing-type>
+
+       <thing-type uid="comfoair:WHR930">
+
+               <instruction-set targetVersion="1">
+                       <update-channel id="fanInRPM" groupIds="ventilation">
+                               <type>comfoair:fan_in_RPM</type>
+                       </update-channel>
+
+                       <update-channel id="fanOutRPM" groupIds="ventilation">
+                               <type>comfoair:fan_out_RPM</type>
+                       </update-channel>
+
+                       <update-channel id="bathroomStartDelay" groupIds="menuP2">
+                               <type>comfoair:bathroom_start_delay</type>
+                       </update-channel>
+
+                       <update-channel id="bathroomEndDelay" groupIds="menuP2">
+                               <type>comfoair:bathroom_end_delay</type>
+                       </update-channel>
+
+                       <update-channel id="L1EndDelay" groupIds="menuP2">
+                               <type>comfoair:L1_end_delay</type>
+                       </update-channel>
+
+                       <update-channel id="filterWeeks" groupIds="menuP2">
+                               <type>comfoair:filter_weeks</type>
+                       </update-channel>
+
+                       <update-channel id="RFShortDelay" groupIds="menuP2">
+                               <type>comfoair:RF_short_delay</type>
+                       </update-channel>
+
+                       <update-channel id="RFLongDelay" groupIds="menuP2">
+                               <type>comfoair:RF_long_delay</type>
+                       </update-channel>
+
+                       <update-channel id="preheaterFrostTime" groupIds="preheater">
+                               <type>comfoair:preheater_frost_time</type>
+                       </update-channel>
+
+                       <update-channel id="preheaterSafety" groupIds="preheater">
+                               <type>comfoair:preheater_safety</type>
+                       </update-channel>
+               </instruction-set>
+
+       </thing-type>
+
+</update:update-descriptions>