added migrated 2.x add-ons

Signed-off-by: Kai Kreuzer <kai@openhab.org>
This commit is contained in:
Kai Kreuzer
2020-09-21 01:58:32 +02:00
parent bbf1a7fd29
commit 6df6783b60
11662 changed files with 1302875 additions and 11 deletions

View File

@@ -0,0 +1,33 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="src" output="target/classes" path="src/main/java">
<attributes>
<attribute name="optional" value="true"/>
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry excluding="**" kind="src" output="target/classes" path="src/main/resources">
<attributes>
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="src" output="target/test-classes" path="src/test/java">
<attributes>
<attribute name="test" value="true"/>
<attribute name="optional" value="true"/>
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry exported="true" kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/J2SE-1.5">
<attributes>
<attribute name="module" value="true"/>
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="con" path="org.eclipse.m2e.MAVEN2_CLASSPATH_CONTAINER">
<attributes>
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="output" path="target/classes"/>
</classpath>

View File

@@ -0,0 +1,23 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>org.openhab.binding.modbus.helioseasycontrols</name>
<comment></comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>org.eclipse.jdt.core.javabuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.m2e.core.maven2Builder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>org.eclipse.jdt.core.javanature</nature>
<nature>org.eclipse.m2e.core.maven2Nature</nature>
</natures>
</projectDescription>

View File

@@ -0,0 +1,13 @@
This content is produced and maintained by the openHAB project.
* Project home: https://www.openhab.org
== Declared Project Licenses
This program and the accompanying materials are made available under the terms
of the Eclipse Public License 2.0 which is available at
https://www.eclipse.org/legal/epl-2.0/.
== Source Code
https://github.com/openhab/openhab-addons

View File

@@ -0,0 +1,379 @@
# Helios easyControls Binding
Helios Heat-Recovery Ventilation devices use a Modbus protocol to communicate with different sensors, switches, etc. Some devices come with an integrated web interface (easyControls) as well as a Modbus TCP/IP Gateway.
See https://www.easycontrols.net/de/service/downloads/send/4-software/16-modbus-dokumentation-f%C3%BCr-kwl-easycontrols-ger%C3%A4te for the corresponding specification.
## Supported Things
| Thing | Description |
|---------------------|------------------------------------------------------------|
| helios-easycontrols | Helios Heat-Recovery Ventilation devices with easyControls |
## Configuration
You first need to set up a Modbus bridge according to the [Modbus documentation](https://www.openhab.org/addons/bindings/modbus/).
Things in this extension will use the selected bridge to connect to the device.
The configuration of a Helios Ventilation device via a `.things` file would look like the following code sample.
It's required to provide the device's IP address, port and unit ID (port and unit ID cannot be changed and always have to be 502 and 180; in fact the values provided here are ignored by the binding and the fixed values 502 and 180 are used):
```
Bridge modbus:tcp:modbus-gateway "Modbus TCP/IP Gateway" [ host="x.x.x.x", port=502, id=180, enableDiscovery=true ] {
Thing helios-easycontrols kwl "KWL"
}
```
## Channels
The following channels are supported:
| Channel | Channel Group | Description | Item Type | RW |
| -------------------------------- | --------------- | -------------------------------------------------------------------------------------------------------------------------------- | ------------------------ | -- |
| sysdate | general | The KWL's system date and time | DateTime | RW |
| summerWinter | general | Indicates if summertime or wintertime is active (OFF = wintertime, ON = summertime) | Switch | RW |
| autoSwUpdate | general | Indicates if automatic software updates are enable | Switch | RW |
| accessHeliosPortal | general | Indicates if access to Helios portal is enabled | Switch | RW |
| minFanStage | unitConfig | Minimum fan stage (0 or 1) (0, 1) | Number | RW |
| preHeaterStatus | general | Pre-Heater Status | Switch | RW |
| humidityControlSetValue | humidityControl | Humidity control set value (in percent) (20 - 80 %) | Number:Dimensionless | RW |
| humidityControlSteps | humidityControl | Humidity control steps (in percent) (5 - 20 %) | Number:Dimensionless | RW |
| humidityStopTime | humidityControl | Humidity stop time in hours (0-24) (0 - 24 h) | Number:Time | RW |
| co2ControlSetValue | co2Control | CO2 control set value (in ppm) (300 - 2000 ppm) | Number:Dimensionless | RW |
| co2ControlSteps | co2Control | CO2 control steps (in ppm) (50 - 400 ppm) | Number:Dimensionless | RW |
| vocControlStatus | vocControl | VOC control status (0 = off, 1 = stepped, 2 = stepless) | Number | RW |
| vocControlSetValue | vocControl | VOC control set value (in ppm) (300 - 2000 ppm) | Number:Dimensionless | RW |
| vocControlSteps | vocControl | VOC control steps (in ppm) (50 - 400 ppm) | Number:Dimensionless | RW |
| comfortTemp | unitConfig | Comfort Temperature (10.0 - 25.0 °C) | Number:Temperature | RW |
| partyModeDuration | operation | Party mode duration (in minutes) (5 - 180 min) | Number:Time | RW |
| partyModeFanStage | operation | Party mode fan stage (0 - 4) | Number | RW |
| partyModeRemainingTime | operation | Party mode remaining time (0 - 180 min) | Number:Time | R |
| partyModeStatus | operation | Party mode status | Switch | RW |
| standbyModeDuration | operation | Standby mode duration (in minutes) (5 - 180 min) | Number:Time | RW |
| standbyModeFanStage | operation | Standby mode fan stage (0 - 4) | Number | RW |
| standbyModeRemainingTime | operation | Standby mode remaining time (0 - 180 min) | Number:Time | R |
| standbyModeStatus | operation | Standby mode status | Switch | RW |
| operatingMode | operation | Operating mode (automatic/manual) (OFF = automatic, ON = manual) | Switch | RW |
| fanStage | operation | Fan stage (0 - 4) | Number | RW |
| percentageFanStage | operation | Fan stage in percent (0 - 100 %) | Number:Dimensionless | R |
| temperatureOutsideAir | general | Ouside air temperature in °C (-27.0 - 9998.9 °C) | Number:Temperature | R |
| temperatureSupplyAir | general | Supply air temperature in °C (-27.0 - 9998.9 °C) | Number:Temperature | R |
| temperatureOutgoingAir | general | Outgoing air temperature in °C (-27.0 - 9998.9 °C) | Number:Temperature | R |
| temperatureExtractAir | general | Extract air temperature in °C (-27.0 - 9998.9 °C) | Number:Temperature | R |
| vhzDuctSensor | general | Pre-heater intake temperature in °C (-27.0 - 9998.9 °C) | Number:Temperature | R |
| nhzReturnSensor | general | After-heater return temperature in °C (-27.0 - 9998.9 °C) | Number:Temperature | R |
| externalSensorKwlFtfHumidity1 | humidityControl | External humidity sensor 1 (-0.0 - 9998.9 %) | Number:Dimensionless | R |
| externalSensorKwlFtfHumidity2 | humidityControl | External humidity sensor 2 (-0.0 - 9998.9 %) | Number:Dimensionless | R |
| externalSensorKwlFtfHumidity3 | humidityControl | External humidity sensor 3 (-0.0 - 9998.9 %) | Number:Dimensionless | R |
| externalSensorKwlFtfHumidity4 | humidityControl | External humidity sensor 4 (-0.0 - 9998.9 %) | Number:Dimensionless | R |
| externalSensorKwlFtfHumidity5 | humidityControl | External humidity sensor 5 (-0.0 - 9998.9 %) | Number:Dimensionless | R |
| externalSensorKwlFtfHumidity6 | humidityControl | External humidity sensor 6 (-0.0 - 9998.9 %) | Number:Dimensionless | R |
| externalSensorKwlFtfHumidity7 | humidityControl | External humidity sensor 7 (-0.0 - 9998.9 %) | Number:Dimensionless | R |
| externalSensorKwlFtfHumidity8 | humidityControl | External humidity sensor 8 (-0.0 - 9998.9 %) | Number:Dimensionless | R |
| externalSensorKwlFtfTemperature1 | humidityControl | External temperature sensor 1 (-27.0 - 9998.9 °C) | Number:Temperature | R |
| externalSensorKwlFtfTemperature2 | humidityControl | External temperature sensor 2 (-27.0 - 9998.9 °C) | Number:Temperature | R |
| externalSensorKwlFtfTemperature3 | humidityControl | External temperature sensor 3 (-27.0 - 9998.9 °C) | Number:Temperature | R |
| externalSensorKwlFtfTemperature4 | humidityControl | External temperature sensor 4 (-27.0 - 9998.9 °C) | Number:Temperature | R |
| externalSensorKwlFtfTemperature5 | humidityControl | External temperature sensor 5 (-27.0 - 9998.9 °C) | Number:Temperature | R |
| externalSensorKwlFtfTemperature6 | humidityControl | External temperature sensor 6 (-27.0 - 9998.9 °C) | Number:Temperature | R |
| externalSensorKwlFtfTemperature7 | humidityControl | External temperature sensor 7 (-27.0 - 9998.9 °C) | Number:Temperature | R |
| externalSensorKwlFtfTemperature8 | humidityControl | External temperature sensor 8 (-27.0 - 9998.9 °C) | Number:Temperature | R |
| externalSensorKwlCo21 | co2Control | External CO2 sensor 1 (-0.0 - 9998.9 ppm) | Number:Dimensionless | R |
| externalSensorKwlCo22 | co2Control | External CO2 sensor 2 (-0.0 - 9998.9 ppm) | Number:Dimensionless | R |
| externalSensorKwlCo23 | co2Control | External CO2 sensor 3 (-0.0 - 9998.9 ppm) | Number:Dimensionless | R |
| externalSensorKwlCo24 | co2Control | External CO2 sensor 4 (-0.0 - 9998.9 ppm) | Number:Dimensionless | R |
| externalSensorKwlCo25 | co2Control | External CO2 sensor 5 (-0.0 - 9998.9 ppm) | Number:Dimensionless | R |
| externalSensorKwlCo26 | co2Control | External CO2 sensor 6 (-0.0 - 9998.9 ppm) | Number:Dimensionless | R |
| externalSensorKwlCo27 | co2Control | External CO2 sensor 7 (-0.0 - 9998.9 ppm) | Number:Dimensionless | R |
| externalSensorKwlCo28 | co2Control | External CO2 sensor 8 (-0.0 - 9998.9 ppm) | Number:Dimensionless | R |
| externalSensorKwlVoc1 | vocControl | External VOC sensor 1 (-0.0 - 9998.9 ppm) | Number:Dimensionless | R |
| externalSensorKwlVoc2 | vocControl | External VOC sensor 2 (-0.0 - 9998.9 ppm) | Number:Dimensionless | R |
| externalSensorKwlVoc3 | vocControl | External VOC sensor 3 (-0.0 - 9998.9 ppm) | Number:Dimensionless | R |
| externalSensorKwlVoc4 | vocControl | External VOC sensor 4 (-0.0 - 9998.9 ppm) | Number:Dimensionless | R |
| externalSensorKwlVoc5 | vocControl | External VOC sensor 5 (-0.0 - 9998.9 ppm) | Number:Dimensionless | R |
| externalSensorKwlVoc6 | vocControl | External VOC sensor 6 (-0.0 - 9998.9 ppm) | Number:Dimensionless | R |
| externalSensorKwlVoc7 | vocControl | External VOC sensor 7 (-0.0 - 9998.9 ppm) | Number:Dimensionless | R |
| externalSensorKwlVoc8 | vocControl | External VOC sensor 8 (-0.0 - 9998.9 ppm) | Number:Dimensionless | R |
| nhzDuctSensor | general | After-heater intake temperature in °C (-27.0 - 9998.9 °C) | Number:Temperature | R |
| weekProfileNhz | profiles | Week profile after-heater (0 = standard 1, 1 = standard 2, 2 = fixed value, 3 = individual 1, 4 = individual 2, 5 = NA, 6 = off) | Number | RW |
| supplyAirRpm | general | Supply air fan RPM (0 - 9999) | Number | R |
| extractAirRpm | general | Extract air fan RPM (0 - 9999) | Number | R |
| holidayProgramme | operation | Holiday programme (0 = off, 1 = interval, 2 = constant) | Number | RW |
| holidayProgrammeFanStage | operation | Holiday programme fan stage (0 - 4) | Number | RW |
| holidayProgrammeStart | operation | Holiday programme start | DateTime | RW |
| holidayProgrammeEnd | operation | Holiday programme end | DateTime | RW |
| holidayProgrammeInterval | operation | Holiday programme interval in hours (1 - 24 h) | Number:Time | RW |
| holidayProgrammeActivationTime | operation | Holiday programme activation time in minutes (5 - 300 min) | Number:Time | RW |
| runOnTimeVhzNhz | unitConfig | Stopping time preheater/afterheater in seconds (60 - 120 s) | Number:Time | RW |
| errorOutputFunction | unitConfig | Error output function (collective error or just error) (1 = collective error, 2 = only error) | Number | RW |
| filterChange | unitConfig | Filter change | Switch | RW |
| filterChangeInterval | unitConfig | Filter change interval in months (1 - 12) | Number | RW |
| filterChangeRemainingTime | general | Filter change remaining time in minutes (1 - 55000 min) | Number:Time | R |
| bypassRoomTemperature | unitConfig | Bypass room temperature in °C (10 - 40 °C) | Number:Temperature | RW |
| bypassMinOutsideTemperature | unitConfig | Bypass outside temperature in °C (5 - 20 °C) | Number:Temperature | RW |
| supplyAirFanStage | operation | Supply air fan stage (0 - 4) | Number | RW |
| extractAirFanStage | operation | Extract air fan stage (0 - 4) | Number | RW |
| operatingHoursSupplyAirVent | general | Operating hours supply air fan (in minutes) (0 - 2^32-1 min) | Number:Time | R |
| operatingHoursExtractAirVent | general | Operating hours extract air fan (in minutes) (0 - 2^32-1 min) | Number:Time | R |
| operatingHoursVhz | general | Operating hours preheater (in minutes) (0 - 2^32-1 min) | Number:Time | R |
| operatingHoursNhz | general | Operating hours afterheater (in minutes) (0 - 2^32-1 min) | Number:Time | R |
| outputPowerVhz | general | Output power of preheater (in percent) (0 - 2^32-1 %) | Number:Dimensionless | R |
| outputPowerNhz | general | Output power of afterheater (in percent) (0 - 2^32-1 %) | Number:Dimensionless | R |
| errors | general | Errors as integer value (0 - 2^32-1) | Number | R |
| warnings | general | Warnings as integer value (0 - 2^32-1) | Number | R |
| infos | general | Infos as integer value (0 - 2^32-1) | Number | R |
| noOfErrors | general | Number of bit-coded errors (0 - 32) | Number | R |
| noOfWarnings | general | Number of bit-coded warnings (0 - 8) | Number | R |
| noOfInfos | general | Number of bit-coded infos (0 - 8) | Number | R |
| errorsMsg | general | Errors as string | String | R |
| warningsMsg | general | Warnings as string | String | R |
| infosMsg | general | Infos as string | String | R |
| statusFlags | general | Status flags | String | R |
| bypassStatus | general | Status of the bypass (OFF = closed, ON = open) | Switch | R |
| bypassFrom | unitConfig | Bypass active from | DateTime | RW |
| bypassTo | unitConfig | Bypass active to | DateTime | RW |
## Thing Actions
### Reset Filter Change Timer
Resets the timer for the next filter change back to 0.
```
public void resetFilterChangeTimer()
```
### Reset Errors
Resets the error messages.
```
public void resetErrors()
```
### Reset To Factory Defaults
Resets the device to its factory defaults.
```
public void presetToFactoryDefaults()
```
### Reset Switching Times
Resets the device's individual switching times back to the default values.
```
public void resetSwitchingTimes()
```
### Set System Date and Time
Sets the device's system date and time to the openHAB server's system date and time.
```
public void setSysDateTime()
```
### Set Bypass Dates
Sets the devices start and end date for the active bypass functionality.
```
public void setBypassFrom(int day, int month)
```
*Parameters:*
* *day:* The day from when the bypass should be active
* *month:* The month from when the bypass should be active
```
public void setBypassTo(int day, int month)
```
*Parameters:*
* *day:* The day until when the bypass should be active
* *month:* The month until when the bypass should be active
## Properties
The binding provides the following properties:
| Property | Description |
| -------------------------------- | -------------------------------------------------------------------------------------------------------------------------------- |
| articleDescription | The KWL's article description |
| refNo | The KWL's reference number |
| macAddress | The KWL's MAC Address |
| language | The KWL user interface's language (de, en, fr, hr, hu, it, pl, sk, sl) |
| voltageFanStage1ExtractAir | Voltage of extract air fan mapped to fan stage 1 (1.6 - 10 V) |
| voltageFanStage2ExtractAir | Voltage of extract air fan mapped to fan stage 2 (1.6 - 10 V) |
| voltageFanStage3ExtractAir | Voltage of extract air fan mapped to fan stage 3 (1.6 - 10 V) |
| voltageFanStage4ExtractAir | Voltage of extract air fan mapped to fan stage 4 (1.6 - 10 V) |
| voltageFanStage1SupplyAir | Voltage of supply air fan mapped to fan stage 1 (1.6 - 10 V) |
| voltageFanStage2SupplyAir | Voltage of supply air fan mapped to fan stage 2 (1.6 - 10 V) |
| voltageFanStage3SupplyAir | Voltage of supply air fan mapped to fan stage 3 (1.6 - 10 V) |
| voltageFanStage4SupplyAir | Voltage of supply air fan mapped to fan stage 4 (1.6 - 10 V) |
| kwlBe | Slide switch controller KWL-BE activated |
| kwlBec | Comfort controller KWL-BEC activated |
| unitConfig | Ventilation unit configuration (type of house) (1 = DiBt, 2 = passive-house) |
| kwlFtfConfig0 | Humidity/temperature sensor configuration 0 (1 = only humidity, 2 = only temperature, 3 = combined) |
| kwlFtfConfig1 | Humidity/temperature sensor configuration 1 (1 = only humidity, 2 = only temperature, 3 = combined) |
| kwlFtfConfig2 | Humidity/temperature sensor configuration 2 (1 = only humidity, 2 = only temperature, 3 = combined) |
| kwlFtfConfig3 | Humidity/temperature sensor configuration 3 (1 = only humidity, 2 = only temperature, 3 = combined) |
| kwlFtfConfig4 | Humidity/temperature sensor configuration 4 (1 = only humidity, 2 = only temperature, 3 = combined) |
| kwlFtfConfig5 | Humidity/temperature sensor configuration 5 (1 = only humidity, 2 = only temperature, 3 = combined) |
| kwlFtfConfig6 | Humidity/temperature sensor configuration 6 (1 = only humidity, 2 = only temperature, 3 = combined) |
| kwlFtfConfig7 | Humidity/temperature sensor configuration 7 (1 = only humidity, 2 = only temperature, 3 = combined) |
| humidityControlStatus | Humidity control status (0 = off, 1 = stepped, 2 = stepless) |
| co2ControlStatus | CO2 control status (0 = off, 1 = stepped, 2 = stepless) |
| dateFormat | Date format (0 = dd.mm.yyyy, 1 = mm.dd.yyyy, 2 = yyyy.mm.dd) |
| heatExchangerType | Heat exchanger type (0 = plastic, 1 = aluminium, 2 = enthalpy) |
| serNo | Serial number |
| prodCode | Production Code |
| vhzType | Pre-heater type (1 = EH-Basis, 2 EH-ERW, 3 = SEWT, 4 = LEWT) |
| functionTypeKwlEm | Function KWL-EM (1 = function 1, 2 = function 2) |
| externalContact | External contact (1 -6 (function 1-6)) |
| fanStageStepped0to2v | Fan stage for stepped mode - range 0-2V (0 - 2) |
| fanStageStepped2to4v | Fan stage for stepped mode - range 2-4V (0 - 4) |
| fanStageStepped4to6v | Fan stage for stepped mode - range 4-6V (0 - 4) |
| fanStageStepped6to8v | Fan stage for stepped mode - range 6-8V (0 - 4) |
| fanStageStepped8to10v | Fan stage for stepped mode - range 8-10V (0 - 4) |
| offsetExtractAir | Offset extract air (float) |
| assignmentFanStages | Assignment fan stages - stepped or 0-10V (OFF = 0-10V, ON = stepped) |
| sensorNameHumidityAndTemp1 | Sensor name - humidity and temperature 1 |
| sensorNameHumidityAndTemp2 | Sensor name - humidity and temperature 2 |
| sensorNameHumidityAndTemp3 | Sensor name - humidity and temperature 3 |
| sensorNameHumidityAndTemp4 | Sensor name - humidity and temperature 4 |
| sensorNameHumidityAndTemp5 | Sensor name - humidity and temperature 5 |
| sensorNameHumidityAndTemp6 | Sensor name - humidity and temperature 6 |
| sensorNameHumidityAndTemp7 | Sensor name - humidity and temperature 7 |
| sensorNameHumidityAndTemp8 | Sensor name - humidity and temperature 8 |
| sensorNameCo21 | Sensor name - CO2 1 |
| sensorNameCo22 | Sensor name - CO2 2 |
| sensorNameCo23 | Sensor name - CO2 3 |
| sensorNameCo24 | Sensor name - CO2 4 |
| sensorNameCo25 | Sensor name - CO2 5 |
| sensorNameCo26 | Sensor name - CO2 6 |
| sensorNameCo27 | Sensor name - CO2 7 |
| sensorNameCo28 | Sensor name - CO2 8 |
| sensorNameVoc1 | Sensor name - VOC 1 |
| sensorNameVoc2 | Sensor name - VOC 2 |
| sensorNameVoc3 | Sensor name - VOC 3 |
| sensorNameVoc4 | Sensor name - VOC 4 |
| sensorNameVoc5 | Sensor name - VOC 5 |
| sensorNameVoc6 | Sensor name - VOC 6 |
| sensorNameVoc7 | Sensor name - VOC 7 |
| sensorNameVoc8 | Sensor name - VOC 8 |
| softwareVersionBasis | Software version basis (format xx.xx) |
| sensorConfigKwlFtf1 | Sensor configuration (installed or not) KWL-FTF 1 (OFF = no sensor, ON = sensor installed) |
| sensorConfigKwlFtf2 | Sensor configuration (installed or not) KWL-FTF 2 (OFF = no sensor, ON = sensor installed) |
| sensorConfigKwlFtf3 | Sensor configuration (installed or not) KWL-FTF 3 (OFF = no sensor, ON = sensor installed) |
| sensorConfigKwlFtf4 | Sensor configuration (installed or not) KWL-FTF 4 (OFF = no sensor, ON = sensor installed) |
| sensorConfigKwlFtf5 | Sensor configuration (installed or not) KWL-FTF 5 (OFF = no sensor, ON = sensor installed) |
| sensorConfigKwlFtf6 | Sensor configuration (installed or not) KWL-FTF 6 (OFF = no sensor, ON = sensor installed) |
| sensorConfigKwlFtf7 | Sensor configuration (installed or not) KWL-FTF 7 (OFF = no sensor, ON = sensor installed) |
| sensorConfigKwlFtf8 | Sensor configuration (installed or not) KWL-FTF 8 (OFF = no sensor, ON = sensor installed) |
## Full Example
### Thing Configuration
```
Bridge modbus:tcp:modbus-gateway "Modbus TCP/IP Gateway" [ host="192.168.47.11", port=502, id=180, enableDiscovery=true ] {
Thing helios-ventilation-easycontrols kwl "KWL"
}
```
### Item Configuration
```
// Manual operation
Number KWL_Manual "Manual operation" <fan> (gKWL) {channel="modbus:helios-ventilation-easycontrols:modbus-gateway:kwl:operation#operatingMode"}
Number KWL_Stage "KWL fan stage" <fan> (gKWL) {channel="modbus:helios-ventilation-easycontrols:modbus-gateway:kwl:operation#fanStage"}
Number:Dimensionless KWL_Stage_Percent "KWL fan stage [%d %unit%]" <fan> (gKWL) {channel="modbus:helios-ventilation-easycontrols:modbus-gateway:kwl:operation#percentageFanStage"}
// Party mode
Switch KWL_Party_Mode "Party mode" <parents> (gKWL) {channel="modbus:helios-ventilation-easycontrols:modbus-gateway:kwl:operation#partyModeStatus"}
Number KWL_Party_Mode_Duration "Party mode duration" <clock> (gKWL) {channel="modbus:helios-ventilation-easycontrols:modbus-gateway:kwl:operation#partyModeDuration"}
Number KWL_Party_Mode_Stage "Party mode fan stage" <fan> (gKWL) {channel="modbus:helios-ventilation-easycontrols:modbus-gateway:kwl:operation#partyModeFanStage"}
Number KWL_Party_Mode_Remaining "Party mode remaining time [%d min]" <clock> (gKWL) {channel="modbus:helios-ventilation-easycontrols:modbus-gateway:kwl:operation#partyModeRemainingTime"}
// Standby mode
Switch KWL_Standby_Mode "Standby mode" <fan_off> (gKWL) {channel="modbus:helios-ventilation-easycontrols:modbus-gateway:kwl:operation#standbyModeStatus"}
Number KWL_Standby_Mode_Duration "Standby mode duration" <clock> (gKWL) {channel="modbus:helios-ventilation-easycontrols:modbus-gateway:kwl:operation#standbyModeDuration"}
Number KWL_Standby_Mode_Stage "Standby mode fan stage" <fan> (gKWL) {channel="modbus:helios-ventilation-easycontrols:modbus-gateway:kwl:operation#standbyModeFanStage"}
Number KWL_Standby_Mode_Remaining "Standby mode remaining time [%d min]" <clock> (gKWL) {channel="modbus:helios-ventilation-easycontrols:modbus-gateway:kwl:operation#standbyModeRemainingTime"}
// Status infos
Number:Temperature KWL_Temp_Outide_Air "Temperature outside air [%.1f °C]" <temperature> (gKWL) {channel="modbus:helios-ventilation-easycontrols:modbus-gateway:kwl:general#temperatureOutsideAir"}
Number:Temperature KWL_Temp_Supply_Air "Temperature supply air [%.1f °C]" <temperature> (gKWL) {channel="modbus:helios-ventilation-easycontrols:modbus-gateway:kwl:general#temperatureSupplyAir"}
Number:Temperature KWL_Temp_Outgoing_Air "Temperature outgoing air [%.1f °C]" <temperature> (gKWL) {channel="modbus:helios-ventilation-easycontrols:modbus-gateway:kwl:general#temperatureOutgoingAir"}
Number:Temperature KWL_Temp_Extract_Air "Temperature extract air [%.1f °C]" <temperature> (gKWL) {channel="modbus:helios-ventilation-easycontrols:modbus-gateway:kwl:general#temperatureExtractAir"}
Number KWL_Supply_Air_RPM "RPM supply air [%d]" <fan> (gKWL) {channel="modbus:helios-ventilation-easycontrols:modbus-gateway:kwl:general#supplyAirRpm"}
Number KWL_Extract_Air_RPM "RPM extract air [%d]" <fan> (gKWL) {channel="modbus:helios-ventilation-easycontrols:modbus-gateway:kwl:general#extractAirRpm"}
Number KWL_Filter_Change "Filter change [MAP(helios_yes_no.map):%s]" <none> (gKWL) {channel="modbus:helios-ventilation-easycontrols:modbus-gateway:kwl:unitConfig#filterChange"}
Number KWL_Filter_Change_Remaining "Filter change [%d %unit%]" <clock> (gKWL) {channel="modbus:helios-ventilation-easycontrols:modbus-gateway:kwl:general#filterChangeRemainingTime"}
Number KWL_Errors "Number errors [%d]" <error> (gKWL) {channel="modbus:helios-ventilation-easycontrols:modbus-gateway:kwl:general#noOfErrors"}
String KWL_Errors_String "Error messages [%s]" <error> (gKWL) {channel="modbus:helios-ventilation-easycontrols:modbus-gateway:kwl:general#errorsMsg"}
Number KWL_Warnings "Number warnings [%d]" <warning> (gKWL) {channel="modbus:helios-ventilation-easycontrols:modbus-gateway:kwl:general#noOfWarnings"}
String KWL_Warnings_String "Warning messages [%s]" <warning> (gKWL) {channel="modbus:helios-ventilation-easycontrols:modbus-gateway:kwl:general#warningsMsg"}
Number KWL_Infos "Number infos [%d]" <info> (gKWL) {channel="modbus:helios-ventilation-easycontrols:modbus-gateway:kwl:general#noOfInfos"}
String KWL_Infos_String "Info messages [%s]" <info> (gKWL) {channel="modbus:helios-ventilation-easycontrols:modbus-gateway:kwl:general#infosMsg"}
```
### Transformation
```
0=no
1=yes
OFF=no
ON=yes
-=-
NULL=-
```
### Sitemap
```
Text label="KWL" icon="fan" {
Frame label="Manual operation" {
Selection item=KWL_Manual mappings=[0=Auto, 1=Manual]
Selection item=KWL_Stage mappings=[0=off, 1="Stage 1", 2="Stage 2", 3="Stage 3", 4="Stage 4"]
Text item=KWL_Stage_Percent
}
Frame label="Party mode" {
Switch item=KWL_Party_Mode mappings=[OFF=off, ON=on]
Selection item=KWL_Party_Mode_Stage mappings=[0=off, 1="Stage 1", 2="Stage 2", 3="Stage 3", 4="Stage 4"]
Selection item=KWL_Standby_Mode_Duration mappings=[60="60 Minutes", 120="120 Minutes", 180="180 Minutes", 240="240 Minutes"]
Text item=KWL_Party_Mode_Remaining
}
Frame label="Standby mode" {
Switch item=KWL_Standby_Mode mappings=[OFF=Aus, ON=Ein]
Selection item=KWL_Standby_Mode_Stage mappings=[0=off, 1="Stage 1", 2="Stage 2", 3="Stage 3", 4="Stage 4"]
Selection item=KWL_Standby_Mode_Duration mappings=[60="60 Minutes", 120="120 Minutes", 180="180 Minutes", 240="240 Minutes"]
Text item=KWL_Standby_Mode_Remaining
}
Frame label="Status infos" {
Text item=KWL_Temp_Outide_Air
Text item=KWL_Temp_Supply_Air
Text item=KWL_Temp_Outgoing_Air
Text item=KWL_Temp_Extract_Air
Text item=KWL_Supply_Air_RPM
Text item=KWL_Extract_Air_RPM
Text item=KWL_Filter_Change
Text item=KWL_Filter_Change_Remaining
Text item=KWL_Errors_String
Text item=KWL_Warnings_String
Text item=KWL_Infos_String
Text item=KWL_Datum
Text item=KWL_Zeit
}
}
```

View File

@@ -0,0 +1,32 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.openhab.addons.bundles</groupId>
<artifactId>org.openhab.addons.reactor.bundles</artifactId>
<version>3.0.0-SNAPSHOT</version>
</parent>
<artifactId>org.openhab.binding.modbus.helioseasycontrols</artifactId>
<name>openHAB Add-ons :: Bundles :: HeliosEasyControls Binding</name>
<dependencies>
<dependency>
<groupId>org.openhab.addons.bundles</groupId>
<artifactId>org.openhab.io.transport.modbus</artifactId>
<version>${project.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.openhab.addons.bundles</groupId>
<artifactId>org.openhab.binding.modbus</artifactId>
<version>${project.version}</version>
<scope>provided</scope>
</dependency>
</dependencies>
</project>

View File

@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<features name="org.openhab.binding.modbus.helioseasycontrols-${project.version}" xmlns="http://karaf.apache.org/xmlns/features/v1.4.0">
<repository>file:${basedirRoot}/bundles/org.openhab.io.transport.modbus/target/feature/feature.xml</repository>
<feature name="openhab-binding-modbus.helioseasycontrols" description="Modbus.HeliosEasyControls Binding" version="${project.version}">
<feature>openhab-runtime-base</feature>
<feature>openhab-transport-modbus</feature>
<bundle start-level="80">mvn:org.openhab.addons.bundles/org.openhab.binding.modbus/${project.version}</bundle>
<bundle start-level="80">mvn:org.openhab.addons.bundles/org.openhab.binding.modbus.helioseasycontrols/${project.version}</bundle>
</feature>
</features>

View File

@@ -0,0 +1,162 @@
/**
* Copyright (c) 2010-2020 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.modbus.helioseasycontrols.internal;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.core.automation.annotation.ActionInput;
import org.openhab.core.automation.annotation.RuleAction;
import org.openhab.core.thing.binding.ThingActions;
import org.openhab.core.thing.binding.ThingActionsScope;
import org.openhab.core.thing.binding.ThingHandler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* This class provides the actions available for the Helios device
*
* @author Bernhard Bauer - Initial contribution
*/
@ThingActionsScope(name = "modbus.helioseasycontrols")
@NonNullByDefault
public class HeliosEasyControlsActions implements ThingActions {
private @Nullable HeliosEasyControlsHandler handler;
private final Logger logger = LoggerFactory.getLogger(HeliosEasyControlsActions.class);
@Override
public void setThingHandler(@Nullable ThingHandler handler) {
this.handler = (HeliosEasyControlsHandler) handler;
}
@Override
public @Nullable ThingHandler getThingHandler() {
return handler;
}
private void triggerSwitch(String variableName) {
try {
if (this.handler != null) {
this.handler.writeValue(variableName, "1");
}
} catch (HeliosException e) {
logger.warn("Error executing action 'resetFilterChangeTimer': {}", e.getMessage());
}
}
@RuleAction(label = "Reset filter change timer", description = "Sets the filter change timer back to the configured interval")
public void resetFilterChangeTimer() {
this.triggerSwitch(HeliosEasyControlsBindingConstants.FILTER_CHANGE_RESET);
}
public static void resetFilterChangeTimer(@Nullable ThingActions actions) {
if (actions instanceof HeliosEasyControlsActions) {
((HeliosEasyControlsActions) actions).resetFilterChangeTimer();
} else {
throw new IllegalArgumentException("Instance is not an HeliosEasyControlsActions class.");
}
}
@RuleAction(label = "Reset error messages", description = "Reset error/warning/info messages")
public void resetErrors() {
this.triggerSwitch(HeliosEasyControlsBindingConstants.RESET_FLAG);
}
public static void resetErrors(@Nullable ThingActions actions) {
if (actions instanceof HeliosEasyControlsActions) {
((HeliosEasyControlsActions) actions).resetErrors();
} else {
throw new IllegalArgumentException("Instance is not an HeliosEasyControlsActions class.");
}
}
@RuleAction(label = "Reset to factory defaults", description = "Reset device to factory defaults")
public void resetToFactoryDefaults() {
this.triggerSwitch(HeliosEasyControlsBindingConstants.FACTORY_RESET);
}
public static void resetToFactoryDefaults(@Nullable ThingActions actions) {
if (actions instanceof HeliosEasyControlsActions) {
((HeliosEasyControlsActions) actions).resetToFactoryDefaults();
} else {
throw new IllegalArgumentException("Instance is not an HeliosEasyControlsActions class.");
}
}
@RuleAction(label = "Reset individual switching times", description = "Reset individual switching times")
public void resetSwitchingTimes() {
this.triggerSwitch(HeliosEasyControlsBindingConstants.FACTORY_SETTING_WZU);
}
public static void resetSwitchingTimes(@Nullable ThingActions actions) {
if (actions instanceof HeliosEasyControlsActions) {
((HeliosEasyControlsActions) actions).resetSwitchingTimes();
} else {
throw new IllegalArgumentException("Instance is not an HeliosEasyControlsActions class.");
}
}
@RuleAction(label = "Set system date and time", description = "Sets the device's system date and time based on OH's system date and time")
public void setSysDateTime() {
HeliosEasyControlsHandler handler = this.handler;
if (handler != null) {
handler.setSysDateTime();
}
}
public static void setSysDateTime(@Nullable ThingActions actions) {
if (actions instanceof HeliosEasyControlsActions) {
((HeliosEasyControlsActions) actions).setSysDateTime();
} else {
throw new IllegalArgumentException("Instance is not an HeliosEasyControlsActions class.");
}
}
private void setBypass(boolean from, int day, int month) {
HeliosEasyControlsHandler handler = this.handler;
if (handler != null) {
handler.setBypass(from, day, month);
}
}
@RuleAction(label = "Set the bypass from day and month", description = "Sets the day and month from when the bypass should be active")
public void setBypassFrom(
@ActionInput(name = "day", label = "bypass from day", description = "The day from when the bypass should be active") int day,
@ActionInput(name = "month", label = "bypass from month", description = "The month from when the bypass should be active") int month) {
this.setBypass(true, day, month);
}
public static void setBypassFrom(@Nullable ThingActions actions, int day, int month) {
if (actions instanceof HeliosEasyControlsActions) {
((HeliosEasyControlsActions) actions).setBypassFrom(day, month);
} else {
throw new IllegalArgumentException("Instance is not an HeliosEasyControlsActions class.");
}
}
@RuleAction(label = "Set the bypass to day and month", description = "Sets the day and month until when the bypass should be active")
public void setBypassTo(
@ActionInput(name = "day", label = "bypass to day", description = "The day until when the bypass should be active") int day,
@ActionInput(name = "month", label = "bypass to month", description = "The month until when the bypass should be active") int month) {
this.setBypass(false, day, month);
}
public static void setBypassTo(@Nullable ThingActions actions, int day, int month) {
if (actions instanceof HeliosEasyControlsActions) {
((HeliosEasyControlsActions) actions).setBypassTo(day, month);
} else {
throw new IllegalArgumentException("Instance is not an HeliosEasyControlsActions class.");
}
}
}

View File

@@ -0,0 +1,319 @@
/**
* Copyright (c) 2010-2020 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.modbus.helioseasycontrols.internal;
import java.util.Arrays;
import java.util.List;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.binding.modbus.ModbusBindingConstants;
import org.openhab.core.thing.ThingTypeUID;
/**
* The {@link HeliosEasyControlsBindingConstants} class defines common constants, which are
* used across the whole binding.
*
* @author Bernhard Bauer - Initial contribution
*/
@NonNullByDefault
public class HeliosEasyControlsBindingConstants {
private static final String BINDING_ID = ModbusBindingConstants.BINDING_ID;
// List of all Thing Type UIDs
public static final ThingTypeUID THING_TYPE_HELIOS_VENTILATION_EASY_CONTROLS = new ThingTypeUID(BINDING_ID,
"helios-easycontrols");
// List of all Channel IDs
// -----------------------
// Device Config
public final static String SYS_DATE = "sysdate"; // for the combined item (based on DATE, TIME and
// TIME_ZONE_DIFFERENCE_TO_GMT)
public final static String DATE = "date";
public final static String TIME = "time";
public final static String TIME_ZONE_DIFFERENCE_TO_GMT = "timeZoneDifferenceToGmt";
public final static String SUMMER_WINTER = "summerWinter";
public final static String ACCESS_HELIOS_PORTAL = "accessHeliosPortal";
public final static String AUTO_SW_UPDATE = "autoSwUpdate";
public final static String MIN_FAN_STAGE = "minFanStage";
public final static String COMFORT_TEMP = "comfortTemp";
public final static String SUPPLY_AIR_FAN_STAGE = "supplyAirFanStage";
public final static String EXTRACT_AIR_FAN_STAGE = "extractAirFanStage";
// Operation
public final static String PARTY_MODE_DURATION = "partyModeDuration";
public final static String PARTY_MODE_FAN_STAGE = "partyModeFanStage";
public final static String PARTY_MODE_REMAINING_TIME = "partyModeRemainingTime";
public final static String PARTY_MODE_STATUS = "partyModeStatus";
public final static String STANDBY_MODE_DURATION = "standbyModeDuration";
public final static String STANDBY_MODE_FAN_STAGE = "standbyModeFanStage";
public final static String STANDBY_MODE_REMAINING_TIME = "standbyModeRemainingTime";
public final static String STANDBY_MODE_STATUS = "standbyModeStatus";
public final static String HOLIDAY_PROGRAMME = "holidayProgramme";
public final static String HOLIDAY_PROGRAMME_FAN_STAGE = "holidayProgrammeFanStage";
public final static String HOLIDAY_PROGRAMME_START = "holidayProgrammeStart";
public final static String HOLIDAY_PROGRAMME_END = "holidayProgrammeEnd";
public final static String HOLIDAY_PROGRAMME_INTERVAL = "holidayProgrammeInterval";
public final static String HOLIDAY_PROGRAMME_ACTIVATION_TIME = "holidayProgrammeActivationTime";
public final static String OPERATING_MODE = "operatingMode";
public final static String FAN_STAGE = "fanStage";
public final static String PERCENTAGE_FAN_STAGE = "percentageFanStage";
public final static String TEMPERATURE_OUTSIDE_AIR = "temperatureOutsideAir";
public final static String TEMPERATURE_SUPPLY_AIR = "temperatureSupplyAir";
public final static String TEMPERATURE_OUTGOING_AIR = "temperatureOutgoingAir";
public final static String TEMPERATURE_EXTRACT_AIR = "temperatureExtractAir";
public final static String VHZ_DUCT_SENSOR = "vhzDuctSensor";
public final static String NHZ_DUCT_SENSOR = "nhzDuctSensor";
public final static String NHZ_RETURN_SENSOR = "nhzReturnSensor";
public final static String SUPPLY_AIR_RPM = "supplyAirRpm";
public final static String EXTRACT_AIR_RPM = "extractAirRpm";
public final static String OPERATING_HOURS_SUPPLY_AIR_VENT = "operatingHoursSupplyAirVent";
public final static String OPERATING_HOURS_EXTRACT_AIR_VENT = "operatingHoursExtractAirVent";
// Heater
public final static String PRE_HEATER_STATUS = "preHeaterStatus";
public final static String WEEK_PROFILE_NHZ = "weekProfileNhz";
public final static String RUN_ON_TIME_VHZ_NHZ = "runOnTimeVhzNhz";
public final static String OPERATING_HOURS_VHZ = "operatingHoursVhz";
public final static String OPERATING_HOURS_NHZ = "operatingHoursNhz";
public final static String OUTPUT_POWER_VHZ = "outputPowerVhz";
public final static String OUTPUT_POWER_NHZ = "outputPowerNhz";
// Humidity control
public final static String HUMIDITY_CONTROL_SET_VALUE = "humidityControlSetValue";
public final static String HUMIDITY_CONTROL_STEPS = "humidityControlSteps";
public final static String HUMIDITY_STOP_TIME = "humidityStopTime";
public final static String EXTERNAL_SENSOR_KWL_FTF_HUMIDITY_1 = "externalSensorKwlFtfHumidity1";
public final static String EXTERNAL_SENSOR_KWL_FTF_HUMIDITY_2 = "externalSensorKwlFtfHumidity2";
public final static String EXTERNAL_SENSOR_KWL_FTF_HUMIDITY_3 = "externalSensorKwlFtfHumidity3";
public final static String EXTERNAL_SENSOR_KWL_FTF_HUMIDITY_4 = "externalSensorKwlFtfHumidity4";
public final static String EXTERNAL_SENSOR_KWL_FTF_HUMIDITY_5 = "externalSensorKwlFtfHumidity5";
public final static String EXTERNAL_SENSOR_KWL_FTF_HUMIDITY_6 = "externalSensorKwlFtfHumidity6";
public final static String EXTERNAL_SENSOR_KWL_FTF_HUMIDITY_7 = "externalSensorKwlFtfHumidity7";
public final static String EXTERNAL_SENSOR_KWL_FTF_HUMIDITY_8 = "externalSensorKwlFtfHumidity8";
public final static String EXTERNAL_SENSOR_KWL_FTF_TEMPERATURE_1 = "externalSensorKwlFtfTemperature1";
public final static String EXTERNAL_SENSOR_KWL_FTF_TEMPERATURE_2 = "externalSensorKwlFtfTemperature2";
public final static String EXTERNAL_SENSOR_KWL_FTF_TEMPERATURE_3 = "externalSensorKwlFtfTemperature3";
public final static String EXTERNAL_SENSOR_KWL_FTF_TEMPERATURE_4 = "externalSensorKwlFtfTemperature4";
public final static String EXTERNAL_SENSOR_KWL_FTF_TEMPERATURE_5 = "externalSensorKwlFtfTemperature5";
public final static String EXTERNAL_SENSOR_KWL_FTF_TEMPERATURE_6 = "externalSensorKwlFtfTemperature6";
public final static String EXTERNAL_SENSOR_KWL_FTF_TEMPERATURE_7 = "externalSensorKwlFtfTemperature7";
public final static String EXTERNAL_SENSOR_KWL_FTF_TEMPERATURE_8 = "externalSensorKwlFtfTemperature8";
// CO2 control
public final static String CO2_CONTROL_SET_VALUE = "co2ControlSetValue";
public final static String CO2_CONTROL_STEPS = "co2ControlSteps";
public final static String EXTERNAL_SENSOR_KWL_CO2_1 = "externalSensorKwlCo21";
public final static String EXTERNAL_SENSOR_KWL_CO2_2 = "externalSensorKwlCo22";
public final static String EXTERNAL_SENSOR_KWL_CO2_3 = "externalSensorKwlCo23";
public final static String EXTERNAL_SENSOR_KWL_CO2_4 = "externalSensorKwlCo24";
public final static String EXTERNAL_SENSOR_KWL_CO2_5 = "externalSensorKwlCo25";
public final static String EXTERNAL_SENSOR_KWL_CO2_6 = "externalSensorKwlCo26";
public final static String EXTERNAL_SENSOR_KWL_CO2_7 = "externalSensorKwlCo27";
public final static String EXTERNAL_SENSOR_KWL_CO2_8 = "externalSensorKwlCo28";
public final static String SENSOR_NAME_CO2_1 = "sensorNameCo21";
public final static String SENSOR_NAME_CO2_2 = "sensorNameCo22";
public final static String SENSOR_NAME_CO2_3 = "sensorNameCo23";
public final static String SENSOR_NAME_CO2_4 = "sensorNameCo24";
public final static String SENSOR_NAME_CO2_5 = "sensorNameCo25";
public final static String SENSOR_NAME_CO2_6 = "sensorNameCo26";
public final static String SENSOR_NAME_CO2_7 = "sensorNameCo27";
public final static String SENSOR_NAME_CO2_8 = "sensorNameCo28";
// VOC control
public final static String VOC_CONTROL_SET_VALUE = "vocControlSetValue";
public final static String VOC_CONTROL_STEPS = "vocControlSteps";
public final static String EXTERNAL_SENSOR_KWL_VOC_1 = "externalSensorKwlVoc1";
public final static String EXTERNAL_SENSOR_KWL_VOC_2 = "externalSensorKwlVoc2";
public final static String EXTERNAL_SENSOR_KWL_VOC_3 = "externalSensorKwlVoc3";
public final static String EXTERNAL_SENSOR_KWL_VOC_4 = "externalSensorKwlVoc4";
public final static String EXTERNAL_SENSOR_KWL_VOC_5 = "externalSensorKwlVoc5";
public final static String EXTERNAL_SENSOR_KWL_VOC_6 = "externalSensorKwlVoc6";
public final static String EXTERNAL_SENSOR_KWL_VOC_7 = "externalSensorKwlVoc7";
public final static String EXTERNAL_SENSOR_KWL_VOC_8 = "externalSensorKwlVoc8";
public final static String SENSOR_NAME_VOC_1 = "sensorNameVoc1";
public final static String SENSOR_NAME_VOC_2 = "sensorNameVoc2";
public final static String SENSOR_NAME_VOC_3 = "sensorNameVoc3";
public final static String SENSOR_NAME_VOC_4 = "sensorNameVoc4";
public final static String SENSOR_NAME_VOC_5 = "sensorNameVoc5";
public final static String SENSOR_NAME_VOC_6 = "sensorNameVoc6";
public final static String SENSOR_NAME_VOC_7 = "sensorNameVoc7";
public final static String SENSOR_NAME_VOC_8 = "sensorNameVoc8";
// Errors
public final static String ERROR_OUTPUT_FUNCTION = "errorOutputFunction";
public final static String ERRORS = "errors";
public final static String WARNINGS = "warnings";
public final static String INFOS = "infos";
public final static String NO_OF_ERRORS = "noOfErrors";
public final static String NO_OF_WARNINGS = "noOfWarnings";
public final static String NO_OF_INFOS = "noOfInfos";
public final static String ERRORS_MSG = "errorsMsg";
public final static String WARNINGS_MSG = "warningsMsg";
public final static String INFOS_MSG = "infosMsg";
public final static String STATUS_FLAGS = "statusFlags";
// Filter
public final static String FILTER_CHANGE = "filterChange";
public final static String FILTER_CHANGE_INTERVAL = "filterChangeInterval";
public final static String FILTER_CHANGE_REMAINING_TIME = "filterChangeRemainingTime";
// Bypass
public final static String BYPASS_ROOM_TEMPERATURE = "bypassRoomTemperature";
public final static String BYPASS_MIN_OUTSIDE_TEMPERATURE = "bypassMinOutsideTemperature";
public final static String BYPASS_STATUS = "bypassStatus";
public final static String BYPASS_FROM = "bypassFrom"; // for the combined item (based on BYPASS_FROM_DAY and
// BYPASS_FROM_MONTH)
public final static String BYPASS_FROM_DAY = "bypassFromDay";
public final static String BYPASS_FROM_MONTH = "bypassFromMonth";
public final static String BYPASS_TO = "bypassTo"; // for the combined item (based on BYPASS_TO_DAY and
// BYPASS_TO_MONTH)
public final static String BYPASS_TO_DAY = "bypassToDay";
public final static String BYPASS_TO_MONTH = "bypassToMonth";
// List of all Properties
// ----------------------
// Device Config
public final static String ARTICLE_DESCRIPTION = "articleDescription";
public final static String REF_NO = "refNo";
public final static String SER_NO = "serNo";
public final static String PROD_CODE = "prodCode";
public final static String MAC_ADDRESS = "macAddress";
public final static String SOFTWARE_VERSION_BASIS = "softwareVersionBasis";
public final static String DATE_FORMAT = "dateFormat";
public final static String LANGUAGE = "language";
public final static String UNIT_CONFIG = "unitConfig";
public final static String KWL_BE = "kwlBe";
public final static String KWL_BEC = "kwlBec";
public final static String EXTERNAL_CONTACT = "externalContact";
public final static String FUNCTION_TYPE_KWL_EM = "functionTypeKwlEm";
public final static String HEAT_EXCHANGER_TYPE = "heatExchangerType";
public final static String OFFSET_EXTRACT_AIR = "offsetExtractAir";
public final static String ASSIGNMENT_FAN_STAGES = "assignmentFanStages";
public final static String VOLTAGE_FAN_STAGE_1_EXTRACT_AIR = "voltageFanStage1ExtractAir";
public final static String VOLTAGE_FAN_STAGE_2_EXTRACT_AIR = "voltageFanStage2ExtractAir";
public final static String VOLTAGE_FAN_STAGE_3_EXTRACT_AIR = "voltageFanStage3ExtractAir";
public final static String VOLTAGE_FAN_STAGE_4_EXTRACT_AIR = "voltageFanStage4ExtractAir";
public final static String VOLTAGE_FAN_STAGE_1_SUPPLY_AIR = "voltageFanStage1SupplyAir";
public final static String VOLTAGE_FAN_STAGE_2_SUPPLY_AIR = "voltageFanStage2SupplyAir";
public final static String VOLTAGE_FAN_STAGE_3_SUPPLY_AIR = "voltageFanStage3SupplyAir";
public final static String VOLTAGE_FAN_STAGE_4_SUPPLY_AIR = "voltageFanStage4SupplyAir";
public final static String FAN_STAGE_STEPPED_0TO2V = "fanStageStepped0to2v";
public final static String FAN_STAGE_STEPPED_2TO4V = "fanStageStepped2to4v";
public final static String FAN_STAGE_STEPPED_4TO6V = "fanStageStepped4to6v";
public final static String FAN_STAGE_STEPPED_6TO8V = "fanStageStepped6to8v";
public final static String FAN_STAGE_STEPPED_8TO10V = "fanStageStepped8to10v";
// Heater
public final static String VHZ_TYPE = "vhzType";
// Humidty control
public final static String HUMIDITY_CONTROL_STATUS = "humidityControlStatus";
public final static String KWL_FTF_CONFIG_0 = "kwlFtfConfig0";
public final static String KWL_FTF_CONFIG_1 = "kwlFtfConfig1";
public final static String KWL_FTF_CONFIG_2 = "kwlFtfConfig2";
public final static String KWL_FTF_CONFIG_3 = "kwlFtfConfig3";
public final static String KWL_FTF_CONFIG_4 = "kwlFtfConfig4";
public final static String KWL_FTF_CONFIG_5 = "kwlFtfConfig5";
public final static String KWL_FTF_CONFIG_6 = "kwlFtfConfig6";
public final static String KWL_FTF_CONFIG_7 = "kwlFtfConfig7";
public final static String SENSOR_CONFIG_KWL_FTF_1 = "sensorConfigKwlFtf1";
public final static String SENSOR_CONFIG_KWL_FTF_2 = "sensorConfigKwlFtf2";
public final static String SENSOR_CONFIG_KWL_FTF_3 = "sensorConfigKwlFtf3";
public final static String SENSOR_CONFIG_KWL_FTF_4 = "sensorConfigKwlFtf4";
public final static String SENSOR_CONFIG_KWL_FTF_5 = "sensorConfigKwlFtf5";
public final static String SENSOR_CONFIG_KWL_FTF_6 = "sensorConfigKwlFtf6";
public final static String SENSOR_CONFIG_KWL_FTF_7 = "sensorConfigKwlFtf7";
public final static String SENSOR_CONFIG_KWL_FTF_8 = "sensorConfigKwlFtf8";
public final static String SENSOR_NAME_HUMIDITY_AND_TEMP_1 = "sensorNameHumidityAndTemp1";
public final static String SENSOR_NAME_HUMIDITY_AND_TEMP_2 = "sensorNameHumidityAndTemp2";
public final static String SENSOR_NAME_HUMIDITY_AND_TEMP_3 = "sensorNameHumidityAndTemp3";
public final static String SENSOR_NAME_HUMIDITY_AND_TEMP_4 = "sensorNameHumidityAndTemp4";
public final static String SENSOR_NAME_HUMIDITY_AND_TEMP_5 = "sensorNameHumidityAndTemp5";
public final static String SENSOR_NAME_HUMIDITY_AND_TEMP_6 = "sensorNameHumidityAndTemp6";
public final static String SENSOR_NAME_HUMIDITY_AND_TEMP_7 = "sensorNameHumidityAndTemp7";
public final static String SENSOR_NAME_HUMIDITY_AND_TEMP_8 = "sensorNameHumidityAndTemp8";
// CO2 control
public final static String CO2_CONTROL_STATUS = "co2ControlStatus";
// VOC control
public final static String VOC_CONTROL_STATUS = "vocControlStatus";
// List of all variables used in actions
public final static String FILTER_CHANGE_RESET = "filterChangeReset";
public final static String FACTORY_SETTING_WZU = "factorySettingWzu";
public final static String FACTORY_RESET = "factoryReset";
public final static String RESET_FLAG = "resetFlag";
// List of all unused variables (defined in the specification but not implemented as channels, properties or
// actions)
public final static String GLOBAL_MANUAL_WEB_UPDATE = "globalManualWebUpdate";
public final static String PORTAL_GLOBALS_ERROR_FOR_WEB = "portalGlobalsErrorForWeb";
public final static String CLEAR_ERROR = "clearError";
public final static String TBD = "tbd";
public final static String LOGOUT = "logout";
// List of all Configuration Parameters
public final static String CONFIG_REFRESH_INTERVAL = "refreshInterval";
// Other constants
public final static int UNIT_ID = 180;
public final static int START_ADDRESS = 1;
public final static String VARIABLES_DEFINITION_FILE = "variables.json";
public final static int MAX_TRIES = 5;
// List of all variables that have to be updated regardless if they are linked to an item
public final static List<String> ALWAYS_UPDATE_VARIABLES = Arrays.asList(
HeliosEasyControlsBindingConstants.DATE_FORMAT, HeliosEasyControlsBindingConstants.DATE,
HeliosEasyControlsBindingConstants.TIME, HeliosEasyControlsBindingConstants.TIME_ZONE_DIFFERENCE_TO_GMT,
HeliosEasyControlsBindingConstants.BYPASS_FROM_DAY, HeliosEasyControlsBindingConstants.BYPASS_FROM_MONTH,
HeliosEasyControlsBindingConstants.BYPASS_TO_DAY, HeliosEasyControlsBindingConstants.BYPASS_TO_MONTH);
// List of all properties
public final static List<String> PROPERTY_NAMES = Arrays.asList(
HeliosEasyControlsBindingConstants.ARTICLE_DESCRIPTION, HeliosEasyControlsBindingConstants.REF_NO,
HeliosEasyControlsBindingConstants.SER_NO, HeliosEasyControlsBindingConstants.PROD_CODE,
HeliosEasyControlsBindingConstants.MAC_ADDRESS, HeliosEasyControlsBindingConstants.SOFTWARE_VERSION_BASIS,
HeliosEasyControlsBindingConstants.DATE_FORMAT, HeliosEasyControlsBindingConstants.LANGUAGE,
HeliosEasyControlsBindingConstants.UNIT_CONFIG, HeliosEasyControlsBindingConstants.KWL_BE,
HeliosEasyControlsBindingConstants.KWL_BEC, HeliosEasyControlsBindingConstants.EXTERNAL_CONTACT,
HeliosEasyControlsBindingConstants.FUNCTION_TYPE_KWL_EM,
HeliosEasyControlsBindingConstants.HEAT_EXCHANGER_TYPE,
HeliosEasyControlsBindingConstants.OFFSET_EXTRACT_AIR,
HeliosEasyControlsBindingConstants.ASSIGNMENT_FAN_STAGES,
HeliosEasyControlsBindingConstants.VOLTAGE_FAN_STAGE_1_EXTRACT_AIR,
HeliosEasyControlsBindingConstants.VOLTAGE_FAN_STAGE_2_EXTRACT_AIR,
HeliosEasyControlsBindingConstants.VOLTAGE_FAN_STAGE_3_EXTRACT_AIR,
HeliosEasyControlsBindingConstants.VOLTAGE_FAN_STAGE_4_EXTRACT_AIR,
HeliosEasyControlsBindingConstants.VOLTAGE_FAN_STAGE_1_SUPPLY_AIR,
HeliosEasyControlsBindingConstants.VOLTAGE_FAN_STAGE_2_SUPPLY_AIR,
HeliosEasyControlsBindingConstants.VOLTAGE_FAN_STAGE_3_SUPPLY_AIR,
HeliosEasyControlsBindingConstants.VOLTAGE_FAN_STAGE_4_SUPPLY_AIR,
HeliosEasyControlsBindingConstants.FAN_STAGE_STEPPED_0TO2V,
HeliosEasyControlsBindingConstants.FAN_STAGE_STEPPED_2TO4V,
HeliosEasyControlsBindingConstants.FAN_STAGE_STEPPED_4TO6V,
HeliosEasyControlsBindingConstants.FAN_STAGE_STEPPED_6TO8V,
HeliosEasyControlsBindingConstants.FAN_STAGE_STEPPED_8TO10V, HeliosEasyControlsBindingConstants.VHZ_TYPE,
HeliosEasyControlsBindingConstants.HUMIDITY_CONTROL_STATUS,
HeliosEasyControlsBindingConstants.KWL_FTF_CONFIG_0, HeliosEasyControlsBindingConstants.KWL_FTF_CONFIG_1,
HeliosEasyControlsBindingConstants.KWL_FTF_CONFIG_2, HeliosEasyControlsBindingConstants.KWL_FTF_CONFIG_3,
HeliosEasyControlsBindingConstants.KWL_FTF_CONFIG_4, HeliosEasyControlsBindingConstants.KWL_FTF_CONFIG_5,
HeliosEasyControlsBindingConstants.KWL_FTF_CONFIG_6, HeliosEasyControlsBindingConstants.KWL_FTF_CONFIG_7,
HeliosEasyControlsBindingConstants.SENSOR_CONFIG_KWL_FTF_1,
HeliosEasyControlsBindingConstants.SENSOR_CONFIG_KWL_FTF_2,
HeliosEasyControlsBindingConstants.SENSOR_CONFIG_KWL_FTF_3,
HeliosEasyControlsBindingConstants.SENSOR_CONFIG_KWL_FTF_4,
HeliosEasyControlsBindingConstants.SENSOR_CONFIG_KWL_FTF_5,
HeliosEasyControlsBindingConstants.SENSOR_CONFIG_KWL_FTF_6,
HeliosEasyControlsBindingConstants.SENSOR_CONFIG_KWL_FTF_7,
HeliosEasyControlsBindingConstants.SENSOR_CONFIG_KWL_FTF_8,
HeliosEasyControlsBindingConstants.SENSOR_NAME_HUMIDITY_AND_TEMP_1,
HeliosEasyControlsBindingConstants.SENSOR_NAME_HUMIDITY_AND_TEMP_2,
HeliosEasyControlsBindingConstants.SENSOR_NAME_HUMIDITY_AND_TEMP_3,
HeliosEasyControlsBindingConstants.SENSOR_NAME_HUMIDITY_AND_TEMP_4,
HeliosEasyControlsBindingConstants.SENSOR_NAME_HUMIDITY_AND_TEMP_5,
HeliosEasyControlsBindingConstants.SENSOR_NAME_HUMIDITY_AND_TEMP_6,
HeliosEasyControlsBindingConstants.SENSOR_NAME_HUMIDITY_AND_TEMP_7,
HeliosEasyControlsBindingConstants.SENSOR_NAME_HUMIDITY_AND_TEMP_8,
HeliosEasyControlsBindingConstants.CO2_CONTROL_STATUS,
HeliosEasyControlsBindingConstants.VOC_CONTROL_STATUS);
}

View File

@@ -0,0 +1,37 @@
/**
* Copyright (c) 2010-2020 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.modbus.helioseasycontrols.internal;
import org.eclipse.jdt.annotation.NonNullByDefault;
/**
* The {@link HeliosEasyControlsConfiguration} class contains fields mapping thing configuration parameters.
*
* @author Bernhard Bauer - Initial contribution
*/
@NonNullByDefault
public class HeliosEasyControlsConfiguration {
/**
* The binding's refresh interval
*/
private int refreshInterval;
public int getRefreshInterval() {
return refreshInterval;
}
public void setRefreshInterval(int refreshInterval) {
this.refreshInterval = refreshInterval;
}
}

View File

@@ -0,0 +1,791 @@
/**
* Copyright (c) 2010-2020 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.modbus.helioseasycontrols.internal;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.lang.reflect.Type;
import java.nio.charset.StandardCharsets;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.util.Collection;
import java.util.Collections;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.binding.modbus.handler.ModbusEndpointThingHandler;
import org.openhab.core.library.types.DateTimeType;
import org.openhab.core.library.types.DecimalType;
import org.openhab.core.library.types.OnOffType;
import org.openhab.core.library.types.QuantityType;
import org.openhab.core.library.types.StringType;
import org.openhab.core.library.unit.SIUnits;
import org.openhab.core.library.unit.SmartHomeUnits;
import org.openhab.core.thing.Bridge;
import org.openhab.core.thing.Channel;
import org.openhab.core.thing.ChannelUID;
import org.openhab.core.thing.Thing;
import org.openhab.core.thing.ThingStatus;
import org.openhab.core.thing.ThingStatusDetail;
import org.openhab.core.thing.binding.BaseThingHandler;
import org.openhab.core.thing.binding.ThingHandler;
import org.openhab.core.thing.binding.ThingHandlerService;
import org.openhab.core.types.Command;
import org.openhab.core.types.RefreshType;
import org.openhab.core.types.State;
import org.openhab.io.transport.modbus.ModbusBitUtilities;
import org.openhab.io.transport.modbus.ModbusCommunicationInterface;
import org.openhab.io.transport.modbus.ModbusReadFunctionCode;
import org.openhab.io.transport.modbus.ModbusReadRequestBlueprint;
import org.openhab.io.transport.modbus.ModbusRegister;
import org.openhab.io.transport.modbus.ModbusRegisterArray;
import org.openhab.io.transport.modbus.ModbusWriteRegisterRequestBlueprint;
import org.openhab.io.transport.modbus.endpoint.ModbusSlaveEndpoint;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
/**
* The {@link HeliosEasyControlsHandler} is responsible for handling commands, which are
* sent to one of the channels.
*
* @author Bernhard Bauer - Initial contribution
*/
@NonNullByDefault
public class HeliosEasyControlsHandler extends BaseThingHandler {
private final Logger logger = LoggerFactory.getLogger(HeliosEasyControlsHandler.class);
private @Nullable HeliosEasyControlsConfiguration config;
private @Nullable ScheduledFuture<?> pollingJob;
private @Nullable Map<String, HeliosVariable> variableMap;
/**
* This flag is used to ensure read requests (consisting of a write and subsequent read) are not influenced by
* another transaction
*/
private final Map<ModbusSlaveEndpoint, Semaphore> transactionLocks = new ConcurrentHashMap<>();
private final Gson gson = new Gson();
private @Nullable ModbusCommunicationInterface comms;
private int dateFormat = -1;
private ZonedDateTime sysDate = ZonedDateTime.now(); // initialize with local system time as a best guess
// before reading from device
private class BypassDate {
// initialization to avoid issues when updating before all variables were read
private int month = 1;
private int day = 1;
public void setMonth(int month) {
this.month = month;
}
public void setDay(int day) {
this.day = day;
}
public DateTimeType toDateTimeType() {
return new DateTimeType(ZonedDateTime.of(1900, this.month, this.day, 0, 0, 0, 0, ZoneId.of("UTC+00:00")));
}
}
private @Nullable BypassDate bypassFrom, bypassTo;
public HeliosEasyControlsHandler(Thing thing) {
super(thing);
}
/**
* Reads variable definitions from JSON file and store them in variableMap
*/
private void readVariableDefinition() {
Type vMapType = new TypeToken<Map<String, HeliosVariable>>() {
}.getType();
try (InputStreamReader jsonFile = new InputStreamReader(
getClass().getResourceAsStream(HeliosEasyControlsBindingConstants.VARIABLES_DEFINITION_FILE));
BufferedReader reader = new BufferedReader(jsonFile)) {
this.variableMap = gson.fromJson(reader, vMapType);
} catch (IOException e) {
this.handleError("Error reading variable definition file", ThingStatusDetail.CONFIGURATION_ERROR);
}
if (variableMap != null) {
// add the name to the variable itself
for (Map.Entry<String, HeliosVariable> entry : this.variableMap.entrySet()) {
entry.getValue().setName(entry.getKey()); // workaround to set the variable name inside the
// HeliosVariable object
if (!entry.getValue().isOk()) {
this.handleError("Variables definition file contains inconsistent data",
ThingStatusDetail.CONFIGURATION_ERROR);
}
}
} else {
this.handleError("Variables definition file not found or of illegal format",
ThingStatusDetail.CONFIGURATION_ERROR);
}
}
/**
* Get the endpoint handler from the bridge this handler is connected to
* Checks that we're connected to the right type of bridge
*
* @return the endpoint handler or null if the bridge does not exist
*/
private @Nullable ModbusEndpointThingHandler getEndpointThingHandler() {
Bridge bridge = getBridge();
if (bridge == null) {
logger.debug("Bridge is null");
return null;
}
if (bridge.getStatus() != ThingStatus.ONLINE) {
logger.debug("Bridge is not online");
return null;
}
ThingHandler handler = bridge.getHandler();
if (handler == null) {
logger.debug("Bridge handler is null");
return null;
}
if (handler instanceof ModbusEndpointThingHandler) {
return (ModbusEndpointThingHandler) handler;
} else {
logger.debug("Unexpected bridge handler: {}", handler);
return null;
}
}
/**
* Get a reference to the modbus endpoint
*/
private void connectEndpoint() {
if (this.comms != null) {
return;
}
ModbusEndpointThingHandler slaveEndpointThingHandler = getEndpointThingHandler();
if (slaveEndpointThingHandler == null) {
@SuppressWarnings("null")
String label = Optional.ofNullable(getBridge()).map(b -> b.getLabel()).orElse("<null>");
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.BRIDGE_OFFLINE,
String.format("Bridge '%s' is offline", label));
logger.debug("No bridge handler available -- aborting init for {}", label);
return;
}
comms = slaveEndpointThingHandler.getCommunicationInterface();
if (comms == null) {
@SuppressWarnings("null")
String label = Optional.ofNullable(getBridge()).map(b -> b.getLabel()).orElse("<null>");
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.BRIDGE_OFFLINE,
String.format("Bridge '%s' not completely initialized", label));
logger.debug("Bridge not initialized fully (no endpoint) -- aborting init for {}", this);
return;
}
}
@Override
public void initialize() {
this.config = getConfigAs(HeliosEasyControlsConfiguration.class);
this.readVariableDefinition();
this.connectEndpoint();
if ((this.comms != null) && (this.variableMap != null) && (this.config != null)) {
this.transactionLocks.putIfAbsent(this.comms.getEndpoint(), new Semaphore(1, true));
updateStatus(ThingStatus.UNKNOWN);
// background initialization
scheduler.execute(() -> {
readValue(HeliosEasyControlsBindingConstants.DATE_FORMAT);
// status will be updated to ONLINE by the read callback function (via processResponse)
});
// poll for status updates regularly
HeliosEasyControlsConfiguration config = this.config;
if (config != null) {
this.pollingJob = scheduler.scheduleWithFixedDelay(() -> {
if (variableMap != null) {
for (Map.Entry<String, HeliosVariable> entry : variableMap.entrySet()) {
if (this.isProperty(entry.getKey()) || isLinked(entry.getValue().getGroupAndName())
|| HeliosEasyControlsBindingConstants.ALWAYS_UPDATE_VARIABLES
.contains(entry.getKey())) {
readValue(entry.getKey());
}
}
} else {
handleError("Variable definition is null", ThingStatusDetail.CONFIGURATION_ERROR);
}
}, config.getRefreshInterval(), config.getRefreshInterval(), TimeUnit.MILLISECONDS);
}
} else { // at least one null assertion has failed, let's log the problem and update the thing status
if (this.comms == null) {
this.handleError("Modbus communication interface is unavailable",
ThingStatusDetail.COMMUNICATION_ERROR);
}
if (this.variableMap == null) {
this.handleError("Variable definition is unavailable", ThingStatusDetail.CONFIGURATION_ERROR);
}
if (this.config == null) {
this.handleError("Binding configuration is unavailable", ThingStatusDetail.CONFIGURATION_ERROR);
}
}
}
@Override
public void dispose() {
if (this.pollingJob != null) {
this.pollingJob.cancel(true);
}
this.comms = null;
}
@Override
public void handleCommand(ChannelUID channelUID, Command command) {
String channelId = channelUID.getIdWithoutGroup();
if (command instanceof RefreshType) {
if (channelId.equals(HeliosEasyControlsBindingConstants.SYS_DATE)) {
scheduler.submit(() -> readValue(HeliosEasyControlsBindingConstants.DATE));
scheduler.submit(() -> readValue(HeliosEasyControlsBindingConstants.TIME));
} else if (channelId.equals(HeliosEasyControlsBindingConstants.BYPASS_FROM)) {
scheduler.submit(() -> readValue(HeliosEasyControlsBindingConstants.BYPASS_FROM_DAY));
scheduler.submit(() -> readValue(HeliosEasyControlsBindingConstants.BYPASS_FROM_MONTH));
} else if (channelId.equals(HeliosEasyControlsBindingConstants.BYPASS_TO)) {
scheduler.submit(() -> readValue(HeliosEasyControlsBindingConstants.BYPASS_TO_DAY));
scheduler.submit(() -> readValue(HeliosEasyControlsBindingConstants.BYPASS_TO_MONTH));
} else {
scheduler.submit(() -> readValue(channelId));
}
} else { // write command
String value = null;
if (command instanceof OnOffType) {
value = command == OnOffType.ON ? "1" : "0";
} else if (command instanceof DateTimeType) {
ZonedDateTime d = ((DateTimeType) command).getZonedDateTime();
if (channelId.equals(HeliosEasyControlsBindingConstants.SYS_DATE)) {
setSysDateTime(d);
} else if (channelId.equals(HeliosEasyControlsBindingConstants.BYPASS_FROM)) {
this.setBypass(true, d.getDayOfMonth(), d.getMonthValue());
} else if (channelId.equals(HeliosEasyControlsBindingConstants.BYPASS_TO)) {
this.setBypass(false, d.getDayOfMonth(), d.getMonthValue());
} else {
value = formatDate(channelId, ((DateTimeType) command).getZonedDateTime());
}
} else if ((command instanceof DecimalType) || (command instanceof StringType)) {
value = command.toString();
} else if (command instanceof QuantityType<?>) {
// convert item's unit to the Helios device's unit
Map<String, HeliosVariable> variableMap = this.variableMap;
if (variableMap != null) {
String unit = variableMap.get(channelId).getUnit();
QuantityType<?> val = (QuantityType<?>) command;
if (unit != null) {
switch (unit) {
case HeliosVariable.UNIT_DAY:
val = val.toUnit(SmartHomeUnits.DAY);
break;
case HeliosVariable.UNIT_HOUR:
val = val.toUnit(SmartHomeUnits.HOUR);
break;
case HeliosVariable.UNIT_MIN:
val = val.toUnit(SmartHomeUnits.MINUTE);
break;
case HeliosVariable.UNIT_SEC:
val = val.toUnit(SmartHomeUnits.SECOND);
break;
case HeliosVariable.UNIT_VOLT:
val = val.toUnit(SmartHomeUnits.VOLT);
break;
case HeliosVariable.UNIT_PERCENT:
val = val.toUnit(SmartHomeUnits.PERCENT);
break;
case HeliosVariable.UNIT_PPM:
val = val.toUnit(SmartHomeUnits.PARTS_PER_MILLION);
break;
case HeliosVariable.UNIT_TEMP:
val = val.toUnit(SIUnits.CELSIUS);
break;
}
value = val != null ? String.valueOf(val.doubleValue()) : null; // ignore the UoM
}
}
}
if (value != null) {
final String v = value;
scheduler.submit(() -> {
try {
writeValue(channelId, v);
if (variableMap != null) {
updateState(variableMap.get(channelId), v);
updateStatus(ThingStatus.ONLINE);
}
} catch (HeliosException e) {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
"Writing value " + v + "to channel " + channelId + " failed: " + e.getMessage());
}
});
}
}
}
@Override
public Collection<Class<? extends ThingHandlerService>> getServices() {
return Collections.singleton(HeliosEasyControlsActions.class);
}
/**
* Checks if the provided variable name is a property
*
* @param variableName The variable's name
* @return true if the variable is a property
*/
private boolean isProperty(String variableName) {
return HeliosEasyControlsBindingConstants.PROPERTY_NAMES.contains(variableName);
}
/**
* Writes a variable value to the Helios device
*
* @param variableName The variable name
* @param value The new value
* @return The value if the transaction succeeded, <tt>null</tt> otherwise
* @throws HeliosException Thrown if the variable is read-only or the provided value is out of range
*/
public void writeValue(String variableName, String value) throws HeliosException {
if (this.variableMap == null) {
this.handleError("Variable definition is unavailable.", ThingStatusDetail.CONFIGURATION_ERROR);
return;
} else {
Map<String, HeliosVariable> variableMap = this.variableMap;
if (variableMap != null) {
HeliosVariable v = variableMap.get(variableName);
if (!v.hasWriteAccess()) {
throw new HeliosException("Variable " + variableName + " is read-only");
} else if (!v.isInAllowedRange(value)) {
throw new HeliosException(
"Value " + value + " is outside of allowed range of variable " + variableName);
} else if (this.comms != null) {
// write to device
String payload = v.getVariableString() + "=" + value;
ModbusCommunicationInterface comms = this.comms;
if (comms != null) {
final Semaphore lock = transactionLocks.get(comms.getEndpoint());
try {
lock.acquire();
comms.submitOneTimeWrite(
new ModbusWriteRegisterRequestBlueprint(HeliosEasyControlsBindingConstants.UNIT_ID,
HeliosEasyControlsBindingConstants.START_ADDRESS,
new ModbusRegisterArray(preparePayload(payload)), true,
HeliosEasyControlsBindingConstants.MAX_TRIES),
result -> {
lock.release();
updateStatus(ThingStatus.ONLINE);
}, failureInfo -> {
lock.release();
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
"Error writing to device: " + failureInfo.getCause().getMessage());
});
} catch (InterruptedException e) {
logger.warn(
"{} encountered Exception when trying to lock Semaphore for writing variable {} to the device: {}",
HeliosEasyControlsHandler.class.getSimpleName(), variableName, e.getMessage());
}
}
} else { // comms is null
this.handleError("Modbus communication interface is null", ThingStatusDetail.COMMUNICATION_ERROR);
}
}
}
}
/**
* Read a variable from the Helios device
*
* @param variableName The variable name
* @return The value
*/
public void readValue(String variableName) {
Map<String, HeliosVariable> variableMap = this.variableMap;
ModbusCommunicationInterface comms = this.comms;
if ((comms != null) && (variableMap != null)) {
final Semaphore lock = transactionLocks.get(comms.getEndpoint());
HeliosVariable v = variableMap.get(variableName);
if (v.hasReadAccess()) {
try {
lock.acquire(); // will block until lock is available
} catch (InterruptedException e) {
logger.warn("{} encountered Exception when trying to read variable {} from the device: {}",
HeliosEasyControlsHandler.class.getSimpleName(), variableName, e.getMessage());
return;
}
// write variable name to register
String payload = v.getVariableString();
comms.submitOneTimeWrite(new ModbusWriteRegisterRequestBlueprint(
HeliosEasyControlsBindingConstants.UNIT_ID, HeliosEasyControlsBindingConstants.START_ADDRESS,
new ModbusRegisterArray(preparePayload(payload)), true,
HeliosEasyControlsBindingConstants.MAX_TRIES), result -> {
comms.submitOneTimePoll(
new ModbusReadRequestBlueprint(HeliosEasyControlsBindingConstants.UNIT_ID,
ModbusReadFunctionCode.READ_MULTIPLE_REGISTERS,
HeliosEasyControlsBindingConstants.START_ADDRESS, v.getCount(),
HeliosEasyControlsBindingConstants.MAX_TRIES),
pollResult -> {
lock.release();
Optional<ModbusRegisterArray> registers = pollResult.getRegisters();
if (registers.isPresent()) {
processResponse(v, registers.get());
}
}, failureInfo -> {
lock.release();
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
"Error reading from device: " + failureInfo.getCause().getMessage());
});
}, failureInfo -> {
lock.release();
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
"Error writing to device: " + failureInfo.getCause().getMessage());
});
}
} else {
if (this.comms == null) {
this.handleError("Modbus communication interface is unavailable",
ThingStatusDetail.COMMUNICATION_ERROR);
}
if (variableMap == null) {
this.handleError("Variable definition is unavailable", ThingStatusDetail.CONFIGURATION_ERROR);
}
}
}
private void updateSysDate(DateTimeType dateTime) {
this.updateSysDateTime(dateTime.getZonedDateTime(), true, sysDate.getOffset().getTotalSeconds() / 60 / 60);
}
private void updateSysTime(DateTimeType dateTime) {
this.updateSysDateTime(dateTime.getZonedDateTime(), false, sysDate.getOffset().getTotalSeconds() / 60 / 60);
}
private void updateUtcOffset(int utcOffset) {
this.updateSysDateTime(this.sysDate, true, sysDate.getOffset().getTotalSeconds() / 60 / 60);
}
private void updateSysDateTime(ZonedDateTime dateTime, boolean updateDate, int utcOffset) {
ZonedDateTime sysDate = this.sysDate;
sysDate = ZonedDateTime.of(updateDate ? dateTime.getYear() : sysDate.getYear(),
updateDate ? dateTime.getMonthValue() : sysDate.getMonthValue(),
updateDate ? dateTime.getDayOfMonth() : sysDate.getDayOfMonth(),
updateDate ? sysDate.getHour() : dateTime.getHour(),
updateDate ? sysDate.getMinute() : dateTime.getMinute(),
updateDate ? sysDate.getSecond() : dateTime.getSecond(), 0,
ZoneId.of("UTC" + (utcOffset >= 0 ? "+" : "") + String.format("%02d", utcOffset) + ":00"));
updateState("general#" + HeliosEasyControlsBindingConstants.SYS_DATE, new DateTimeType(sysDate));
this.sysDate = sysDate;
}
private void setSysDateTime(ZonedDateTime date) {
try {
this.writeValue(HeliosEasyControlsBindingConstants.DATE,
this.formatDate(HeliosEasyControlsBindingConstants.DATE, date));
this.writeValue(HeliosEasyControlsBindingConstants.TIME,
date.getHour() + ":" + date.getMinute() + ":" + date.getSecond());
this.writeValue(HeliosEasyControlsBindingConstants.TIME_ZONE_DIFFERENCE_TO_GMT,
Integer.toString(date.getOffset().getTotalSeconds() / 60 / 60));
} catch (HeliosException e) {
logger.warn("{} encountered Exception when trying to set system date: {}",
HeliosEasyControlsHandler.class.getSimpleName(), e.getMessage());
}
}
protected void setSysDateTime() {
this.setSysDateTime(ZonedDateTime.now());
}
private void updateBypass(boolean from, boolean month, int val) {
BypassDate bypassDate = from ? this.bypassFrom : this.bypassTo;
if (bypassDate == null) {
bypassDate = new BypassDate();
}
if (month) {
bypassDate.setMonth(val);
} else {
bypassDate.setDay(val);
}
updateState("unitConfig#" + (from ? HeliosEasyControlsBindingConstants.BYPASS_FROM
: HeliosEasyControlsBindingConstants.BYPASS_TO), bypassDate.toDateTimeType());
if (from) {
this.bypassFrom = bypassDate;
} else {
this.bypassTo = bypassDate;
}
}
protected void setBypass(boolean from, int day, int month) {
try {
this.writeValue(from ? HeliosEasyControlsBindingConstants.BYPASS_FROM_DAY
: HeliosEasyControlsBindingConstants.BYPASS_TO_DAY, Integer.toString(day));
this.writeValue(from ? HeliosEasyControlsBindingConstants.BYPASS_FROM_MONTH
: HeliosEasyControlsBindingConstants.BYPASS_TO_MONTH, Integer.toString(month));
} catch (HeliosException e) {
logger.warn("{} encountered Exception when trying to set bypass period: {}",
HeliosEasyControlsHandler.class.getSimpleName(), e.getMessage());
}
}
/**
* Formats the provided date to a string in the device's configured date format
*
* @param variableName the variable name
* @param date the date to be formatted
* @return a string in the device's configured date format
*/
public String formatDate(String variableName, ZonedDateTime date) {
String y = Integer.toString(date.getYear());
String m = Integer.toString(date.getMonthValue());
if (m.length() == 1) {
m = "0" + m;
}
String d = Integer.toString(date.getDayOfMonth());
if (d.length() == 1) {
d = "0" + d;
}
if (variableName.equals(HeliosEasyControlsBindingConstants.DATE)) { // fixed format for writing the system date
return d + "." + m + "." + y;
} else {
switch (this.dateFormat) {
case 0: // dd.mm.yyyy
return d + "." + m + "." + y;
case 1: // mm.dd.yyyy
return m + "." + d + "." + y;
case 2: // yyyy.mm.dd
return y + "." + m + "." + d;
default:
return d + "." + m + "." + y;
}
}
}
/**
* Returns a DateTimeType object based on the provided String and the device's configured date format
*
* @param date The date string read from the device
* @return A DateTimeType object representing the date or time specified
*/
private DateTimeType toDateTime(String date) {
String[] dateTimeParts = null;
String dateTime = date;
dateTimeParts = date.split("\\."); // try to split date components
if (dateTimeParts.length == 1) { // time
return DateTimeType.valueOf(date);
} else if (dateTimeParts.length == 3) { // date - we'll try the device's date format
switch (this.dateFormat) {
case 0: // dd.mm.yyyy
dateTime = dateTimeParts[2] + "-" + dateTimeParts[1] + "-" + dateTimeParts[0];
break;
case 1: // mm.dd.yyyy
dateTime = dateTimeParts[2] + "-" + dateTimeParts[0] + "-" + dateTimeParts[1];
break;
case 2: // yyyy.mm.dd
dateTime = dateTimeParts[0] + "-" + dateTimeParts[1] + "-" + dateTimeParts[2];
break;
default:
dateTime = dateTimeParts[2] + "-" + dateTimeParts[1] + "-" + dateTimeParts[0];
break;
}
return DateTimeType.valueOf(dateTime);
}
// falling back to default date format (apparently using the configured format has failed)
dateTime = dateTimeParts[2] + "-" + dateTimeParts[1] + "-" + dateTimeParts[0];
return DateTimeType.valueOf(dateTime);
}
private @Nullable QuantityType<?> toQuantityType(String value, @Nullable String unit) {
if (unit == null) {
return null;
} else if (unit.equals(HeliosVariable.UNIT_DAY)) {
return new QuantityType<>(Integer.parseInt(value), SmartHomeUnits.DAY);
} else if (unit.equals(HeliosVariable.UNIT_HOUR)) {
return new QuantityType<>(Integer.parseInt(value), SmartHomeUnits.HOUR);
} else if (unit.equals(HeliosVariable.UNIT_MIN)) {
return new QuantityType<>(Integer.parseInt(value), SmartHomeUnits.MINUTE);
} else if (unit.equals(HeliosVariable.UNIT_SEC)) {
return new QuantityType<>(Integer.parseInt(value), SmartHomeUnits.SECOND);
} else if (unit.equals(HeliosVariable.UNIT_VOLT)) {
return new QuantityType<>(Float.parseFloat(value), SmartHomeUnits.VOLT);
} else if (unit.equals(HeliosVariable.UNIT_PERCENT)) {
return new QuantityType<>(Float.parseFloat(value), SmartHomeUnits.PERCENT);
} else if (unit.equals(HeliosVariable.UNIT_PPM)) {
return new QuantityType<>(Float.parseFloat(value), SmartHomeUnits.PARTS_PER_MILLION);
} else if (unit.equals(HeliosVariable.UNIT_TEMP)) {
return new QuantityType<>(Float.parseFloat(value), SIUnits.CELSIUS);
} else {
return null;
}
}
/**
* Prepares the payload for the request
*
* @param payload The String representation of the payload
* @return The Register representation of the payload
*/
private ModbusRegister[] preparePayload(String payload) {
// determine number of registers
int l = (payload.length() + 1) / 2; // +1 because we need to include at least one termination symbol 0x00
if ((payload.length() + 1) % 2 != 0) {
l++;
}
ModbusRegister reg[] = new ModbusRegister[l];
byte[] b = payload.getBytes();
int ch = 0;
for (int i = 0; i < reg.length; i++) {
byte b1 = ch < b.length ? b[ch] : (byte) 0x00; // terminate with 0x00 if at the end of the payload
ch++;
byte b2 = ch < b.length ? b[ch] : (byte) 0x00;
ch++;
reg[i] = new ModbusRegister(b1, b2);
}
return reg;
}
/**
* Decodes the Helios device' response and updates the channel with the actual value of the variable
*
* @param response The registers received from the Helios device
* @return The value or <tt>null</tt> if an error occurred
*/
private void processResponse(HeliosVariable v, ModbusRegisterArray registers) {
String r = ModbusBitUtilities
.extractStringFromRegisters(registers, 0, registers.size() * 2, StandardCharsets.US_ASCII).toString();
String[] parts = r.split("=", 2); // remove the part "vXXXX=" from the string
// making sure we have a proper response and the response matches the requested variable
if ((parts.length == 2) && (v.getVariableString().equals(parts[0]))) {
if (this.isProperty(v.getName())) {
try {
updateProperty(v.getName(), v.formatPropertyValue(parts[1]));
} catch (HeliosException e) {
logger.warn("{} encountered Exception when trying to update property: {}",
HeliosEasyControlsHandler.class.getSimpleName(), e.getMessage());
}
} else {
this.updateState(v, parts[1]);
}
} else { // another variable was read
logger.warn("{} tried to read value from variable {} and the result provided by the device was {}",
HeliosEasyControlsHandler.class.getSimpleName(), v.getName(), r);
}
}
private void updateState(HeliosVariable v, String value) {
String variableType = v.getType();
// System date and time
if (v.getName().equals(HeliosEasyControlsBindingConstants.DATE)) {
this.updateSysDate(this.toDateTime(value));
} else if (v.getName().equals(HeliosEasyControlsBindingConstants.TIME)) {
this.updateSysTime(this.toDateTime(value));
} else if (v.getName().equals(HeliosEasyControlsBindingConstants.TIME_ZONE_DIFFERENCE_TO_GMT)) {
this.updateUtcOffset(Integer.parseInt(value));
// Bypass
} else if (v.getName().equals(HeliosEasyControlsBindingConstants.BYPASS_FROM_DAY)) {
this.updateBypass(true, false, Integer.parseInt(value));
} else if (v.getName().equals(HeliosEasyControlsBindingConstants.BYPASS_FROM_MONTH)) {
this.updateBypass(true, true, Integer.parseInt(value));
} else if (v.getName().equals(HeliosEasyControlsBindingConstants.BYPASS_TO_DAY)) {
this.updateBypass(false, false, Integer.parseInt(value));
} else if (v.getName().equals(HeliosEasyControlsBindingConstants.BYPASS_TO_MONTH)) {
this.updateBypass(false, true, Integer.parseInt(value));
} else {
Channel channel = getThing().getChannel(v.getGroupAndName());
String itemType;
if (channel != null) {
itemType = channel.getAcceptedItemType();
if (itemType != null) {
if (itemType.startsWith("Number:")) {
itemType = "Number";
}
switch (itemType) {
case "Number":
if (((variableType.equals(HeliosVariable.TYPE_INTEGER))
|| (variableType == HeliosVariable.TYPE_FLOAT)) && (!value.equals("-"))) {
State state = null;
if (v.getUnit() == null) {
state = DecimalType.valueOf(value);
} else { // QuantityType
state = this.toQuantityType(value, v.getUnit());
}
if (state != null) {
updateState(v.getGroupAndName(), state);
updateStatus(ThingStatus.ONLINE);
// update date format and UTC offset upon read
if (v.getName().equals(HeliosEasyControlsBindingConstants.DATE_FORMAT)) {
this.dateFormat = Integer.parseInt(value);
}
}
}
break;
case "Switch":
if (variableType.equals(HeliosVariable.TYPE_INTEGER)) {
updateState(v.getGroupAndName(), value.equals("1") ? OnOffType.ON : OnOffType.OFF);
}
break;
case "String":
if (variableType.equals(HeliosVariable.TYPE_STRING)) {
updateState(v.getGroupAndName(), StringType.valueOf(value));
}
break;
case "DateTime":
if (variableType.equals(HeliosVariable.TYPE_STRING)) {
updateState(v.getGroupAndName(), toDateTime(value));
}
break;
}
} else { // itemType was null
logger.warn("{} couldn't determine item type of variable {}",
HeliosEasyControlsHandler.class.getSimpleName(), v.getName());
}
} else { // channel was null
logger.warn("{} couldn't find channel for variable {}", HeliosEasyControlsHandler.class.getSimpleName(),
v.getName());
}
}
}
/**
* Logs an error (as a warning entry) and updates the thing status
*
* @param errorMsg The error message to be logged and provided with the Thing's status update
* @param status The Thing's new status
*/
private void handleError(String errorMsg, ThingStatusDetail status) {
updateStatus(ThingStatus.OFFLINE, status, errorMsg);
}
}

View File

@@ -0,0 +1,55 @@
/**
* Copyright (c) 2010-2020 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.modbus.helioseasycontrols.internal;
import static org.openhab.binding.modbus.helioseasycontrols.internal.HeliosEasyControlsBindingConstants.THING_TYPE_HELIOS_VENTILATION_EASY_CONTROLS;
import java.util.Collections;
import java.util.Set;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.core.thing.Thing;
import org.openhab.core.thing.ThingTypeUID;
import org.openhab.core.thing.binding.BaseThingHandlerFactory;
import org.openhab.core.thing.binding.ThingHandler;
import org.openhab.core.thing.binding.ThingHandlerFactory;
import org.osgi.service.component.annotations.Component;
/**
* The {@link HeliosEasyControlsHandlerFactory} is responsible for creating things and thing
* handlers.
*
* @author Bernhard Bauer - Initial contribution
*/
@NonNullByDefault
@Component(configurationPid = "binding.helioseasycontrols", service = ThingHandlerFactory.class)
public class HeliosEasyControlsHandlerFactory extends BaseThingHandlerFactory {
private static final Set<ThingTypeUID> SUPPORTED_THING_TYPES_UIDS = Collections
.singleton(THING_TYPE_HELIOS_VENTILATION_EASY_CONTROLS);
@Override
public boolean supportsThingType(ThingTypeUID thingTypeUID) {
return SUPPORTED_THING_TYPES_UIDS.contains(thingTypeUID);
}
@Override
protected @Nullable ThingHandler createHandler(Thing thing) {
ThingTypeUID thingTypeUID = thing.getThingTypeUID();
if (THING_TYPE_HELIOS_VENTILATION_EASY_CONTROLS.equals(thingTypeUID)) {
return new HeliosEasyControlsHandler(thing);
}
return null;
}
}

View File

@@ -0,0 +1,31 @@
/**
* Copyright (c) 2010-2020 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.modbus.helioseasycontrols.internal;
import org.eclipse.jdt.annotation.NonNullByDefault;
/**
* This class represents an exception specific to the HeliosEasyControls protocol.
*
* @author Bernhard Bauer - Initial contribution
* @version 2.0
*/
@NonNullByDefault
public class HeliosException extends Exception {
private static final long serialVersionUID = -7256846679824295950L;
public HeliosException(String msg) {
super(msg);
}
}

View File

@@ -0,0 +1,531 @@
/**
* Copyright (c) 2010-2020 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.modbus.helioseasycontrols.internal;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
/**
* This class represents a variable of the Helios modbus.
*
* @author Bernhard Bauer - Initial contribution
* @version 2.0
*/
@NonNullByDefault
public class HeliosVariable implements Comparable<HeliosVariable> {
/**
* Read access
*/
public static final String ACCESS_R = "R";
/**
* Write access
*/
public static final String ACCESS_W = "W";
/**
* Read and write access
*/
public static final String ACCESS_RW = "RW";
/**
* Integer type
*/
public static final String TYPE_INTEGER = "int";
/**
* Float type
*/
public static final String TYPE_FLOAT = "float";
/**
* String type
*/
public static final String TYPE_STRING = "string";
/**
* Unit Volt
*/
public static final String UNIT_VOLT = "V";
/**
* Unit %
*/
public static final String UNIT_PERCENT = "%";
/**
* Unit ppm
*/
public static final String UNIT_PPM = "ppm";
/**
* Unit degrees Celsius
*/
public static final String UNIT_TEMP = "°C";
/**
* Unit day
*/
public static final String UNIT_DAY = "d";
/**
* Unit hour
*/
public static final String UNIT_HOUR = "h";
/**
* Unit minute
*/
public static final String UNIT_MIN = "min";
/**
* Unit second
*/
public static final String UNIT_SEC = "s";
/**
* The variable number
*/
private int variable;
/**
* The variable name
*/
private String name;
/**
* The variable group
*/
private @Nullable String group;
/**
* The access to the variable
*/
private String access;
/**
* The length of the variable (number of chars)
*/
private int length;
/**
* The register count for this variable
*/
private int count;
/**
* The variable type
*/
private String type;
/**
* The variable's unit
*/
private @Nullable String unit;
/**
* The minimal value (or null if not applicable)
*/
private @Nullable Double minVal;
/**
* The maximum value (or null if not applicable)
*/
private @Nullable Double maxVal;
/**
* Constructor to set the member variables
*
* @param variable The variable's number
* @param name The variable's name
* @param group The variable's group
* @param access Access possibilities
* @param length Number of expected characters when writing to / reading from Modbus
* @param count Exact number of characters to write to Modbus
* @param type Variable type (string, integer or float)
* @param unit Variable's unit
* @param minVal Minimum value (only applicable for numeric values)
* @param maxVal Maximum value (only applicable for numeric values)
*/
public HeliosVariable(int variable, String name, @Nullable String group, String access, int length, int count,
String type, @Nullable String unit, @Nullable Double minVal, @Nullable Double maxVal) {
this.variable = variable;
this.name = name;
this.group = group;
this.access = access;
this.length = length;
this.count = count;
this.type = type;
this.unit = unit;
this.minVal = minVal;
this.maxVal = maxVal;
}
/**
* Constructor to set the member variables
*
* @param variable The variable's number
* @param name The variable's name
* @param group The variable's group
* @param access Access possibilities
* @param length Number of expected characters when writing to / reading from Modbus
* @param count Exact number of characters to write to Modbus
* @param type Variable type (string, integer or float)
* @param unit Variable's unit
*/
public HeliosVariable(int variable, String name, @Nullable String group, String access, int length, int count,
String type, String unit) {
this(variable, name, group, access, length, count, type, unit, null, null);
}
/**
* Constructor to set the member variables
*
* @param variable The variable's number
* @param name The variable's name
* @param group The variable's group
* @param access Access possibilities
* @param length Number of expected characters when writing to / reading from Modbus
* @param count Exact number of characters to write to Modbus
* @param type Variable type (string, integer or float)
*/
public HeliosVariable(int variable, String name, @Nullable String group, String access, int length, int count,
String type) {
this(variable, name, group, access, length, count, type, null, null, null);
}
/**
* Getter for variable
*
* @return variable
*/
public int getVariable() {
return this.variable;
}
/**
* Returns a formatted string representation for the variable
*
* @return String The string representation for the variable (e.g. 'v00020' for variable number 20)
*/
public String getVariableString() {
return String.format("v%05d", variable);
}
/**
* Setter for name
*
*/
public void setName(String name) {
this.name = name;
}
/**
* Getter for name
*
* @return name
*/
public String getName() {
return this.name;
}
/**
* Getter for group
*
* @return group
*/
public @Nullable String getGroup() {
return this.group;
}
/**
* Getter for access
*
* @return access
*/
public String getAccess() {
return this.access;
}
/**
* Getter for length
*
* @return length
*/
public int getLength() {
return this.length;
}
/**
* Getter for count
*
* @return count
*/
public int getCount() {
return this.count;
}
/**
* Getter for the type
*/
public String getType() {
return this.type;
}
/**
* Getter for the unit
*/
public @Nullable String getUnit() {
return this.unit;
}
/**
* Getter for minimum value
*
* @return minimum value
*/
public @Nullable Double getMinVal() {
return this.minVal;
}
/**
* Getter for maximum value
*
* @return maximum value
*/
public @Nullable Double getMaxVal() {
return this.maxVal;
}
/**
* Returns the variable's name and prefixes the group, separated by a # if available
*
* @return the variable's name and prefixes the group, separated by a # if available
*/
public String getGroupAndName() {
return this.group != null ? this.group + "#" + this.name : this.name;
}
/**
* Checks if the variable's data are consistent
*
* @return true if the variable contains consistent data
*/
public boolean isOk() {
boolean check;
// this.access has one of the allowed values
check = (this.access.equals(HeliosVariable.ACCESS_R)) || (this.access.equals(HeliosVariable.ACCESS_W))
|| (this.access.equals(HeliosVariable.ACCESS_RW));
// this.type has one of the allowed values
check = check && ((this.type.equals(HeliosVariable.TYPE_STRING))
|| (this.type.equals(HeliosVariable.TYPE_INTEGER)) || (this.type.equals(HeliosVariable.TYPE_FLOAT)));
// this.minValue and this.maxValue are either not set or minValue is less than maxValue
Double minVal = this.getMinVal();
Double maxVal = this.getMaxVal();
check = check && (((minVal == null) && (maxVal == null))
|| ((minVal != null) && (maxVal != null) && (minVal <= maxVal)));
// length is set
check = check && (this.length > 0);
// count is set
check = check && (this.count > 0);
return check;
}
/**
* Checks if the variable has write access
*
* @return true if the variable has write access
*/
public boolean hasWriteAccess() {
return (this.access.equals(HeliosVariable.ACCESS_W)) || (this.access.equals(HeliosVariable.ACCESS_RW));
}
/**
* Checks if the variable has read access
*
* @return true if the variable has read access
*/
public boolean hasReadAccess() {
return (this.access.equals(HeliosVariable.ACCESS_R)) || (this.access.equals(HeliosVariable.ACCESS_RW));
}
/**
* Checks if the provided value is within the accepted range
*
* @param value The value as a string
* @return true if the value is within the accepted range
*/
public boolean isInAllowedRange(String value) {
Double minVal = this.getMinVal();
Double maxVal = this.getMaxVal();
if ((minVal != null) && (maxVal != null)) { // min and max value are set
try {
if (this.type.equals(HeliosVariable.TYPE_INTEGER)) {
// using long becuase some variable are specified with a max of 2^32-1
// parsing double to allow floating point values to be processed as well
long l = new Double(value).longValue();
return (minVal.longValue() <= l) && (maxVal.longValue() >= l);
} else if (this.type.equals(HeliosVariable.TYPE_FLOAT)) {
double d = Double.parseDouble(value);
return (minVal <= d) && (maxVal >= d);
}
} catch (NumberFormatException e) {
return false;
}
} else {
return true; // no range to check
}
return false;
}
/**
* Depending on the type of variable this method formats the provided value according to the interpretation of its
* value
*
* @param value The value to format
* @return The formatted value
* @throws HeliosException if the provided value doesn't fit to the variable
*/
public String formatPropertyValue(String value) throws HeliosException {
switch (this.getName()) {
case HeliosEasyControlsBindingConstants.DATE_FORMAT:
switch (value) {
case "0":
return "dd.mm.yyyy";
case "1":
return "mm.dd.yyyy";
case "2":
return "yyyy.mm.dd";
}
throw new HeliosException(this.createErrorMessage(value));
case HeliosEasyControlsBindingConstants.UNIT_CONFIG:
return value.equals("1") ? "DIBt" : "PHI";
case HeliosEasyControlsBindingConstants.KWL_BE:
case HeliosEasyControlsBindingConstants.KWL_BEC:
return value.equals("1") ? "On" : "Off";
case HeliosEasyControlsBindingConstants.EXTERNAL_CONTACT:
case HeliosEasyControlsBindingConstants.FUNCTION_TYPE_KWL_EM:
return "Function " + value;
case HeliosEasyControlsBindingConstants.HEAT_EXCHANGER_TYPE:
switch (value) {
case "0":
return "Plastic";
case "1":
return "Aluminium";
case "2":
return "Enthalpy";
}
throw new HeliosException(this.createErrorMessage(value));
case HeliosEasyControlsBindingConstants.OFFSET_EXTRACT_AIR:
case HeliosEasyControlsBindingConstants.VOLTAGE_FAN_STAGE_1_EXTRACT_AIR:
case HeliosEasyControlsBindingConstants.VOLTAGE_FAN_STAGE_2_EXTRACT_AIR:
case HeliosEasyControlsBindingConstants.VOLTAGE_FAN_STAGE_3_EXTRACT_AIR:
case HeliosEasyControlsBindingConstants.VOLTAGE_FAN_STAGE_4_EXTRACT_AIR:
case HeliosEasyControlsBindingConstants.VOLTAGE_FAN_STAGE_1_SUPPLY_AIR:
case HeliosEasyControlsBindingConstants.VOLTAGE_FAN_STAGE_2_SUPPLY_AIR:
case HeliosEasyControlsBindingConstants.VOLTAGE_FAN_STAGE_3_SUPPLY_AIR:
case HeliosEasyControlsBindingConstants.VOLTAGE_FAN_STAGE_4_SUPPLY_AIR:
return this.getUnit() != null ? value + this.getUnit() : value;
case HeliosEasyControlsBindingConstants.ASSIGNMENT_FAN_STAGES:
return value.equals("0") ? "0...10V" : "stepped";
case HeliosEasyControlsBindingConstants.FAN_STAGE_STEPPED_0TO2V:
case HeliosEasyControlsBindingConstants.FAN_STAGE_STEPPED_2TO4V:
case HeliosEasyControlsBindingConstants.FAN_STAGE_STEPPED_4TO6V:
case HeliosEasyControlsBindingConstants.FAN_STAGE_STEPPED_6TO8V:
case HeliosEasyControlsBindingConstants.FAN_STAGE_STEPPED_8TO10V:
case HeliosEasyControlsBindingConstants.SENSOR_NAME_HUMIDITY_AND_TEMP_1:
case HeliosEasyControlsBindingConstants.SENSOR_NAME_HUMIDITY_AND_TEMP_2:
case HeliosEasyControlsBindingConstants.SENSOR_NAME_HUMIDITY_AND_TEMP_3:
case HeliosEasyControlsBindingConstants.SENSOR_NAME_HUMIDITY_AND_TEMP_4:
case HeliosEasyControlsBindingConstants.SENSOR_NAME_HUMIDITY_AND_TEMP_5:
case HeliosEasyControlsBindingConstants.SENSOR_NAME_HUMIDITY_AND_TEMP_6:
case HeliosEasyControlsBindingConstants.SENSOR_NAME_HUMIDITY_AND_TEMP_7:
case HeliosEasyControlsBindingConstants.SENSOR_NAME_HUMIDITY_AND_TEMP_8:
return value;
case HeliosEasyControlsBindingConstants.VHZ_TYPE:
switch (value) {
case "1":
return "EH-basis";
case "2":
return "EH-EWR";
case "3":
return "SEWT";
case "4":
return "LEWT";
}
throw new HeliosException(this.createErrorMessage(value));
case HeliosEasyControlsBindingConstants.KWL_FTF_CONFIG_0:
case HeliosEasyControlsBindingConstants.KWL_FTF_CONFIG_1:
case HeliosEasyControlsBindingConstants.KWL_FTF_CONFIG_2:
case HeliosEasyControlsBindingConstants.KWL_FTF_CONFIG_3:
case HeliosEasyControlsBindingConstants.KWL_FTF_CONFIG_4:
case HeliosEasyControlsBindingConstants.KWL_FTF_CONFIG_5:
case HeliosEasyControlsBindingConstants.KWL_FTF_CONFIG_6:
case HeliosEasyControlsBindingConstants.KWL_FTF_CONFIG_7:
switch (value) {
case "1":
return "Relative Humidity";
case "2":
return "Temperature";
case "3":
return "Combined";
}
throw new HeliosException(this.createErrorMessage(value));
case HeliosEasyControlsBindingConstants.SENSOR_CONFIG_KWL_FTF_1:
case HeliosEasyControlsBindingConstants.SENSOR_CONFIG_KWL_FTF_2:
case HeliosEasyControlsBindingConstants.SENSOR_CONFIG_KWL_FTF_3:
case HeliosEasyControlsBindingConstants.SENSOR_CONFIG_KWL_FTF_4:
case HeliosEasyControlsBindingConstants.SENSOR_CONFIG_KWL_FTF_5:
case HeliosEasyControlsBindingConstants.SENSOR_CONFIG_KWL_FTF_6:
case HeliosEasyControlsBindingConstants.SENSOR_CONFIG_KWL_FTF_7:
case HeliosEasyControlsBindingConstants.SENSOR_CONFIG_KWL_FTF_8:
return value.equals("0") ? "No sensor" : "Sensor installed";
case HeliosEasyControlsBindingConstants.HUMIDITY_CONTROL_STATUS:
case HeliosEasyControlsBindingConstants.CO2_CONTROL_STATUS:
case HeliosEasyControlsBindingConstants.VOC_CONTROL_STATUS:
switch (value) {
case "0":
return "Off";
case "1":
return "Stepped";
case "2":
return "Continuous";
}
throw new HeliosException(this.createErrorMessage(value));
default:
return value;
}
}
private String createErrorMessage(String value) {
return "Illegal value for variable " + this.getName() + ": " + value;
}
@Override
public int compareTo(HeliosVariable v) {
return getVariable() - v.getVariable();
}
@Override
public String toString() {
return this.getVariableString() + ": " + this.getName() + " (" + this.getAccess() + ", " + this.getType()
+ (this.getMinVal() != null ? "[" + this.getMinVal() + "," + this.getMaxVal() + "]" : ")");
}
}

View File

@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<binding:binding id="modbus" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:binding="https://openhab.org/schemas/binding/v1.0.0"
xsi:schemaLocation="https://openhab.org/schemas/binding/v1.0.0 https://openhab.org/schemas/binding-1.0.0.xsd">
<name>HeliosEasyControls Binding</name>
<description>This is the binding for a Helios ventilation system with easyControls using a Modbus TCP implementation.</description>
<author>Bernhard Bauer</author>
</binding:binding>

View File

@@ -0,0 +1,658 @@
<?xml version="1.0" encoding="UTF-8"?>
<thing:thing-descriptions bindingId="modbus"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:thing="https://openhab.org/schemas/thing-description/v1.0.0"
xsi:schemaLocation="https://openhab.org/schemas/thing-description/v1.0.0 https://openhab.org/schemas/thing-description-1.0.0.xsd">
<thing-type id="helios-easycontrols">
<supported-bridge-type-refs>
<bridge-type-ref id="tcp"/>
</supported-bridge-type-refs>
<label>Helios Ventilation</label>
<description>Supports controlling a Helios Heat-Recovery Ventilation Device with easyControls using the Modbus Gateway
TCP</description>
<category>HVAC</category>
<channel-groups>
<channel-group id="general" typeId="general"/>
<channel-group id="operation" typeId="operation"/>
<channel-group id="unitConfig" typeId="unitConfig"/>
<channel-group id="profiles" typeId="profiles"/>
<channel-group id="humidityControl" typeId="humidityControl"/>
<channel-group id="co2Control" typeId="co2Control"/>
<channel-group id="vocControl" typeId="vocControl"/>
</channel-groups>
<config-description>
<parameter name="refreshInterval" type="integer" unit="ms" min="30000">
<label>Refresh Interval</label>
<description>Refresh interval</description>
<default>60000</default>
</parameter>
</config-description>
</thing-type>
<!-- Channel Group Types -->
<channel-group-type id="general">
<label>General</label>
<description>General Parameters / Status Information</description>
<channels>
<!-- General Status Infos -->
<channel id="preHeaterStatus" typeId="onOff">
<label>Pre-Heater Status</label>
<description>Pre-Heater Status</description>
</channel>
<channel id="bypassStatus" typeId="bypassStatus"/>
<!-- Temperatures -->
<channel id="nhzDuctSensor" typeId="temperature">
<label>After Heater Duct Temperature</label>
</channel>
<channel id="nhzReturnSensor" typeId="temperature">
<label>After Heater Return Temperature</label>
</channel>
<channel id="vhzDuctSensor" typeId="temperature">
<label>Pre-Heater Duct Temperature</label>
</channel>
<channel id="temperatureOutsideAir" typeId="temperature">
<label>Outside Air Temperature</label>
</channel>
<channel id="temperatureSupplyAir" typeId="temperature">
<label>Supply Air Temperature</label>
</channel>
<channel id="temperatureOutgoingAir" typeId="temperature">
<label>Outgoing Air Temperature</label>
</channel>
<channel id="temperatureExtractAir" typeId="temperature">
<label>Extract Air Temperature</label>
</channel>
<!-- RPM -->
<channel id="supplyAirRpm" typeId="rpm">
<label>Supply Air Fan RPM</label>
</channel>
<channel id="extractAirRpm" typeId="rpm">
<label>Extract Air Fan RPM</label>
</channel>
<!-- Filter Change -->
<channel id="filterChangeRemainingTime" typeId="filterChangeRemainingTime"/>
<!-- Operating Hours -->
<channel id="operatingHoursSupplyAirVent" typeId="operatingHours">
<label>Operating Hours Supply Air Fan</label>
</channel>
<channel id="operatingHoursExtractAirVent" typeId="operatingHours">
<label>Operating Hours Extract Air Fan</label>
</channel>
<channel id="operatingHoursVhz" typeId="operatingHours">
<label>Operating Hours Pre-Heater</label>
</channel>
<channel id="operatingHoursNhz" typeId="operatingHours">
<label>Operating Hours After Heater</label>
</channel>
<!-- Power -->
<channel id="outputPowerVhz" typeId="outputPower">
<label>Output Power Pre-Heater</label>
</channel>
<channel id="outputPowerNhz" typeId="outputPower">
<label>Output Power After Heater</label>
</channel>
<!-- Infos / Warnings / Errors -->
<channel id="errors" typeId="errors"/>
<channel id="warnings" typeId="warnings"/>
<channel id="infos" typeId="infos"/>
<channel id="noOfErrors" typeId="noOfErrors"/>
<channel id="noOfWarnings" typeId="noOfWarnings"/>
<channel id="noOfInfos" typeId="noOfInfos"/>
<channel id="errorsMsg" typeId="message"/>
<channel id="warningsMsg" typeId="message"/>
<channel id="infosMsg" typeId="message"/>
<channel id="statusFlags" typeId="message"/>
<!-- System Settings -->
<channel id="sysdate" typeId="sysdate"/>
<channel id="summerWinter" typeId="summerWinter"/>
<!-- Software / Firmware -->
<channel id="autoSwUpdate" typeId="enableDisable">
<label>Automatic SW Updates</label>
<description>Indicates if automatic software updates are enabled</description>
</channel>
<channel id="accessHeliosPortal" typeId="enableDisable">
<label>Access Helios Portal</label>
<description>Indicates if access to Helios portal is enabled</description>
</channel>
</channels>
</channel-group-type>
<channel-group-type id="operation">
<label>Operation</label>
<description>Control of operating mode</description>
<channels>
<!-- Party Mode -->
<channel id="partyModeDuration" typeId="duration">
<label>Party Mode Duration</label>
<description>Party mode duration (in minutes)</description>
</channel>
<channel id="partyModeFanStage" typeId="fanStage">
<label>Party Mode Fan Stage</label>
<description>Party mode fan stage</description>
</channel>
<channel id="partyModeRemainingTime" typeId="remainingTime">
<label>Party Mode Remaining Time</label>
<description>Party mode remaining time</description>
</channel>
<channel id="partyModeStatus" typeId="onOff">
<label>Party Mode Status</label>
<description>Party mode status</description>
</channel>
<!-- Standby Mode -->
<channel id="standbyModeDuration" typeId="duration">
<label>Standby Mode Duration</label>
<description>Standby mode duration (in minutes)</description>
</channel>
<channel id="standbyModeFanStage" typeId="fanStage">
<label>Standby Mode Fan Stage</label>
<description>Standby mode fan stage</description>
</channel>
<channel id="standbyModeRemainingTime" typeId="remainingTime">
<label>Standby Mode Remaining Time</label>
<description>Standby mode remaining time</description>
</channel>
<channel id="standbyModeStatus" typeId="onOff">
<label>Standby Mode Status</label>
<description>Standby mode status</description>
</channel>
<!-- Holiday Programme -->
<channel id="holidayProgramme" typeId="holidayProgramme"/>
<channel id="holidayProgrammeFanStage" typeId="fanStage"/>
<channel id="holidayProgrammeStart" typeId="date">
<label>Holiday Programme Start</label>
<description>Holiday programme start</description>
</channel>
<channel id="holidayProgrammeEnd" typeId="date">
<label>Holiday Programme End</label>
<description>Holiday programme end</description>
</channel>
<channel id="holidayProgrammeInterval" typeId="holidayProgrammeInterval"/>
<channel id="holidayProgrammeActivationTime" typeId="holidayProgrammeActivationTime"/>
<!-- Operating Mode / Fan Stage -->
<channel id="operatingMode" typeId="operatingMode"/>
<channel id="fanStage" typeId="fanStage"/>
<channel id="percentageFanStage" typeId="percentage">
<label>Percentage Fan Stage</label>
<description>Fan stage in percent</description>
</channel>
<channel id="extractAirFanStage" typeId="fanStage"/>
<channel id="supplyAirFanStage" typeId="fanStage"/>
</channels>
</channel-group-type>
<channel-group-type id="unitConfig">
<label>Unit Config</label>
<description>Configuration parameters of the ventilation unit</description>
<channels>
<!-- Fan Stage Configuration -->
<channel id="minFanStage" typeId="minFanStage"/>
<!-- Bypass Configuration -->
<channel id="bypassRoomTemperature" typeId="bypassRoomTemperature"/>
<channel id="bypassMinOutsideTemperature" typeId="bypassMinOutsideTemperature"/>
<channel id="bypassFrom" typeId="bypass"/>
<channel id="bypassTo" typeId="bypass"/>
<!-- Comfort Temperature -->
<channel id="comfortTemp" typeId="comfortTemp"/>
<!-- Error Output Function -->
<channel id="errorOutputFunction" typeId="errorOutputFunction"/>
<!-- Filter Change -->
<channel id="filterChange" typeId="filterChange"/>
<channel id="filterChangeInterval" typeId="filterChangeInterval"/>
<!-- System Components and Extensions -->
<channel id="runOnTimeVhzNhz" typeId="runOnTimeVhzNhz"/>
</channels>
</channel-group-type>
<channel-group-type id="profiles">
<label>Profiles</label>
<description>Profiles for Device Operation</description>
<channels>
<channel id="weekProfileNhz" typeId="weekProfileNhz"/>
</channels>
</channel-group-type>
<channel-group-type id="humidityControl">
<label>Humidity Control</label>
<description>Config of Sensors for Humidity and/or Temperature Control</description>
<channels>
<channel id="humidityControlSetValue" typeId="humidityControlSetValue"/>
<channel id="humidityControlSteps" typeId="humidityControlSteps"/>
<channel id="humidityStopTime" typeId="humidityStopTime"/>
<!-- External Humidity Sensors -->
<channel id="externalSensorKwlFtfHumidity1" typeId="sensorValue"/>
<channel id="externalSensorKwlFtfHumidity2" typeId="sensorValue"/>
<channel id="externalSensorKwlFtfHumidity3" typeId="sensorValue"/>
<channel id="externalSensorKwlFtfHumidity4" typeId="sensorValue"/>
<channel id="externalSensorKwlFtfHumidity5" typeId="sensorValue"/>
<channel id="externalSensorKwlFtfHumidity6" typeId="sensorValue"/>
<channel id="externalSensorKwlFtfHumidity7" typeId="sensorValue"/>
<channel id="externalSensorKwlFtfHumidity8" typeId="sensorValue"/>
<!-- External Temperature Sensors -->
<channel id="externalSensorKwlFtfTemperature1" typeId="temperature"/>
<channel id="externalSensorKwlFtfTemperature2" typeId="temperature"/>
<channel id="externalSensorKwlFtfTemperature3" typeId="temperature"/>
<channel id="externalSensorKwlFtfTemperature4" typeId="temperature"/>
<channel id="externalSensorKwlFtfTemperature5" typeId="temperature"/>
<channel id="externalSensorKwlFtfTemperature6" typeId="temperature"/>
<channel id="externalSensorKwlFtfTemperature7" typeId="temperature"/>
<channel id="externalSensorKwlFtfTemperature8" typeId="temperature"/>
</channels>
</channel-group-type>
<channel-group-type id="co2Control">
<label>CO2 Control</label>
<description>Config of Sensors for CO2 Control</description>
<channels>
<channel id="co2ControlSetValue" typeId="ppmControlSetValue">
<label>CO2 Control Status</label>
<description>CO2 control status</description>
</channel>
<channel id="co2ControlSteps" typeId="ppmControlSteps">
<label>CO2 Control Steps</label>
<description>CO2 control steps (in ppm)</description>
</channel>
<!-- External CO2 Sensors -->
<channel id="externalSensorKwlCo21" typeId="sensorValue"/>
<channel id="externalSensorKwlCo22" typeId="sensorValue"/>
<channel id="externalSensorKwlCo23" typeId="sensorValue"/>
<channel id="externalSensorKwlCo24" typeId="sensorValue"/>
<channel id="externalSensorKwlCo25" typeId="sensorValue"/>
<channel id="externalSensorKwlCo26" typeId="sensorValue"/>
<channel id="externalSensorKwlCo27" typeId="sensorValue"/>
<channel id="externalSensorKwlCo28" typeId="sensorValue"/>
</channels>
</channel-group-type>
<channel-group-type id="vocControl">
<label>VOC Control</label>
<description>Config of Sensors for VOC Control</description>
<channels>
<channel id="vocControlSetValue" typeId="ppmControlSetValue">
<label>VOC Control Status</label>
<description>VOC control status</description>
</channel>
<channel id="vocControlSteps" typeId="ppmControlSteps">
<label>CO2 Control Steps</label>
<description>CO2 control steps (in ppm)</description>
</channel>
<!-- External CO2 Sensors -->
<channel id="externalSensorKwlVoc1" typeId="sensorValue"/>
<channel id="externalSensorKwlVoc2" typeId="sensorValue"/>
<channel id="externalSensorKwlVoc3" typeId="sensorValue"/>
<channel id="externalSensorKwlVoc4" typeId="sensorValue"/>
<channel id="externalSensorKwlVoc5" typeId="sensorValue"/>
<channel id="externalSensorKwlVoc6" typeId="sensorValue"/>
<channel id="externalSensorKwlVoc7" typeId="sensorValue"/>
<channel id="externalSensorKwlVoc8" typeId="sensorValue"/>
</channels>
</channel-group-type>
<!-- Channel Types -->
<channel-type id="sysdate" advanced="true">
<item-type>DateTime</item-type>
<label>System Date and Time</label>
<description>The KWL's system date and time</description>
<category>Time</category>
</channel-type>
<channel-type id="summerWinter" advanced="true">
<item-type>Number</item-type>
<label>Summertime / Wintertime</label>
<description>Indicates if summertime or wintertime is active</description>
<category>Time</category>
<state>
<options>
<option value="0">Wintertime</option>
<option value="1">Summertime</option>
</options>
</state>
</channel-type>
<channel-type id="enableDisable">
<item-type>Switch</item-type>
<label>Enable/Disable</label>
<description>Used for functionality that can be enabled or disabled</description>
</channel-type>
<channel-type id="minFanStage" advanced="true">
<item-type>Number</item-type>
<label>Minimum Fan Stage</label>
<description>Minimum fan stage (0 or 1)</description>
<category>HVAC</category>
<state min="0" max="1" step="1" readOnly="false"/>
</channel-type>
<channel-type id="onOff">
<item-type>Switch</item-type>
<label>On/Off</label>
<description>Used for configurations that can be on or off</description>
</channel-type>
<channel-type id="humidityControlSetValue" advanced="true">
<item-type>Number:Dimensionless</item-type>
<label>Humidity Control Set Value</label>
<description>Humidity control set value (in percent)</description>
<category>Humidity</category>
<state min="20" max="80" step="1" pattern="%d %unit%" readOnly="false"/>
</channel-type>
<channel-type id="humidityControlSteps" advanced="true">
<item-type>Number:Dimensionless</item-type>
<label>Humidity Control Steps</label>
<description>Humidity control steps (in percent)</description>
<category>Humidity</category>
<state min="5" max="20" step="1" pattern="%d %unit%" readOnly="false"/>
</channel-type>
<channel-type id="humidityStopTime" advanced="true">
<item-type>Number:Time</item-type>
<label>Humidity Stop Time</label>
<description>Humidity stop time in hours (0-24)</description>
<category>Humidity</category>
<state min="0" max="24" step="1" pattern="%d %unit%" readOnly="false"/>
</channel-type>
<channel-type id="ppmControlSetValue" advanced="true">
<item-type>Number:Dimensionless</item-type>
<label>Control Set Value</label>
<description>Control set value (in ppm)</description>
<category>Gas</category>
<state min="300" max="2000" step="1" pattern="%d %unit%" readOnly="false"/>
</channel-type>
<channel-type id="ppmControlSteps" advanced="true">
<item-type>Number:Dimensionless</item-type>
<label>Control Steps</label>
<description>Control steps (in ppm)</description>
<category>Gas</category>
<state min="50" max="400" step="1" pattern="%d %unit%" readOnly="false"/>
</channel-type>
<channel-type id="comfortTemp" advanced="true">
<item-type>Number:Temperature</item-type>
<label>Comfort Temperature</label>
<description>Comfort temperature</description>
<category>Temperature</category>
<state min="10" max="25" step="0.1" pattern="%.1f %unit%" readOnly="false"/>
</channel-type>
<channel-type id="duration" advanced="false">
<item-type>Number:Time</item-type>
<label>Duration</label>
<description>Duration for operating mode (in minutes)</description>
<state min="5" max="180" step="1" pattern="%d %unit%" readOnly="false"/>
</channel-type>
<channel-type id="fanStage" advanced="false">
<item-type>Number</item-type>
<label>Fan Stage</label>
<description>Fan stage</description>
<category>HVAC</category>
<state min="0" max="4" step="1" pattern="%d" readOnly="false"/>
</channel-type>
<channel-type id="remainingTime" advanced="false">
<item-type>Number:Time</item-type>
<label>Remaining Time</label>
<description>Remaining time for operating mode (in minutes)</description>
<state min="0" max="180" step="1" pattern="%d %unit%" readOnly="true"/>
</channel-type>
<channel-type id="operatingMode" advanced="false">
<item-type>Number</item-type>
<label>Operating Mode</label>
<description>Operating mode (automatic/manual)</description>
<state>
<options>
<option value="0">Automatic</option>
<option value="1">Manual</option>
</options>
</state>
</channel-type>
<channel-type id="percentage" advanced="false">
<item-type>Number:Dimensionless</item-type>
<label>Percentage</label>
<description>Percentage</description>
<state min="0" max="100" step="1" pattern="%d %unit%" readOnly="true"/>
</channel-type>
<channel-type id="temperature" advanced="false">
<item-type>Number:Temperature</item-type>
<label>Temperature</label>
<description>Temperature in °C</description>
<category>Temperature</category>
<state min="-27" max="9998.9" step="0.1" pattern="%.1f %unit%" readOnly="true"/>
</channel-type>
<channel-type id="sensorValue" advanced="false">
<item-type>Number:Dimensionless</item-type>
<label>Sensor Value</label>
<description>Measurement of a sensor</description>
<state min="0" max="9998.9" step="0.1" pattern="%.1f %unit%" readOnly="true"/>
</channel-type>
<channel-type id="weekProfileNhz" advanced="true">
<item-type>Number</item-type>
<label>Week Profile Afterheater</label>
<description>Week profile afterheater</description>
<state>
<options>
<option value="0">Standard 1</option>
<option value="1">Standard 2</option>
<option value="2">Fixed value</option>
<option value="3">Individual 1</option>
<option value="4">Individual 2</option>
<option value="5">NA</option>
<option value="6">Off</option>
</options>
</state>
</channel-type>
<channel-type id="rpm" advanced="false">
<item-type>Number</item-type>
<label>RPM</label>
<description>RPM</description>
<state min="0" max="9999" step="1" pattern="%d rpm" readOnly="true"/>
</channel-type>
<channel-type id="holidayProgramme" advanced="false">
<item-type>Number</item-type>
<label>Holiday Programme</label>
<description>Holiday programme</description>
<category>Vacation</category>
<state>
<options>
<option value="0">Off</option>
<option value="1">Interval</option>
<option value="2">Constant</option>
</options>
</state>
</channel-type>
<channel-type id="date" advanced="false">
<item-type>DateTime</item-type>
<label>Date</label>
<description>Date</description>
</channel-type>
<channel-type id="holidayProgrammeInterval" advanced="true">
<item-type>Number:Time</item-type>
<label>Holiday Programme Interval</label>
<description>Holiday programme interval in hours</description>
<category>Vacation</category>
<state min="1" max="24" step="1" pattern="%d %unit%" readOnly="false"/>
</channel-type>
<channel-type id="holidayProgrammeActivationTime" advanced="true">
<item-type>Number:Time</item-type>
<label>Holiday Programme Activation Time</label>
<description>Holiday programme activation time in minutes</description>
<category>Vacation</category>
<state min="5" max="300" step="1" pattern="%d %unit%" readOnly="false"/>
</channel-type>
<channel-type id="runOnTimeVhzNhz" advanced="true">
<item-type>Number:Time</item-type>
<label>Stopping Time Preheater/Afterheater</label>
<description>Stopping time preheater/afterheater in seconds</description>
<category>Heating</category>
<state min="60" max="120" step="1" pattern="%d %unit%" readOnly="false"/>
</channel-type>
<channel-type id="errorOutputFunction" advanced="true">
<item-type>Number</item-type>
<label>Error Output Function</label>
<description>Error output function (collective error or just error)</description>
<state>
<options>
<option value="1">Collective error</option>
<option value="2">Only error</option>
</options>
</state>
</channel-type>
<channel-type id="filterChange" advanced="false">
<item-type>Number</item-type>
<label>Filter Change</label>
<description>Filter change</description>
<state>
<options>
<option value="0">No</option>
<option value="1">Yes</option>
</options>
</state>
</channel-type>
<channel-type id="filterChangeInterval" advanced="true">
<item-type>Number:Time</item-type>
<label>Filter Change Interval</label>
<description>Filter change interval in months</description>
<state min="1" max="12" step="1" pattern="%d %unit%" readOnly="false"/>
</channel-type>
<channel-type id="filterChangeRemainingTime" advanced="true">
<item-type>Number:Time</item-type>
<label>Filter Change Remaining Time</label>
<description>Filter change remaining time in minutes</description>
<state min="1" max="550000" step="1" pattern="%d %unit%" readOnly="true"/>
</channel-type>
<channel-type id="bypassRoomTemperature" advanced="true">
<item-type>Number</item-type>
<label>Bypass Room Temperature</label>
<description>Bypass room temperature</description>
<category>Temperature</category>
<state min="10" max="40" step="1" pattern="%d %unit%" readOnly="false"/>
</channel-type>
<channel-type id="bypassMinOutsideTemperature" advanced="true">
<item-type>Number</item-type>
<label>Bypass Minimum Outside Temperature</label>
<description>Bypass minimum outside temperature</description>
<category>Temperature</category>
<state min="5" max="20" step="1" pattern="%d %unit%" readOnly="false"/>
</channel-type>
<channel-type id="offsetExtractAir" advanced="true">
<item-type>Number</item-type>
<label>Offset Extract Air</label>
<description>Offset extract air</description>
<category>HVAC</category>
<state pattern="%.1f" readOnly="false"/>
</channel-type>
<channel-type id="operatingHours" advanced="false">
<item-type>Number</item-type>
<label>Operating Hours</label>
<description>Operating hours (in minutes)</description>
<category>Time</category>
<state min="0" max="100000000" step="1" pattern="%d" readOnly="true"/>
</channel-type>
<channel-type id="outputPower" advanced="false">
<item-type>Number</item-type>
<label>Output Power</label>
<description>Output power of preheater/afterheater (in percent)</description>
<category>Energy</category>
<state min="0" max="100000000" step="1" pattern="%d %unit%" readOnly="true"/>
</channel-type>
<channel-type id="errors" advanced="false">
<item-type>Number</item-type>
<label>Errors</label>
<description>Errors as integer value</description>
<state min="0" max="4294967295" step="1" pattern="%d" readOnly="true"/>
</channel-type>
<channel-type id="warnings" advanced="false">
<item-type>Number</item-type>
<label>Warnings</label>
<description>Warnings as integer value</description>
<state min="0" max="255" step="1" pattern="%d" readOnly="true"/>
</channel-type>
<channel-type id="infos" advanced="false">
<item-type>Number</item-type>
<label>Infos</label>
<description>Infos as integer value</description>
<state min="0" max="255" step="1" pattern="%d" readOnly="true"/>
</channel-type>
<channel-type id="noOfErrors" advanced="false">
<item-type>Number</item-type>
<label>Number of Errors</label>
<description>Number of bit-coded errors</description>
<state min="0" max="32" step="1" pattern="%d" readOnly="true"/>
</channel-type>
<channel-type id="noOfWarnings" advanced="false">
<item-type>Number</item-type>
<label>Number of Warnings</label>
<description>Number of bit-coded warnings</description>
<state min="0" max="8" step="1" pattern="%d" readOnly="true"/>
</channel-type>
<channel-type id="noOfInfos" advanced="false">
<item-type>Number</item-type>
<label>Number of Infos</label>
<description>Number of bit-coded infos</description>
<state min="0" max="8" step="1" pattern="%d" readOnly="true"/>
</channel-type>
<channel-type id="message" advanced="false">
<item-type>String</item-type>
<label>Errors / Warnings / Infos</label>
<description>Errors / warnings / infos as string</description>
<state readOnly="true"/>
</channel-type>
<channel-type id="sensorConfig" advanced="false">
<item-type>Switch</item-type>
<label>Sensor Configuration</label>
<description>Sensor configuration (installed or not)</description>
</channel-type>
<channel-type id="bypassStatus" advanced="true">
<item-type>Switch</item-type>
<label>Bypass Status</label>
<description>Status of the bypass</description>
</channel-type>
<channel-type id="bypass" advanced="true">
<item-type>DateTime</item-type>
<label>Bypass Active from/to (Day and Month)</label>
<description>Bypass will be active/deactivated from that day and month on</description>
<category>Time</category>
</channel-type>
</thing:thing-descriptions>

View File

@@ -0,0 +1,189 @@
{
"articleDescription": {"group": "general", "variable": 0, "access": "RW", "length": 31, "count": 20, "type": "string"},
"refNo": {"group": "general", "variable": 1, "access": "RW", "length": 16, "count": 12, "type": "string"},
"macAddress": {"group": "general", "variable": 2, "access": "R", "length": 18, "count": 13, "type": "string"},
"language": {"group": "general", "variable": 3, "access": "RW", "length": 2, "count": 5, "type": "string"},
"date": {"group": "general", "variable": 4, "access": "RW", "length": 10, "count": 9, "type": "string"},
"time": {"group": "general", "variable": 5, "access": "RW", "length": 10, "count": 9, "type": "string"},
"summerWinter": {"group": "general", "variable": 6, "access": "RW", "length": 1, "count": 5, "type": "int"},
"autoSwUpdate": {"group": "general", "variable": 7, "access": "RW", "length": 1, "count": 5, "type": "int"},
"accessHeliosPortal": {"group": "general", "variable": 8, "access": "RW", "length": 1, "count": 5, "type": "int"},
"voltageFanStage1ExtractAir": {"group": "unitConfig", "variable": 12, "access": "RW", "length": 3, "count": 6, "type": "float", "unit": "V", "minVal": 1.6, "maxVal": 10.0},
"voltageFanStage2ExtractAir": {"group": "unitConfig", "variable": 13, "access": "RW", "length": 3, "count": 6, "type": "float", "unit": "V", "minVal": 1.6, "maxVal": 10.0},
"voltageFanStage3ExtractAir": {"group": "unitConfig", "variable": 14, "access": "RW", "length": 3, "count": 6, "type": "float", "unit": "V", "minVal": 1.6, "maxVal": 10.0},
"voltageFanStage4ExtractAir": {"group": "unitConfig", "variable": 15, "access": "RW", "length": 3, "count": 6, "type": "float", "unit": "V", "minVal": 1.6, "maxVal": 10.0},
"voltageFanStage1SupplyAir": {"group": "unitConfig", "variable": 16, "access": "RW", "length": 3, "count": 6, "type": "float", "unit": "V", "minVal": 1.6, "maxVal": 10.0},
"voltageFanStage2SupplyAir": {"group": "unitConfig", "variable": 17, "access": "RW", "length": 3, "count": 6, "type": "float", "unit": "V", "minVal": 1.6, "maxVal": 10.0},
"voltageFanStage3SupplyAir": {"group": "unitConfig", "variable": 18, "access": "RW", "length": 3, "count": 6, "type": "float", "unit": "V", "minVal": 1.6, "maxVal": 10.0},
"voltageFanStage4SupplyAir": {"group": "unitConfig", "variable": 19, "access": "RW", "length": 3, "count": 6, "type": "float", "unit": "V", "minVal": 1.6, "maxVal": 10.0},
"minFanStage": {"group": "unitConfig", "variable": 20, "access": "RW", "length": 1, "count": 5, "type": "int", "minVal": 0, "maxVal": 1},
"kwlBe": {"group": "unitConfig", "variable": 21, "access": "RW", "length": 1, "count": 5, "type": "int", "minVal": 0, "maxVal": 1},
"kwlBec": {"group": "unitConfig", "variable": 22, "access": "RW", "length": 1, "count": 5, "type": "int", "minVal": 0, "maxVal": 1},
"unitConfig": {"group": "unitConfig", "variable": 23, "access": "RW", "length": 1, "count": 5, "type": "int", "minVal": 0, "maxVal": 1},
"preHeaterStatus": {"group": "general", "variable": 24, "access": "RW", "length": 1, "count": 5, "type": "int", "minVal": 0, "maxVal": 1},
"kwlFtfConfig0": {"group": "humidityControl", "variable": 25, "access": "RW", "length": 1, "count": 5, "type": "int", "minVal": 1, "maxVal": 3},
"kwlFtfConfig1": {"group": "humidityControl", "variable": 26, "access": "RW", "length": 1, "count": 5, "type": "int", "minVal": 1, "maxVal": 3},
"kwlFtfConfig2": {"group": "humidityControl", "variable": 27, "access": "RW", "length": 1, "count": 5, "type": "int", "minVal": 1, "maxVal": 3},
"kwlFtfConfig3": {"group": "humidityControl", "variable": 28, "access": "RW", "length": 1, "count": 5, "type": "int", "minVal": 1, "maxVal": 3},
"kwlFtfConfig4": {"group": "humidityControl", "variable": 29, "access": "RW", "length": 1, "count": 5, "type": "int", "minVal": 1, "maxVal": 3},
"kwlFtfConfig5": {"group": "humidityControl", "variable": 30, "access": "RW", "length": 1, "count": 5, "type": "int", "minVal": 1, "maxVal": 3},
"kwlFtfConfig6": {"group": "humidityControl", "variable": 31, "access": "RW", "length": 1, "count": 5, "type": "int", "minVal": 1, "maxVal": 3},
"kwlFtfConfig7": {"group": "humidityControl", "variable": 32, "access": "RW", "length": 1, "count": 5, "type": "int", "minVal": 1, "maxVal": 3},
"humidityControlStatus": {"group": "humidityControl", "variable": 33, "access": "RW", "length": 1, "count": 5, "type": "int", "minVal": 0, "maxVal": 2},
"humidityControlSetValue": {"group": "humidityControl", "variable": 34, "access": "RW", "length": 2, "count": 5, "type": "int", "unit": "%", "minVal": 20, "maxVal": 80},
"humidityControlSteps": {"group": "humidityControl", "variable": 35, "access": "RW", "length": 2, "count": 5, "type": "int", "unit": "%", "minVal": 5, "maxVal": 20},
"humidityStopTime": {"group": "humidityControl", "variable": 36, "access": "RW", "length": 2, "count": 5, "type": "int", "unit": "h", "minVal": 0, "maxVal": 24},
"co2ControlStatus": {"group": "co2Control", "variable": 37, "access": "RW", "length": 1, "count": 5, "type": "int", "minVal": 0, "maxVal": 2},
"co2ControlSetValue": {"group": "co2Control", "variable": 38, "access": "RW", "length": 4, "count": 6, "type": "int", "unit": "ppm", "minVal": 300, "maxVal": 2000},
"co2ControlSteps": {"group": "co2Control", "variable": 39, "access": "RW", "length": 3, "count": 6, "type": "int", "unit": "ppm", "minVal": 50, "maxVal": 400},
"vocControlStatus": {"group": "vocControl", "variable": 40, "access": "RW", "length": 1, "count": 5, "type": "int", "minVal": 0, "maxVal": 2},
"vocControlSetValue": {"group": "vocControl", "variable": 41, "access": "RW", "length": 4, "count": 6, "type": "int", "unit": "ppm", "minVal": 300, "maxVal": 2000},
"vocControlSteps": {"group": "vocControl", "variable": 42, "access": "RW", "length": 3, "count": 6, "type": "int", "unit": "ppm", "minVal": 50, "maxVal": 400},
"comfortTemp": {"group": "unitConfig", "variable": 43, "access": "RW", "length": 4, "count": 6, "type": "int", "unit": "°C", "minVal": 10, "maxVal": 25},
"timeZoneDifferenceToGmt": {"group": "general", "variable": 51, "access": "RW", "length": 3, "count": 6, "type": "int", "unit": "h", "minVal": -12, "maxVal": 14},
"dateFormat": {"group": "general", "variable": 52, "access": "RW", "length": 1, "count": 5, "type": "int", "minVal": 0, "maxVal": 2},
"heatExchangerType": {"group": "unitConfig", "variable": 53, "access": "RW", "length": 1, "count": 5, "type": "int", "minVal": 1, "maxVal": 3},
"partyModeDuration": {"group": "operation", "variable": 91, "access": "RW", "length": 3, "count": 6, "type": "int", "unit": "min", "minVal": 5, "maxVal": 180},
"partyModeFanStage": {"group": "operation", "variable": 92, "access": "RW", "length": 3, "count": 5, "type": "int", "minVal": 0, "maxVal": 4},
"partyModeRemainingTime": {"group": "operation", "variable": 93, "access": "R", "length": 3, "count": 6, "type": "int", "unit": "min", "minVal": 0, "maxVal": 180},
"partyModeStatus": {"group": "operation", "variable": 94, "access": "RW", "length": 1, "count": 5, "type": "int", "minVal": 0, "maxVal": 1},
"standbyModeDuration": {"group": "operation", "variable": 96, "access": "RW", "length": 3, "count": 6, "type": "int", "unit": "min", "minVal": 5, "maxVal": 180},
"standbyModeFanStage": {"group": "operation", "variable": 97, "access": "RW", "length": 1, "count": 5, "type": "int", "minVal": 0, "maxVal": 4},
"standbyModeRemainingTime": {"group": "operation", "variable": 98, "access": "R", "length": 3, "count": 6, "type": "int", "unit": "min", "minVal": 0, "maxVal": 180},
"standbyModeStatus": {"group": "operation", "variable": 99, "access": "RW", "length": 1, "count": 5, "type": "int", "minVal": 0, "maxVal": 1},
"operatingMode": {"group": "operation", "variable": 101, "access": "RW", "length": 1, "count": 5, "type": "int", "minVal": 0, "maxVal": 1},
"fanStage": {"group": "operation", "variable": 102, "access": "RW", "length": 1, "count": 5, "type": "int", "minVal": 0, "maxVal": 4},
"percentageFanStage": {"group": "operation", "variable": 103, "access": "R", "length": 3, "count": 6, "type": "int", "unit": "%", "minVal": 0, "maxVal": 100},
"temperatureOutsideAir": {"group": "general", "variable": 104, "access": "R", "length": 7, "count": 8, "type": "int", "unit": "°C", "minVal": -27, "maxVal": 9998},
"temperatureSupplyAir": {"group": "general", "variable": 105, "access": "R", "length": 7, "count": 8, "type": "int", "unit": "°C", "minVal": -27, "maxVal": 9998},
"temperatureOutgoingAir": {"group": "general", "variable": 106, "access": "R", "length": 7, "count": 8, "type": "int", "unit": "°C", "minVal": -27, "maxVal": 9998},
"temperatureExtractAir": {"group": "general", "variable": 107, "access": "R", "length": 7, "count": 8, "type": "int", "unit": "°C", "minVal": -27, "maxVal": 9998},
"vhzDuctSensor": {"group": "general", "variable": 108, "access": "R", "length": 7, "count": 8, "type": "int", "unit": "°C", "minVal": -27, "maxVal": 9998},
"nhzReturnSensor": {"group": "general", "variable": 110, "access": "R", "length": 7, "count": 8, "type": "int", "unit": "°C", "minVal": -27, "maxVal": 9998},
"externalSensorKwlFtfHumidity1": {"group": "humidityControl", "variable": 111, "access": "R", "length": 4, "count": 6, "type": "int", "unit": "%", "minVal": 0, "maxVal": 9998},
"externalSensorKwlFtfHumidity2": {"group": "humidityControl", "variable": 112, "access": "R", "length": 4, "count": 6, "type": "int", "unit": "%", "minVal": 0, "maxVal": 9998},
"externalSensorKwlFtfHumidity3": {"group": "humidityControl", "variable": 113, "access": "R", "length": 4, "count": 6, "type": "int", "unit": "%", "minVal": 0, "maxVal": 9998},
"externalSensorKwlFtfHumidity4": {"group": "humidityControl", "variable": 114, "access": "R", "length": 4, "count": 6, "type": "int", "unit": "%", "minVal": 0, "maxVal": 9998},
"externalSensorKwlFtfHumidity5": {"group": "humidityControl", "variable": 115, "access": "R", "length": 4, "count": 6, "type": "int", "unit": "%", "minVal": 0, "maxVal": 9998},
"externalSensorKwlFtfHumidity6": {"group": "humidityControl", "variable": 116, "access": "R", "length": 4, "count": 6, "type": "int", "unit": "%", "minVal": 0, "maxVal": 9998},
"externalSensorKwlFtfHumidity7": {"group": "humidityControl", "variable": 117, "access": "R", "length": 4, "count": 6, "type": "int", "unit": "%", "minVal": 0, "maxVal": 9998},
"externalSensorKwlFtfHumidity8": {"group": "humidityControl", "variable": 118, "access": "R", "length": 4, "count": 6, "type": "int", "unit": "%", "minVal": 0, "maxVal": 9998},
"externalSensorKwlFtfTemperature1": {"group": "humidityControl", "variable": 119, "access": "R", "length": 7, "count": 8, "type": "int", "unit": "°C", "minVal": -27, "maxVal": 9998},
"externalSensorKwlFtfTemperature2": {"group": "humidityControl", "variable": 120, "access": "R", "length": 7, "count": 8, "type": "int", "unit": "°C", "minVal": -27, "maxVal": 9998},
"externalSensorKwlFtfTemperature3": {"group": "humidityControl", "variable": 121, "access": "R", "length": 7, "count": 8, "type": "int", "unit": "°C", "minVal": -27, "maxVal": 9998},
"externalSensorKwlFtfTemperature4": {"group": "humidityControl", "variable": 122, "access": "R", "length": 7, "count": 8, "type": "int", "unit": "°C", "minVal": -27, "maxVal": 9998},
"externalSensorKwlFtfTemperature5": {"group": "humidityControl", "variable": 123, "access": "R", "length": 7, "count": 8, "type": "int", "unit": "°C", "minVal": -27, "maxVal": 9998},
"externalSensorKwlFtfTemperature6": {"group": "humidityControl", "variable": 124, "access": "R", "length": 7, "count": 8, "type": "int", "unit": "°C", "minVal": -27, "maxVal": 9998},
"externalSensorKwlFtfTemperature7": {"group": "humidityControl", "variable": 125, "access": "R", "length": 7, "count": 8, "type": "int", "unit": "°C", "minVal": -27, "maxVal": 9998},
"externalSensorKwlFtfTemperature8": {"group": "humidityControl", "variable": 126, "access": "R", "length": 7, "count": 8, "type": "int", "unit": "°C", "minVal": -27, "maxVal": 9998},
"externalSensorKwlCo21": {"group": "co2Control", "variable": 128, "access": "R", "length": 4, "count": 6, "type": "int", "unit": "ppm", "minVal": 0, "maxVal": 9998},
"externalSensorKwlCo22": {"group": "co2Control", "variable": 129, "access": "R", "length": 4, "count": 6, "type": "int", "unit": "ppm", "minVal": 0, "maxVal": 9998},
"externalSensorKwlCo23": {"group": "co2Control", "variable": 130, "access": "R", "length": 4, "count": 6, "type": "int", "unit": "ppm", "minVal": 0, "maxVal": 9998},
"externalSensorKwlCo24": {"group": "co2Control", "variable": 131, "access": "R", "length": 4, "count": 6, "type": "int", "unit": "ppm", "minVal": 0, "maxVal": 9998},
"externalSensorKwlCo25": {"group": "co2Control", "variable": 132, "access": "R", "length": 4, "count": 6, "type": "int", "unit": "ppm", "minVal": 0, "maxVal": 9998},
"externalSensorKwlCo26": {"group": "co2Control", "variable": 133, "access": "R", "length": 4, "count": 6, "type": "int", "unit": "ppm", "minVal": 0, "maxVal": 9998},
"externalSensorKwlCo27": {"group": "co2Control", "variable": 134, "access": "R", "length": 4, "count": 6, "type": "int", "unit": "ppm", "minVal": 0, "maxVal": 9998},
"externalSensorKwlCo28": {"group": "co2Control", "variable": 135, "access": "R", "length": 4, "count": 6, "type": "int", "unit": "ppm", "minVal": 0, "maxVal": 9998},
"externalSensorKwlVoc1": {"group": "vocControl", "variable": 136, "access": "R", "length": 4, "count": 6, "type": "int", "unit": "ppm", "minVal": 0, "maxVal": 9998},
"externalSensorKwlVoc2": {"group": "vocControl", "variable": 137, "access": "R", "length": 4, "count": 6, "type": "int", "unit": "ppm", "minVal": 0, "maxVal": 9998},
"externalSensorKwlVoc3": {"group": "vocControl", "variable": 138, "access": "R", "length": 4, "count": 6, "type": "int", "unit": "ppm", "minVal": 0, "maxVal": 9998},
"externalSensorKwlVoc4": {"group": "vocControl", "variable": 139, "access": "R", "length": 4, "count": 6, "type": "int", "unit": "ppm", "minVal": 0, "maxVal": 9998},
"externalSensorKwlVoc5": {"group": "vocControl", "variable": 140, "access": "R", "length": 4, "count": 6, "type": "int", "unit": "ppm", "minVal": 0, "maxVal": 9998},
"externalSensorKwlVoc6": {"group": "vocControl", "variable": 141, "access": "R", "length": 4, "count": 6, "type": "int", "unit": "ppm", "minVal": 0, "maxVal": 9998},
"externalSensorKwlVoc7": {"group": "vocControl", "variable": 142, "access": "R", "length": 4, "count": 6, "type": "int", "unit": "ppm", "minVal": 0, "maxVal": 9998},
"externalSensorKwlVoc8": {"group": "vocControl", "variable": 143, "access": "R", "length": 4, "count": 6, "type": "int", "unit": "ppm", "minVal": 0, "maxVal": 9998},
"nhzDuctSensor": {"group": "general", "variable": 146, "access": "R", "length": 7, "count": 8, "type": "int", "unit": "°C", "minVal": -27, "maxVal": 9998},
"weekProfileNhz": {"group": "profiles", "variable": 201, "access": "RW", "length": 1, "count": 5, "type": "int", "minVal": 0, "maxVal": 6},
"serNo": {"group": "general", "variable": 303, "access": "RW", "length": 16, "count": 12, "type": "string"},
"prodCode": {"group": "general", "variable": 304, "access": "RW", "length": 13, "count": 11, "type": "string"},
"supplyAirRpm": {"group": "general", "variable": 348, "access": "R", "length": 4, "count": 6, "type": "int", "minVal": 0, "maxVal": 9999},
"extractAirRpm": {"group": "general", "variable": 349, "access": "R", "length": 4, "count": 6, "type": "int", "minVal": 0, "maxVal": 9999},
"logout": {"group": "general", "variable": 403, "access": "W", "length": 1, "count": 5, "type": "int", "minVal": 1, "maxVal": 1},
"holidayProgramme": {"group": "operation", "variable": 601, "access": "RW", "length": 1, "count": 5, "type": "int", "minVal": 0, "maxVal": 2},
"holidayProgrammeFanStage": {"group": "operation", "variable": 602, "access": "RW", "length": 1, "count": 5, "type": "int", "minVal": 1, "maxVal": 4},
"holidayProgrammeStart": {"group": "operation", "variable": 603, "access": "RW", "length": 10, "count": 9, "type": "string"},
"holidayProgrammeEnd": {"group": "operation", "variable": 604, "access": "RW", "length": 10, "count": 9, "type": "string"},
"holidayProgrammeInterval": {"group": "operation", "variable": 605, "access": "RW", "length": 2, "count": 5, "type": "int", "unit": "h", "minVal": 1, "maxVal": 24},
"holidayProgrammeActivationTime": {"group": "operation", "variable": 606, "access": "RW", "length": 3, "count": 6, "type": "int", "unit": "min", "minVal": 5, "maxVal": 300},
"vhzType": {"group": "unitConfig", "variable": 1010, "access": "RW", "length": 1, "count": 5, "type": "int", "minVal": 1, "maxVal": 4},
"functionTypeKwlEm": {"group": "unitConfig", "variable": 1017, "access": "RW", "length": 1, "count": 5, "type": "int", "minVal": 1, "maxVal": 2},
"runOnTimeVhzNhz": {"group": "unitConfig", "variable": 1019, "access": "RW", "length": 3, "count": 6, "type": "int", "unit": "s", "minVal": 60, "maxVal": 120},
"externalContact": {"group": "unitConfig", "variable": 1020, "access": "RW", "length": 1, "count": 5, "type": "int", "minVal": 1, "maxVal": 6},
"errorOutputFunction": {"group": "unitConfig", "variable": 1021, "access": "RW", "length": 1, "count": 5, "type": "int", "minVal": 1, "maxVal": 2},
"filterChange": {"group": "unitConfig", "variable": 1031, "access": "RW", "length": 1, "count": 5, "type": "int", "minVal": 0, "maxVal": 1},
"filterChangeInterval": {"group": "unitConfig", "variable": 1032, "access": "RW", "length": 2, "count": 5, "type": "int", "minVal": 0, "maxVal": 12},
"filterChangeRemainingTime": {"group": "general", "variable": 1033, "access": "R", "length": 10, "count": 9, "type": "int", "unit": "min", "minVal": 2, "maxVal": 4294967295},
"filterChangeReset": {"group": "general", "variable": 1034, "access": "W", "length": 1, "count": 5, "type": "int", "minVal": 0, "maxVal": 1},
"bypassRoomTemperature": {"group": "unitConfig", "variable": 1035, "access": "RW", "length": 2, "count": 5, "type": "int", "unit": "°C", "minVal": 10, "maxVal": 40},
"bypassMinOutsideTemperature": {"group": "unitConfig", "variable": 1036, "access": "RW", "length": 2, "count": 5, "type": "int", "unit": "°C", "minVal": 5, "maxVal": 20},
"tbd": {"group": "general", "variable": 1037, "access": "RW", "length": 2, "count": 5, "type": "int", "unit": "°C", "minVal": 3, "maxVal": 10},
"factorySettingWzu": {"group": "general", "variable": 1041, "access": "RW", "length": 1, "count": 5, "type": "int", "minVal": 1, "maxVal": 1},
"factoryReset": {"group": "general", "variable": 1042, "access": "RW", "length": 1, "count": 5, "type": "int", "minVal": 1, "maxVal": 1},
"supplyAirFanStage": {"group": "operation", "variable": 1050, "access": "RW", "length": 1, "count": 5, "type": "int", "minVal": 1, "maxVal": 4},
"extractAirFanStage": {"group": "operation", "variable": 1051, "access": "RW", "length": 1, "count": 5, "type": "int", "minVal": 1, "maxVal": 4},
"fanStageStepped0to2v": {"group": "unitConfig", "variable": 1061, "access": "RW", "length": 1, "count": 5, "type": "int", "minVal": 0, "maxVal": 2},
"fanStageStepped2to4v": {"group": "unitConfig", "variable": 1062, "access": "RW", "length": 1, "count": 5, "type": "int", "minVal": 0, "maxVal": 4},
"fanStageStepped4to6v": {"group": "unitConfig", "variable": 1063, "access": "RW", "length": 1, "count": 5, "type": "int", "minVal": 0, "maxVal": 4},
"fanStageStepped6to8v": {"group": "unitConfig", "variable": 1064, "access": "RW", "length": 1, "count": 5, "type": "int", "minVal": 0, "maxVal": 4},
"fanStageStepped8to10v": {"group": "unitConfig", "variable": 1065, "access": "RW", "length": 1, "count": 5, "type": "int", "minVal": 0, "maxVal": 4},
"offsetExtractAir": {"group": "unitConfig", "variable": 1066, "access": "RW", "length": 10, "count": 9, "type": "float"},
"assignmentFanStages": {"group": "unitConfig", "variable": 1068, "access": "RW", "length": 1, "count": 5, "type": "int", "minVal": 0, "maxVal": 1},
"sensorNameHumidityAndTemp1": {"group": "humidityControl", "variable": 1071, "access": "RW", "length": 15, "count": 12, "type": "string"},
"sensorNameHumidityAndTemp2": {"group": "humidityControl", "variable": 1072, "access": "RW", "length": 15, "count": 12, "type": "string"},
"sensorNameHumidityAndTemp3": {"group": "humidityControl", "variable": 1073, "access": "RW", "length": 15, "count": 12, "type": "string"},
"sensorNameHumidityAndTemp4": {"group": "humidityControl", "variable": 1074, "access": "RW", "length": 15, "count": 12, "type": "string"},
"sensorNameHumidityAndTemp5": {"group": "humidityControl", "variable": 1075, "access": "RW", "length": 15, "count": 12, "type": "string"},
"sensorNameHumidityAndTemp6": {"group": "humidityControl", "variable": 1076, "access": "RW", "length": 15, "count": 12, "type": "string"},
"sensorNameHumidityAndTemp7": {"group": "humidityControl", "variable": 1077, "access": "RW", "length": 15, "count": 12, "type": "string"},
"sensorNameHumidityAndTemp8": {"group": "humidityControl", "variable": 1078, "access": "RW", "length": 15, "count": 12, "type": "string"},
"sensorNameCo21": {"group": "co2Control", "variable": 1081, "access": "RW", "length": 15, "count": 12, "type": "string"},
"sensorNameCo22": {"group": "co2Control", "variable": 1082, "access": "RW", "length": 15, "count": 12, "type": "string"},
"sensorNameCo23": {"group": "co2Control", "variable": 1083, "access": "RW", "length": 15, "count": 12, "type": "string"},
"sensorNameCo24": {"group": "co2Control", "variable": 1084, "access": "RW", "length": 15, "count": 12, "type": "string"},
"sensorNameCo25": {"group": "co2Control", "variable": 1085, "access": "RW", "length": 15, "count": 12, "type": "string"},
"sensorNameCo26": {"group": "co2Control", "variable": 1086, "access": "RW", "length": 15, "count": 12, "type": "string"},
"sensorNameCo27": {"group": "co2Control", "variable": 1087, "access": "RW", "length": 15, "count": 12, "type": "string"},
"sensorNameCo28": {"group": "co2Control", "variable": 1088, "access": "RW", "length": 15, "count": 12, "type": "string"},
"sensorNameVoc1": {"group": "vocControl", "variable": 1091, "access": "RW", "length": 15, "count": 12, "type": "string"},
"sensorNameVoc2": {"group": "vocControl", "variable": 1092, "access": "RW", "length": 15, "count": 12, "type": "string"},
"sensorNameVoc3": {"group": "vocControl", "variable": 1093, "access": "RW", "length": 15, "count": 12, "type": "string"},
"sensorNameVoc4": {"group": "vocControl", "variable": 1094, "access": "RW", "length": 15, "count": 12, "type": "string"},
"sensorNameVoc5": {"group": "vocControl", "variable": 1095, "access": "RW", "length": 15, "count": 12, "type": "string"},
"sensorNameVoc6": {"group": "vocControl", "variable": 1096, "access": "RW", "length": 15, "count": 12, "type": "string"},
"sensorNameVoc7": {"group": "vocControl", "variable": 1097, "access": "RW", "length": 15, "count": 12, "type": "string"},
"sensorNameVoc8": {"group": "vocControl", "variable": 1098, "access": "RW", "length": 15, "count": 12, "type": "string"},
"softwareVersionBasis": {"group": "general", "variable": 1101, "access": "R", "length": 5, "count": 7, "type": "float", "minVal": 0.0, "maxVal": 99.99},
"operatingHoursSupplyAirVent": {"group": "general", "variable": 1103, "access": "R", "length": 10, "count": 9, "type": "int", "unit": "min", "minVal": 0, "maxVal": 4294967295},
"operatingHoursExtractAirVent": {"group": "general", "variable": 1104, "access": "R", "length": 10, "count": 9, "type": "int", "unit": "min", "minVal": 0, "maxVal": 4294967295},
"operatingHoursVhz": {"group": "general", "variable": 1105, "access": "R", "length": 10, "count": 9, "type": "int", "unit": "min", "minVal": 0, "maxVal": 4294967295},
"operatingHoursNhz": {"group": "general", "variable": 1106, "access": "R", "length": 10, "count": 9, "type": "int", "unit": "min", "minVal": 0, "maxVal": 4294967295},
"outputPowerVhz": {"group": "general", "variable": 1108, "access": "R", "length": 10, "count": 9, "type": "int", "unit": "%", "minVal": 0, "maxVal": 4294967295},
"outputPowerNhz": {"group": "general", "variable": 1109, "access": "R", "length": 10, "count": 9, "type": "int", "unit": "%", "minVal": 0, "maxVal": 4294967295},
"resetFlag": {"group": "general", "variable": 1120, "access": "W", "length": 1, "count": 5, "type": "int", "minVal": 1, "maxVal": 1},
"errors": {"group": "general", "variable": 1123, "access": "R", "length": 10, "count": 9, "type": "int", "minVal": 0, "maxVal": 4294967295},
"warnings": {"group": "general", "variable": 1124, "access": "R", "length": 3, "count": 6, "type": "int", "minVal": 0, "maxVal": 255},
"infos": {"group": "general", "variable": 1125, "access": "R", "length": 3, "count": 6, "type": "int", "minVal": 0, "maxVal": 255},
"noOfErrors": {"group": "general", "variable": 1300, "access": "R", "length": 2, "count": 5, "type": "int", "minVal": 0, "maxVal": 32},
"noOfWarnings": {"group": "general", "variable": 1301, "access": "R", "length": 1, "count": 5, "type": "int", "minVal": 0, "maxVal": 8},
"noOfInfos": {"group": "general", "variable": 1302, "access": "R", "length": 1, "count": 5, "type": "int", "minVal": 0, "maxVal": 8},
"errorsMsg": {"group": "general", "variable": 1303, "access": "R", "length": 32, "count": 20, "type": "string"},
"warningsMsg": {"group": "general", "variable": 1304, "access": "R", "length": 8, "count": 8, "type": "string"},
"infosMsg": {"group": "general", "variable": 1305, "access": "R", "length": 8, "count": 8, "type": "string"},
"statusFlags": {"group": "general", "variable": 1306, "access": "R", "length": 32, "count": 20, "type": "string"},
"globalManualWebUpdate": {"group": "general", "variable": 2013, "access": "RW", "length": 1, "count": 5, "type": "int", "minVal": 1, "maxVal": 1},
"portalGlobalsErrorForWeb": {"group": "general", "variable": 2014, "access": "R", "length": 3, "count": 6, "type": "int", "minVal": 1, "maxVal": 255},
"clearError": {"group": "general", "variable": 2015, "access": "W", "length": 1, "count": 5, "type": "int", "minVal": 1, "maxVal": 1},
"sensorConfigKwlFtf1": {"group": "humidityControl", "variable": 2020, "access": "R", "length": 1, "count": 5, "type": "int", "minVal": 0, "maxVal": 1},
"sensorConfigKwlFtf2": {"group": "humidityControl", "variable": 2021, "access": "R", "length": 1, "count": 5, "type": "int", "minVal": 0, "maxVal": 1},
"sensorConfigKwlFtf3": {"group": "humidityControl", "variable": 2022, "access": "R", "length": 1, "count": 5, "type": "int", "minVal": 0, "maxVal": 1},
"sensorConfigKwlFtf4": {"group": "humidityControl", "variable": 2023, "access": "R", "length": 1, "count": 5, "type": "int", "minVal": 0, "maxVal": 1},
"sensorConfigKwlFtf5": {"group": "humidityControl", "variable": 2024, "access": "R", "length": 1, "count": 5, "type": "int", "minVal": 0, "maxVal": 1},
"sensorConfigKwlFtf6": {"group": "humidityControl", "variable": 2025, "access": "R", "length": 1, "count": 5, "type": "int", "minVal": 0, "maxVal": 1},
"sensorConfigKwlFtf7": {"group": "humidityControl", "variable": 2026, "access": "R", "length": 1, "count": 5, "type": "int", "minVal": 0, "maxVal": 1},
"sensorConfigKwlFtf8": {"group": "humidityControl", "variable": 2027, "access": "R", "length": 1, "count": 5, "type": "int", "minVal": 0, "maxVal": 1},
"bypassStatus": {"group": "general", "variable": 2119, "access": "R", "length": 1, "count": 5, "type": "int", "minVal": 0, "maxVal": 1},
"bypassFromDay": {"group": "unitConfig", "variable": 2120, "access": "RW", "length": 2, "count": 5, "type": "int", "minVal": 1, "maxVal": 31},
"bypassFromMonth": {"group": "unitConfig", "variable": 2121, "access": "RW", "length": 2, "count": 5, "type": "int", "minVal": 1, "maxVal": 12},
"bypassToDay": {"group": "unitConfig", "variable": 2128, "access": "RW", "length": 2, "count": 5, "type": "int", "minVal": 1, "maxVal": 31},
"bypassToMonth": {"group": "unitConfig", "variable": 2129, "access": "RW", "length": 2, "count": 5, "type": "int", "minVal": 1, "maxVal": 12}
}