# OpenTherm Gateway Binding
This binding is used to integrate the OpenTherm Gateway into openHAB.
-The OpenTherm Gateway is a module designed by Schelte Bron that is connected in between a boiler and a thermostat and communicates using the OpenTherm protocol.
+The OpenTherm Gateway is a module designed by Schelte Bron that can be connected to units that support communication using the OpenTherm protocol, such as boiler or ventilation / heat recovery unit.
More information on the OpenTherm Gateway device can be found at https://otgw.tclcode.com/
-## Supported Things
-
-The OpenTherm Gateway binding currently only supports one thing, and that's the gateway itself.
-
## Discovery
The binding does not support auto discovery.
## Binding Configuration
-The binding itself does not require any configuration.
+The binding does not require any configuration.
+
+## Supported Things
+
+The OpenTherm Gateway binding supports three Things:
+
+- `openthermgateway` which is the bridge that handles communication with the OpenTherm Gateway device.
+- `boiler` which represents a central heating boiler unit.
+- `ventilationheatrecovery` which represents a ventilation / heat recovery unit.
## Thing Configuration
-The binding is designed to support various ways of connecting to the OpenTherm Gateway device, but currently only supports a TCP socket connection.
-The configuration settings for the thing are Hostname/IP address and Port, which are used to connect to the gateway, and an automatic connection retry interval in case the connection to the OpenTherm Gateway device is lost.
+### Thing Configuration for `openthermgateway`
+
+The `openthermgateway` bridge is designed to support various ways of connecting to the OpenTherm Gateway device, but currently only supports a TCP socket connection.
+The configuration settings for the bridge are Hostname/IP address and Port, which are used to connect to the gateway, and an automatic connection retry interval in case the connection to the OpenTherm Gateway device is lost.
-| Parameter | Name | Description | Required | Default |
-|---------------------------|---------------------------|-----------------------------------------------------------------|----------|---------|
-| `ipaddress` | Hostname or IP address | The hostname or IP address to connect to the OpenTherm Gateway. | yes | |
-| `port` | Port | The port used to connect to the OpenTherm Gateway. | yes | |
-| `connectionRetryInterval` | Connection Retry Interval | The interval in seconds to retry connecting (0 = disabled). | yes | 60 |
+| Parameter | Name | Description | Required | Default |
+|---------------------------|---------------------------|----------------------------------------------------------------------------------|----------|---------|
+| `ipaddress` | Hostname or IP address | The hostname or IP address to connect to the OpenTherm Gateway. | yes | |
+| `port` | Port | The port used to connect to the OpenTherm Gateway. | yes | |
+| `connectionRetryInterval` | Connection Retry Interval | The interval in seconds to retry connecting (0 = disabled). | yes | 60 |
+| `connectTimeoutSeconds` | Connect Timeout | The maximum time (seconds) to wait for establishing a connection to the gateway. | yes | 5 |
+| `readTimeoutSeconds` | Read Timeout | The maximum time (seconds) to wait for reading responses from the gateway. | yes | 20 |
+
+### Thing Configuration for `boiler` and `ventilationheatrecovery`
+
+The `boiler` and `ventilationheatrecovery` things do not require any configuration settings.
## Channels
-The OpenTherm Gateway binding supports the following channels:
+### Channels for `openthermgateway`
+
+The `openthermgateway` bridge supports the following channels:
| Channel Type ID | Item Type | Description | Access |
|---------------------------|----------------------|----------------------------------------------------------|--------|
-| roomtemp | Number:Temperature | Current sensed room temperature | R |
-| roomsetpoint | Number:Temperature | Current room temperature setpoint | R |
-| temperaturetemporary | Number:Temperature | Temporary override room temperature setpoint | R/W |
-| temperatureconstant | Number:Temperature | Constant override room temperature setpoint | R/W |
-| controlsetpoint | Number:Temperature | Central heating water setpoint set at boiler | R |
-| controlsetpointrequested | Number:Temperature | Central heating water setpoint requested by thermostat | R |
-| controlsetpointoverride | Number:Temperature | Central heating water setpoint configured at gateway | R/W |
-| controlsetpoint2 | Number:Temperature | Central heating 2 water setpoint set at boiler | R |
-| controlsetpoint2requested | Number:Temperature | Central heating 2 water setpoint requested by thermostat | R |
-| controlsetpoint2override | Number:Temperature | Central heating 2 water setpoint configured at gateway | R/W |
-| dhwtemp | Number:Temperature | Domestic hot water temperature | R |
-| tdhwset | Number:Temperature | Domestic hot water temperature setpoint | R |
-| overridedhwsetpoint | Number:Temperature | Domestic hot water temperature setpoint override | R/W |
-| flowtemp | Number:Temperature | Boiler water temperature | R |
-| returntemp | Number:Temperature | Return water temperature | R |
-| outsidetemp | Number:Temperature | Outside temperature | R/W |
-| waterpressure | Number:Pressure | Central heating water pressure | R |
-| ch_enable | Switch | Central heating enabled set at boiler | R |
-| ch_enablerequested | Switch | Central heating enabled requested by thermostat | R |
-| ch_enableoverride | Switch | Central heating enabled overridden at gateway | R |
-| ch2_enable | Switch | Central heating 2 enabled set at boiler | R |
-| ch2_enablerequested | Switch | Central heating 2 enabled requested by thermostat | R |
-| ch2_enableoverride | Switch | Central heating 2 enabled overridden at gateway | R |
-| ch_mode | Switch | Central heating active | R |
-| dhw_enable | Switch | Domestic hot water enabled | R |
-| dhw_mode | Switch | Domestic hot water active | R |
-| flame | Switch | Burner active | R |
-| modulevel | Number:Dimensionless | Relative modulation level | R |
-| maxrelmdulevel | Number:Dimensionless | Maximum relative modulation level | R |
-| fault | Switch | Fault indication | R |
-| servicerequest | Switch | Service required | R |
-| lockout-reset | Switch | Lockout-reset enabled | R |
-| lowwaterpress | Switch | Low water pressure fault | R |
-| gasflamefault | Switch | Gas or flame fault | R |
-| airpressfault | Switch | Air pressure fault | R |
-| waterovtemp | Switch | Water over-temperature fault | R |
-| oemfaultcode | Switch | OEM fault code | R |
-| diag | Switch | Diagnostics indication | R |
-| unsuccessfulburnerstarts | Number:Dimensionless | Unsuccessful burner starts | R |
-| burnerstarts | Number:Dimensionless | Burner starts | R |
-| chpumpstarts | Number:Dimensionless | Central heating pump starts | R |
-| dhwpvstarts | Number:Dimensionless | Domestic hot water pump/valve starts | R |
-| dhwburnerstarts | Number:Dimensionless | Domestic hot water burner starts | R |
-| burnerhours | Number:Dimensionless | Burner hours | R |
-| chpumphours | Number:Dimensionless | Central heating pump hours | R |
-| dhwpvhours | Number:Dimensionless | Domestic hot water pump/valve hours | R |
-| dhwburnerhours | Number:Dimensionless | Domestic hot water burner hours | R |
| sendcommand | Text | Channel to send commands to the OpenTherm Gateway device | W |
+### Channels for `boiler`
+
+The `boiler` thing supports the following channels:
+
+| Channel ID | Item Type | Description | Access |
+|------------|-----------|-------------|--------|
+| roomtemp | Number:Temperature | Current sensed room temperature | R |
+| roomsetpoint | Number:Temperature | Current room temperature setpoint | R |
+| temperaturetemporary | Number:Temperature | Temporary override room temperature setpoint | R/W |
+| temperatureconstant | Number:Temperature | Constant override room temperature setpoint | R/W |
+| controlsetpoint | Number:Temperature | Central heating water setpoint set at boiler | R |
+| controlsetpointrequested | Number:Temperature | Central heating water setpoint requested by Thermostat | R |
+| controlsetpointoverride | Number:Temperature | Central heating water setpoint configured on OTGW | R/W |
+| controlsetpoint2 | Number:Temperature | Central heating 2 water setpoint set at boiler | R |
+| controlsetpoint2requested | Number:Temperature | Central heating 2 water setpoint requested by Thermostat | R |
+| controlsetpoint2override | Number:Temperature | Central heating 2 water setpoint configured on OTGW | R/W |
+| dhwtemp | Number:Temperature | Domestic hot water temperature | R |
+| tdhwset | Number:Temperature | Domestic hot water temperature setpoint | R |
+| overridedhwsetpoint | Number:Temperature | Domestic hot water temperature setpoint override | R/W |
+| flowtemp | Number:Temperature | Boiler water temperature | R |
+| returntemp | Number:Temperature | Return water temperature | R |
+| outsidetemp | Number:Temperature | Outside temperature | R/W |
+| waterpressure | Number:Dimensionless | Central heating water pressure | R |
+| ch_enable | Switch | Central heating enabled set at boiler | R |
+| ch_enablerequested | Switch | Central heating enabled requested by thermostat | R |
+| ch_enableoverride | Switch | Central heating enabled overridden at OTGW | R/W |
+| ch2_enable | Switch | Central heating 2 enabled set at boiler | R |
+| ch2_enablerequested | Switch | Central heating 2 enabled requested by thermostat | R |
+| ch2_enableoverride | Switch | Central heating 2 enabled overridden at OTGW | R/W |
+| ch_mode | Switch | Central heating active | R |
+| dhw_enable | Switch | Domestic hot water enabled | R |
+| dhw_mode | Switch | Domestic hot water active | R |
+| flame | Switch | Burner active | R |
+| modulevel | Number:Dimensionless | Relative modulation level | R |
+| maxrelmdulevel | Number:Dimensionless | Maximum relative modulation level | R |
+| fault | Switch | Fault indication | R |
+| servicerequest | Switch | Service required | R |
+| lockout-reset | Switch | Lockout-reset enabled | R |
+| lowwaterpress | Switch | Low water pressure fault | R |
+| gasflamefault | Switch | Gas or flame fault | R |
+| airpressfault | Switch | Air pressure fault | R |
+| waterovtemp | Switch | Water over-temperature fault | R |
+| oemfaultcode | Number:Dimensionless | OEM fault code | R |
+| diag | Switch | Diagnostics indication | R |
+| unsuccessfulburnerstarts | Number:Dimensionless | Unsuccessful burner starts | R |
+| burnerstarts | Number:Dimensionless | Burner starts | R |
+| chpumpstarts | Number:Dimensionless | Central heating pump starts | R |
+| dhwpvstarts | Number:Dimensionless | Domestic hot water pump/valve starts | R |
+| dhwburnerstarts | Number:Dimensionless | Domestic hot water burner starts | R |
+| burnerhours | Number:Time | Burner hours | R |
+| chpumphours | Number:Time | Central heating pump hours | R |
+| dhwpvhours | Number:Time | Domestic hot water pump/valve hours | R |
+| dhwburnerhours | Number:Time | Domestic hot water burner hours | R |
+| tspnumber | Number:Dimensionless | Number of transparant slave parameter entries | R |
+| tspentry | Number:Dimensionless | Transparent slave parameter entry | R |
+| fhbnumber | Number:Dimensionless | Number of fault history buffer entries | R |
+| fhbentry | Number:Dimensionless | Fault history buffer entry | R |
+
+### Channels for `ventilationheatrecovery`
+
+The `ventilationheatrecovery` thing supports the following channels:
+
+| Channel ID | Item Type | Description | Access |
+|------------|-----------|-------------|--------|
+| vh_ventilationenable | Switch | Ventilation enabled | R |
+| vh_bypassposition | Number:Dimensionless | Bypass position | R |
+| vh_bypassmode | Number:Dimensionless | Bypass mode | R |
+| vh_freeventilationmode | Switch | Free ventilation mode | R |
+| vh_faultindication | Switch | Fault indication | R |
+| vh_ventilationmode | Switch | Ventilation mode | R |
+| vh_bypassstatus | Switch | Bypass status | R |
+| vh_bypassautomaticstatus | Number:Dimensionless | Bypass automatic status | R |
+| vh_freeventilationstatus | Switch | Free ventilation status | R |
+| vh_filtercheck | Switch | Filter Check enabled | R |
+| vh_diagnosticindication | Switch | Diagnostic indication | R |
+| vh_controlsetpoint | Number:Dimensionless | Control setpoint | R |
+| vh_servicerequest | Switch | Service request | R |
+| vh_exhaustfanfault | Switch | Exhaust fan fault | R |
+| vh_inletfanfault | Switch | Inlet fan fault | R |
+| vh_frostprotection | Switch | Frost protection | R |
+| vh_faultcode | Number:Dimensionless | Fault code | R |
+| vh_diagnosticcode | Number:Dimensionless | Diagnostic code | R |
+| vh_systemtype | Number:Dimensionless | System type | R |
+| vh_bypass | Switch | Bypass | R |
+| vh_speedcontrol | Number:Dimensionless | Speed control | R |
+| vh_memberid | Number:Dimensionless | Member ID | R |
+| vh_openthermversion | Number:Dimensionless | OpenTherm version | R |
+| vh_versiontype | Number:Dimensionless | Version type | R |
+| vh_relativeventilation | Number:Dimensionless | Relative ventilation position | R |
+| vh_relativehumidity | Number:Dimensionless | Relative humidity exhaust air | R |
+| vh_co2level | Number:Dimensionless | CO2 level exhaust air | R |
+| vh_supplyinlettemp | Number:Temperature | Supply inlet temperature | R |
+| vh_supplyoutlettemp | Number:Temperature | Supply outlet temperature | R |
+| vh_exhaustinlettemp | Number:Temperature | Exhaust inlet temperature | R |
+| vh_exhaustoutlettemp | Number:Temperature | Exhaust outlet temperature | R |
+| vh_actualexhaustfanspeed | Number:Dimensionless | Actual exhaust fan speed | R |
+| vh_actualinletfanspeed | Number:Dimensionless | Actual inlet fan speed | R |
+| vh_nominalventenable | Switch | Nominal ventilation value transfer enabled | R |
+| vh_nominalventrw | Number:Dimensionless | Nominal ventilation value | R |
+| vh_nominalventilationvalue | Number:Dimensionless | Nominal ventilation value | R |
+| vh_ventilationsetpoint | Number:Dimensionless | Ventilation setpoint override | R/W |
+| vh_tspnumber | Number:Dimensionless | Number of transparent slave parameter entries | R |
+| vh_tspentry | Number:Dimensionless | Transparent slave parameter entry | R |
+| vh_fhbnumber | Number:Dimensionless | Number of fault history buffer entries | R |
+| vh_fhbentry | Number:Dimensionless | Fault history buffer entry | R |
+
+## Transparent Slave Parameters and Fault History Buffer channels
+
+The transparent slave parameters (TSP) and fault history buffer (FHB) use a variable number of entries.
+The number of entries is determined by a TSP or FHB size message.
+Channels for TSP and FHB entries are automatically created when a TSP or FHB size message is received.
+An index number is added to the base channel name to create a unique channel name for each entry.
+
+For example, if a TSP size message is received for a boiler unit (OpenTherm DATA-ID 10) with value 60, then channels `tspentry_0` through `tspentry_59` will be automatically created and linked to the corresponding TSP entry (OpenTherm DATA-ID 11).
+
+## Using OpenTherm Gateway as a master device
+
+When using OpenTherm with a boiler and a thermostat, the thermostat (master) periodically sends messages to the boiler to request data.
+The boiler (slave) then sends a response message with the requested data which is then used by the OpenTherm Gateway binding to update the channel values in openHAB.
+
+If you have a setup without a master device requesting data, then the slave device may send fewer or even no OpenTherm mesages at all.
+
+In this case, you can make the OpenTherm Gateway act as a master device by sending Priority Message (PM) commands.
+With openHAB rules, you can use the `sendcommand` channel of the `openthermgateway` bridge to periodically send PM commands to the OpenTherm Gateway.
+
+Example:
+
+```
+SendCommand.sendCommand("PM=10")
+```
+
+This will cause the OpenTherm Gateway to send a READ-DATA message to the slave device with DATA-ID 10. If supported, the slave device will respond with a READ-ACK message and the current value.
+
## Full Example
-### demo.things
-
-```
-Thing openthermgateway:otgw:1 [ ipaddress="192.168.1.100", port=8000, connectionRetryInterval=60 ]
-```
-
-### demo.items
-
-```
-Number:Temperature RoomTemperature "Room temperature [%.1f °C]" <temperature> { channel="openthermgateway:otgw:1:roomtemp" }
-Number:Temperature RoomSetpoint "Room setpoint [%.1f °C]" <temperature> { channel="openthermgateway:otgw:1:roomsetpoint" }
-Number:Temperature TemporaryRoomSetpointOverride "Temporary room setpoint override [%.1f °C]" <temperature> { channel="openthermgateway:otgw:1:temperaturetemporary" }
-Number:Temperature ConstantRoomSetpointOverride "Constant room setpoint override [%.1f °C]" <temperature> { channel="openthermgateway:otgw:1:temperatureconstant" }
-Number:Temperature ControlSetpoint "Control setpoint [%.1f °C]" <temperature> { channel="openthermgateway:otgw:1:controlsetpoint" }
-Number:Temperature ControlSetpointRequested "Control setpoint requested [%.1f °C]" <temperature> { channel="openthermgateway:otgw:1:controlsetpointrequested" }
-Number:Temperature ControlSetpointOverride "Control setpoint override [%.1f °C]" <temperature> { channel="openthermgateway:otgw:1:controlsetpointoverride" }
-Number:Temperature ControlSetpoint2 "Control setpoint 2 [%.1f °C]" <temperature> { channel="openthermgateway:otgw:1:controlsetpoint2" }
-Number:Temperature ControlSetpoint2Requested "Control setpoint 2 requested [%.1f °C]" <temperature> { channel="openthermgateway:otgw:1:controlsetpoint2requested" }
-Number:Temperature ControlSetpoint2Override "Control setpoint 2 override [%.1f °C]" <temperature> { channel="openthermgateway:otgw:1:controlsetpoint2override" }
-Number:Temperature DomesticHotWaterTemperature "Domestic hot water temperature [%.1f °C]" <temperature> { channel="openthermgateway:otgw:1:dhwtemp" }
-Number:Temperature DomesticHotWaterSetpoint "Domestic hot water setpoint [%.1f °C]" <temperature> { channel="openthermgateway:otgw:1:tdhwset" }
-Number:Temperature DomesticHotWaterSetpointOverride "Domestic hot water setpoint override [%.1f °C]" <temperature> { channel="openthermgateway:otgw:1:overridedhwsetpoint" }
-Number:Temperature BoilerWaterTemperature "Boiler water temperature [%.1f °C]" <temperature> { channel="openthermgateway:otgw:1:flowtemp" }
-Number:Temperature ReturnWaterTemperature "Return water temperature [%.1f °C]" <temperature> { channel="openthermgateway:otgw:1:returntemp" }
-Number:Temperature OutsideTemperature "Outside temperature [%.1f °C]" <temperature> { channel="openthermgateway:otgw:1:outsidetemp" }
-Number:Pressure CentralHeatingWaterPressure "Central heating water pressure [%.1f bar]" { channel="openthermgateway:otgw:1:waterpressure" }
-Switch CentralHeatingEnabled "Central heating enabled" <switch> { channel="openthermgateway:otgw:1:ch_enable" }
-Switch CentralHeatingEnabledRequested "Central heating enabled requested" <switch> { channel="openthermgateway:otgw:1:ch_enablerequested" }
-Switch CentralHeatingEnabledOverride "Central heating enabled override" <switch> { channel="openthermgateway:otgw:1:ch_enableoverride" }
-Switch CentralHeating2Enabled "Central heating 2 enabled" <switch> { channel="openthermgateway:otgw:1:ch2_enable" }
-Switch CentralHeating2EnabledRequested "Central 2 heating enabled requested" <switch> { channel="openthermgateway:otgw:1:ch2_enablerequested" }
-Switch CentralHeating2EnabledOverride "Central 2 heating enabled override" <switch> { channel="openthermgateway:otgw:1:ch2_enableoverride" }
-Switch CentralHeatingActive "Central heating active" <switch> { channel="openthermgateway:otgw:1:ch_mode" }
-Switch DomesticHotWaterEnabled "Domestic hot water enabled" <switch> { channel="openthermgateway:otgw:1:dhw_enable" }
-Switch DomesticHotWaterActive "Domestic hot water active" <switch> { channel="openthermgateway:otgw:1:dhw_mode" }
-Switch BurnerActive "Burner active" <switch> { channel="openthermgateway:otgw:1:flame" }
-Number:Dimensionless RelativeModulationLevel "Relative modulation level [%.1f %%]" { channel="openthermgateway:otgw:1:modulevel" }
-Number:Dimensionless MaximumRelativeModulationLevel "Maximum relative modulation level [%.1f %%]" { channel="openthermgateway:otgw:1:maxrelmdulevel" }
-Switch Fault "Fault indication" <switch> { channel="openthermgateway:otgw:1:fault" }
-Switch ServiceRequest "Service required" <switch> { channel="openthermgateway:otgw:1:servicerequest" }
-Switch LockoutReset "Lockout-reset" <switch> { channel="openthermgateway:otgw:1:lockout-reset" }
-Switch LowWaterPress "Low water pressure fault" <switch> { channel="openthermgateway:otgw:1:lowwaterpress" }
-Switch GasFlameFault "Gas or flame fault" <switch> { channel="openthermgateway:otgw:1:gasflamefault" }
-Switch AirPressFault "Air pressure fault" <switch> { channel="openthermgateway:otgw:1:airpressfault" }
-Switch WaterOvTemp "Water over-temperature fault" <switch> { channel="openthermgateway:otgw:1:waterovtemp" }
-Number OemFaultCode "OEM fault code" { channel="openthermgateway:otgw:1:oemfaultcode" }
-Switch Diagnostics "Diagnostics indication" { channel="openthermgateway:otgw:1:diag" }
-Number:Dimensionless UnsuccessfulBurnerStarts "Unsuccessful burner starts" { channel="openthermgateway:otgw:1:unsuccessfulburnerstarts" }
-Number:Dimensionless BurnerStarts "Burner starts" { channel="openthermgateway:otgw:1:burnerstarts" }
-Number:Dimensionless CentralHeatingPumpStarts "Central heating pump starts" { channel="openthermgateway:otgw:1:chpumpstarts" }
-Number:Dimensionless DomesticHotWaterPumpValveStarts "Domestic hot water pump/valve starts" { channel="openthermgateway:otgw:1:dhwpvstarts" }
-Number:Dimensionless DomesticHotWaterBurnerStarts "Domestic hot water burner starts" { channel="openthermgateway:otgw:1:dhwburnerstarts" }
-Number:Time BurnerHours "Burner hours" { channel="openthermgateway:otgw:1:burnerhours" }
-Number:Time CentralHeatingPumpHours "Central heating pump hours" { channel="openthermgateway:otgw:1:chpumphours" }
-Number:Time DomesticHotWaterPumpValveHours "Domestic hot water pump/valve hours" { channel="openthermgateway:otgw:1:dhwpvhours" }
-Number:Time DomesticHotWaterBurnerHours "Domestic hot water burner hours" { channel="openthermgateway:otgw:1:dhwburnerhours" }
-Text SendCommand "Send command channel" { channel="openthermgateway:otgw:1:sendcommand" }
+### demo.things
+
+```
+Bridge openthermgateway:openthermgateway:1 "OpenTherm Gateway" [ ipaddress="192.168.1.100", port="8000", connectionRetryInterval=60 ] {
+ Thing boiler remeha "Remeha Avanta 28c"
+ Thing ventilationheatrecovery brink "Brink Renovent Excellent 300"
+}
+```
+
+### demo.items for `openthermgateway`
+
+```
+Text SendCommand "Send command channel" { channel="openthermgateway:openthermgateway:1:sendcommand" }
+```
+
+### demo.items for `boiler`
+
+```
+Number:Temperature RoomTemperature "Room Temperature [%.1f %unit%]" <temperature> { channel="openthermgateway:boiler:1:remeha:roomtemp }
+Number:Temperature RoomSetpoint "Room Setpoint [%.1f %unit%]" <temperature> { channel="openthermgateway:boiler:1:remeha:roomsetpoint }
+Number:Temperature TemporaryRoomSetpointOverride "Temporary Room Setpoint Override [%.1f %unit%]" <temperature> { channel="openthermgateway:boiler:1:remeha:temperaturetemporary }
+Number:Temperature ConstantRoomSetpointOverride "Constant Room Setpoint Override [%.1f %unit%]" <temperature> { channel="openthermgateway:boiler:1:remeha:temperatureconstant }
+Number:Temperature ControlSetpoint "Control Setpoint [%.1f %unit%]" <temperature> { channel="openthermgateway:boiler:1:remeha:controlsetpoint }
+Number:Temperature ControlSetpointRequested "Control Setpoint Requested [%.1f %unit%]" <temperature> { channel="openthermgateway:boiler:1:remeha:controlsetpointrequested }
+Number:Temperature ControlSetpointOverride "Control Setpoint Override [%.1f %unit%]" <temperature> { channel="openthermgateway:boiler:1:remeha:controlsetpointoverride }
+Number:Temperature ControlSetpoint2 "Control Setpoint 2 [%.1f %unit%]" <temperature> { channel="openthermgateway:boiler:1:remeha:controlsetpoint2 }
+Number:Temperature ControlSetpoint2Requested "Control Setpoint 2 Requested [%.1f %unit%]" <temperature> { channel="openthermgateway:boiler:1:remeha:controlsetpoint2requested }
+Number:Temperature ControlSetpoint2Override "Control Setpoint 2 Override [%.1f %unit%]" <temperature> { channel="openthermgateway:boiler:1:remeha:controlsetpoint2override }
+Number:Temperature DomesticHotWaterTemperature "Domestic Hot Water Temperature [%.1f %unit%]" <temperature> { channel="openthermgateway:boiler:1:remeha:dhwtemp }
+Number:Temperature DomesticHotWaterSetpoint "Domestic Hot Water Setpoint [%.1f %unit%]" <temperature> { channel="openthermgateway:boiler:1:remeha:tdhwset }
+Number:Temperature DomesticHotWaterSetpointOverride "Domestic Hot Water Setpoint Override [%.1f %unit%]" <temperature> { channel="openthermgateway:boiler:1:remeha:overridedhwsetpoint }
+Number:Temperature BoilerWaterTemperature "Boiler Water Temperature [%.1f %unit%]" <temperature> { channel="openthermgateway:boiler:1:remeha:flowtemp }
+Number:Temperature ReturnWaterTemperature "Return Water Temperature [%.1f %unit%]" <temperature> { channel="openthermgateway:boiler:1:remeha:returntemp }
+Number:Temperature OutsideTemperature "Outside Temperature [%.1f %unit%]" <temperature> { channel="openthermgateway:boiler:1:remeha:outsidetemp }
+Number:Dimensionless CentralHeatingWaterPressure "Central Heating Water Pressure [%.1f bar]" { channel="openthermgateway:boiler:1:remeha:waterpressure }
+Switch CentralHeatingEnabled "Central Heating Enabled" <switch> { channel="openthermgateway:boiler:1:remeha:ch_enable }
+Switch CentralHeatingEnabledThermostat "Central Heating Enabled Thermostat" <switch> { channel="openthermgateway:boiler:1:remeha:ch_enablerequested }
+Switch CentralHeatingOverridden "Central Heating Overridden" <switch> { channel="openthermgateway:boiler:1:remeha:ch_enableoverride }
+Switch CentralHeating2Enabled "Central Heating 2 Enabled" <switch> { channel="openthermgateway:boiler:1:remeha:ch2_enable }
+Switch CentralHeating2EnabledThermostat "Central Heating 2 Enabled Thermostat" <switch> { channel="openthermgateway:boiler:1:remeha:ch2_enablerequested }
+Switch CentralHeating2Overridden "Central Heating 2 Overridden" <switch> { channel="openthermgateway:boiler:1:remeha:ch2_enableoverride }
+Switch CentralHeatingActive "Central Heating Active" <switch> { channel="openthermgateway:boiler:1:remeha:ch_mode }
+Switch DomesticHotWaterEnabled "Domestic Hot Water Enabled" <switch> { channel="openthermgateway:boiler:1:remeha:dhw_enable }
+Switch DomesticHotWaterActive "Domestic Hot Water Active" <switch> { channel="openthermgateway:boiler:1:remeha:dhw_mode }
+Switch BurnerActive "Burner Active" <switch> { channel="openthermgateway:boiler:1:remeha:flame }
+Number:Dimensionless RelativeModulationLevel "Relative Modulation Level [%.1f %%]" { channel="openthermgateway:boiler:1:remeha:modulevel }
+Number:Dimensionless MaximumRelativeModulationLevel "Maximum Relative Modulation Level [%.1f %%]" { channel="openthermgateway:boiler:1:remeha:maxrelmdulevel }
+Switch FaultIndication "Fault Indication" <switch> { channel="openthermgateway:boiler:1:remeha:fault }
+Switch ServiceRequired "Service Required" <switch> { channel="openthermgateway:boiler:1:remeha:servicerequest }
+Switch LockoutResetEnabled "Lockout-Reset Enabled" <switch> { channel="openthermgateway:boiler:1:remeha:lockout-reset }
+Switch LowWaterPressureFault "Low Water Pressure Fault" <switch> { channel="openthermgateway:boiler:1:remeha:lowwaterpress }
+Switch GasOrFlameFault "Gas Or Flame Fault" <switch> { channel="openthermgateway:boiler:1:remeha:gasflamefault }
+Switch AirPressureFault "Air Pressure Fault" <switch> { channel="openthermgateway:boiler:1:remeha:airpressfault }
+Switch WaterOverTemperatureFault "Water Over-Temperature Fault" <switch> { channel="openthermgateway:boiler:1:remeha:waterovtemp }
+Number:Dimensionless OEMFaultCode "OEM Fault Code" { channel="openthermgateway:boiler:1:remeha:oemfaultcode }
+Number:Dimensionless UnsuccessfulBurnerStarts "Unsuccessful Burner Starts" { channel="openthermgateway:boiler:1:remeha:unsuccessfulburnerstarts }
+Number:Dimensionless BurnerStarts "Burner Starts" { channel="openthermgateway:boiler:1:remeha:burnerstarts }
+Number:Dimensionless CentralHeatingPumpStarts "Central Heating Pump Starts" { channel="openthermgateway:boiler:1:remeha:chpumpstarts }
+Number:Dimensionless DomesticHotWaterPump/ValveStarts "Domestic Hot Water Pump/Valve Starts" { channel="openthermgateway:boiler:1:remeha:dhwpvstarts }
+Number:Dimensionless DomesticHotWaterBurnerStarts "Domestic Hot Water Burner Starts" { channel="openthermgateway:boiler:1:remeha:dhwburnerstarts }
+Number:Time BurnerHours "Burner Hours" { channel="openthermgateway:boiler:1:remeha:burnerhours }
+Number:Time CentralHeatingPumpHours "Central Heating Pump Hours" { channel="openthermgateway:boiler:1:remeha:chpumphours }
+Number:Time DomesticHotWaterPumpValveHours "Domestic Hot Water Pump/Valve Hours" { channel="openthermgateway:boiler:1:remeha:dhwpvhours }
+Number:Time DomesticHotWaterBurnerHours "Domestic Hot Water Burner Hours" { channel="openthermgateway:boiler:1:remeha:dhwburnerhours }
+Number:Dimensionless TransparentSlaveParameterNumber "Transparent Slave Parameter Number" { channel="openthermgateway:boiler:1:remeha:tspnumber }
+Number:Dimensionless TransparentSlaveParameterEntry "Transparent Slave Parameter Entry" { channel="openthermgateway:boiler:1:remeha:tspentry }
+Number:Dimensionless FaultHistoryBufferNumber "Fault History Buffer Number" { channel="openthermgateway:boiler:1:remeha:fhbnumber }
+Number:Dimensionless FaultHistoryBufferEntry "Fault History Buffer Entry" { channel="openthermgateway:boiler:1:remeha:fhbentry }
+```
+
+### demo.items for `ventilationheatrecovery`
+
+```
+Switch VentilationEnabled "Ventilation Enabled" <switch> { channel="openthermgateway:ventilationheatrecovery:1:brink:vh_ventilationenable }
+Number:Dimensionless BypassPosition "Bypass Position" { channel="openthermgateway:ventilationheatrecovery:1:brink:vh_bypassposition }
+Number:Dimensionless BypassMode "Bypass Mode" { channel="openthermgateway:ventilationheatrecovery:1:brink:vh_bypassmode }
+Switch FreeVentilationMode "Free Ventilation Mode" <switch> { channel="openthermgateway:ventilationheatrecovery:1:brink:vh_freeventilationmode }
+Switch FaultIndication "Fault Indication" <switch> { channel="openthermgateway:ventilationheatrecovery:1:brink:vh_faultindication }
+Switch VentilationMode "Ventilation Mode" <switch> { channel="openthermgateway:ventilationheatrecovery:1:brink:vh_ventilationmode }
+Switch BypassStatus "Bypass Status" <switch> { channel="openthermgateway:ventilationheatrecovery:1:brink:vh_bypassstatus }
+Number:Dimensionless BypassAutomaticStatus "Bypass Automatic Status" { channel="openthermgateway:ventilationheatrecovery:1:brink:vh_bypassautomaticstatus }
+Switch FreeVentilationStatus "Free Ventilation Status" <switch> { channel="openthermgateway:ventilationheatrecovery:1:brink:vh_freeventilationstatus }
+Switch FilterCheck "Filter Check" <switch> { channel="openthermgateway:ventilationheatrecovery:1:brink:vh_filtercheck }
+Switch DiagnosticIndication "Diagnostic Indication" <switch> { channel="openthermgateway:ventilationheatrecovery:1:brink:vh_diagnosticindication }
+Number:Dimensionless ControlSetpoint "Control Setpoint" { channel="openthermgateway:ventilationheatrecovery:1:brink:vh_controlsetpoint }
+Switch ServiceRequest "Service Request" <switch> { channel="openthermgateway:ventilationheatrecovery:1:brink:vh_servicerequest }
+Switch ExhaustFanFault "Exhaust Fan Fault" <switch> { channel="openthermgateway:ventilationheatrecovery:1:brink:vh_exhaustfanfault }
+Switch InletFanFault "Inlet Fan Fault" <switch> { channel="openthermgateway:ventilationheatrecovery:1:brink:vh_inletfanfault }
+Switch FrostProtection "Frost Protection" <switch> { channel="openthermgateway:ventilationheatrecovery:1:brink:vh_frostprotection }
+Number:Dimensionless FaultCode "Fault Code" { channel="openthermgateway:ventilationheatrecovery:1:brink:vh_faultcode }
+Number:Dimensionless DiagnosticCode "Diagnostic Code" { channel="openthermgateway:ventilationheatrecovery:1:brink:vh_diagnosticcode }
+Number:Dimensionless SystemType "System Type" { channel="openthermgateway:ventilationheatrecovery:1:brink:vh_systemtype }
+Switch Bypass "Bypass" <switch> { channel="openthermgateway:ventilationheatrecovery:1:brink:vh_bypass }
+Number:Dimensionless SpeedControl "Speed Control" { channel="openthermgateway:ventilationheatrecovery:1:brink:vh_speedcontrol }
+Number:Dimensionless MemberID "Member ID" { channel="openthermgateway:ventilationheatrecovery:1:brink:vh_memberid }
+Number:Dimensionless OpenThermVersion "OpenTherm Version" { channel="openthermgateway:ventilationheatrecovery:1:brink:vh_openthermversion }
+Number:Dimensionless VersionType "Version Type" { channel="openthermgateway:ventilationheatrecovery:1:brink:vh_versiontype }
+Number:Dimensionless RelativeVentilation "Relative Ventilation [%d %%]" { channel="openthermgateway:ventilationheatrecovery:1:brink:vh_relativeventilation }
+Number:Dimensionless RelativeHumidity "Relative Humidity [%d %%]" { channel="openthermgateway:ventilationheatrecovery:1:brink:vh_relativehumidity }
+Number:Dimensionless CO2Level "CO2 Level [%d ppm]" { channel="openthermgateway:ventilationheatrecovery:1:brink:vh_co2level }
+Number:Temperature SupplyInletTemperature "Supply Inlet Temperature [%.1f %unit%]" { channel="openthermgateway:ventilationheatrecovery:1:brink:vh_supplyinlettemp }
+Number:Temperature SupplyOutletTemperature "Supply Outlet Temperature [%.1f %unit%]" { channel="openthermgateway:ventilationheatrecovery:1:brink:vh_supplyoutlettemp }
+Number:Temperature ExhaustInletTemperature "Exhaust Inlet Temperature [%.1f %unit%]" { channel="openthermgateway:ventilationheatrecovery:1:brink:vh_exhaustinlettemp }
+Number:Temperature ExhaustOutletTemperature "Exhaust Outlet Temperature [%.1f %unit%]" { channel="openthermgateway:ventilationheatrecovery:1:brink:vh_exhaustoutlettemp }
+Number:Dimensionless ActualExhaustFanSpeed "Actual Exhaust Fan Speed [%d rpm]" { channel="openthermgateway:ventilationheatrecovery:1:brink:vh_actualexhaustfanspeed }
+Number:Dimensionless ActualInletFanSpeed "Actual Inlet Fan Speed [%d rpm]" { channel="openthermgateway:ventilationheatrecovery:1:brink:vh_actualinletfanspeed }
+Switch NominalVentilationValueTransfer "Nominal Ventilation Value Transfer" <switch> { channel="openthermgateway:ventilationheatrecovery:1:brink:vh_nominalventenable }
+Number:Dimensionless NominalVentilationValue "Nominal Ventilation Value" { channel="openthermgateway:ventilationheatrecovery:1:brink:vh_nominalventrw }
+Number:Dimensionless NominalVentilationValue "Nominal Ventilation Value [%d %%]" { channel="openthermgateway:ventilationheatrecovery:1:brink:vh_nominalventilationvalue }
+Number:Dimensionless VentilationSetpoint "Ventilation Setpoint" { channel="openthermgateway:ventilationheatrecovery:1:brink:vh_ventilationsetpoint }
+Number:Dimensionless TransparentSlaveParameterNumber "Transparent Slave Parameter Number" { channel="openthermgateway:ventilationheatrecovery:1:brink:vh_tspnumber }
+Number:Dimensionless TransparentSlaveParameterEntry "Transparent Slave Parameter Entry" { channel="openthermgateway:ventilationheatrecovery:1:brink:vh_tspentry }
+Number:Dimensionless FaultHistoryBufferNumber "Fault History Buffer Number" { channel="openthermgateway:ventilationheatrecovery:1:brink:vh_fhbnumber }
+Number:Dimensionless FaultHistoryBufferEntry "Fault History Buffer Entry" { channel="openthermgateway:ventilationheatrecovery:1:brink:vh_fhbentry }
```
### demo.sitemap
```
sitemap demo label="Main Menu" {
- Frame label="OpenTherm Gateway" {
- Text item="RoomTemperature" icon="temperature" label="Room temperature [%.1f °C]"
- Text item="RoomSetpoint" icon="temperature" label="Room setpoint [%.1f °C]"
- Setpoint item="TemporaryRoomSetpointOverride" icon="temperature" label="Temporary room setpoint override [%.1f °C]" minValue="0" maxValue="30" step="0.1"
- Setpoint item="ConstantRoomSetpointOverride" icon="temperature" label="Constant room setpoint override [%.1f °C]" minValue="0" maxValue="30" step="0.1"
- Text item="ControlSetpoint" icon="temperature" label="Control setpoint [%.1f °C]"
- Text item="ControlSetpointRequested" icon="temperature" label="Control setpoint requested [%.1f °C]"
- Setpoint item="ControlSetpointOverride" icon="temperature" label="Control setpoint override [%.1f °C]" minValue="0" maxValue="100" step="1"
- Text item="DomesticHotWaterTemperature" icon="temperature" label="Domestic hot water temperature [%.1f °C]"
- Text item="DomesticHotWaterSetpoint" icon="temperature" label="Domestic hot water setpoint [%.1f °C]"
- Setpoint item="DomesticHotWaterSetpointOverride" icon="temperature" label="Domestic hot water setpoint override [%.1f °C]" minValue="0" maxValue="100" step="0.1"
- Text item="BoilerWaterTemperature" icon="temperature" label="Boiler water temperature [%.1f °C]"
- Text item="ReturnWaterTemperature" icon="temperature" label="Return water temperature [%.1f °C]"
- Setpoint item="OutsideTemperature" icon="temperature" label="Outside temperature [%.1f °C]" minValue="-40" maxValue="100" step="0.1"
- Text item="CentralHeatingWaterPressure" icon="" label="Central heating water pressure [%.1f bar]"
- Switch item="CentralHeatingEnabled" icon="switch" label="Central heating enabled"
- Switch item="CentralHeatingEnabledRequested" icon="switch" label="Central heating enabled requested"
- Switch item="CentralHeatingEnabledOverride" icon="switch" label="Central heating enabled override"
- Switch item="CentralHeatingActive" icon="switch" label="Central heating active"
- Switch item="DomesticHotWaterEnabled" icon="switch" label="Domestic hot water enabled"
- Switch item="DomesticHotWaterActive" icon="switch" label="Domestic hot water active"
- Switch item="BurnerActive" icon="switch" label="Burner active"
- Text item="RelativeModulationLevel" icon="" label="Relative modulation level [%.1f %%]"
- Text item="MaximumRelativeModulationLevel" icon="" label="Maximum relative modulation level [%.1f %%]"
- Switch item="Fault" icon="" label="Fault indication"
- Switch item="ServiceRequest" icon="" label="Service required"
- Switch item="LockoutReset" icon="" label="Lockout-reset"
- Switch item="LowWaterPress" icon="" label="Low water pressure fault"
- Switch item="GasFlameFault" icon="" label="Gas or flame fault"
- Switch item="AirPressFault" icon="" label="Air pressure fault"
- Switch item="waterOvTemp" icon="" label="Water over-temperature fault"
- Text item="OemFaultCode" icon="" label="OEM fault code"
- Switch item="Diagnostics" icon="" label="Diagnostics indication"
- Text item="UnsuccessfulBurnerStarts" icon="" label="Unsuccessful burner starts"
- Text item="BurnerStarts" icon="" label="Burner starts"
- Text item="CentralHeatingPumpStarts" icon="" label="Central heating pump starts"
- Text item="DomesticHotWaterPumpValveStarts" icon="" label="Domestic hot water pump/valve starts"
- Text item="DomesticHotWaterBurnerStarts" icon="" label="Domestic hot water burner starts"
- Text item="BurnerHours" icon="" label="Burner hours"
- Text item="CentralHeatingPumpHours" icon="" label="Central heating pump hours"
- Text item="DomesticHotWaterPumpValveHours" icon="" label="Domestic hot water pump/valve hours"
- Text item="DomesticHotWaterBurnerHours" icon="" label="Domestic hot water burner hours"
+ Frame label="Boiler" {
+ Text item="RoomTemperature" icon="temperature" label="Room Temperature [%.1f %unit%]"
+ Text item="RoomSetpoint" icon="temperature" label="Room Setpoint [%.1f %unit%]"
+ Text item="TemporaryRoomSetpointOverride" icon="temperature" label="Temporary Room Setpoint Override [%.1f %unit%]" minValue="0" maxValue="30" step="0.1"
+ Text item="ConstantRoomSetpointOverride" icon="temperature" label="Constant Room Setpoint Override [%.1f %unit%]" minValue="0" maxValue="30" step="0.1"
+ Text item="ControlSetpoint" icon="temperature" label="Control Setpoint [%.1f %unit%]"
+ Text item="ControlSetpointRequested" icon="temperature" label="Control Setpoint Requested [%.1f %unit%]"
+ Text item="ControlSetpointOverride" icon="temperature" label="Control Setpoint Override [%.1f %unit%]" minValue="0" maxValue="100" step="0.1"
+ Text item="ControlSetpoint2" icon="temperature" label="Control Setpoint 2 [%.1f %unit%]"
+ Text item="ControlSetpoint2Requested" icon="temperature" label="Control Setpoint 2 Requested [%.1f %unit%]"
+ Text item="ControlSetpoint2Override" icon="temperature" label="Control Setpoint 2 Override [%.1f %unit%]" minValue="0" maxValue="100" step="0.1"
+ Text item="DomesticHotWaterTemperature" icon="temperature" label="Domestic Hot Water Temperature [%.1f %unit%]"
+ Text item="DomesticHotWaterSetpoint" icon="temperature" label="Domestic Hot Water Setpoint [%.1f %unit%]"
+ Text item="DomesticHotWaterSetpointOverride" icon="temperature" label="Domestic Hot Water Setpoint Override [%.1f %unit%]" minValue="0" maxValue="100" step="0.1"
+ Text item="BoilerWaterTemperature" icon="temperature" label="Boiler Water Temperature [%.1f %unit%]"
+ Text item="ReturnWaterTemperature" icon="temperature" label="Return Water Temperature [%.1f %unit%]"
+ Text item="OutsideTemperature" icon="temperature" label="Outside Temperature [%.1f %unit%]" minValue="-40" maxValue="100" step="0.1"
+ Text item="CentralHeatingWaterPressure" label="Central Heating Water Pressure [%.1f bar]"
+ Switch item="CentralHeatingEnabled" icon="switch" label="Central Heating Enabled"
+ Switch item="CentralHeatingEnabledThermostat" icon="switch" label="Central Heating Enabled Thermostat"
+ Switch item="CentralHeatingOverridden" icon="switch" label="Central Heating Overridden"
+ Switch item="CentralHeating2Enabled" icon="switch" label="Central Heating 2 Enabled"
+ Switch item="CentralHeating2EnabledThermostat" icon="switch" label="Central Heating 2 Enabled Thermostat"
+ Switch item="CentralHeating2Overridden" icon="switch" label="Central Heating 2 Overridden"
+ Switch item="CentralHeatingActive" icon="switch" label="Central Heating Active"
+ Switch item="DomesticHotWaterEnabled" icon="switch" label="Domestic Hot Water Enabled"
+ Switch item="DomesticHotWaterActive" icon="switch" label="Domestic Hot Water Active"
+ Switch item="BurnerActive" icon="switch" label="Burner Active"
+ Text item="RelativeModulationLevel" label="Relative Modulation Level [%.1f %%]"
+ Text item="MaximumRelativeModulationLevel" label="Maximum Relative Modulation Level [%.1f %%]"
+ Switch item="FaultIndication" icon="switch" label="Fault Indication"
+ Switch item="ServiceRequired" icon="switch" label="Service Required"
+ Switch item="Lockout-ResetEnabled" icon="switch" label="Lockout-Reset Enabled"
+ Switch item="LowWaterPressureFault" icon="switch" label="Low Water Pressure Fault"
+ Switch item="GasOrFlameFault" icon="switch" label="Gas Or Flame Fault"
+ Switch item="AirPressureFault" icon="switch" label="Air Pressure Fault"
+ Switch item="WaterOver-TemperatureFault" icon="switch" label="Water Over-Temperature Fault"
+ Text item="OEMFaultCode" label="OEM Fault Code"
+ Text item="UnsuccessfulBurnerStarts" label="Unsuccessful Burner Starts"
+ Text item="BurnerStarts" label="Burner Starts"
+ Text item="CentralHeatingPumpStarts" label="Central Heating Pump Starts"
+ Text item="DomesticHotWaterPump/ValveStarts" label="Domestic Hot Water Pump/Valve Starts"
+ Text item="DomesticHotWaterBurnerStarts" label="Domestic Hot Water Burner Starts"
+ Text item="BurnerHours" label="Burner Hours"
+ Text item="CentralHeatingPumpHours" label="Central Heating Pump Hours"
+ Text item="DomesticHotWaterPumpValveHours" label="Domestic Hot Water Pump/Valve Hours"
+ Text item="DomesticHotWaterBurnerHours" label="Domestic Hot Water Burner Hours"
+ Text item="TransparentSlaveParameterNumber" label="Transparent Slave Parameter Number"
+ Text item="TransparentSlaveParameterEntry" label="Transparent Slave Parameter Entry"
+ Text item="FaultHistoryBufferNumber" label="Fault History Buffer Number"
+ Text item="FaultHistoryBufferEntry" label="Fault History Buffer Entry"
}
+
+ Frame label="Ventilation / Heat Recovery" {
+ Switch item="VentilationEnabled" icon="switch" label="Ventilation Enabled"
+ Text item="BypassPosition" label="Bypass Position"
+ Text item="BypassMode" label="Bypass Mode"
+ Switch item="FreeVentilationMode" icon="switch" label="Free Ventilation Mode"
+ Switch item="FaultIndication" icon="switch" label="Fault Indication"
+ Switch item="VentilationMode" icon="switch" label="Ventilation Mode"
+ Switch item="BypassStatus" icon="switch" label="Bypass Status"
+ Text item="BypassAutomaticStatus" label="Bypass Automatic Status"
+ Switch item="FreeVentilationStatus" icon="switch" label="Free Ventilation Status"
+ Switch item="FilterCheck" icon="switch" label="Filter Check"
+ Switch item="DiagnosticIndication" icon="switch" label="Diagnostic Indication"
+ Text item="ControlSetpoint" label="Control Setpoint"
+ Switch item="ServiceRequest" icon="switch" label="Service Request"
+ Switch item="ExhaustFanFault" icon="switch" label="Exhaust Fan Fault"
+ Switch item="InletFanFault" icon="switch" label="Inlet Fan Fault"
+ Switch item="FrostProtection" icon="switch" label="Frost Protection"
+ Text item="FaultCode" label="Fault Code"
+ Text item="DiagnosticCode" label="Diagnostic Code"
+ Text item="SystemType" label="System Type"
+ Switch item="Bypass" icon="switch" label="Bypass"
+ Text item="SpeedControl" label="Speed Control"
+ Text item="MemberID" label="Member ID"
+ Text item="OpenThermVersion" label="OpenTherm Version"
+ Text item="VersionType" label="Version Type"
+ Text item="RelativeVentilation" label="Relative Ventilation [%d %%]"
+ Text item="RelativeHumidity" label="Relative Humidity [%d %%]"
+ Text item="CO2Level" label="CO2 Level [%d ppm]"
+ Text item="SupplyInletTemperature" label="Supply Inlet Temperature [%.1f %unit%]"
+ Text item="SupplyOutletTemperature" label="Supply Outlet Temperature [%.1f %unit%]"
+ Text item="ExhaustInletTemperature" label="Exhaust Inlet Temperature [%.1f %unit%]"
+ Text item="ExhaustOutletTemperature" label="Exhaust Outlet Temperature [%.1f %unit%]"
+ Text item="ActualExhaustFanSpeed" label="Actual Exhaust Fan Speed [%d rpm]"
+ Text item="ActualInletFanSpeed" label="Actual Inlet Fan Speed [%d rpm]"
+ Switch item="NominalVentilationValueTransfer" icon="switch" label="Nominal Ventilation Value Transfer"
+ Text item="NominalVentilationValue" label="Nominal Ventilation Value"
+ Text item="NominalVentilationValue" label="Nominal Ventilation Value [%d %%]"
+ Text item="VentilationSetpoint" label="Ventilation Setpoint" minValue="0" maxValue="100" step="1"
+ Text item="TransparentSlaveParameterNumber" label="Transparent Slave Parameter Number"
+ Text item="TransparentSlaveParameterEntry" label="Transparent Slave Parameter Entry"
+ Text item="FaultHistoryBufferNumber" label="Fault History Buffer Number"
+ Text item="FaultHistoryBufferEntry" label="Fault History Buffer Entry"
+ }
+ }
+```
+
+## Migration from Prior Versions of the Binding
+
+Between openHAB v3.2 and v3.3 the structure of Things and Channels was changed.
+This means that Things and their respective Channels and Items that were created on v3.2 or earlier will no longer function on version v3.3 or later.
+To be specific the change is as follows..
+
+- **openHAB Versions v3.2 or earlier**: There was just one single `otgw` Thing that combined the functions that communicate with the OpenTherm Gateway together with the functions of the Channels that monitor/control the connected Boiler.
+
+- **openHAB Versions v3.3 or later**: The communication functions have been moved to a new `openthermgateway` Bridge Thing. The connected Boiler functions have been moved to a new `boiler` Thing. And in addition (if needed) new functions for a connected Ventilation / Heat-Recovery system have been added in a new `ventilationheatrecovery` Thing.
+
+So if you upgrade your system from openHAB v3.2 (or lower) to v3.3 (or higher), then your Thing and Item definitions must be migrated as shown below..
+
+- Divide the contents of your old `openthermgateway:otgw:yourGatewayId` Thing definition into two new parts, namely 1) a new `openthermgateway:openthermgateway:yourGatewayId` Bridge definition for the OpenTherm Gateway, and 2) a new `openthermgateway:boiler:yourGatewayId:yourBoilerId` Thing definition for the connected Boiler.
+
+- Change the `channel=".."` configuration entries of all your Items from referring to the ThingUID of the old `otgw` Thing to refer instead to the ThingUID of the respective newly created `boiler` Thing.
+
+**Old Thing Definition and respective Item Definition (example)**
+
+```
+Thing openthermgateway:otgw:yourGatewayId [ ipaddress="192.168.1.100", port=8000, connectionRetryInterval=60 ]
+
+e.g.
+Number:Temperature Boiler_DHW_Temperature "Boiler DHW Temperature [%.1f %unit%]" <temperature> {channel="openthermgateway:otgw:yourGatewayId:dhwtemp"}
+&c.
+```
+
+**New Thing Definition and respective and Item Definition (example)**
+
+```
+Bridge openthermgateway:openthermgateway:yourGatewayId "OpenTherm Gateway" @ "Kitchen" [ipaddress="192.168.1.100", port=20108, connectionRetryInterval=60] {
+ Thing boiler remeha "Boiler" @ "Kitchen"
}
+
+e.g.
+Number:Temperature Boiler_DHW_Temperature "Boiler DHW Temperature [%.1f %unit%]" <temperature> {channel="openthermgateway:boiler:yourGatewayId:remeha:dhwtemp"}
+&c.
```
<name>openHAB Add-ons :: Bundles :: OpenTherm Gateway Binding</name>
+ <description>This binding integrates OpenTherm capable devices via an OpenThermGateway bridge.</description>
</project>
+++ /dev/null
-/**
- * Copyright (c) 2010-2022 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.openthermgateway;
-
-import java.util.Set;
-
-import org.eclipse.jdt.annotation.NonNullByDefault;
-import org.openhab.core.thing.ThingTypeUID;
-
-/**
- * The {@link OpenThermGatewayBindingConstants} class defines common constants, which are
- * used across the whole binding.
- *
- * @author Arjen Korevaar - Initial contribution
- */
-@NonNullByDefault
-public class OpenThermGatewayBindingConstants {
-
- private static final String BINDING_ID = "openthermgateway";
-
- // List of all Thing Type UID's
- public static final ThingTypeUID MAIN_THING_TYPE = new ThingTypeUID(BINDING_ID, "otgw");
-
- // List of all Channel id's
- public static final String CHANNEL_SEND_COMMAND = "sendcommand";
-
- public static final String CHANNEL_OVERRIDE_SETPOINT_TEMPORARY = "temperaturetemporary";
- public static final String CHANNEL_OVERRIDE_SETPOINT_CONSTANT = "temperatureconstant";
- public static final String CHANNEL_OVERRIDE_DHW_SETPOINT = "overridedhwsetpoint";
- public static final String CHANNEL_ROOM_TEMPERATURE = "roomtemp";
- public static final String CHANNEL_ROOM_SETPOINT = "roomsetpoint";
- public static final String CHANNEL_FLOW_TEMPERATURE = "flowtemp";
- public static final String CHANNEL_RETURN_TEMPERATURE = "returntemp";
- public static final String CHANNEL_OUTSIDE_TEMPERATURE = "outsidetemp";
- public static final String CHANNEL_CENTRAL_HEATING_WATER_SETPOINT = "controlsetpoint";
- public static final String CHANNEL_REQUESTED_CENTRAL_HEATING_WATER_SETPOINT = "controlsetpointrequested";
- public static final String CHANNEL_OVERRIDE_CENTRAL_HEATING_WATER_SETPOINT = "controlsetpointoverride";
- public static final String CHANNEL_CENTRAL_HEATING2_WATER_SETPOINT = "controlsetpoint2";
- public static final String CHANNEL_REQUESTED_CENTRAL_HEATING2_WATER_SETPOINT = "controlsetpoint2requested";
- public static final String CHANNEL_OVERRIDE_CENTRAL_HEATING2_WATER_SETPOINT = "controlsetpoint2override";
- public static final String CHANNEL_CENTRAL_HEATING_WATER_PRESSURE = "waterpressure";
- public static final String CHANNEL_CENTRAL_HEATING_ENABLED = "ch_enable";
- public static final String CHANNEL_REQUESTED_CENTRAL_HEATING_ENABLED = "ch_enablerequested";
- public static final String CHANNEL_OVERRIDE_CENTRAL_HEATING_ENABLED = "ch_enableoverride";
- public static final String CHANNEL_CENTRAL_HEATING2_ENABLED = "ch2_enable";
- public static final String CHANNEL_REQUESTED_CENTRAL_HEATING2_ENABLED = "ch2_enablerequested";
- public static final String CHANNEL_OVERRIDE_CENTRAL_HEATING2_ENABLED = "ch2_enableoverride";
- public static final String CHANNEL_CENTRAL_HEATING_MODE = "ch_mode";
- public static final String CHANNEL_DOMESTIC_HOT_WATER_TEMPERATURE = "dhwtemp";
- public static final String CHANNEL_DOMESTIC_HOT_WATER_ENABLED = "dhw_enable";
- public static final String CHANNEL_DOMESTIC_HOT_WATER_MODE = "dhw_mode";
- public static final String CHANNEL_DOMESTIC_HOT_WATER_SETPOINT = "tdhwset";
- public static final String CHANNEL_FLAME = "flame";
- public static final String CHANNEL_RELATIVE_MODULATION_LEVEL = "modulevel";
- public static final String CHANNEL_MAXIMUM_MODULATION_LEVEL = "maxrelmdulevel";
- public static final String CHANNEL_FAULT = "fault";
- public static final String CHANNEL_SERVICEREQUEST = "servicerequest";
- public static final String CHANNEL_REMOTE_RESET = "lockout-reset";
- public static final String CHANNEL_LOW_WATER_PRESSURE = "lowwaterpress";
- public static final String CHANNEL_GAS_FLAME_FAULT = "gasflamefault";
- public static final String CHANNEL_AIR_PRESSURE_FAULT = "airpressfault";
- public static final String CHANNEL_WATER_OVER_TEMP = "waterovtemp";
- public static final String CHANNEL_OEM_FAULTCODE = "oemfaultcode";
- public static final String CHANNEL_DIAGNOSTICS_INDICATION = "diag";
- public static final String CHANNEL_UNSUCCESSFUL_BURNER_STARTS = "unsuccessfulburnerstarts";
- public static final String CHANNEL_BURNER_STARTS = "burnerstarts";
- public static final String CHANNEL_CH_PUMP_STARTS = "chpumpstarts";
- public static final String CHANNEL_DHW_PV_STARTS = "dhwpvstarts";
- public static final String CHANNEL_DHW_BURNER_STARTS = "dhwburnerstarts";
- public static final String CHANNEL_BURNER_HOURS = "burnerhours";
- public static final String CHANNEL_CH_PUMP_HOURS = "chpumphours";
- public static final String CHANNEL_DHW_PV_HOURS = "dhwpvhours";
- public static final String CHANNEL_DHW_BURNER_HOURS = "dhwburnerhours";
-
- public static final Set<String> SUPPORTED_CHANNEL_IDS = Set.of(CHANNEL_ROOM_TEMPERATURE, CHANNEL_ROOM_SETPOINT,
- CHANNEL_FLOW_TEMPERATURE, CHANNEL_RETURN_TEMPERATURE, CHANNEL_OUTSIDE_TEMPERATURE,
- CHANNEL_CENTRAL_HEATING_WATER_PRESSURE, CHANNEL_CENTRAL_HEATING_ENABLED,
- CHANNEL_REQUESTED_CENTRAL_HEATING_ENABLED, CHANNEL_OVERRIDE_CENTRAL_HEATING_ENABLED,
- CHANNEL_CENTRAL_HEATING2_ENABLED, CHANNEL_REQUESTED_CENTRAL_HEATING2_ENABLED,
- CHANNEL_OVERRIDE_CENTRAL_HEATING2_ENABLED, CHANNEL_CENTRAL_HEATING_MODE,
- CHANNEL_CENTRAL_HEATING_WATER_SETPOINT, CHANNEL_REQUESTED_CENTRAL_HEATING_WATER_SETPOINT,
- CHANNEL_OVERRIDE_CENTRAL_HEATING_WATER_SETPOINT, CHANNEL_CENTRAL_HEATING2_WATER_SETPOINT,
- CHANNEL_REQUESTED_CENTRAL_HEATING2_WATER_SETPOINT, CHANNEL_OVERRIDE_CENTRAL_HEATING2_WATER_SETPOINT,
- CHANNEL_DOMESTIC_HOT_WATER_TEMPERATURE, CHANNEL_DOMESTIC_HOT_WATER_ENABLED, CHANNEL_DOMESTIC_HOT_WATER_MODE,
- CHANNEL_DOMESTIC_HOT_WATER_SETPOINT, CHANNEL_FLAME, CHANNEL_RELATIVE_MODULATION_LEVEL,
- CHANNEL_MAXIMUM_MODULATION_LEVEL, CHANNEL_FAULT, CHANNEL_SERVICEREQUEST, CHANNEL_REMOTE_RESET,
- CHANNEL_LOW_WATER_PRESSURE, CHANNEL_GAS_FLAME_FAULT, CHANNEL_AIR_PRESSURE_FAULT, CHANNEL_WATER_OVER_TEMP,
- CHANNEL_OEM_FAULTCODE, CHANNEL_DIAGNOSTICS_INDICATION, CHANNEL_UNSUCCESSFUL_BURNER_STARTS,
- CHANNEL_BURNER_STARTS, CHANNEL_CH_PUMP_STARTS, CHANNEL_DHW_PV_STARTS, CHANNEL_DHW_BURNER_STARTS,
- CHANNEL_BURNER_HOURS, CHANNEL_CH_PUMP_HOURS, CHANNEL_DHW_PV_HOURS, CHANNEL_DHW_BURNER_HOURS);
-}
--- /dev/null
+/**
+ * Copyright (c) 2010-2022 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.openthermgateway.handler;
+
+import static org.openhab.binding.openthermgateway.internal.OpenThermGatewayBindingConstants.*;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.openhab.binding.openthermgateway.internal.DataItem;
+import org.openhab.binding.openthermgateway.internal.DataItemGroup;
+import org.openhab.binding.openthermgateway.internal.Message;
+import org.openhab.binding.openthermgateway.internal.TspFhbSizeDataItem;
+import org.openhab.binding.openthermgateway.internal.TspFhbValueDataItem;
+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.ThingHandlerCallback;
+import org.openhab.core.thing.type.ChannelKind;
+import org.openhab.core.thing.type.ChannelTypeUID;
+import org.openhab.core.types.Command;
+import org.openhab.core.types.State;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * The {@link BaseDeviceHandler} is a base class for actual Things.
+ *
+ * @author Arjen Korevaar - Initial contribution
+ */
+@NonNullByDefault
+public abstract class BaseDeviceHandler extends BaseThingHandler {
+
+ private final Logger logger = LoggerFactory.getLogger(BaseDeviceHandler.class);
+
+ public BaseDeviceHandler(Thing thing) {
+ super(thing);
+ }
+
+ @Override
+ public void initialize() {
+ if (getBridge() == null) {
+ updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR);
+ } else {
+ // note: the framework handles bridge configuration resp. offline errors
+ updateStatus(ThingStatus.ONLINE);
+ }
+ }
+
+ @Override
+ public void handleCommand(ChannelUID channelUID, Command command) {
+ Bridge bridge = getBridge();
+
+ if (bridge != null) {
+ OpenThermGatewayHandler handler = (OpenThermGatewayHandler) bridge.getHandler();
+ if (handler != null) {
+ handler.handleCommand(channelUID, command);
+ }
+ } else {
+ logger.debug("Bridge is missing");
+ }
+ }
+
+ public void receiveMessage(Message message) {
+ DataItem[] dataItems = DataItemGroup.DATAITEMGROUPS.get(message.getID());
+
+ if (dataItems == null) {
+ logger.debug("No DataItem found for message id {}", message.getID());
+ return;
+ }
+
+ for (DataItem dataItem : dataItems) {
+ if (dataItem instanceof TspFhbSizeDataItem) {
+ logger.debug("Received TSP or FHB size message {} ({})", message.getID(), dataItem.getSubject());
+
+ verifyTspFhbChannels(((TspFhbSizeDataItem) dataItem).getValueId(),
+ message.getUInt(dataItem.getByteType()));
+ } else {
+ String channelId = dataItem.getChannelId(message);
+
+ if (thing.getChannel(channelId) == null || !dataItem.hasValidCodeType(message)) {
+ continue;
+ }
+
+ State state = dataItem.createState(message);
+
+ logger.debug("Received update for channel {}: {}", channelId, state);
+ updateState(channelId, state);
+ }
+ }
+ }
+
+ private void verifyTspFhbChannels(int id, int size) {
+ // Dynamically create TSP or FHB value channels based on TSP or FHB size message
+ ThingHandlerCallback callback = getCallback();
+
+ if (callback == null) {
+ logger.debug("Unable to get thing handler callback");
+ return;
+ }
+
+ DataItem[] dataItems = DataItemGroup.DATAITEMGROUPS.get(id);
+
+ if (dataItems == null) {
+ logger.debug("Unable to find dataItem for id {}", id);
+ return;
+ }
+
+ if (dataItems.length != 1) {
+ logger.debug("Found zero or multiple dataItems for id {}", id);
+ return;
+ }
+
+ TspFhbValueDataItem dataItem = (TspFhbValueDataItem) dataItems[0];
+
+ logger.debug("Checking number of TSP or FHB channels for DATA-ID {}: {}", id, size);
+
+ // A generic Number:Dimensionless channel type for TSP and FHB values
+ ChannelTypeUID channelTypeUID = new ChannelTypeUID(BINDING_ID, CHANNEL_TSPFHB);
+
+ List<Channel> channels = new ArrayList<>(getThing().getChannels());
+
+ boolean changed = false;
+ for (int i = 0; i < size; i++) {
+ String channelId = dataItem.getChannelId(i);
+ ChannelUID channelUID = new ChannelUID(thing.getUID(), channelId);
+
+ if (!channels.stream().map(Channel::getUID).anyMatch(channelUID::equals)) {
+ String label = dataItem.getLabel(i);
+
+ logger.debug("Adding channel {}", channelId);
+
+ channels.add(callback.createChannelBuilder(channelUID, channelTypeUID).withKind(ChannelKind.STATE)
+ .withLabel(label).build());
+ changed = true;
+ } else {
+ logger.debug("Channel {} already exists", channelId);
+ }
+ }
+
+ if (changed) {
+ logger.debug("Updating Thing with new channels");
+ updateThing(editThing().withChannels(channels).build());
+ }
+ }
+}
--- /dev/null
+/**
+ * Copyright (c) 2010-2022 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.openthermgateway.handler;
+
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.openhab.core.thing.Thing;
+
+/**
+ * The {@link BoilerHandler} represemts a boiler with thermostat.
+ *
+ * @author Arjen Korevaar - Initial contribution
+ */
+@NonNullByDefault
+public class BoilerHandler extends BaseDeviceHandler {
+
+ public BoilerHandler(Thing thing) {
+ super(thing);
+ }
+}
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
-import javax.measure.Unit;
-
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
-import org.openhab.binding.openthermgateway.OpenThermGatewayBindingConstants;
-import org.openhab.binding.openthermgateway.internal.DataItem;
+import org.openhab.binding.openthermgateway.internal.ConnectionState;
import org.openhab.binding.openthermgateway.internal.DataItemGroup;
import org.openhab.binding.openthermgateway.internal.GatewayCommand;
import org.openhab.binding.openthermgateway.internal.GatewayCommandCode;
import org.openhab.binding.openthermgateway.internal.Message;
+import org.openhab.binding.openthermgateway.internal.OpenThermGatewayBindingConstants;
import org.openhab.binding.openthermgateway.internal.OpenThermGatewayCallback;
import org.openhab.binding.openthermgateway.internal.OpenThermGatewayConfiguration;
import org.openhab.binding.openthermgateway.internal.OpenThermGatewayConnector;
import org.openhab.binding.openthermgateway.internal.OpenThermGatewaySocketConnector;
-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.unit.SIUnits;
+import org.openhab.core.thing.Bridge;
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.BaseBridgeHandler;
import org.openhab.core.types.Command;
import org.openhab.core.types.RefreshType;
-import org.openhab.core.types.State;
import org.openhab.core.types.UnDefType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
* @author Arjen Korevaar - Initial contribution
*/
@NonNullByDefault
-public class OpenThermGatewayHandler extends BaseThingHandler implements OpenThermGatewayCallback {
+public class OpenThermGatewayHandler extends BaseBridgeHandler implements OpenThermGatewayCallback {
private final Logger logger = LoggerFactory.getLogger(OpenThermGatewayHandler.class);
- private @Nullable OpenThermGatewayConfiguration config;
+ private @Nullable OpenThermGatewayConfiguration configuration;
private @Nullable OpenThermGatewayConnector connector;
private @Nullable ScheduledFuture<?> reconnectTask;
- private boolean connecting = false;
- private boolean explicitDisconnect = false;
+ private @Nullable ConnectionState state;
+ private boolean autoReconnect = true;
+ private boolean disposing = false;
- public OpenThermGatewayHandler(Thing thing) {
- super(thing);
+ public OpenThermGatewayHandler(Bridge bridge) {
+ super(bridge);
}
@Override
public void initialize() {
- logger.debug("Initializing OpenTherm Gateway handler for uid '{}'", getThing().getUID());
-
- updateStatus(ThingStatus.UNKNOWN, ThingStatusDetail.NONE, "Initializing");
+ logger.debug("Initializing OpenThermGateway handler for uid {}", getThing().getUID());
- config = getConfigAs(OpenThermGatewayConfiguration.class);
+ configuration = getConfigAs(OpenThermGatewayConfiguration.class);
+ logger.debug("Using configuration: {}", configuration);
+ disposing = false;
+ updateStatus(ThingStatus.UNKNOWN);
connect();
}
@Override
public void handleCommand(ChannelUID channelUID, Command command) {
- @Nullable
- OpenThermGatewayConnector conn = connector;
-
- logger.debug("Received channel: {}, command: {}", channelUID, command);
+ logger.debug("Received command {} for channel {}", command, channelUID);
if (!(command instanceof RefreshType)) {
String channel = channelUID.getId();
gatewayCommand = GatewayCommand.parse(code, command.toFullString());
}
- if (conn != null && conn.isConnected()) {
- conn.sendCommand(gatewayCommand);
+ sendCommand(gatewayCommand);
- if (GatewayCommandCode.ControlSetpoint.equals(code)) {
- if (gatewayCommand.getMessage().equals("0.0")) {
- updateState(OpenThermGatewayBindingConstants.CHANNEL_OVERRIDE_CENTRAL_HEATING_WATER_SETPOINT,
- UnDefType.UNDEF);
- }
- updateState(OpenThermGatewayBindingConstants.CHANNEL_OVERRIDE_CENTRAL_HEATING_ENABLED,
- OnOffType.from(!gatewayCommand.getMessage().equals("0.0")));
- } else if (GatewayCommandCode.ControlSetpoint2.equals(code)) {
- if (gatewayCommand.getMessage().equals("0.0")) {
- updateState(OpenThermGatewayBindingConstants.CHANNEL_OVERRIDE_CENTRAL_HEATING2_WATER_SETPOINT,
- UnDefType.UNDEF);
- }
- updateState(OpenThermGatewayBindingConstants.CHANNEL_OVERRIDE_CENTRAL_HEATING2_ENABLED,
- OnOffType.from(!gatewayCommand.getMessage().equals("0.0")));
+ if (GatewayCommandCode.CONTROLSETPOINT.equals(code)) {
+ if (gatewayCommand.getMessage().equals("0.0")) {
+ updateState(OpenThermGatewayBindingConstants.CHANNEL_OVERRIDE_CENTRAL_HEATING_WATER_SETPOINT,
+ UnDefType.UNDEF);
}
- } else {
- connect();
+ updateState(OpenThermGatewayBindingConstants.CHANNEL_OVERRIDE_CENTRAL_HEATING_ENABLED,
+ OnOffType.from(!gatewayCommand.getMessage().equals("0.0")));
+ } else if (GatewayCommandCode.CONTROLSETPOINT2.equals(code)) {
+ if (gatewayCommand.getMessage().equals("0.0")) {
+ updateState(OpenThermGatewayBindingConstants.CHANNEL_OVERRIDE_CENTRAL_HEATING2_WATER_SETPOINT,
+ UnDefType.UNDEF);
+ }
+ updateState(OpenThermGatewayBindingConstants.CHANNEL_OVERRIDE_CENTRAL_HEATING2_ENABLED,
+ OnOffType.from(!gatewayCommand.getMessage().equals("0.0")));
}
}
}
- @Override
- public void connecting() {
- connecting = true;
- updateStatus(ThingStatus.UNKNOWN, ThingStatusDetail.NONE, "Connecting");
+ public void sendCommand(GatewayCommand gatewayCommand) {
+ @Nullable
+ OpenThermGatewayConnector conn = connector;
+
+ if (conn != null && conn.isConnected()) {
+ conn.sendCommand(gatewayCommand);
+ } else {
+ logger.debug("Unable to send command {}: connector not connected", gatewayCommand.toFullString());
+ }
}
@Override
- public void connected() {
- connecting = false;
- updateStatus(ThingStatus.ONLINE);
+ public void receiveMessage(Message message) {
+ scheduler.submit(() -> receiveMessageTask(message));
}
- @Override
- public void disconnected() {
- @Nullable
- OpenThermGatewayConfiguration conf = config;
+ private void receiveMessageTask(Message message) {
+ int msgId = message.getID();
- connecting = false;
+ if (!DataItemGroup.DATAITEMGROUPS.containsKey(msgId)) {
+ logger.debug("Unsupported message id {}", msgId);
+ return;
+ }
- updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.NONE, "Disconnected");
+ for (Thing thing : getThing().getThings()) {
+ BaseDeviceHandler handler = (BaseDeviceHandler) thing.getHandler();
- // retry connection if disconnect is not explicitly requested
- if (!explicitDisconnect && conf != null && conf.connectionRetryInterval > 0) {
- logger.debug("Scheduling to reconnect in {} seconds.", conf.connectionRetryInterval);
- reconnectTask = scheduler.schedule(this::connect, conf.connectionRetryInterval, TimeUnit.SECONDS);
+ if (handler != null) {
+ handler.receiveMessage(message);
+ }
}
}
@Override
- public void receiveMessage(Message message) {
- if (DataItemGroup.dataItemGroups.containsKey(message.getID())) {
- DataItem[] dataItems = DataItemGroup.dataItemGroups.get(message.getID());
-
- for (DataItem dataItem : dataItems) {
- String channelId = dataItem.getSubject();
-
- if (!OpenThermGatewayBindingConstants.SUPPORTED_CHANNEL_IDS.contains(channelId)
- || (dataItem.getFilteredCode() != null && dataItem.getFilteredCode() != message.getCode())) {
- continue;
- }
-
- State state = null;
-
- switch (dataItem.getDataType()) {
- case FLAGS:
- state = OnOffType.from(message.getBit(dataItem.getByteType(), dataItem.getBitPos()));
- break;
- case UINT8:
- case UINT16:
- state = new DecimalType(message.getUInt(dataItem.getByteType()));
- break;
- case INT8:
- case INT16:
- state = new DecimalType(message.getInt(dataItem.getByteType()));
- break;
- case FLOAT:
- float value = message.getFloat();
- @Nullable
- Unit<?> unit = dataItem.getUnit();
- state = (unit == null) ? new DecimalType(value) : new QuantityType<>(value, unit);
- break;
- case DOWTOD:
- break;
- }
+ public void connectionStateChanged(ConnectionState state) {
+ scheduler.submit(() -> connectionStateChangedTask(state));
+ }
- if (state != null) {
- logger.debug("Received update for channel '{}': {}", channelId, state);
- updateState(channelId, state);
- }
+ private void connectionStateChangedTask(ConnectionState state) {
+ if (this.state != state) {
+ this.state = state;
+
+ switch (state) {
+ case CONNECTED:
+ updateStatus(ThingStatus.ONLINE);
+ cancelAutoReconnect();
+ break;
+ case DISCONNECTED:
+ if (!disposing) {
+ updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR);
+ autoReconnect();
+ }
+ default:
}
}
}
@Override
public void handleRemoval() {
- logger.debug("Removing OpenTherm Gateway handler");
+ logger.debug("Removing OpenThermGateway handler");
disconnect();
super.handleRemoval();
}
@Override
public void dispose() {
+ logger.debug("Disposing OpenThermGateway handler");
+ disposing = true;
disconnect();
-
- ScheduledFuture<?> localReconnectTask = reconnectTask;
- if (localReconnectTask != null) {
- localReconnectTask.cancel(true);
- reconnectTask = null;
- }
-
super.dispose();
}
private void connect() {
@Nullable
- OpenThermGatewayConfiguration conf = config;
-
- explicitDisconnect = false;
+ OpenThermGatewayConfiguration config = configuration;
- if (connecting) {
- logger.debug("OpenTherm Gateway connector is already connecting ...");
+ if (this.state == ConnectionState.CONNECTING) {
+ logger.debug("OpenThermGateway connector is already connecting");
return;
}
+ // Make sure everything is cleaned up before creating a new connection
disconnect();
- if (conf != null) {
- logger.debug("Starting OpenTherm Gateway connector");
+ if (config != null) {
+ connectionStateChanged(ConnectionState.INITIALIZING);
+
+ logger.debug("Starting OpenThermGateway connector");
- connector = new OpenThermGatewaySocketConnector(this, conf.ipaddress, conf.port);
+ autoReconnect = true;
- Thread thread = new Thread(connector, "OpenTherm Gateway Binding - socket listener thread");
- thread.setDaemon(true);
- thread.start();
+ OpenThermGatewayConnector conn = connector = new OpenThermGatewaySocketConnector(this, config);
+ conn.start();
- logger.debug("OpenTherm Gateway connector started");
+ logger.debug("OpenThermGateway connector started");
}
}
@Nullable
OpenThermGatewayConnector conn = connector;
- explicitDisconnect = true;
+ autoReconnect = false;
+
+ cancelAutoReconnect();
if (conn != null) {
- if (conn.isConnected()) {
- logger.debug("Stopping OpenTherm Gateway connector");
- conn.stop();
+ conn.stop();
+ connector = null;
+ }
+ }
+
+ private void autoReconnect() {
+ @Nullable
+ OpenThermGatewayConfiguration config = configuration;
+
+ if (autoReconnect && config != null && config.connectionRetryInterval > 0) {
+ logger.debug("Scheduling to auto reconnect in {} seconds", config.connectionRetryInterval);
+ reconnectTask = scheduler.schedule(this::connect, config.connectionRetryInterval, TimeUnit.SECONDS);
+ }
+ }
+
+ private void cancelAutoReconnect() {
+ ScheduledFuture<?> localReconnectTask = reconnectTask;
+
+ if (localReconnectTask != null) {
+ if (!localReconnectTask.isDone()) {
+ logger.debug("Cancelling auto reconnect task");
+ localReconnectTask.cancel(true);
}
- connector = null;
+ reconnectTask = null;
}
}
private @Nullable String getGatewayCodeFromChannel(String channel) throws IllegalArgumentException {
switch (channel) {
case OpenThermGatewayBindingConstants.CHANNEL_OVERRIDE_SETPOINT_TEMPORARY:
- return GatewayCommandCode.TemperatureTemporary;
+ return GatewayCommandCode.TEMPERATURETEMPORARY;
case OpenThermGatewayBindingConstants.CHANNEL_OVERRIDE_SETPOINT_CONSTANT:
- return GatewayCommandCode.TemperatureConstant;
+ return GatewayCommandCode.TEMPERATURECONSTANT;
case OpenThermGatewayBindingConstants.CHANNEL_OUTSIDE_TEMPERATURE:
- return GatewayCommandCode.TemperatureOutside;
+ return GatewayCommandCode.TEMPERATUREOUTSIDE;
case OpenThermGatewayBindingConstants.CHANNEL_OVERRIDE_DHW_SETPOINT:
- return GatewayCommandCode.SetpointWater;
+ return GatewayCommandCode.SETPOINTWATER;
case OpenThermGatewayBindingConstants.CHANNEL_OVERRIDE_CENTRAL_HEATING_WATER_SETPOINT:
- return GatewayCommandCode.ControlSetpoint;
+ return GatewayCommandCode.CONTROLSETPOINT;
case OpenThermGatewayBindingConstants.CHANNEL_OVERRIDE_CENTRAL_HEATING_ENABLED:
- return GatewayCommandCode.CentralHeating;
+ return GatewayCommandCode.CENTRALHEATING;
case OpenThermGatewayBindingConstants.CHANNEL_OVERRIDE_CENTRAL_HEATING2_WATER_SETPOINT:
- return GatewayCommandCode.ControlSetpoint2;
+ return GatewayCommandCode.CONTROLSETPOINT2;
case OpenThermGatewayBindingConstants.CHANNEL_OVERRIDE_CENTRAL_HEATING2_ENABLED:
- return GatewayCommandCode.CentralHeating2;
+ return GatewayCommandCode.CENTRALHEATING2;
+ case OpenThermGatewayBindingConstants.CHANNEL_OVERRIDE_VENTILATION_SETPOINT:
+ return GatewayCommandCode.VENTILATIONSETPOINT;
case OpenThermGatewayBindingConstants.CHANNEL_SEND_COMMAND:
return null;
default:
--- /dev/null
+/**
+ * Copyright (c) 2010-2022 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.openthermgateway.handler;
+
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.openhab.core.thing.Thing;
+
+/**
+ * The {@link VentilationHeatRecoveryHandler} represents a Ventilation/Heat Recovery unit.
+ *
+ * @author Arjen Korevaar - Initial contribution
+ */
+@NonNullByDefault
+public class VentilationHeatRecoveryHandler extends BaseDeviceHandler {
+
+ public VentilationHeatRecoveryHandler(Thing thing) {
+ super(thing);
+ }
+}
*/
package org.openhab.binding.openthermgateway.internal;
+import org.eclipse.jdt.annotation.NonNullByDefault;
+
/**
* The {@link ByteType} enum specifies whether the upper, lower or both bytes are used
*
* @author Arjen Korevaar - Initial contribution
*/
+@NonNullByDefault
public enum ByteType {
HIGHBYTE,
LOWBYTE,
*/
package org.openhab.binding.openthermgateway.internal;
+import org.eclipse.jdt.annotation.NonNullByDefault;
+
/**
* The {@link CodeType} field is not part of OpenTherm specification, but added by OpenTherm Gateway.
* It can be any of the following:
* @author Arjen Korevaar - Initial contribution
* @author James Melville - Introduced code filtering functionality
*/
+@NonNullByDefault
public enum CodeType {
/**
* Message received from the thermostat
--- /dev/null
+/**
+ * Copyright (c) 2010-2022 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.openthermgateway.internal;
+
+import org.eclipse.jdt.annotation.NonNullByDefault;
+
+/**
+ * The {@link ConnectionState} is used to indicate changes in connection state.
+ *
+ * @author Arjen Korevaar - Initial contribution
+ */
+@NonNullByDefault
+public enum ConnectionState {
+ INITIALIZING,
+ DISCONNECTED,
+ CONNECTING,
+ CONNECTED
+}
*/
package org.openhab.binding.openthermgateway.internal;
-import javax.measure.Unit;
-
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
+import org.openhab.core.types.State;
/**
- * The {@link DataItem} holds the internal OpenTherm message and meta data.
+ * The {@link DataItem} represents the base dataitem.
*
* @author Arjen Korevaar - Initial contribution
*/
+
@NonNullByDefault
-public class DataItem {
- private int id;
+public abstract class DataItem {
private Msg msg;
private ByteType byteType;
- private DataType dataType;
- private int bitpos;
private String subject;
- private @Nullable Unit<?> unit;
- private @Nullable CodeType filteredCode;
-
- public int getID() {
- return id;
- }
+ private @Nullable CodeType codeType;
public Msg getMsg() {
return msg;
}
public ByteType getByteType() {
- return this.byteType;
- }
-
- public DataType getDataType() {
- return dataType;
- }
-
- public int getBitPos() {
- return bitpos;
+ return byteType;
}
public String getSubject() {
return subject;
}
- public @Nullable Unit<?> getUnit() {
- return unit;
+ public @Nullable CodeType getCodeType() {
+ return codeType;
}
- public @Nullable CodeType getFilteredCode() {
- return filteredCode;
+ public DataItem(Msg msg, ByteType byteType, String subject, @Nullable CodeType codeType) {
+ this.msg = msg;
+ this.byteType = byteType;
+ this.subject = subject;
+ this.codeType = codeType;
}
- public DataItem(int id, Msg msg, ByteType byteType, DataType dataType, int bit, String subject) {
- this(id, msg, byteType, dataType, bit, subject, null, null);
- }
+ public boolean hasValidCodeType(Message message) {
+ // Used to bind a dataitem to a specific TBRA code
+ @Nullable
+ CodeType code = this.getCodeType();
- public DataItem(int id, Msg msg, ByteType byteType, DataType dataType, int bit, String subject, Unit<?> unit) {
- this(id, msg, byteType, dataType, bit, subject, unit, null);
+ return (code == null || code == message.getCodeType());
}
- public DataItem(int id, Msg msg, ByteType byteType, DataType dataType, int bit, String subject,
- CodeType filteredCode) {
- this(id, msg, byteType, dataType, bit, subject, null, filteredCode);
+ /**
+ * @param message unused in this default implementation
+ * @return the channel id
+ */
+ public String getChannelId(Message message) {
+ // Default implementation
+ return subject;
}
- public DataItem(int id, Msg msg, ByteType byteType, DataType dataType, int bit, String subject,
- @Nullable Unit<?> unit, @Nullable CodeType filteredCode) {
- this.id = id;
- this.msg = msg;
- this.byteType = byteType;
- this.dataType = dataType;
- this.bitpos = bit;
- this.subject = subject;
- this.unit = unit;
- this.filteredCode = filteredCode;
- }
+ public abstract State createState(Message message);
}
@NonNullByDefault
public class DataItemGroup {
- public static final Map<Integer, DataItem[]> dataItemGroups = createDataItemGroups();
+ public static final Map<Integer, DataItem[]> DATAITEMGROUPS = createDataItemGroups();
private static Map<Integer, DataItem[]> createDataItemGroups() {
HashMap<Integer, DataItem[]> g = new HashMap<>();
- g.put(0, new DataItem[] {
- new DataItem(0, Msg.READ, ByteType.HIGHBYTE, DataType.FLAGS, 0, "ch_enable", CodeType.B),
- new DataItem(0, Msg.READ, ByteType.HIGHBYTE, DataType.FLAGS, 0, "ch_enablerequested", CodeType.T),
- new DataItem(0, Msg.READ, ByteType.HIGHBYTE, DataType.FLAGS, 0, "ch_enableoverride", CodeType.R),
- new DataItem(0, Msg.READ, ByteType.HIGHBYTE, DataType.FLAGS, 1, "dhw_enable", CodeType.B),
- new DataItem(0, Msg.READ, ByteType.HIGHBYTE, DataType.FLAGS, 2, "cooling_enabled", CodeType.B),
- new DataItem(0, Msg.READ, ByteType.HIGHBYTE, DataType.FLAGS, 3, "otc_active", CodeType.B),
- new DataItem(0, Msg.READ, ByteType.HIGHBYTE, DataType.FLAGS, 4, "ch2_enable", CodeType.B),
- new DataItem(0, Msg.READ, ByteType.HIGHBYTE, DataType.FLAGS, 4, "ch2_enablerequested", CodeType.T),
- new DataItem(0, Msg.READ, ByteType.HIGHBYTE, DataType.FLAGS, 4, "ch2_enableoverride", CodeType.R),
- new DataItem(0, Msg.READ, ByteType.HIGHBYTE, DataType.FLAGS, 5, "0x00:5", CodeType.B),
- new DataItem(0, Msg.READ, ByteType.HIGHBYTE, DataType.FLAGS, 6, "0x00:6", CodeType.B),
- new DataItem(0, Msg.READ, ByteType.HIGHBYTE, DataType.FLAGS, 7, "0x00:7", CodeType.B),
- new DataItem(0, Msg.READ, ByteType.LOWBYTE, DataType.FLAGS, 0, "fault", CodeType.B),
- new DataItem(0, Msg.READ, ByteType.LOWBYTE, DataType.FLAGS, 1, "ch_mode", CodeType.B),
- new DataItem(0, Msg.READ, ByteType.LOWBYTE, DataType.FLAGS, 2, "dhw_mode", CodeType.B),
- new DataItem(0, Msg.READ, ByteType.LOWBYTE, DataType.FLAGS, 3, "flame", CodeType.B),
- new DataItem(0, Msg.READ, ByteType.LOWBYTE, DataType.FLAGS, 4, "cooling", CodeType.B),
- new DataItem(0, Msg.READ, ByteType.LOWBYTE, DataType.FLAGS, 5, "ch2E", CodeType.B),
- new DataItem(0, Msg.READ, ByteType.LOWBYTE, DataType.FLAGS, 6, "diag", CodeType.B),
- new DataItem(0, Msg.READ, ByteType.LOWBYTE, DataType.FLAGS, 7, "0x00:7", CodeType.B) });
- g.put(1, new DataItem[] {
- new DataItem(1, Msg.WRITE, ByteType.BOTH, DataType.FLOAT, 0, "controlsetpoint", SIUnits.CELSIUS,
- CodeType.B),
- new DataItem(1, Msg.WRITE, ByteType.BOTH, DataType.FLOAT, 0, "controlsetpointrequested",
- SIUnits.CELSIUS, CodeType.T),
- new DataItem(1, Msg.WRITE, ByteType.BOTH, DataType.FLOAT, 0, "controlsetpointoverride", SIUnits.CELSIUS,
- CodeType.R) });
- g.put(2, new DataItem[] { new DataItem(2, Msg.WRITE, ByteType.HIGHBYTE, DataType.FLAGS, 0, "0x02:0"),
- new DataItem(2, Msg.WRITE, ByteType.HIGHBYTE, DataType.FLAGS, 1, "0x02:1"),
- new DataItem(2, Msg.WRITE, ByteType.HIGHBYTE, DataType.FLAGS, 2, "0x02:2"),
- new DataItem(2, Msg.WRITE, ByteType.HIGHBYTE, DataType.FLAGS, 3, "0x02:3"),
- new DataItem(2, Msg.WRITE, ByteType.HIGHBYTE, DataType.FLAGS, 4, "0x02:4"),
- new DataItem(2, Msg.WRITE, ByteType.HIGHBYTE, DataType.FLAGS, 5, "0x02:5"),
- new DataItem(2, Msg.WRITE, ByteType.HIGHBYTE, DataType.FLAGS, 6, "0x02:6"),
- new DataItem(2, Msg.WRITE, ByteType.HIGHBYTE, DataType.FLAGS, 7, "0x02:7"),
- new DataItem(2, Msg.WRITE, ByteType.LOWBYTE, DataType.UINT8, 0, "mastermemberid") });
- g.put(3, new DataItem[] { new DataItem(3, Msg.READ, ByteType.HIGHBYTE, DataType.FLAGS, 0, "dhwpresent"),
- new DataItem(3, Msg.READ, ByteType.HIGHBYTE, DataType.FLAGS, 1, "controltype"),
- new DataItem(3, Msg.READ, ByteType.HIGHBYTE, DataType.FLAGS, 2, "coolingsupport"),
- new DataItem(3, Msg.READ, ByteType.HIGHBYTE, DataType.FLAGS, 3, "dhwconfig"),
- new DataItem(3, Msg.READ, ByteType.HIGHBYTE, DataType.FLAGS, 4, "masterlowoff"),
- new DataItem(3, Msg.READ, ByteType.HIGHBYTE, DataType.FLAGS, 5, "ch2present"),
- new DataItem(3, Msg.READ, ByteType.HIGHBYTE, DataType.FLAGS, 6, "0x03:6"),
- new DataItem(3, Msg.READ, ByteType.HIGHBYTE, DataType.FLAGS, 7, "0x03:7"),
- new DataItem(3, Msg.READ, ByteType.LOWBYTE, DataType.UINT8, 0, "slavememberid") });
- g.put(4, new DataItem[] { new DataItem(4, Msg.WRITE, ByteType.HIGHBYTE, DataType.UINT8, 0, "commandcode"),
- new DataItem(4, Msg.READ, ByteType.LOWBYTE, DataType.UINT8, 0, "commandresponse") });
- g.put(5, new DataItem[] { new DataItem(5, Msg.READ, ByteType.HIGHBYTE, DataType.FLAGS, 0, "servicerequest"),
- new DataItem(5, Msg.READ, ByteType.HIGHBYTE, DataType.FLAGS, 1, "lockout-reset"),
- new DataItem(5, Msg.READ, ByteType.HIGHBYTE, DataType.FLAGS, 2, "lowwaterpress"),
- new DataItem(5, Msg.READ, ByteType.HIGHBYTE, DataType.FLAGS, 3, "gasflamefault"),
- new DataItem(5, Msg.READ, ByteType.HIGHBYTE, DataType.FLAGS, 4, "airpressfault"),
- new DataItem(5, Msg.READ, ByteType.HIGHBYTE, DataType.FLAGS, 5, "waterovtemp"),
- new DataItem(5, Msg.READ, ByteType.HIGHBYTE, DataType.FLAGS, 6, "0x05:6"),
- new DataItem(5, Msg.READ, ByteType.HIGHBYTE, DataType.FLAGS, 7, "0x05:7"),
- new DataItem(5, Msg.READ, ByteType.LOWBYTE, DataType.UINT8, 0, "oemfaultcode") });
- g.put(6, new DataItem[] { new DataItem(6, Msg.READ, ByteType.LOWBYTE, DataType.FLAGS, 0, "0x06:l0"),
- new DataItem(6, Msg.READ, ByteType.LOWBYTE, DataType.FLAGS, 1, "0x06:l1"),
- new DataItem(6, Msg.READ, ByteType.LOWBYTE, DataType.FLAGS, 2, "0x06:l2"),
- new DataItem(6, Msg.READ, ByteType.LOWBYTE, DataType.FLAGS, 3, "0x06:l3"),
- new DataItem(6, Msg.READ, ByteType.LOWBYTE, DataType.FLAGS, 4, "0x06:l4"),
- new DataItem(6, Msg.READ, ByteType.LOWBYTE, DataType.FLAGS, 5, "0x06:l5"),
- new DataItem(6, Msg.READ, ByteType.LOWBYTE, DataType.FLAGS, 6, "0x06:l6"),
- new DataItem(6, Msg.READ, ByteType.LOWBYTE, DataType.FLAGS, 7, "0x06:l7"),
- new DataItem(6, Msg.READ, ByteType.HIGHBYTE, DataType.FLAGS, 0, "0x06:h0"),
- new DataItem(6, Msg.READ, ByteType.HIGHBYTE, DataType.FLAGS, 1, "0x06:h1"),
- new DataItem(6, Msg.READ, ByteType.HIGHBYTE, DataType.FLAGS, 2, "0x06:h2"),
- new DataItem(6, Msg.READ, ByteType.HIGHBYTE, DataType.FLAGS, 3, "0x06:h3"),
- new DataItem(6, Msg.READ, ByteType.HIGHBYTE, DataType.FLAGS, 4, "0x06:h4"),
- new DataItem(6, Msg.READ, ByteType.HIGHBYTE, DataType.FLAGS, 5, "0x06:h5"),
- new DataItem(6, Msg.READ, ByteType.HIGHBYTE, DataType.FLAGS, 6, "0x06:h6"),
- new DataItem(6, Msg.READ, ByteType.HIGHBYTE, DataType.FLAGS, 7, "0x06:h7") });
- g.put(7, new DataItem[] { new DataItem(7, Msg.WRITE, ByteType.BOTH, DataType.FLOAT, 0, "0x07") });
- g.put(8, new DataItem[] {
- new DataItem(8, Msg.WRITE, ByteType.BOTH, DataType.FLOAT, 0, "controlsetpoint2", SIUnits.CELSIUS,
- CodeType.B),
- new DataItem(8, Msg.WRITE, ByteType.BOTH, DataType.FLOAT, 0, "controlsetpoint2requested",
- SIUnits.CELSIUS, CodeType.T),
- new DataItem(8, Msg.WRITE, ByteType.BOTH, DataType.FLOAT, 0, "controlsetpoint2override",
- SIUnits.CELSIUS, CodeType.R) });
- g.put(9, new DataItem[] { new DataItem(9, Msg.READ, ByteType.BOTH, DataType.FLOAT, 0, "overridesetpoint") });
- g.put(10, new DataItem[] { new DataItem(10, Msg.WRITE, ByteType.HIGHBYTE, DataType.UINT8, 0, "0x0a:h"),
- new DataItem(10, Msg.WRITE, ByteType.LOWBYTE, DataType.UINT8, 0, "0x0a:l") });
- g.put(11, new DataItem[] { new DataItem(11, Msg.READWRITE, ByteType.HIGHBYTE, DataType.UINT8, 0, "tspindex"),
- new DataItem(11, Msg.READWRITE, ByteType.LOWBYTE, DataType.UINT8, 0, "tspvalue") });
- g.put(12, new DataItem[] { new DataItem(12, Msg.READ, ByteType.HIGHBYTE, DataType.UINT8, 0, "0x0c:h"),
- new DataItem(12, Msg.READ, ByteType.LOWBYTE, DataType.UINT8, 0, "0x0c:l") });
- g.put(13, new DataItem[] { new DataItem(13, Msg.READ, ByteType.HIGHBYTE, DataType.UINT8, 0, "0x0d:h"),
- new DataItem(13, Msg.READ, ByteType.LOWBYTE, DataType.UINT8, 0, "0x0d:l") });
- g.put(14, new DataItem[] {
- new DataItem(14, Msg.READ, ByteType.LOWBYTE, DataType.FLOAT, 0, "maxrelmdulevel", Units.PERCENT) });
- g.put(15, new DataItem[] { new DataItem(15, Msg.READ, ByteType.HIGHBYTE, DataType.UINT8, 0, "maxcapkw"),
- new DataItem(15, Msg.READ, ByteType.LOWBYTE, DataType.UINT8, 0, "maxcapprc") });
- g.put(16, new DataItem[] {
- new DataItem(16, Msg.WRITE, ByteType.BOTH, DataType.FLOAT, 0, "roomsetpoint", SIUnits.CELSIUS) });
- g.put(17, new DataItem[] {
- new DataItem(17, Msg.READ, ByteType.BOTH, DataType.FLOAT, 0, "modulevel", Units.PERCENT) });
- g.put(18, new DataItem[] {
- new DataItem(18, Msg.READ, ByteType.BOTH, DataType.FLOAT, 0, "waterpressure", Units.BAR) });
- g.put(19, new DataItem[] { new DataItem(19, Msg.READ, ByteType.BOTH, DataType.FLOAT, 0, "dhwflow") });
- g.put(20, new DataItem[] { new DataItem(20, Msg.READWRITE, ByteType.BOTH, DataType.DOWTOD, 0, "dowtod") });
- g.put(21, new DataItem[] { new DataItem(21, Msg.READWRITE, ByteType.HIGHBYTE, DataType.UINT8, 0, "month"),
- new DataItem(21, Msg.READWRITE, ByteType.LOWBYTE, DataType.UINT8, 0, "dom") });
- g.put(22, new DataItem[] { new DataItem(22, Msg.READWRITE, ByteType.LOWBYTE, DataType.UINT8, 0, "year") });
- g.put(23, new DataItem[] { new DataItem(23, Msg.WRITE, ByteType.BOTH, DataType.FLOAT, 0, "setpointch2") });
- g.put(24, new DataItem[] {
- new DataItem(24, Msg.WRITE, ByteType.BOTH, DataType.FLOAT, 0, "roomtemp", SIUnits.CELSIUS) });
- g.put(25, new DataItem[] {
- new DataItem(25, Msg.READ, ByteType.BOTH, DataType.FLOAT, 0, "flowtemp", SIUnits.CELSIUS) });
- g.put(26, new DataItem[] {
- new DataItem(26, Msg.READ, ByteType.BOTH, DataType.FLOAT, 0, "dhwtemp", SIUnits.CELSIUS) });
- g.put(27, new DataItem[] {
- new DataItem(27, Msg.READ, ByteType.BOTH, DataType.FLOAT, 0, "outsidetemp", SIUnits.CELSIUS) });
- g.put(28, new DataItem[] {
- new DataItem(28, Msg.READ, ByteType.BOTH, DataType.FLOAT, 0, "returntemp", SIUnits.CELSIUS) });
- g.put(29, new DataItem[] { new DataItem(29, Msg.READ, ByteType.BOTH, DataType.FLOAT, 0, "solstortemp") });
- g.put(30, new DataItem[] { new DataItem(30, Msg.READ, ByteType.BOTH, DataType.FLOAT, 0, "solcolltemp") });
- g.put(31, new DataItem[] { new DataItem(31, Msg.READ, ByteType.BOTH, DataType.FLOAT, 0, "flowtemp2") });
- g.put(32, new DataItem[] { new DataItem(32, Msg.READ, ByteType.BOTH, DataType.FLOAT, 0, "dhw2temp") });
- g.put(33, new DataItem[] { new DataItem(33, Msg.READ, ByteType.BOTH, DataType.INT16, 0, "exhausttemp") });
- g.put(48, new DataItem[] { new DataItem(48, Msg.READ, ByteType.HIGHBYTE, DataType.INT8, 0, "tdhwsetu"),
- new DataItem(48, Msg.READ, ByteType.LOWBYTE, DataType.INT8, 0, "tdhwsetl") });
- g.put(49, new DataItem[] { new DataItem(49, Msg.READ, ByteType.HIGHBYTE, DataType.INT8, 0, "maxchu"),
- new DataItem(49, Msg.READ, ByteType.LOWBYTE, DataType.INT8, 0, "maxchl") });
- g.put(50, new DataItem[] { new DataItem(50, Msg.READ, ByteType.HIGHBYTE, DataType.INT8, 0, "otcu"),
- new DataItem(50, Msg.READ, ByteType.LOWBYTE, DataType.INT8, 0, "otcl") });
- g.put(56, new DataItem[] {
- new DataItem(56, Msg.READWRITE, ByteType.BOTH, DataType.FLOAT, 0, "tdhwset", SIUnits.CELSIUS) });
- g.put(57, new DataItem[] { new DataItem(57, Msg.READWRITE, ByteType.BOTH, DataType.FLOAT, 0, "tchmax") });
- g.put(58, new DataItem[] { new DataItem(58, Msg.READWRITE, ByteType.BOTH, DataType.FLOAT, 0, "otchcratio") });
+ g.put(0, new DataItem[] { new FlagDataItem(Msg.READ, ByteType.HIGHBYTE, 0, "ch_enable", CodeType.B),
+ new FlagDataItem(Msg.READ, ByteType.HIGHBYTE, 0, "ch_enablerequested", CodeType.T),
+ new FlagDataItem(Msg.READ, ByteType.HIGHBYTE, 0, "ch_enableoverride", CodeType.R),
+ new FlagDataItem(Msg.READ, ByteType.HIGHBYTE, 1, "dhw_enable", CodeType.B),
+ new FlagDataItem(Msg.READ, ByteType.HIGHBYTE, 2, "cooling_enabled", CodeType.B),
+ new FlagDataItem(Msg.READ, ByteType.HIGHBYTE, 3, "otc_active", CodeType.B),
+ new FlagDataItem(Msg.READ, ByteType.HIGHBYTE, 4, "ch2_enable", CodeType.B),
+ new FlagDataItem(Msg.READ, ByteType.HIGHBYTE, 4, "ch2_enablerequested", CodeType.T),
+ new FlagDataItem(Msg.READ, ByteType.HIGHBYTE, 4, "ch2_enableoverride", CodeType.R),
+ new FlagDataItem(Msg.READ, ByteType.HIGHBYTE, 5, "0x00:5", CodeType.B),
+ new FlagDataItem(Msg.READ, ByteType.HIGHBYTE, 6, "0x00:6", CodeType.B),
+ new FlagDataItem(Msg.READ, ByteType.HIGHBYTE, 7, "0x00:7", CodeType.B),
+ new FlagDataItem(Msg.READ, ByteType.LOWBYTE, 0, "fault", CodeType.B),
+ new FlagDataItem(Msg.READ, ByteType.LOWBYTE, 1, "ch_mode", CodeType.B),
+ new FlagDataItem(Msg.READ, ByteType.LOWBYTE, 2, "dhw_mode", CodeType.B),
+ new FlagDataItem(Msg.READ, ByteType.LOWBYTE, 3, "flame", CodeType.B),
+ new FlagDataItem(Msg.READ, ByteType.LOWBYTE, 4, "cooling", CodeType.B),
+ new FlagDataItem(Msg.READ, ByteType.LOWBYTE, 5, "ch2E", CodeType.B),
+ new FlagDataItem(Msg.READ, ByteType.LOWBYTE, 6, "diag", CodeType.B),
+ new FlagDataItem(Msg.READ, ByteType.LOWBYTE, 7, "0x00:7", CodeType.B) });
+ g.put(1, new DataItem[] { new FloatDataItem(Msg.WRITE, "controlsetpoint", SIUnits.CELSIUS, CodeType.B),
+ new FloatDataItem(Msg.WRITE, "controlsetpointrequested", SIUnits.CELSIUS, CodeType.T),
+ new FloatDataItem(Msg.WRITE, "controlsetpointoverride", SIUnits.CELSIUS, CodeType.R) });
+ g.put(2, new DataItem[] { new FlagDataItem(Msg.WRITE, ByteType.HIGHBYTE, 0, "0x02:0"),
+ new FlagDataItem(Msg.WRITE, ByteType.HIGHBYTE, 1, "0x02:1"),
+ new FlagDataItem(Msg.WRITE, ByteType.HIGHBYTE, 2, "0x02:2"),
+ new FlagDataItem(Msg.WRITE, ByteType.HIGHBYTE, 3, "0x02:3"),
+ new FlagDataItem(Msg.WRITE, ByteType.HIGHBYTE, 4, "0x02:4"),
+ new FlagDataItem(Msg.WRITE, ByteType.HIGHBYTE, 5, "0x02:5"),
+ new FlagDataItem(Msg.WRITE, ByteType.HIGHBYTE, 6, "0x02:6"),
+ new FlagDataItem(Msg.WRITE, ByteType.HIGHBYTE, 7, "0x02:7"),
+ new UIntDataItem(Msg.WRITE, ByteType.LOWBYTE, "mastermemberid") });
+ g.put(3, new DataItem[] { new FlagDataItem(Msg.READ, ByteType.HIGHBYTE, 0, "dhwpresent"),
+ new FlagDataItem(Msg.READ, ByteType.HIGHBYTE, 1, "controltype"),
+ new FlagDataItem(Msg.READ, ByteType.HIGHBYTE, 2, "coolingsupport"),
+ new FlagDataItem(Msg.READ, ByteType.HIGHBYTE, 3, "dhwconfig"),
+ new FlagDataItem(Msg.READ, ByteType.HIGHBYTE, 4, "masterlowoff"),
+ new FlagDataItem(Msg.READ, ByteType.HIGHBYTE, 5, "ch2present"),
+ new FlagDataItem(Msg.READ, ByteType.HIGHBYTE, 6, "0x03:6"),
+ new FlagDataItem(Msg.READ, ByteType.HIGHBYTE, 7, "0x03:7"),
+ new UIntDataItem(Msg.READ, ByteType.LOWBYTE, "slavememberid") });
+ g.put(4, new DataItem[] { new UIntDataItem(Msg.WRITE, ByteType.HIGHBYTE, "commandcode"),
+ new UIntDataItem(Msg.READ, ByteType.LOWBYTE, "commandresponse") });
+ g.put(5, new DataItem[] { new FlagDataItem(Msg.READ, ByteType.HIGHBYTE, 0, "servicerequest"),
+ new FlagDataItem(Msg.READ, ByteType.HIGHBYTE, 1, "lockout-reset"),
+ new FlagDataItem(Msg.READ, ByteType.HIGHBYTE, 2, "lowwaterpress"),
+ new FlagDataItem(Msg.READ, ByteType.HIGHBYTE, 3, "gasflamefault"),
+ new FlagDataItem(Msg.READ, ByteType.HIGHBYTE, 4, "airpressfault"),
+ new FlagDataItem(Msg.READ, ByteType.HIGHBYTE, 5, "waterovtemp"),
+ new FlagDataItem(Msg.READ, ByteType.HIGHBYTE, 6, "0x05:6"),
+ new FlagDataItem(Msg.READ, ByteType.HIGHBYTE, 7, "0x05:7"),
+ new IntDataItem(Msg.READ, ByteType.LOWBYTE, "oemfaultcode") });
+ g.put(6, new DataItem[] { new FlagDataItem(Msg.READ, ByteType.HIGHBYTE, 0, "0x06:h0"),
+ new FlagDataItem(Msg.READ, ByteType.HIGHBYTE, 1, "0x06:h1"),
+ new FlagDataItem(Msg.READ, ByteType.HIGHBYTE, 2, "0x06:h2"),
+ new FlagDataItem(Msg.READ, ByteType.HIGHBYTE, 3, "0x06:h3"),
+ new FlagDataItem(Msg.READ, ByteType.HIGHBYTE, 4, "0x06:h4"),
+ new FlagDataItem(Msg.READ, ByteType.HIGHBYTE, 5, "0x06:h5"),
+ new FlagDataItem(Msg.READ, ByteType.HIGHBYTE, 6, "0x06:h6"),
+ new FlagDataItem(Msg.READ, ByteType.HIGHBYTE, 7, "0x06:h7"),
+ new FlagDataItem(Msg.READ, ByteType.LOWBYTE, 0, "0x06:l0"),
+ new FlagDataItem(Msg.READ, ByteType.LOWBYTE, 1, "0x06:l1"),
+ new FlagDataItem(Msg.READ, ByteType.LOWBYTE, 2, "0x06:l2"),
+ new FlagDataItem(Msg.READ, ByteType.LOWBYTE, 3, "0x06:l3"),
+ new FlagDataItem(Msg.READ, ByteType.LOWBYTE, 4, "0x06:l4"),
+ new FlagDataItem(Msg.READ, ByteType.LOWBYTE, 5, "0x06:l5"),
+ new FlagDataItem(Msg.READ, ByteType.LOWBYTE, 6, "0x06:l6"),
+ new FlagDataItem(Msg.READ, ByteType.LOWBYTE, 7, "0x06:l7") });
+ g.put(7, new DataItem[] { new FloatDataItem(Msg.WRITE, "coolingcontrolsignal") });
+ g.put(8, new DataItem[] { new FloatDataItem(Msg.WRITE, "controlsetpoint2", SIUnits.CELSIUS, CodeType.B),
+ new FloatDataItem(Msg.WRITE, "controlsetpoint2requested", SIUnits.CELSIUS, CodeType.T),
+ new FloatDataItem(Msg.WRITE, "controlsetpoint2override", SIUnits.CELSIUS, CodeType.R) });
+ g.put(9, new DataItem[] { new FloatDataItem(Msg.READ, "overridesetpoint") });
+ g.put(10, new DataItem[] { new TspFhbSizeDataItem(Msg.WRITE, ByteType.HIGHBYTE, 11, "tspnumber") });
+ g.put(11, new DataItem[] { new TspFhbValueDataItem(Msg.READWRITE, "tspentry") });
+ g.put(12, new DataItem[] { new TspFhbSizeDataItem(Msg.READ, ByteType.HIGHBYTE, 13, "fhbnumber") });
+ g.put(13, new DataItem[] { new TspFhbValueDataItem(Msg.READ, "fhbentry") });
+ g.put(14, new DataItem[] { new FloatDataItem(Msg.READ, "maxrelmdulevel", Units.PERCENT) });
+ g.put(15, new DataItem[] { new UIntDataItem(Msg.READ, ByteType.HIGHBYTE, "maxcapkw"),
+ new UIntDataItem(Msg.READ, ByteType.LOWBYTE, "maxcapprc") });
+ g.put(16, new DataItem[] { new FloatDataItem(Msg.WRITE, "roomsetpoint", SIUnits.CELSIUS) });
+ g.put(17, new DataItem[] { new FloatDataItem(Msg.READ, "modulevel", Units.PERCENT) });
+ g.put(18, new DataItem[] { new FloatDataItem(Msg.READ, "waterpressure", Units.BAR) });
+ g.put(19, new DataItem[] { new FloatDataItem(Msg.READ, "dhwflow") });
+ g.put(20, new DataItem[] { new UIntDataItem(Msg.READWRITE, ByteType.BOTH, "dowtod") });
+ g.put(21, new DataItem[] { new UIntDataItem(Msg.READWRITE, ByteType.HIGHBYTE, "month"),
+ new UIntDataItem(Msg.READWRITE, ByteType.LOWBYTE, "day") });
+ g.put(22, new DataItem[] { new UIntDataItem(Msg.READWRITE, ByteType.BOTH, "year") });
+ g.put(23, new DataItem[] { new FloatDataItem(Msg.WRITE, "setpointch2") });
+ g.put(24, new DataItem[] { new FloatDataItem(Msg.WRITE, "roomtemp", SIUnits.CELSIUS) });
+ g.put(25, new DataItem[] { new FloatDataItem(Msg.READ, "flowtemp", SIUnits.CELSIUS) });
+ g.put(26, new DataItem[] { new FloatDataItem(Msg.READ, "dhwtemp", SIUnits.CELSIUS) });
+ g.put(27, new DataItem[] { new FloatDataItem(Msg.READ, "outsidetemp", SIUnits.CELSIUS) });
+ g.put(28, new DataItem[] { new FloatDataItem(Msg.READ, "returntemp", SIUnits.CELSIUS) });
+
+ g.put(29, new DataItem[] { new FloatDataItem(Msg.READ, "ss_temperature") });
+ g.put(30, new DataItem[] { new FloatDataItem(Msg.READ, "ss_collectortemperature") });
+
+ g.put(31, new DataItem[] { new FloatDataItem(Msg.READ, "flowtemp2") });
+ g.put(32, new DataItem[] { new FloatDataItem(Msg.READ, "dhw2temp") });
+ g.put(33, new DataItem[] { new UIntDataItem(Msg.READ, ByteType.BOTH, "exhausttemp") });
+ g.put(48, new DataItem[] { new IntDataItem(Msg.READ, ByteType.HIGHBYTE, "tdhwsetu"),
+ new IntDataItem(Msg.READ, ByteType.LOWBYTE, "tdhwsetl") });
+ g.put(49, new DataItem[] { new IntDataItem(Msg.READ, ByteType.HIGHBYTE, "maxchu"),
+ new IntDataItem(Msg.READ, ByteType.LOWBYTE, "maxchl") });
+ g.put(50, new DataItem[] { new IntDataItem(Msg.READ, ByteType.HIGHBYTE, "otcu"),
+ new IntDataItem(Msg.READ, ByteType.LOWBYTE, "otcl") });
+ g.put(56, new DataItem[] { new FloatDataItem(Msg.READWRITE, "tdhwset", SIUnits.CELSIUS) });
+ g.put(57, new DataItem[] { new FloatDataItem(Msg.READWRITE, "tchmax") });
+ g.put(58, new DataItem[] { new FloatDataItem(Msg.READWRITE, "otchcratio") });
+ g.put(70,
+ new DataItem[] { new FlagDataItem(Msg.READ, ByteType.HIGHBYTE, 0, "vh_ventilationenable"),
+ new FlagDataItem(Msg.READ, ByteType.HIGHBYTE, 1, "vh_bypassposition"),
+ new FlagDataItem(Msg.READ, ByteType.HIGHBYTE, 2, "vh_bypassmode"),
+ new FlagDataItem(Msg.READ, ByteType.HIGHBYTE, 3, "vh_freeventilationmode"),
+ new FlagDataItem(Msg.READ, ByteType.LOWBYTE, 0, "vh_faultindication"),
+ new FlagDataItem(Msg.READ, ByteType.LOWBYTE, 1, "vh_ventilationmode"),
+ new FlagDataItem(Msg.READ, ByteType.LOWBYTE, 2, "vh_bypassstatus"),
+ new FlagDataItem(Msg.READ, ByteType.LOWBYTE, 3, "vh_bypassautomaticstatus"),
+ new FlagDataItem(Msg.READ, ByteType.LOWBYTE, 4, "vh_freeventilationstatus"),
+ new FlagDataItem(Msg.READ, ByteType.LOWBYTE, 5, "vh_filtercheck"),
+ new FlagDataItem(Msg.READ, ByteType.LOWBYTE, 6, "vh_diagnosticindication") });
+ g.put(71, new DataItem[] { new UIntDataItem(Msg.WRITE, ByteType.LOWBYTE, "vh_controlsetpoint") });
+ g.put(72,
+ new DataItem[] { new FlagDataItem(Msg.READ, ByteType.HIGHBYTE, 0, "vh_servicerequest"),
+ new FlagDataItem(Msg.READ, ByteType.HIGHBYTE, 1, "vh_exhaustfanfault"),
+ new FlagDataItem(Msg.READ, ByteType.HIGHBYTE, 2, "vh_inletfanfault"),
+ new FlagDataItem(Msg.READ, ByteType.HIGHBYTE, 3, "vh_frostprotection"),
+ new UIntDataItem(Msg.READ, ByteType.LOWBYTE, "vh_faultcode") });
+ g.put(73, new DataItem[] { new UIntDataItem(Msg.READ, ByteType.BOTH, "vh_diagnosticcode") });
+ g.put(74,
+ new DataItem[] { new FlagDataItem(Msg.READ, ByteType.HIGHBYTE, 0, "vh_systemtype"),
+ new FlagDataItem(Msg.READ, ByteType.HIGHBYTE, 1, "vh_bypass"),
+ new FlagDataItem(Msg.READ, ByteType.HIGHBYTE, 2, "vh_speedcontrol"),
+ new UIntDataItem(Msg.READ, ByteType.LOWBYTE, "vh_memberid") });
+ g.put(75, new DataItem[] { new FloatDataItem(Msg.READ, "vh_openthermversion") });
+ g.put(76, new DataItem[] { new UIntDataItem(Msg.READ, ByteType.BOTH, "vh_versiontype") });
+ g.put(77, new DataItem[] { new UIntDataItem(Msg.READ, ByteType.BOTH, "vh_relativeventilation") });
+ g.put(78, new DataItem[] { new UIntDataItem(Msg.READ, ByteType.BOTH, "vh_relativehumidity") });
+ g.put(79, new DataItem[] { new UIntDataItem(Msg.READ, ByteType.BOTH, "vh_co2level") });
+ g.put(80, new DataItem[] { new FloatDataItem(Msg.READ, "vh_supplyinlettemp") });
+ g.put(81, new DataItem[] { new FloatDataItem(Msg.READ, "vh_supplyoutlettemp") });
+ g.put(82, new DataItem[] { new FloatDataItem(Msg.READ, "vh_exhaustinlettemp") });
+ g.put(83, new DataItem[] { new FloatDataItem(Msg.READ, "vh_exhaustoutlettemp") });
+ g.put(84, new DataItem[] { new UIntDataItem(Msg.READ, ByteType.BOTH, "vh_actualexhaustfanspeed") });
+ g.put(85, new DataItem[] { new UIntDataItem(Msg.READ, ByteType.BOTH, "vh_actualinletfanspeed") });
+ g.put(86, new DataItem[] { new FlagDataItem(Msg.READ, ByteType.HIGHBYTE, 0, "vh_nominalventenable"),
+ new FlagDataItem(Msg.READ, ByteType.LOWBYTE, 0, "vh_nominalventrw") });
+ g.put(87, new DataItem[] { new UIntDataItem(Msg.READ, ByteType.HIGHBYTE, "vh_nominalventilationvalue") });
+ g.put(88, new DataItem[] { new TspFhbSizeDataItem(Msg.READ, ByteType.HIGHBYTE, 89, "vh_tspnumber") });
+ g.put(89, new DataItem[] { new TspFhbValueDataItem(Msg.READ, "vh_tspentry") });
+ g.put(90, new DataItem[] { new TspFhbSizeDataItem(Msg.READ, ByteType.HIGHBYTE, 91, "vh_fhbnumber") });
+ g.put(91, new DataItem[] { new TspFhbValueDataItem(Msg.READ, "vh_fhbentry") });
g.put(100,
- new DataItem[] { new DataItem(100, Msg.READ, ByteType.HIGHBYTE, DataType.FLAGS, 0, "rof0"),
- new DataItem(100, Msg.READ, ByteType.HIGHBYTE, DataType.FLAGS, 1, "rof1"),
- new DataItem(100, Msg.READ, ByteType.HIGHBYTE, DataType.FLAGS, 2, "rof2"),
- new DataItem(100, Msg.READ, ByteType.HIGHBYTE, DataType.FLAGS, 3, "rof3"),
- new DataItem(100, Msg.READ, ByteType.HIGHBYTE, DataType.FLAGS, 4, "rof4"),
- new DataItem(100, Msg.READ, ByteType.HIGHBYTE, DataType.FLAGS, 5, "rof5"),
- new DataItem(100, Msg.READ, ByteType.HIGHBYTE, DataType.FLAGS, 6, "rof6"),
- new DataItem(100, Msg.READ, ByteType.HIGHBYTE, DataType.FLAGS, 7, "rof7") });
- g.put(113, new DataItem[] {
- new DataItem(113, Msg.READ, ByteType.BOTH, DataType.UINT16, 0, "unsuccessfulburnerstarts") });
- g.put(115, new DataItem[] { new DataItem(115, Msg.READ, ByteType.BOTH, DataType.UINT16, 0, "oemdiagcode") });
- g.put(116, new DataItem[] { new DataItem(116, Msg.READ, ByteType.BOTH, DataType.UINT16, 0, "burnerstarts") });
- g.put(117, new DataItem[] { new DataItem(117, Msg.READ, ByteType.BOTH, DataType.UINT16, 0, "chpumpstarts") });
- g.put(118, new DataItem[] { new DataItem(118, Msg.READ, ByteType.BOTH, DataType.UINT16, 0, "dhwpvstarts") });
- g.put(119,
- new DataItem[] { new DataItem(119, Msg.READ, ByteType.BOTH, DataType.UINT16, 0, "dhwburnerstarts") });
- g.put(120, new DataItem[] {
- new DataItem(120, Msg.READ, ByteType.BOTH, DataType.UINT16, 0, "burnerhours", Units.HOUR) });
- g.put(121, new DataItem[] {
- new DataItem(121, Msg.READ, ByteType.BOTH, DataType.UINT16, 0, "chpumphours", Units.HOUR) });
- g.put(122, new DataItem[] {
- new DataItem(122, Msg.READ, ByteType.BOTH, DataType.UINT16, 0, "dhwpvhours", Units.HOUR) });
- g.put(123, new DataItem[] {
- new DataItem(123, Msg.READ, ByteType.BOTH, DataType.UINT16, 0, "dhwburnerhours", Units.HOUR) });
- g.put(124,
- new DataItem[] { new DataItem(124, Msg.WRITE, ByteType.BOTH, DataType.FLOAT, 0, "masterotversion") });
- g.put(125, new DataItem[] { new DataItem(125, Msg.READ, ByteType.BOTH, DataType.FLOAT, 0, "slaveotversion") });
- g.put(126,
- new DataItem[] {
- new DataItem(126, Msg.WRITE, ByteType.HIGHBYTE, DataType.UINT8, 0, "masterproducttype"),
- new DataItem(126, Msg.WRITE, ByteType.LOWBYTE, DataType.UINT8, 0, "masterproductversion") });
- g.put(127,
- new DataItem[] { new DataItem(127, Msg.READ, ByteType.HIGHBYTE, DataType.UINT8, 0, "slaveproducttype"),
- new DataItem(127, Msg.READ, ByteType.LOWBYTE, DataType.UINT8, 0, "slaveproductversion") });
+ new DataItem[] { new FlagDataItem(Msg.READ, ByteType.HIGHBYTE, 0, "rof0"),
+ new FlagDataItem(Msg.READ, ByteType.HIGHBYTE, 1, "rof1"),
+ new FlagDataItem(Msg.READ, ByteType.HIGHBYTE, 2, "rof2"),
+ new FlagDataItem(Msg.READ, ByteType.HIGHBYTE, 3, "rof3"),
+ new FlagDataItem(Msg.READ, ByteType.HIGHBYTE, 4, "rof4"),
+ new FlagDataItem(Msg.READ, ByteType.HIGHBYTE, 5, "rof5"),
+ new FlagDataItem(Msg.READ, ByteType.HIGHBYTE, 6, "rof6"),
+ new FlagDataItem(Msg.READ, ByteType.HIGHBYTE, 7, "rof7") });
+
+ g.put(101,
+ new DataItem[] { new FlagDataItem(Msg.READ, ByteType.HIGHBYTE, 0, "rof0"),
+ new FlagDataItem(Msg.READ, ByteType.HIGHBYTE, 1, "rof1"),
+ new FlagDataItem(Msg.READ, ByteType.HIGHBYTE, 2, "rof2"),
+ new FlagDataItem(Msg.READ, ByteType.HIGHBYTE, 3, "rof3"),
+ new FlagDataItem(Msg.READ, ByteType.HIGHBYTE, 4, "rof4"),
+ new FlagDataItem(Msg.READ, ByteType.HIGHBYTE, 5, "rof5"),
+ new FlagDataItem(Msg.READ, ByteType.HIGHBYTE, 6, "rof6"),
+ new FlagDataItem(Msg.READ, ByteType.HIGHBYTE, 7, "rof7") });
+ g.put(102, new DataItem[] {});
+
+ g.put(105, new DataItem[] { new TspFhbSizeDataItem(Msg.READ, ByteType.HIGHBYTE, 106, "ss_tspnumber") });
+ g.put(106, new DataItem[] { new TspFhbValueDataItem(Msg.READ, "ss_tspentry") });
+
+ g.put(107, new DataItem[] { new TspFhbSizeDataItem(Msg.READ, ByteType.HIGHBYTE, 108, "ss_fhbnumber") });
+ g.put(108, new DataItem[] { new TspFhbValueDataItem(Msg.READ, "ss_fhbentry") });
+ g.put(113, new DataItem[] { new UIntDataItem(Msg.READ, ByteType.BOTH, "unsuccessfulburnerstarts") });
+ g.put(115, new DataItem[] { new UIntDataItem(Msg.READ, ByteType.BOTH, "oemdiagcode") });
+ g.put(116, new DataItem[] { new UIntDataItem(Msg.READ, ByteType.BOTH, "burnerstarts") });
+ g.put(117, new DataItem[] { new UIntDataItem(Msg.READ, ByteType.BOTH, "chpumpstarts") });
+ g.put(118, new DataItem[] { new UIntDataItem(Msg.READ, ByteType.BOTH, "dhwpvstarts") });
+ g.put(119, new DataItem[] { new UIntDataItem(Msg.READ, ByteType.BOTH, "dhwburnerstarts") });
+ g.put(120, new DataItem[] { new UIntDataItem(Msg.READ, ByteType.BOTH, "burnerhours", Units.HOUR) });
+ g.put(121, new DataItem[] { new UIntDataItem(Msg.READ, ByteType.BOTH, "chpumphours", Units.HOUR) });
+ g.put(122, new DataItem[] { new UIntDataItem(Msg.READ, ByteType.BOTH, "dhwpvhours", Units.HOUR) });
+ g.put(123, new DataItem[] { new UIntDataItem(Msg.READ, ByteType.BOTH, "dhwburnerhours", Units.HOUR) });
+ g.put(124, new DataItem[] { new FloatDataItem(Msg.WRITE, "masterotversion") });
+ g.put(125, new DataItem[] { new FloatDataItem(Msg.READ, "slaveotversion") });
+ g.put(126, new DataItem[] { new UIntDataItem(Msg.WRITE, ByteType.HIGHBYTE, "masterproducttype"),
+ new UIntDataItem(Msg.WRITE, ByteType.LOWBYTE, "masterproductversion") });
+ g.put(127, new DataItem[] { new UIntDataItem(Msg.READ, ByteType.HIGHBYTE, "slaveproducttype"),
+ new UIntDataItem(Msg.READ, ByteType.LOWBYTE, "slaveproductversion") });
return g;
}
*/
package org.openhab.binding.openthermgateway.internal;
+import org.eclipse.jdt.annotation.NonNullByDefault;
+
/**
* The {@link DataType} enum indicates the type of data from a DataItem.
- *
+ *
* @author Arjen Korevaar - Initial contribution
*/
+@NonNullByDefault
public enum DataType {
FLAGS,
UINT8,
--- /dev/null
+/**
+ * Copyright (c) 2010-2022 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.openthermgateway.internal;
+
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.eclipse.jdt.annotation.Nullable;
+import org.openhab.core.library.types.OnOffType;
+import org.openhab.core.types.State;
+
+/**
+ * The {@link DataItem} holds the internal OpenTherm message and meta data.
+ *
+ * @author Arjen Korevaar - Initial contribution
+ */
+@NonNullByDefault
+public class FlagDataItem extends DataItem {
+ private int bitpos;
+
+ public int getBitPos() {
+ return bitpos;
+ }
+
+ public FlagDataItem(Msg msg, ByteType byteType, int bitpos, String subject) {
+ this(msg, byteType, bitpos, subject, null);
+ }
+
+ public FlagDataItem(Msg msg, ByteType byteType, int bitpos, String subject, @Nullable CodeType codeType) {
+ super(msg, byteType, subject, codeType);
+
+ this.bitpos = bitpos;
+ }
+
+ @Override
+ public State createState(Message message) {
+ return OnOffType.from(message.getBit(super.getByteType(), this.getBitPos()));
+ }
+}
--- /dev/null
+/**
+ * Copyright (c) 2010-2022 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.openthermgateway.internal;
+
+import javax.measure.Unit;
+
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.eclipse.jdt.annotation.Nullable;
+import org.openhab.core.library.types.DecimalType;
+import org.openhab.core.library.types.QuantityType;
+import org.openhab.core.types.State;
+
+/**
+ * The {@link FloatDataItem} represents a 2-byte float value in a 2's complement format.
+ *
+ * @author Arjen Korevaar - Initial contribution
+ */
+@NonNullByDefault
+public class FloatDataItem extends DataItem {
+
+ private @Nullable Unit<?> unit;
+
+ public @Nullable Unit<?> getUnit() {
+ return unit;
+ }
+
+ public FloatDataItem(Msg msg, String subject) {
+ this(msg, subject, null, null);
+ }
+
+ public FloatDataItem(Msg msg, String subject, Unit<?> unit) {
+ this(msg, subject, unit, null);
+ }
+
+ public FloatDataItem(Msg msg, String subject, CodeType codetype) {
+ this(msg, subject, null, codetype);
+ }
+
+ public FloatDataItem(Msg msg, String subject, @Nullable Unit<?> unit, @Nullable CodeType codetype) {
+ super(msg, ByteType.BOTH, subject, codetype);
+
+ this.unit = unit;
+ }
+
+ @Override
+ public State createState(Message message) {
+ @Nullable
+ Unit<?> unit = this.getUnit();
+ float value = message.getFloat();
+ return (unit == null) ? new DecimalType(value) : new QuantityType<>(value, unit);
+ }
+}
*/
@NonNullByDefault
public class GatewayCommand {
- private static final Map<String, @Nullable String> supportedCommands = getSupportedCommands();
+ private static final Map<String, @Nullable String> SUPPORTEDCOMMANDS = getSupportedCommands();
private String code;
private String validationSet;
if (code != null && code.length() == 2) {
String codeUpperCase = code.toUpperCase();
- if (supportedCommands.containsKey(codeUpperCase)) {
- String validateSet = supportedCommands.get(codeUpperCase);
+ if (SUPPORTEDCOMMANDS.containsKey(codeUpperCase)) {
+ String validateSet = SUPPORTEDCOMMANDS.get(codeUpperCase);
if (validateSet == null) {
validateSet = "";
}
return new GatewayCommand(codeUpperCase, message, validateSet);
- } else {
- throw new IllegalArgumentException(String.format("Unsupported gateway code '%s'", code.toUpperCase()));
}
+ throw new IllegalArgumentException(String.format("Unsupported gateway code '%s'", code.toUpperCase()));
}
-
throw new IllegalArgumentException(
String.format("Unable to parse gateway command with code '%s' and message '%s'", code, message));
}
private static Map<String, @Nullable String> getSupportedCommands() {
Map<String, @Nullable String> c = new HashMap<>();
- c.put(GatewayCommandCode.TemperatureTemporary, null);
- c.put(GatewayCommandCode.TemperatureConstant, null);
- c.put(GatewayCommandCode.TemperatureOutside, null);
- c.put(GatewayCommandCode.SetClock, null);
- c.put(GatewayCommandCode.HotWater, null);
- c.put(GatewayCommandCode.PrintReport, "A,B,C,G,I,L,M,O,P,R,S,T,V,W");
- c.put(GatewayCommandCode.PrintSummary, "0,1");
- c.put(GatewayCommandCode.GateWay, "0,1,R");
- c.put(GatewayCommandCode.LedA, "R,X,T,B,O,F,H,W,C,E,M,P");
- c.put(GatewayCommandCode.LedB, "R,X,T,B,O,F,H,W,C,E,M,P");
- c.put(GatewayCommandCode.LedC, "R,X,T,B,O,F,H,W,C,E,M,P");
- c.put(GatewayCommandCode.LedD, "R,X,T,B,O,F,H,W,C,E,M,P");
- c.put(GatewayCommandCode.LedE, "R,X,T,B,O,F,H,W,C,E,M,P");
- c.put(GatewayCommandCode.LedF, "R,X,T,B,O,F,H,W,C,E,M,P");
- c.put(GatewayCommandCode.GpioA, "0,1,2,3,4,5,6,7");
- c.put(GatewayCommandCode.GpioB, "0,1,2,3,4,5,6,7");
- c.put(GatewayCommandCode.SetBack, null);
- c.put(GatewayCommandCode.TemperatureSensor, "O,R");
- c.put(GatewayCommandCode.AddAlternative, null);
- c.put(GatewayCommandCode.DeleteAlternative, null);
- c.put(GatewayCommandCode.UnknownID, null);
- c.put(GatewayCommandCode.KnownID, null);
- c.put(GatewayCommandCode.PriorityMessage, null);
- c.put(GatewayCommandCode.SetResponse, null);
- c.put(GatewayCommandCode.ClearResponse, null);
- c.put(GatewayCommandCode.SetpointHeating, null);
- c.put(GatewayCommandCode.SetpointWater, null);
- c.put(GatewayCommandCode.MaximumModulation, null);
- c.put(GatewayCommandCode.ControlSetpoint, null);
- c.put(GatewayCommandCode.ControlSetpoint2, null);
- c.put(GatewayCommandCode.CentralHeating, "0,1");
- c.put(GatewayCommandCode.CentralHeating2, "0,1");
- c.put(GatewayCommandCode.VentilationSetpoint, null);
- c.put(GatewayCommandCode.Reset, null);
- c.put(GatewayCommandCode.IgnoreTransition, "0,1");
- c.put(GatewayCommandCode.OverrideHighbyte, "0,1");
- c.put(GatewayCommandCode.ForceThermostat, "0,1");
- c.put(GatewayCommandCode.VoltageReference, "0,1,2,3,4,5,6,7,8,9");
- c.put(GatewayCommandCode.DebugPointer, null);
+ c.put(GatewayCommandCode.TEMPERATURETEMPORARY, null);
+ c.put(GatewayCommandCode.TEMPERATURECONSTANT, null);
+ c.put(GatewayCommandCode.TEMPERATUREOUTSIDE, null);
+ c.put(GatewayCommandCode.SETCLOCK, null);
+ c.put(GatewayCommandCode.HOTWATER, null);
+ c.put(GatewayCommandCode.PRINTREPORT, "A,B,C,G,I,L,M,O,P,R,S,T,V,W");
+ c.put(GatewayCommandCode.PRINTSUMMARY, "0,1");
+ c.put(GatewayCommandCode.GATEWAY, "0,1,R");
+ c.put(GatewayCommandCode.LEDA, "R,X,T,B,O,F,H,W,C,E,M,P");
+ c.put(GatewayCommandCode.LEDB, "R,X,T,B,O,F,H,W,C,E,M,P");
+ c.put(GatewayCommandCode.LEDC, "R,X,T,B,O,F,H,W,C,E,M,P");
+ c.put(GatewayCommandCode.LEDD, "R,X,T,B,O,F,H,W,C,E,M,P");
+ c.put(GatewayCommandCode.LEDE, "R,X,T,B,O,F,H,W,C,E,M,P");
+ c.put(GatewayCommandCode.LEDF, "R,X,T,B,O,F,H,W,C,E,M,P");
+ c.put(GatewayCommandCode.GPIOA, "0,1,2,3,4,5,6,7");
+ c.put(GatewayCommandCode.GPIOB, "0,1,2,3,4,5,6,7");
+ c.put(GatewayCommandCode.SETBACK, null);
+ c.put(GatewayCommandCode.TEMPERATURESENSOR, "O,R");
+ c.put(GatewayCommandCode.ADDALTERNATIVE, null);
+ c.put(GatewayCommandCode.DELETEALTERNATIVE, null);
+ c.put(GatewayCommandCode.UNKNOWNID, null);
+ c.put(GatewayCommandCode.KNOWNID, null);
+ c.put(GatewayCommandCode.PRIORITYMESSAGE, null);
+ c.put(GatewayCommandCode.SETRESPONSE, null);
+ c.put(GatewayCommandCode.CLEARRESPONSE, null);
+ c.put(GatewayCommandCode.SETPOINTHEATING, null);
+ c.put(GatewayCommandCode.SETPOINTWATER, null);
+ c.put(GatewayCommandCode.MAXIMUMMODULATION, null);
+ c.put(GatewayCommandCode.CONTROLSETPOINT, null);
+ c.put(GatewayCommandCode.CONTROLSETPOINT2, null);
+ c.put(GatewayCommandCode.CENTRALHEATING, "0,1");
+ c.put(GatewayCommandCode.CENTRALHEATING2, "0,1");
+ c.put(GatewayCommandCode.VENTILATIONSETPOINT, null);
+ c.put(GatewayCommandCode.RESET, null);
+ c.put(GatewayCommandCode.IGNORETRANSITION, "0,1");
+ c.put(GatewayCommandCode.OVERRIDEHIGHBYTE, "0,1");
+ c.put(GatewayCommandCode.FORCETHERMOSTAT, "0,1");
+ c.put(GatewayCommandCode.VOLTAGEREFERENCE, "0,1,2,3,4,5,6,7,8,9");
+ c.put(GatewayCommandCode.DEBUGPOINTER, null);
return c;
}
*/
@NonNullByDefault
public class GatewayCommandCode {
- public static final String TemperatureTemporary = "TT";
- public static final String TemperatureConstant = "TC";
- public static final String TemperatureOutside = "OT";
- public static final String SetClock = "ST";
- public static final String HotWater = "HW";
- public static final String PrintReport = "PR";
- public static final String PrintSummary = "PS";
- public static final String GateWay = "GW";
- public static final String LedA = "LA";
- public static final String LedB = "LB";
- public static final String LedC = "LC";
- public static final String LedD = "LD";
- public static final String LedE = "LE";
- public static final String LedF = "LF";
- public static final String GpioA = "GA";
- public static final String GpioB = "GB";
- public static final String SetBack = "SB";
- public static final String TemperatureSensor = "TS";
- public static final String AddAlternative = "AA";
- public static final String DeleteAlternative = "DA";
- public static final String UnknownID = "UI";
- public static final String KnownID = "KI";
- public static final String PriorityMessage = "PM";
- public static final String SetResponse = "SR";
- public static final String ClearResponse = "CR";
- public static final String SetpointHeating = "SH";
- public static final String SetpointWater = "SW";
- public static final String MaximumModulation = "MM";
- public static final String ControlSetpoint = "CS";
- public static final String ControlSetpoint2 = "C2";
- public static final String CentralHeating = "CH";
- public static final String CentralHeating2 = "H2";
- public static final String VentilationSetpoint = "VS";
- public static final String Reset = "RS";
- public static final String IgnoreTransition = "IT";
- public static final String OverrideHighbyte = "OH";
- public static final String ForceThermostat = "FT";
- public static final String VoltageReference = "VR";
- public static final String DebugPointer = "DP";
+ public static final String TEMPERATURETEMPORARY = "TT";
+ public static final String TEMPERATURECONSTANT = "TC";
+ public static final String TEMPERATUREOUTSIDE = "OT";
+ public static final String SETCLOCK = "ST";
+ public static final String HOTWATER = "HW";
+ public static final String PRINTREPORT = "PR";
+ public static final String PRINTSUMMARY = "PS";
+ public static final String GATEWAY = "GW";
+ public static final String LEDA = "LA";
+ public static final String LEDB = "LB";
+ public static final String LEDC = "LC";
+ public static final String LEDD = "LD";
+ public static final String LEDE = "LE";
+ public static final String LEDF = "LF";
+ public static final String GPIOA = "GA";
+ public static final String GPIOB = "GB";
+ public static final String SETBACK = "SB";
+ public static final String TEMPERATURESENSOR = "TS";
+ public static final String ADDALTERNATIVE = "AA";
+ public static final String DELETEALTERNATIVE = "DA";
+ public static final String UNKNOWNID = "UI";
+ public static final String KNOWNID = "KI";
+ public static final String PRIORITYMESSAGE = "PM";
+ public static final String SETRESPONSE = "SR";
+ public static final String CLEARRESPONSE = "CR";
+ public static final String SETPOINTHEATING = "SH";
+ public static final String SETPOINTWATER = "SW";
+ public static final String MAXIMUMMODULATION = "MM";
+ public static final String CONTROLSETPOINT = "CS";
+ public static final String CONTROLSETPOINT2 = "C2";
+ public static final String CENTRALHEATING = "CH";
+ public static final String CENTRALHEATING2 = "H2";
+ public static final String VENTILATIONSETPOINT = "VS";
+ public static final String RESET = "RS";
+ public static final String IGNORETRANSITION = "IT";
+ public static final String OVERRIDEHIGHBYTE = "OH";
+ public static final String FORCETHERMOSTAT = "FT";
+ public static final String VOLTAGEREFERENCE = "VR";
+ public static final String DEBUGPOINTER = "DP";
}
--- /dev/null
+/**
+ * Copyright (c) 2010-2022 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.openthermgateway.internal;
+
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.openhab.core.library.types.DecimalType;
+import org.openhab.core.types.State;
+
+/**
+ * The {@link IntDataItem} represents an 8 or 16 bit signed integer.
+ *
+ * @author Arjen Korevaar - Initial contribution
+ */
+@NonNullByDefault
+public class IntDataItem extends DataItem {
+
+ public IntDataItem(Msg msg, ByteType byteType, String subject) {
+ super(msg, byteType, subject, null);
+ }
+
+ @Override
+ public State createState(Message message) {
+ return new DecimalType(message.getInt(super.getByteType()));
+ }
+}
@NonNullByDefault
public class Message {
- private static final Pattern messagePattern = Pattern.compile("[TBRA]{1}[A-F0-9]{8}");
+ private static final Pattern MESSAGEPATTERN = Pattern.compile("[TBRA]{1}[A-F0-9]{8}");
- private CodeType code;
+ private CodeType codeType;
private MessageType messageType;
private int id;
private String data;
- public CodeType getCode() {
- return this.code;
+ public CodeType getCodeType() {
+ return codeType;
}
public MessageType getMessageType() {
// If the message is a Request sent to the boiler or an Answer returned to the
// thermostat, and it's ID is equal to the previous message, then this is an
// override sent by the OpenTherm Gateway
- return other != null && this.getID() == other.getID() && (this.code == CodeType.R || this.code == CodeType.A);
+ return other != null && this.getID() == other.getID() && (codeType == CodeType.R || codeType == CodeType.A);
}
@Override
public String toString() {
- return String.format("%s - %s - %s", this.code, this.id, this.data);
+ return String.format("%s - %s - %s", this.codeType, this.id, this.data);
}
- public Message(CodeType code, MessageType messageType, int id, String data) {
- this.code = code;
+ public Message(CodeType codeType, MessageType messageType, int id, String data) {
+ this.codeType = codeType;
this.messageType = messageType;
this.id = id;
this.data = data;
}
public static @Nullable Message parse(String message) {
- if (messagePattern.matcher(message).matches()) {
+ if (MESSAGEPATTERN.matcher(message).matches()) {
// For now, only parse TBRA codes
- CodeType code = CodeType.valueOf(message.substring(0, 1));
+ CodeType codeType = CodeType.valueOf(message.substring(0, 1));
MessageType messageType = getMessageType(message.substring(1, 3));
int id = Integer.valueOf(message.substring(3, 5), 16);
String data = message.substring(5);
- return new Message(code, messageType, id, data);
+ return new Message(codeType, messageType, id, data);
}
return null;
*/
package org.openhab.binding.openthermgateway.internal;
+import org.eclipse.jdt.annotation.NonNullByDefault;
+
/**
* The {@link MessageType} indicates the type of message received by the OpenTherm Gateway, based
* on the OpenTherm specification.
*
* @author Arjen Korevaar - Initial contribution
*/
+@NonNullByDefault
public enum MessageType {
READDATA, // 000
READACK, // 100
*/
package org.openhab.binding.openthermgateway.internal;
+import org.eclipse.jdt.annotation.NonNullByDefault;
+
/**
* The {@link Msg} flag is used to indicate whether the message is sent for Reading, Writing
* or both, based on the OpenTherm specification.
*
* @author Arjen Korevaar - Initial contribution
*/
+@NonNullByDefault
public enum Msg {
READ,
WRITE,
--- /dev/null
+/**
+ * Copyright (c) 2010-2022 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.openthermgateway.internal;
+
+import java.util.Set;
+
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.openhab.core.thing.ThingTypeUID;
+
+/**
+ * The {@link OpenThermGatewayBindingConstants} class defines common constants, which are
+ * used across the whole binding.
+ *
+ * @author Arjen Korevaar - Initial contribution
+ */
+@NonNullByDefault
+public class OpenThermGatewayBindingConstants {
+
+ // Binding Id
+ public static final String BINDING_ID = "openthermgateway";
+
+ // List of all the ThingType UID's
+ public static final ThingTypeUID OPENTHERM_GATEWAY_THING_TYPE_UID = new ThingTypeUID(BINDING_ID,
+ "openthermgateway");
+ public static final ThingTypeUID BOILER_THING_TYPE_UID = new ThingTypeUID(BINDING_ID, "boiler");
+ public static final ThingTypeUID VENTILATION_HEATRECOVERY_THING_TYPE_UID = new ThingTypeUID(BINDING_ID,
+ "ventilationheatrecovery");
+
+ public static final Set<ThingTypeUID> SUPPORTED_THING_TYPE_UIDS = Set.of(OPENTHERM_GATEWAY_THING_TYPE_UID,
+ BOILER_THING_TYPE_UID, VENTILATION_HEATRECOVERY_THING_TYPE_UID);
+
+ // List of id's for writeable channels
+ public static final String CHANNEL_SEND_COMMAND = "sendcommand";
+ public static final String CHANNEL_OVERRIDE_SETPOINT_TEMPORARY = "temperaturetemporary";
+ public static final String CHANNEL_OVERRIDE_SETPOINT_CONSTANT = "temperatureconstant";
+ public static final String CHANNEL_OVERRIDE_DHW_SETPOINT = "overridedhwsetpoint";
+ public static final String CHANNEL_OVERRIDE_CENTRAL_HEATING_WATER_SETPOINT = "controlsetpointoverride";
+ public static final String CHANNEL_OVERRIDE_CENTRAL_HEATING2_WATER_SETPOINT = "controlsetpoint2override";
+ public static final String CHANNEL_OVERRIDE_CENTRAL_HEATING_ENABLED = "ch_enableoverride";
+ public static final String CHANNEL_OVERRIDE_CENTRAL_HEATING2_ENABLED = "ch2_enableoverride";
+ public static final String CHANNEL_OUTSIDE_TEMPERATURE = "outsidetemp";
+ public static final String CHANNEL_OVERRIDE_VENTILATION_SETPOINT = "vh_ventilationsetpoint";
+
+ // Generic channel type for Transparent Slave Parameter and Fault History Buffer values
+ public static final String CHANNEL_TSPFHB = "tspfhb";
+}
*/
@NonNullByDefault
public interface OpenThermGatewayCallback {
- void connecting();
- void connected();
-
- void disconnected();
+ void connectionStateChanged(ConnectionState state);
void receiveMessage(Message message);
}
public int port = 0;
public int connectionRetryInterval = 60;
+
+ public int connectTimeoutSeconds = 5;
+
+ public int readTimeoutSeconds = 20;
}
*/
package org.openhab.binding.openthermgateway.internal;
+import java.util.concurrent.Callable;
+
import org.eclipse.jdt.annotation.NonNullByDefault;
/**
* The {@link OpenThermGatewayConnector} interface is used to allow multiple types of connectors
* to be implemented and used to connect to the OpenTherm Gateway.
- *
+ *
* @author Arjen Korevaar - Initial contribution
*/
@NonNullByDefault
-public interface OpenThermGatewayConnector extends Runnable {
+public interface OpenThermGatewayConnector extends Callable<Boolean> {
void sendCommand(GatewayCommand command);
boolean isConnected();
void stop();
+
+ void start();
}
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
-import org.openhab.binding.openthermgateway.OpenThermGatewayBindingConstants;
+import org.openhab.binding.openthermgateway.handler.BoilerHandler;
import org.openhab.binding.openthermgateway.handler.OpenThermGatewayHandler;
+import org.openhab.binding.openthermgateway.handler.VentilationHeatRecoveryHandler;
+import org.openhab.core.thing.Bridge;
import org.openhab.core.thing.Thing;
import org.openhab.core.thing.ThingTypeUID;
import org.openhab.core.thing.binding.BaseThingHandlerFactory;
@Override
public boolean supportsThingType(ThingTypeUID thingTypeUID) {
- return thingTypeUID.equals(OpenThermGatewayBindingConstants.MAIN_THING_TYPE);
+ return OpenThermGatewayBindingConstants.SUPPORTED_THING_TYPE_UIDS.contains(thingTypeUID);
}
@Override
protected @Nullable ThingHandler createHandler(Thing thing) {
ThingTypeUID thingTypeUID = thing.getThingTypeUID();
- if (thingTypeUID.equals(OpenThermGatewayBindingConstants.MAIN_THING_TYPE)) {
- return new OpenThermGatewayHandler(thing);
+ if (thingTypeUID.equals(OpenThermGatewayBindingConstants.OPENTHERM_GATEWAY_THING_TYPE_UID)) {
+ return new OpenThermGatewayHandler((Bridge) thing);
+ } else if (thingTypeUID.equals(OpenThermGatewayBindingConstants.BOILER_THING_TYPE_UID)) {
+ return new BoilerHandler(thing);
+ } else if (thingTypeUID.equals(OpenThermGatewayBindingConstants.VENTILATION_HEATRECOVERY_THING_TYPE_UID)) {
+ return new VentilationHeatRecoveryHandler(thing);
}
return null;
*/
package org.openhab.binding.openthermgateway.internal;
+import static org.openhab.binding.openthermgateway.internal.OpenThermGatewayBindingConstants.BINDING_ID;
+
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
-import org.openhab.core.library.types.DecimalType;
-import org.openhab.core.library.types.OnOffType;
-import org.openhab.core.types.State;
+import org.openhab.core.common.NamedThreadFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
*/
@NonNullByDefault
public class OpenThermGatewaySocketConnector implements OpenThermGatewayConnector {
- private static final int COMMAND_RESPONSE_TIME_MILLISECONDS = 100;
- private static final int COMMAND_TIMEOUT_MILLISECONDS = 5000;
+ private static final int COMMAND_RESPONSE_MIN_WAIT_TIME_MILLISECONDS = 100;
+ private static final int COMMAND_RESPONSE_MAX_WAIT_TIME_MILLISECONDS = 5000;
private final Logger logger = LoggerFactory.getLogger(OpenThermGatewaySocketConnector.class);
private final OpenThermGatewayCallback callback;
private final String ipaddress;
private final int port;
+ private final int connectTimeoutMilliseconds;
+ private final int readTimeoutMilliSeconds;
- private @Nullable PrintWriter writer;
-
- private volatile boolean stopping;
- private boolean connected;
+ private @Nullable volatile PrintWriter writer;
+ private @Nullable volatile Thread thread;
+ private @Nullable Future<Boolean> future;
+ private @Nullable ExecutorService executor;
private Map<String, Entry<Long, GatewayCommand>> pendingCommands = new ConcurrentHashMap<>();
- public OpenThermGatewaySocketConnector(OpenThermGatewayCallback callback, String ipaddress, int port) {
+ public OpenThermGatewaySocketConnector(OpenThermGatewayCallback callback, OpenThermGatewayConfiguration config) {
this.callback = callback;
- this.ipaddress = ipaddress;
- this.port = port;
+ ipaddress = config.ipaddress;
+ port = config.port;
+ connectTimeoutMilliseconds = config.connectTimeoutSeconds * 1000;
+ readTimeoutMilliSeconds = config.readTimeoutSeconds * 1000;
}
@Override
- public void run() {
- stopping = false;
- connected = false;
-
- logger.debug("Connecting OpenThermGatewaySocketConnector to {}:{}", this.ipaddress, this.port);
-
- callback.connecting();
-
+ public Boolean call() throws Exception {
+ thread = Thread.currentThread();
try (Socket socket = new Socket()) {
- socket.connect(new InetSocketAddress(this.ipaddress, this.port), COMMAND_TIMEOUT_MILLISECONDS);
- socket.setSoTimeout(COMMAND_TIMEOUT_MILLISECONDS);
+ logger.debug("Connecting OpenThermGatewaySocketConnector to {}:{}", this.ipaddress, this.port);
+ callback.connectionStateChanged(ConnectionState.CONNECTING);
- connected = true;
-
- callback.connected();
+ socket.connect(new InetSocketAddress(ipaddress, port), connectTimeoutMilliseconds);
+ socket.setSoTimeout(readTimeoutMilliSeconds);
logger.debug("OpenThermGatewaySocketConnector connected");
+ callback.connectionStateChanged(ConnectionState.CONNECTED);
try (BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
PrintWriter wrt = new PrintWriter(socket.getOutputStream(), true)) {
// Make writer accessible on class level
writer = wrt;
- sendCommand(GatewayCommand.parse(GatewayCommandCode.PrintReport, "A"));
+ sendCommand(GatewayCommand.parse(GatewayCommandCode.PRINTREPORT, "A"));
// Set the OTGW to report every message it receives and transmits
- sendCommand(GatewayCommand.parse(GatewayCommandCode.PrintSummary, "0"));
+ sendCommand(GatewayCommand.parse(GatewayCommandCode.PRINTSUMMARY, "0"));
- while (!stopping && !Thread.currentThread().isInterrupted()) {
+ while (!Thread.currentThread().isInterrupted()) {
@Nullable
String message = reader.readLine();
if (message != null) {
handleMessage(message);
} else {
- logger.debug("Connection closed by OpenTherm Gateway");
+ logger.debug("Received NULL message from OpenTherm Gateway (EOF)");
break;
}
}
-
- logger.debug("Stopping OpenThermGatewaySocketConnector");
- } finally {
- connected = false;
-
- logger.debug("OpenThermGatewaySocketConnector disconnected");
- callback.disconnected();
+ } catch (IOException ex) {
+ logger.warn("Error communicating with OpenTherm Gateway: '{}'", ex.getMessage());
}
} catch (IOException ex) {
- logger.warn("Unable to connect to the OpenTherm Gateway.", ex);
- callback.disconnected();
+ logger.warn("Unable to connect to the OpenTherm Gateway: '{}'", ex.getMessage());
}
+ thread = null;
+ writer = null;
+ logger.debug("OpenThermGatewaySocketConnector disconnected");
+ callback.connectionStateChanged(ConnectionState.DISCONNECTED);
+ return true;
}
@Override
public void stop() {
logger.debug("Stopping OpenThermGatewaySocketConnector");
- stopping = true;
+
+ Thread thread = this.thread;
+ Future<Boolean> future = this.future;
+ ExecutorService executor = this.executor;
+
+ if (executor != null) {
+ executor.shutdown();
+ }
+ if ((thread != null) && thread.isAlive()) {
+ thread.interrupt();
+ }
+ if (future != null) {
+ try {
+ future.get(readTimeoutMilliSeconds, TimeUnit.MILLISECONDS);
+ } catch (ExecutionException e) {
+ // expected exception due to e.g. IOException on socket close
+ } catch (TimeoutException | InterruptedException e) {
+ // unexpected exception
+ logger.warn("stop() exception '{}' => PLEASE REPORT !!", e.getMessage());
+ }
+ }
+
+ this.thread = null;
+ this.future = null;
+ this.executor = null;
}
@Override
- public boolean isConnected() {
- return connected;
+ public void start() {
+ logger.debug("Starting OpenThermGatewaySocketConnector");
+ ExecutorService executor = this.executor = Executors
+ .newSingleThreadExecutor(new NamedThreadFactory("binding-" + BINDING_ID));
+ future = executor.submit(this);
}
@Override
- public void sendCommand(GatewayCommand command) {
- @Nullable
- PrintWriter wrtr = writer;
+ public synchronized boolean isConnected() {
+ Thread thread = this.thread;
+ return (thread != null) && thread.isAlive();
+ }
- String msg = command.toFullString();
+ @Override
+ public synchronized void sendCommand(GatewayCommand command) {
+ PrintWriter wrt = writer;
pendingCommands.put(command.getCode(),
new AbstractMap.SimpleImmutableEntry<>(System.currentTimeMillis(), command));
- if (connected) {
+ String msg = command.toFullString();
+
+ if (isConnected() && (wrt != null)) {
logger.debug("Sending message: {}", msg);
- if (wrtr != null) {
- wrtr.print(msg + "\r\n");
- wrtr.flush();
+ wrt.print(msg + "\r\n");
+ wrt.flush();
+ if (wrt.checkError()) {
+ logger.warn("sendCommand() error sending message to OpenTherm Gateway => PLEASE REPORT !!");
+ stop();
}
} else {
logger.debug("Unable to send message: {}. OpenThermGatewaySocketConnector is not connected.", msg);
long currentTime = System.currentTimeMillis();
for (Entry<Long, GatewayCommand> timeAndCommand : pendingCommands.values()) {
- long responseTime = timeAndCommand.getKey() + COMMAND_RESPONSE_TIME_MILLISECONDS;
- long timeoutTime = timeAndCommand.getKey() + COMMAND_TIMEOUT_MILLISECONDS;
+ long responseTime = timeAndCommand.getKey() + COMMAND_RESPONSE_MIN_WAIT_TIME_MILLISECONDS;
+ long timeoutTime = timeAndCommand.getKey() + COMMAND_RESPONSE_MAX_WAIT_TIME_MILLISECONDS;
if (currentTime > responseTime && currentTime <= timeoutTime) {
logger.debug("Resending command: {}", timeAndCommand.getValue());
if (msg == null) {
logger.trace("Received message: {}, (unknown)", message);
return;
- } else {
- logger.trace("Received message: {}, {} {} {}", message, msg.getID(), msg.getCode(), msg.getMessageType());
- }
-
- if (DataItemGroup.dataItemGroups.containsKey(msg.getID())) {
- DataItem[] dataItems = DataItemGroup.dataItemGroups.get(msg.getID());
-
- for (DataItem dataItem : dataItems) {
- State state = null;
-
- switch (dataItem.getDataType()) {
- case FLAGS:
- state = OnOffType.from(msg.getBit(dataItem.getByteType(), dataItem.getBitPos()));
- break;
- case UINT8:
- case UINT16:
- state = new DecimalType(msg.getUInt(dataItem.getByteType()));
- break;
- case INT8:
- case INT16:
- state = new DecimalType(msg.getInt(dataItem.getByteType()));
- break;
- case FLOAT:
- state = new DecimalType(msg.getFloat());
- break;
- case DOWTOD:
- break;
- }
-
- logger.trace(" Data: {} {} {} {}", dataItem.getID(), dataItem.getSubject(), dataItem.getDataType(),
- state == null ? "" : state);
- }
}
-
+ logger.trace("Received message: {}, {} {} {}", message, msg.getID(), msg.getCodeType(), msg.getMessageType());
if (msg.getMessageType() == MessageType.READACK || msg.getMessageType() == MessageType.WRITEDATA
|| msg.getID() == 0 || msg.getID() == 1) {
- receiveMessage(msg);
+ callback.receiveMessage(msg);
}
}
-
- private void receiveMessage(Message message) {
- callback.receiveMessage(message);
- }
}
--- /dev/null
+/**
+ * Copyright (c) 2010-2022 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.openthermgateway.internal;
+
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.openhab.core.library.types.DecimalType;
+import org.openhab.core.types.State;
+
+/**
+ * The {@link DataItem} represents a transparent slave parameter or fault history buffer size.
+ *
+ * @author Arjen Korevaar - Initial contribution
+ */
+@NonNullByDefault
+public class TspFhbSizeDataItem extends DataItem {
+ private int valueId;
+
+ public int getValueId() {
+ return valueId;
+ }
+
+ public TspFhbSizeDataItem(Msg msg, ByteType byteType, int valueId, String subject) {
+ super(msg, byteType, subject, null);
+
+ this.valueId = valueId;
+ }
+
+ @Override
+ public State createState(Message message) {
+ return new DecimalType(message.getUInt(super.getByteType()));
+ }
+}
--- /dev/null
+/**
+ * Copyright (c) 2010-2022 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.openthermgateway.internal;
+
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.openhab.core.library.types.DecimalType;
+import org.openhab.core.types.State;
+
+/**
+ * The {@link TspFhbValueDataItem} represents a transparent slave parameter or fault history buffer value.
+ *
+ * @author Arjen Korevaar - Initial contribution
+ */
+@NonNullByDefault
+public class TspFhbValueDataItem extends DataItem {
+
+ public TspFhbValueDataItem(Msg msg, String subject) {
+ super(msg, ByteType.BOTH, subject, null);
+ }
+
+ @Override
+ public String getChannelId(Message message) {
+ // With TSP or FHB values, the index is HIGHBYTE, the value is LOWBYTE
+ int index = message.getUInt(ByteType.HIGHBYTE);
+ return getChannelId(index);
+ }
+
+ public String getChannelId(int index) {
+ return super.getSubject() + "_" + index;
+ }
+
+ public String getLabel(int index) {
+ return super.getSubject() + " " + index;
+ }
+
+ @Override
+ public State createState(Message message) {
+ // With TSP or FHB values, the index is HIGHBYTE, the value is LOWBYTE
+ // TSP values are treated as Number:Dimensionless
+ return new DecimalType(message.getUInt(ByteType.LOWBYTE));
+ }
+}
--- /dev/null
+/**
+ * Copyright (c) 2010-2022 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.openthermgateway.internal;
+
+import javax.measure.Unit;
+
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.eclipse.jdt.annotation.Nullable;
+import org.openhab.core.library.types.DecimalType;
+import org.openhab.core.library.types.QuantityType;
+import org.openhab.core.types.State;
+
+/**
+ * The {@link UIntDataItem} represents an 8 or 16 bit unsigned integer.
+ *
+ * @author Arjen Korevaar - Initial contribution
+ */
+@NonNullByDefault
+public class UIntDataItem extends DataItem {
+
+ private @Nullable Unit<?> unit;
+
+ public @Nullable Unit<?> getUnit() {
+ return unit;
+ }
+
+ public UIntDataItem(Msg msg, ByteType byteType, String subject) {
+ this(msg, byteType, subject, null);
+ }
+
+ public UIntDataItem(Msg msg, ByteType byteType, String subject, @Nullable Unit<?> unit) {
+ super(msg, byteType, subject, null);
+
+ this.unit = unit;
+ }
+
+ @Override
+ public State createState(Message message) {
+ @Nullable
+ Unit<?> unit = getUnit();
+ int value = message.getUInt(super.getByteType());
+ return (unit == null) ? new DecimalType(value) : new QuantityType<>(value, unit);
+ }
+}
+++ /dev/null
-<?xml version="1.0" encoding="UTF-8"?>
-<config-description:config-descriptions
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xmlns:config-description="https://openhab.org/schemas/config-description/v1.0.0"
- xsi:schemaLocation="https://openhab.org/schemas/config-description/v1.0.0 https://openhab.org/schemas/config-description-1.0.0.xsd">
-
- <config-description uri="thing-type:openthermgateway:otgw">
- <parameter-group name="connection">
- <label>Connection</label>
- <description>Connection settings.</description>
- </parameter-group>
-
- <parameter name="ipaddress" type="text" required="true" groupName="connection">
- <label>Hostname or IP address</label>
- <description>The hostname or IP address to connect to the OpenTherm Gateway.</description>
- <context>network-address</context>
- </parameter>
-
- <parameter name="port" type="integer" required="true" groupName="connection" min="0" max="65535">
- <label>Port</label>
- <description>The port used to connect to the OpenTherm Gateway.</description>
- </parameter>
-
- <parameter name="connectionRetryInterval" type="integer" required="true" groupName="connection" min="0"
- max="3600" unit="s">
- <label>Connection Retry Interval</label>
- <description>The interval in seconds to retry connecting (0 = disabled).</description>
- <default>60</default>
- </parameter>
-
- </config-description>
-
-</config-description:config-descriptions>
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<config-description:config-descriptions
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xmlns:config-description="https://openhab.org/schemas/config-description/v1.0.0"
+ xsi:schemaLocation="https://openhab.org/schemas/config-description/v1.0.0 https://openhab.org/schemas/config-description-1.0.0.xsd">
+
+ <config-description uri="thing-type:openthermgateway:openthermgateway">
+ <parameter-group name="connection">
+ <label>Connection</label>
+ <description>Connection settings.</description>
+ </parameter-group>
+
+ <parameter name="ipaddress" type="text" required="true" groupName="connection">
+ <label>Hostname or IP address</label>
+ <description>The hostname or IP address to connect to the OpenTherm Gateway.</description>
+ <context>network-address</context>
+ </parameter>
+
+ <parameter name="port" type="integer" required="true" groupName="connection" min="0" max="65535">
+ <label>Port</label>
+ <description>The port used to connect to the OpenTherm Gateway.</description>
+ </parameter>
+
+ <parameter name="connectionRetryInterval" type="integer" required="true" groupName="connection" min="0"
+ max="3600" unit="s">
+ <label>Connection Retry Interval</label>
+ <description>The interval in seconds to retry connecting (0 = disabled).</description>
+ <default>60</default>
+ </parameter>
+
+ <parameter name="connectTimeoutSeconds" type="integer" required="true" groupName="connection" min="5"
+ max="60" unit="s">
+ <label>Connect Timeout</label>
+ <description>The maximum time (seconds) to wait for establishing a connection to the gateway.</description>
+ <default>5</default>
+ </parameter>
+
+ <parameter name="readTimeoutSeconds" type="integer" required="true" groupName="connection" min="5" max="60"
+ unit="s">
+ <label>Read Timeout</label>
+ <description>The maximum time (seconds) to wait for reading responses from the gateway.</description>
+ <default>20</default>
+ </parameter>
+
+ </config-description>
+
+</config-description:config-descriptions>
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<thing:thing-descriptions bindingId="openthermgateway"
+ 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="boiler">
+ <supported-bridge-type-refs>
+ <bridge-type-ref id="openthermgateway"/>
+ </supported-bridge-type-refs>
+ <label>Boiler</label>
+ <description>Boiler and thermostat</description>
+ <channels>
+ <channel id="roomtemp" typeId="roomtemp"/>
+ <channel id="roomsetpoint" typeId="roomsetpoint"/>
+ <channel id="temperaturetemporary" typeId="temperaturetemporary"/>
+ <channel id="temperatureconstant" typeId="temperatureconstant"/>
+ <channel id="controlsetpoint" typeId="controlsetpoint"/>
+ <channel id="controlsetpointrequested" typeId="controlsetpointrequested"/>
+ <channel id="controlsetpointoverride" typeId="controlsetpointoverride"/>
+ <channel id="controlsetpoint2" typeId="controlsetpoint2"/>
+ <channel id="controlsetpoint2requested" typeId="controlsetpoint2requested"/>
+ <channel id="controlsetpoint2override" typeId="controlsetpoint2override"/>
+ <channel id="dhwtemp" typeId="dhwtemp"/>
+ <channel id="tdhwset" typeId="tdhwset"/>
+ <channel id="overridedhwsetpoint" typeId="overridedhwsetpoint"/>
+ <channel id="flowtemp" typeId="flowtemp"/>
+ <channel id="returntemp" typeId="returntemp"/>
+ <channel id="outsidetemp" typeId="outsidetemp"/>
+ <channel id="waterpressure" typeId="waterpressure"/>
+ <channel id="ch_enable" typeId="ch_enable"/>
+ <channel id="ch_enablerequested" typeId="ch_enablerequested"/>
+ <channel id="ch_enableoverride" typeId="ch_enableoverride"/>
+ <channel id="ch2_enable" typeId="ch2_enable"/>
+ <channel id="ch2_enablerequested" typeId="ch2_enablerequested"/>
+ <channel id="ch2_enableoverride" typeId="ch2_enableoverride"/>
+ <channel id="ch_mode" typeId="ch_mode"/>
+ <channel id="dhw_enable" typeId="dhw_enable"/>
+ <channel id="dhw_mode" typeId="dhw_mode"/>
+ <channel id="flame" typeId="flame"/>
+ <channel id="modulevel" typeId="modulevel"/>
+ <channel id="maxrelmdulevel" typeId="maxrelmdulevel"/>
+ <channel id="fault" typeId="fault"/>
+ <channel id="servicerequest" typeId="servicerequest"/>
+ <channel id="lockout-reset" typeId="lockout-reset"/>
+ <channel id="lowwaterpress" typeId="lowwaterpress"/>
+ <channel id="gasflamefault" typeId="gasflamefault"/>
+ <channel id="airpressfault" typeId="airpressfault"/>
+ <channel id="waterovtemp" typeId="waterovtemp"/>
+ <channel id="oemfaultcode" typeId="oemfaultcode"/>
+ <channel id="diag" typeId="diag"/>
+ <channel id="unsuccessfulburnerstarts" typeId="unsuccessfulburnerstarts"/>
+ <channel id="burnerstarts" typeId="burnerstarts"/>
+ <channel id="chpumpstarts" typeId="chpumpstarts"/>
+ <channel id="dhwpvstarts" typeId="dhwpvstarts"/>
+ <channel id="dhwburnerstarts" typeId="dhwburnerstarts"/>
+ <channel id="burnerhours" typeId="burnerhours"/>
+ <channel id="chpumphours" typeId="chpumphours"/>
+ <channel id="dhwpvhours" typeId="dhwpvhours"/>
+ <channel id="dhwburnerhours" typeId="dhwburnerhours"/>
+ <channel id="tspnumber" typeId="tspnumber"/>
+ <channel id="tspentry" typeId="tspentry"/>
+ <channel id="fhbnumber" typeId="fhbnumber"/>
+ <channel id="fhbentry" typeId="fhbentry"/>
+ </channels>
+ </thing-type>
+
+</thing:thing-descriptions>
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">
+ <!-- generic channel type for dynamic tsp and fhb channels -->
+
+ <channel-type id="tspfhb">
+ <item-type>Number:Dimensionless</item-type>
+ <label>Set Dynamically</label>
+ <description>Transparent slave parameter or Fault history buffer value</description>
+ <state readOnly="true"/>
+ </channel-type>
+
+ <!-- openthermgateway -->
+
+ <channel-type id="sendcommand">
+ <item-type>String</item-type>
+ <label>Send Command</label>
+ <description>Channel to send commands to the OpenTherm Gateway device</description>
+ <state readOnly="false"/>
+ </channel-type>
+
+ <!-- boiler -->
+
<channel-type id="roomtemp">
<item-type>Number:Temperature</item-type>
<label>Room Temperature</label>
<state readOnly="true"/>
</channel-type>
- <channel-type id="sendcommand">
- <item-type>String</item-type>
- <label>Send Command</label>
- <description>Channel to send commands to the OpenTherm Gateway device</description>
- <state readOnly="false"/>
+ <channel-type id="tspnumber">
+ <item-type>Number:Dimensionless</item-type>
+ <label>Transparent Slave Parameter Number</label>
+ <description>Number of transparant slave parameter entries</description>
+ <state readOnly="true"/>
+ </channel-type>
+
+ <channel-type id="tspentry">
+ <item-type>Number:Dimensionless</item-type>
+ <label>Transparent Slave Parameter Entry</label>
+ <description>Transparent slave parameter entry</description>
+ <state readOnly="true"/>
+ </channel-type>
+
+ <channel-type id="fhbnumber">
+ <item-type>Number:Dimensionless</item-type>
+ <label>Fault History Buffer Number</label>
+ <description>Number of fault history buffer entries</description>
+ <state readOnly="true"/>
+ </channel-type>
+
+ <channel-type id="fhbentry">
+ <item-type>Number:Dimensionless</item-type>
+ <label>Fault History Buffer Entry</label>
+ <description>Fault history buffer entry</description>
+ <state readOnly="true"/>
+ </channel-type>
+
+ <!-- ventilationheatrecovery -->
+
+ <channel-type id="vh_ventilationenable">
+ <item-type>Switch</item-type>
+ <label>Ventilation</label>
+ <description>Ventilation enabled</description>
+ <state readOnly="true"/>
+ </channel-type>
+
+ <channel-type id="vh_bypassposition">
+ <item-type>Number:Dimensionless</item-type>
+ <label>Bypass Position</label>
+ <description>Bypass position</description>
+ <state readOnly="true">
+ <options>
+ <option value="0">close</option>
+ <option value="1">open</option>
+ </options>
+ </state>
+ </channel-type>
+
+ <channel-type id="vh_bypassmode">
+ <item-type>Number:Dimensionless</item-type>
+ <label>Bypass Mode</label>
+ <description>Bypass mode</description>
+ <state readOnly="true">
+ <options>
+ <option value="0">manual</option>
+ <option value="1">automatic</option>
+ </options>
+ </state>
+ </channel-type>
+
+ <channel-type id="vh_freeventilationmode">
+ <item-type>Switch</item-type>
+ <label>Free Ventilation Mode</label>
+ <description>Free ventilation mode</description>
+ <state readOnly="true"/>
+ </channel-type>
+
+ <channel-type id="vh_faultindication">
+ <item-type>Switch</item-type>
+ <label>Fault Indication</label>
+ <description>Fault indication</description>
+ <state readOnly="true"/>
+ </channel-type>
+
+ <channel-type id="vh_ventilationmode">
+ <item-type>Switch</item-type>
+ <label>Ventilation Mode</label>
+ <description>Ventilation mode</description>
+ <state readOnly="true"/>
+ </channel-type>
+
+ <channel-type id="vh_bypassstatus">
+ <item-type>Switch</item-type>
+ <label>Bypass Status</label>
+ <description>Bypass status</description>
+ <state readOnly="true"/>
+ </channel-type>
+
+ <channel-type id="vh_bypassautomaticstatus">
+ <item-type>Number:Dimensionless</item-type>
+ <label>Bypass Automatic Status</label>
+ <description>Bypass automatic status</description>
+ <state readOnly="true">
+ <options>
+ <option value="0">manual</option>
+ <option value="1">automatic</option>
+ </options>
+ </state>
+ </channel-type>
+
+ <channel-type id="vh_freeventilationstatus">
+ <item-type>Switch</item-type>
+ <label>Free Ventilation Status</label>
+ <description>Free ventilation status</description>
+ <state readOnly="true"/>
+ </channel-type>
+
+ <channel-type id="vh_diagnosticindication">
+ <item-type>Switch</item-type>
+ <label>Diagnostic Indication</label>
+ <description>Diagnostic indication</description>
+ <state readOnly="true"/>
+ </channel-type>
+
+ <channel-type id="vh_controlsetpoint">
+ <item-type>Number:Dimensionless</item-type>
+ <label>Control Setpoint</label>
+ <description>Control setpoint</description>
+ <state readOnly="true"/>
+ </channel-type>
+
+ <channel-type id="vh_servicerequest">
+ <item-type>Switch</item-type>
+ <label>Service Request</label>
+ <description>Service request</description>
+ <state readOnly="true"/>
+ </channel-type>
+
+ <channel-type id="vh_exhaustfanfault">
+ <item-type>Switch</item-type>
+ <label>Exhaust Fan Fault</label>
+ <description>Exhaust fan fault</description>
+ <state readOnly="true"/>
+ </channel-type>
+
+ <channel-type id="vh_inletfanfault">
+ <item-type>Switch</item-type>
+ <label>Inlet Fan Fault</label>
+ <description>Inlet fan fault</description>
+ <state readOnly="true"/>
+ </channel-type>
+
+ <channel-type id="vh_frostprotection">
+ <item-type>Switch</item-type>
+ <label>Frost Protection</label>
+ <description>Frost protection</description>
+ <state readOnly="true"/>
+ </channel-type>
+
+ <channel-type id="vh_faultcode">
+ <item-type>Number:Dimensionless</item-type>
+ <label>Fault Code</label>
+ <description>Fault code</description>
+ <state readOnly="true"/>
+ </channel-type>
+
+ <channel-type id="vh_diagnosticcode">
+ <item-type>Number:Dimensionless</item-type>
+ <label>Diagnostic Code</label>
+ <description>Diagnostic code</description>
+ <state readOnly="true"/>
+ </channel-type>
+
+ <channel-type id="vh_systemtype">
+ <item-type>Number:Dimensionless</item-type>
+ <label>System Type</label>
+ <description>System type</description>
+ <state readOnly="true">
+ <options>
+ <option value="0">central exaust</option>
+ <option value="1">heat-recovery</option>
+ </options>
+ </state>
+ </channel-type>
+
+ <channel-type id="vh_bypass">
+ <item-type>Switch</item-type>
+ <label>Bypass</label>
+ <description>Bypass</description>
+ <state readOnly="true"/>
+ </channel-type>
+
+ <channel-type id="vh_speedcontrol">
+ <item-type>Number:Dimensionless</item-type>
+ <label>Speed Control</label>
+ <description>Speed control</description>
+ <state readOnly="true">
+ <options>
+ <option value="0">3-speed</option>
+ <option value="1">variable</option>
+ </options>
+ </state>
+ </channel-type>
+
+ <channel-type id="vh_memberid">
+ <item-type>Number:Dimensionless</item-type>
+ <label>Member ID</label>
+ <description>Member ID</description>
+ <state readOnly="true"/>
+ </channel-type>
+
+ <channel-type id="vh_openthermversion">
+ <item-type>Number:Dimensionless</item-type>
+ <label>OpenTherm Version</label>
+ <description>OpenTherm version</description>
+ <state readOnly="true"/>
+ </channel-type>
+
+ <channel-type id="vh_versiontype">
+ <item-type>Number:Dimensionless</item-type>
+ <label>Version Type</label>
+ <description>Version type</description>
+ <state readOnly="true"/>
+ </channel-type>
+
+ <channel-type id="vh_relativeventilation">
+ <item-type>Number:Dimensionless</item-type>
+ <label>Relative Ventilation</label>
+ <description>Relative ventilation position</description>
+ <state readOnly="true" pattern="%d %%"/>
+ </channel-type>
+
+ <channel-type id="vh_relativehumidity">
+ <item-type>Number:Dimensionless</item-type>
+ <label>Relative Humidity</label>
+ <description>Relative humidity exhaust air</description>
+ <state readOnly="true" pattern="%d %%"/>
+ </channel-type>
+
+ <channel-type id="vh_co2level">
+ <item-type>Number:Dimensionless</item-type>
+ <label>CO2 Level</label>
+ <description>CO2 level exhaust air</description>
+ <state readOnly="true" pattern="%d ppm"/>
+ </channel-type>
+
+ <channel-type id="vh_supplyinlettemp">
+ <item-type>Number:Temperature</item-type>
+ <label>Supply Inlet Temperature</label>
+ <description>Supply inlet temperature</description>
+ <state readOnly="true" pattern="%.1f %unit%"/>
+ </channel-type>
+
+ <channel-type id="vh_supplyoutlettemp">
+ <item-type>Number:Temperature</item-type>
+ <label>Supply Outlet Temperature</label>
+ <description>Supply outlet temperature</description>
+ <state readOnly="true" pattern="%.1f %unit%"/>
+ </channel-type>
+
+ <channel-type id="vh_exhaustinlettemp">
+ <item-type>Number:Temperature</item-type>
+ <label>Exhaust Inlet Temperature</label>
+ <description>Exhaust inlet temperature</description>
+ <state readOnly="true" pattern="%.1f %unit%"/>
+ </channel-type>
+
+ <channel-type id="vh_exhaustoutlettemp">
+ <item-type>Number:Temperature</item-type>
+ <label>Exhaust Outlet Temperature</label>
+ <description>Exhaust outlet temperature</description>
+ <state readOnly="true" pattern="%.1f %unit%"/>
+ </channel-type>
+
+ <channel-type id="vh_actualexhaustfanspeed">
+ <item-type>Number:Dimensionless</item-type>
+ <label>Actual Exhaust Fan Speed</label>
+ <description>Actual exhaust fan speed</description>
+ <state readOnly="true" pattern="%d rpm"/>
+ </channel-type>
+
+ <channel-type id="vh_actualinletfanspeed">
+ <item-type>Number:Dimensionless</item-type>
+ <label>Actual Inlet Fan Speed</label>
+ <description>Actual inlet fan speed</description>
+ <state readOnly="true" pattern="%d rpm"/>
+ </channel-type>
+
+ <channel-type id="vh_nominalventenable">
+ <item-type>Switch</item-type>
+ <label>Nominal Ventilation Value Transfer</label>
+ <description>Nominal ventilation value transfer enabled</description>
+ <state readOnly="true"/>
+ </channel-type>
+
+ <channel-type id="vh_nominalventrw">
+ <item-type>Number:Dimensionless</item-type>
+ <label>Nominal Ventilation Value</label>
+ <description>Nominal ventilation value</description>
+ <state readOnly="true">
+ <options>
+ <option value="0">read-only</option>
+ <option value="1">read/write</option>
+ </options>
+ </state>
+ </channel-type>
+
+ <channel-type id="vh_nominalventilationvalue">
+ <item-type>Number:Dimensionless</item-type>
+ <label>Nominal Ventilation Value</label>
+ <description>Nominal ventilation value</description>
+ <state readOnly="true" pattern="%d %%"/>
+ </channel-type>
+
+ <channel-type id="vh_filtercheck">
+ <item-type>Switch</item-type>
+ <label>Filter Check</label>
+ <description>Filter Check enabled</description>
+ <state readOnly="true"/>
+ </channel-type>
+
+ <channel-type id="vh_tspnumber">
+ <item-type>Number:Dimensionless</item-type>
+ <label>Transparent Slave Parameter Number</label>
+ <description>Number of transparent slave parameter entries</description>
+ <state readOnly="true"/>
+ </channel-type>
+
+ <channel-type id="vh_tspentry">
+ <item-type>Number:Dimensionless</item-type>
+ <label>Transparent Slave Parameter Entry</label>
+ <description>Transparent slave parameter entry</description>
+ <state readOnly="true"/>
+ </channel-type>
+
+ <channel-type id="vh_fhbnumber">
+ <item-type>Number:Dimensionless</item-type>
+ <label>Fault History Buffer Number</label>
+ <description>Number of fault history buffer entries</description>
+ <state readOnly="true"/>
+ </channel-type>
+
+ <channel-type id="vh_fhbentry">
+ <item-type>Number:Dimensionless</item-type>
+ <label>Fault History Buffer Entry</label>
+ <description>Fault history buffer entry</description>
+ <state readOnly="true"/>
+ </channel-type>
+
+ <channel-type id="vh_ventilationsetpoint">
+ <item-type>Number:Dimensionless</item-type>
+ <label>Ventilation Setpoint</label>
+ <description>Ventilation setpoint override</description>
+ <state readOnly="false" min="0" max="100" step="1"/>
</channel-type>
</thing:thing-descriptions>
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<thing:thing-descriptions bindingId="openthermgateway"
+ 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">
+ <bridge-type id="openthermgateway">
+ <label>OpenTherm Gateway</label>
+ <description>OpenTherm Gateway</description>
+ <channels>
+ <channel id="sendcommand" typeId="sendcommand"/>
+ </channels>
+ <properties>
+ <property name="version">2.2.0</property>
+ </properties>
+ <config-description-ref uri="thing-type:openthermgateway:openthermgateway"/>
+ </bridge-type>
+
+</thing:thing-descriptions>
+++ /dev/null
-<?xml version="1.0" encoding="UTF-8"?>
-<thing:thing-descriptions bindingId="openthermgateway"
- 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="otgw">
- <label>OpenTherm Gateway</label>
- <description>OpenTherm Gateway binding</description>
- <channels>
- <channel id="roomtemp" typeId="roomtemp"/>
- <channel id="roomsetpoint" typeId="roomsetpoint"/>
- <channel id="temperaturetemporary" typeId="temperaturetemporary"/>
- <channel id="temperatureconstant" typeId="temperatureconstant"/>
- <channel id="controlsetpoint" typeId="controlsetpoint"/>
- <channel id="controlsetpointrequested" typeId="controlsetpointrequested"/>
- <channel id="controlsetpointoverride" typeId="controlsetpointoverride"/>
- <channel id="controlsetpoint2" typeId="controlsetpoint2"/>
- <channel id="controlsetpoint2requested" typeId="controlsetpoint2requested"/>
- <channel id="controlsetpoint2override" typeId="controlsetpoint2override"/>
- <channel id="dhwtemp" typeId="dhwtemp"/>
- <channel id="tdhwset" typeId="tdhwset"/>
- <channel id="overridedhwsetpoint" typeId="overridedhwsetpoint"/>
- <channel id="flowtemp" typeId="flowtemp"/>
- <channel id="returntemp" typeId="returntemp"/>
- <channel id="outsidetemp" typeId="outsidetemp"/>
- <channel id="waterpressure" typeId="waterpressure"/>
- <channel id="ch_enable" typeId="ch_enable"/>
- <channel id="ch_enablerequested" typeId="ch_enablerequested"/>
- <channel id="ch_enableoverride" typeId="ch_enableoverride"/>
- <channel id="ch2_enable" typeId="ch2_enable"/>
- <channel id="ch2_enablerequested" typeId="ch2_enablerequested"/>
- <channel id="ch2_enableoverride" typeId="ch2_enableoverride"/>
- <channel id="ch_mode" typeId="ch_mode"/>
- <channel id="dhw_enable" typeId="dhw_enable"/>
- <channel id="dhw_mode" typeId="dhw_mode"/>
- <channel id="flame" typeId="flame"/>
- <channel id="modulevel" typeId="modulevel"/>
- <channel id="maxrelmdulevel" typeId="maxrelmdulevel"/>
- <channel id="fault" typeId="fault"/>
- <channel id="servicerequest" typeId="servicerequest"/>
- <channel id="lockout-reset" typeId="lockout-reset"/>
- <channel id="lowwaterpress" typeId="lowwaterpress"/>
- <channel id="gasflamefault" typeId="gasflamefault"/>
- <channel id="airpressfault" typeId="airpressfault"/>
- <channel id="waterovtemp" typeId="waterovtemp"/>
- <channel id="oemfaultcode" typeId="oemfaultcode"/>
- <channel id="unsuccessfulburnerstarts" typeId="unsuccessfulburnerstarts"/>
- <channel id="burnerstarts" typeId="burnerstarts"/>
- <channel id="chpumpstarts" typeId="chpumpstarts"/>
- <channel id="dhwpvstarts" typeId="dhwpvstarts"/>
- <channel id="dhwburnerstarts" typeId="dhwburnerstarts"/>
- <channel id="burnerhours" typeId="burnerhours"/>
- <channel id="chpumphours" typeId="chpumphours"/>
- <channel id="dhwpvhours" typeId="dhwpvhours"/>
- <channel id="dhwburnerhours" typeId="dhwburnerhours"/>
- <channel id="sendcommand" typeId="sendcommand"/>
- </channels>
- <properties>
- <property name="version">1.3.0</property>
- </properties>
- <config-description-ref uri="thing-type:openthermgateway:otgw"/>
- </thing-type>
-
-</thing:thing-descriptions>
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<thing:thing-descriptions bindingId="openthermgateway"
+ 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="ventilationheatrecovery">
+ <supported-bridge-type-refs>
+ <bridge-type-ref id="openthermgateway"/>
+ </supported-bridge-type-refs>
+ <label>Ventilation / Heat Recovery</label>
+ <description>Ventilation or Heat Recovery unit</description>
+ <channels>
+ <channel id="vh_ventilationenable" typeId="vh_ventilationenable"/>
+ <channel id="vh_bypassposition" typeId="vh_bypassposition"/>
+ <channel id="vh_bypassmode" typeId="vh_bypassmode"/>
+ <channel id="vh_freeventilationmode" typeId="vh_freeventilationmode"/>
+ <channel id="vh_faultindication" typeId="vh_faultindication"/>
+ <channel id="vh_ventilationmode" typeId="vh_ventilationmode"/>
+ <channel id="vh_bypassstatus" typeId="vh_bypassstatus"/>
+ <channel id="vh_bypassautomaticstatus" typeId="vh_bypassautomaticstatus"/>
+ <channel id="vh_freeventilationstatus" typeId="vh_freeventilationstatus"/>
+ <channel id="vh_filtercheck" typeId="vh_filtercheck"/>
+ <channel id="vh_diagnosticindication" typeId="vh_diagnosticindication"/>
+ <channel id="vh_controlsetpoint" typeId="vh_controlsetpoint"/>
+ <channel id="vh_servicerequest" typeId="vh_servicerequest"/>
+ <channel id="vh_exhaustfanfault" typeId="vh_exhaustfanfault"/>
+ <channel id="vh_inletfanfault" typeId="vh_inletfanfault"/>
+ <channel id="vh_frostprotection" typeId="vh_frostprotection"/>
+ <channel id="vh_faultcode" typeId="vh_faultcode"/>
+ <channel id="vh_diagnosticcode" typeId="vh_diagnosticcode"/>
+ <channel id="vh_systemtype" typeId="vh_systemtype"/>
+ <channel id="vh_bypass" typeId="vh_bypass"/>
+ <channel id="vh_speedcontrol" typeId="vh_speedcontrol"/>
+ <channel id="vh_memberid" typeId="vh_memberid"/>
+ <channel id="vh_openthermversion" typeId="vh_openthermversion"/>
+ <channel id="vh_versiontype" typeId="vh_versiontype"/>
+ <channel id="vh_relativeventilation" typeId="vh_relativeventilation"/>
+ <channel id="vh_relativehumidity" typeId="vh_relativehumidity"/>
+ <channel id="vh_co2level" typeId="vh_co2level"/>
+ <channel id="vh_supplyinlettemp" typeId="vh_supplyinlettemp"/>
+ <channel id="vh_supplyoutlettemp" typeId="vh_supplyoutlettemp"/>
+ <channel id="vh_exhaustinlettemp" typeId="vh_exhaustinlettemp"/>
+ <channel id="vh_exhaustoutlettemp" typeId="vh_exhaustoutlettemp"/>
+ <channel id="vh_actualexhaustfanspeed" typeId="vh_actualexhaustfanspeed"/>
+ <channel id="vh_actualinletfanspeed" typeId="vh_actualinletfanspeed"/>
+ <channel id="vh_nominalventenable" typeId="vh_nominalventenable"/>
+ <channel id="vh_nominalventrw" typeId="vh_nominalventrw"/>
+ <channel id="vh_nominalventilationvalue" typeId="vh_nominalventilationvalue"/>
+ <channel id="vh_ventilationsetpoint" typeId="vh_ventilationsetpoint"/>
+ <channel id="vh_tspnumber" typeId="vh_tspnumber"/>
+ <channel id="vh_tspentry" typeId="vh_tspentry"/>
+ <channel id="vh_fhbnumber" typeId="vh_fhbnumber"/>
+ <channel id="vh_fhbentry" typeId="vh_fhbentry"/>
+ </channels>
+ </thing-type>
+</thing:thing-descriptions>