]> git.basschouten.com Git - openhab-addons.git/commitdiff
[guntamatic] Initial contribution: Binding for Guntamatic Heating Systems (#12011)
authorMikeTheTux <44850211+MikeTheTux@users.noreply.github.com>
Tue, 11 Jan 2022 21:35:18 +0000 (22:35 +0100)
committerGitHub <noreply@github.com>
Tue, 11 Jan 2022 21:35:18 +0000 (22:35 +0100)
Signed-off-by: Michael Weger <weger.michael@gmx.net>
16 files changed:
CODEOWNERS
bom/openhab-addons/pom.xml
bundles/org.openhab.binding.guntamatic/NOTICE [new file with mode: 0644]
bundles/org.openhab.binding.guntamatic/README.md [new file with mode: 0644]
bundles/org.openhab.binding.guntamatic/pom.xml [new file with mode: 0644]
bundles/org.openhab.binding.guntamatic/src/main/feature/feature.xml [new file with mode: 0644]
bundles/org.openhab.binding.guntamatic/src/main/java/org/openhab/binding/guntamatic/internal/GuntamaticBindingConstants.java [new file with mode: 0644]
bundles/org.openhab.binding.guntamatic/src/main/java/org/openhab/binding/guntamatic/internal/GuntamaticChannelTypeProvider.java [new file with mode: 0644]
bundles/org.openhab.binding.guntamatic/src/main/java/org/openhab/binding/guntamatic/internal/GuntamaticConfiguration.java [new file with mode: 0644]
bundles/org.openhab.binding.guntamatic/src/main/java/org/openhab/binding/guntamatic/internal/GuntamaticHandler.java [new file with mode: 0644]
bundles/org.openhab.binding.guntamatic/src/main/java/org/openhab/binding/guntamatic/internal/GuntamaticHandlerFactory.java [new file with mode: 0644]
bundles/org.openhab.binding.guntamatic/src/main/resources/OH-INF/binding/binding.xml [new file with mode: 0644]
bundles/org.openhab.binding.guntamatic/src/main/resources/OH-INF/config/config.xml [new file with mode: 0644]
bundles/org.openhab.binding.guntamatic/src/main/resources/OH-INF/i18n/guntamatic.properties [new file with mode: 0644]
bundles/org.openhab.binding.guntamatic/src/main/resources/OH-INF/thing/thing-types.xml [new file with mode: 0644]
bundles/pom.xml

index 438150878bc276f644752c37ff76d2a0d8b3e3f0..ddca1888bb4e71d5a63b7fadb0ed5132c76be2fc 100644 (file)
 /bundles/org.openhab.binding.gpstracker/ @gbicskei
 /bundles/org.openhab.binding.gree/ @markus7017
 /bundles/org.openhab.binding.groheondus/ @FlorianSW
+/bundles/org.openhab.binding.guntamatic/ @MikeTheTux
 /bundles/org.openhab.binding.haassohnpelletstove/ @chingon007
 /bundles/org.openhab.binding.harmonyhub/ @digitaldan
 /bundles/org.openhab.binding.haywardomnilogic/ @matchews
index 85c2050235f01335404592492af1c8aecbd182de..f71abb96ae7d119a763face431fb743e7d270fde 100644 (file)
       <artifactId>org.openhab.binding.groheondus</artifactId>
       <version>${project.version}</version>
     </dependency>
+    <dependency>
+      <groupId>org.openhab.addons.bundles</groupId>
+      <artifactId>org.openhab.binding.guntamatic</artifactId>
+      <version>${project.version}</version>
+    </dependency>
     <dependency>
       <groupId>org.openhab.addons.bundles</groupId>
       <artifactId>org.openhab.binding.haassohnpelletstove</artifactId>
diff --git a/bundles/org.openhab.binding.guntamatic/NOTICE b/bundles/org.openhab.binding.guntamatic/NOTICE
new file mode 100644 (file)
index 0000000..38d625e
--- /dev/null
@@ -0,0 +1,13 @@
+This content is produced and maintained by the openHAB project.
+
+* Project home: https://www.openhab.org
+
+== Declared Project Licenses
+
+This program and the accompanying materials are made available under the terms
+of the Eclipse Public License 2.0 which is available at
+https://www.eclipse.org/legal/epl-2.0/.
+
+== Source Code
+
+https://github.com/openhab/openhab-addons
diff --git a/bundles/org.openhab.binding.guntamatic/README.md b/bundles/org.openhab.binding.guntamatic/README.md
new file mode 100644 (file)
index 0000000..3fb9a05
--- /dev/null
@@ -0,0 +1,362 @@
+# Guntamatic Binding
+
+The Guntamatic Binding can be used to monitor and control [Guntamatic Heating Systems](https://www.guntamatic.com/en/).
+
+## Supported Things
+
+The Guntamatic Binding was developed and tested using Guntamatic Biostar 15kW Pellets Heating System, running Firmware 3.2d.
+It should work for all other Guntamatic Heating Systems as well, that support the same web interface.
+
+## Things
+
+Guntamatic Heating Systems supported as Thing Types:
+
+| Name          | Thing Type ID | Status                            |
+|---------------|---------------|-----------------------------------|
+| Biostar       | `biostar`     | tested via 15kW, firmware 3.2d    |
+| Powerchip     | `powerchip`   | untested                          |
+| Powercorn     | `powercorn`   | untested                          |
+| Biocom        | `biocom`      | untested                          |
+| Pro           | `pro`         | untested                          |
+| Therm         | `therm`       | untested                          |
+
+### Thing Configuration
+
+| Parameter        | Description                                                                 | Default         |
+|------------------|-----------------------------------------------------------------------------|-----------------|
+| `hostname`         | Hostname or IP address of the Guntamatic Heating System                   |                 |
+| `key`              | Optional, but required to read protected parameters and to control the Guntamatic Heating System.<br/>The key needs to be requested from Guntamatic support, e.g. via https://www.guntamatic.com/en/contact/.                                        |                 |
+| `refreshInterval` | Interval the Guntamatic Heating System is polled in seconds                | `60`            |
+| `encoding`         | Code page used by the Guntamatic Heating System                           | `windows-1252`  |
+
+### Properties
+
+| Property            | Description                                                   |
+|---------------------|---------------------------------------------------------------|
+| `extraWwHeat`       | Parameter used by `controlExtraWwHeat` channels               |
+| `boilerApproval`    | Parameter used by `controlBoilerApproval` channel             |
+| `heatCircProgram`   | Parameter used by `controlHeatCircProgram` channels           |
+| `program`           | Parameter used by `controlProgram` channel                    |
+| `wwHeat`            | Parameter used by `controlWwHeat` channels                    |
+
+## Channels
+
+### Control Channels
+
+The Guntamatic Heating System can be controlled using the following channels:
+
+|      Channel             |   Description                                             | Type  |       Unit    |       Security Access Level   | ReadOnly | Advanced |
+|-----------------------|-----------------------------------------------------------|-------|:---------:|:-------------------------:|:--------:|:--------:|
+|      `controlBoilerApproval` |       Set Boiler Approval (`AUTO`, `OFF`, `ON`)       |       `String`        |               |       🔐 W1 |       R/W     |       true    |
+|      `controlProgram`        |       Set Program (`OFF`, `NORMAL`, `WARMWATER`, `MANUAL`)    |       `String`        |               |       🔐 W1 |       R/W     |       false   |
+|      `controlHeatCircProgram0`       |       Set Heat Circle 0 Program (`OFF`, `NORMAL`, `HEAT`, `LOWER`)    |       `String`        |               |       🔐 W1 |       R/W     |       true    |
+|      `controlHeatCircProgram1`       |       Set Heat Circle 1 Program (`OFF`, `NORMAL`, `HEAT`, `LOWER`)    |       `String`        |               |       🔐 W1 |       R/W     |       true    |
+|      `controlHeatCircProgram2`       |       Set Heat Circle 2 Program (`OFF`, `NORMAL`, `HEAT`, `LOWER`)    |       `String`        |               |       🔐 W1 |       R/W     |       true    |
+|      `controlHeatCircProgram3`       |       Set Heat Circle 3 Program (`OFF`, `NORMAL`, `HEAT`, `LOWER`)    |       `String`        |               |       🔐 W1 |       R/W     |       true    |
+|      `controlHeatCircProgram4`       |       Set Heat Circle 4 Program (`OFF`, `NORMAL`, `HEAT`, `LOWER`)    |       `String`        |               |       🔐 W1 |       R/W     |       true    |
+|      `controlHeatCircProgram5`       |       Set Heat Circle 5 Program (`OFF`, `NORMAL`, `HEAT`, `LOWER`)    |       `String`        |               |       🔐 W1 |       R/W     |       true    |
+|      `controlHeatCircProgram6`       |       Set Heat Circle 6 Program (`OFF`, `NORMAL`, `HEAT`, `LOWER`)    |       `String`        |               |       🔐 W1 |       R/W     |       true    |
+|      `controlHeatCircProgram7`       |       Set Heat Circle 7 Program (`OFF`, `NORMAL`, `HEAT`, `LOWER`)    |       `String`        |               |       🔐 W1 |       R/W     |       true    |
+|      `controlHeatCircProgram8`       |       Set Heat Circle 8 Program (`OFF`, `NORMAL`, `HEAT`, `LOWER`)    |       `String`        |               |       🔐 W1 |       R/W     |       true    |
+|      `controlWwHeat0`        |       Trigger Warm Water Circle 0 (`RECHARGE`)        |       `String`        |               |       🔐 W1 |       R/W     |       true    |
+|      `controlWwHeat1`        |       Trigger Warm Water Circle 1 (`RECHARGE`)        |       `String`        |               |       🔐 W1 |       R/W     |       true    |
+|      `controlWwHeat2`        |       Trigger Warm Water Circle 2 (`RECHARGE`)        |       `String`        |               |       🔐 W1 |       R/W     |       true    |
+|      `controlExtraWwHeat0`   |       Trigger Extra Warm Water Circle 0 (`RECHARGE`)  |       `String`        |               |       🔐 W1 |       R/W     |       true    |
+|      `controlExtraWwHeat1`   |       Trigger Extra Warm Water Circle 1 (`RECHARGE`)  |       `String`        |               |       🔐 W1 |       R/W     |       true    |
+|      `controlExtraWwHeat2`   |       Trigger Extra Warm Water Circle 2 (`RECHARGE`)  |       `String`        |               |       🔐 W1 |       R/W     |       true    |
+
+#### Response of Control Channels
+
+- `{"ack":"confirmation message"}` ... in case of success
+- `{"err":"error message"}`        ... in case of error
+
+### Monitoring Channels
+
+The Binding dynamically generates Channels, derived from the data provided from the actual Guntamatic Heating System.
+
+Example list of Channels using a Guntamatic Biostar 15kW Pellets Heating System running firmware 3.2d and Guntamatic System Language configured to English:
+
+|      Channel             |   Description                                             | Type  |       Unit    |       Security Access Level   | ReadOnly | Advanced |
+|-----------------------|-----------------------------------------------------------|-------|:---------:|:-------------------------:|:--------:|:--------:|
+|      `running`       |       Running |       `String`        |               |       🔓 W0 |       R/O     |       false   |
+|      `outsideTemp`   |       Outside Temp.   |       `Number:Temperature`    |       `°C`   |       🔓 W0 |       R/O     |       false   |
+|      `blrTargetTemp` |       Blr.Target Temp |       `Number:Temperature`    |       `°C`   |       🔐 W1 |       R/O     |       false   |
+|      `boilerTemperature`     |       Boiler Temperature      |       `Number:Temperature`    |       `°C`   |       🔓 W0 |       R/O     |       false   |
+|      `flueGasUtilisation`    |       Flue gas utilisation    |       `Number:Dimensionless`  |       `%`     |       🔐 W1 |       R/O     |       false   |
+|      `output`        |       Output  |       `Number:Dimensionless`  |       `%`     |       🔓 W0 |       R/O     |       false   |
+|      `returnTemp`    |       Return temp     |       `Number:Temperature`    |       `°C`   |       🔐 W1 |       R/O     |       false   |
+|      `co2Target`     |       CO2 Target      |       `Number:Dimensionless`  |       `%`     |       🔐 W1 |       R/O     |       false   |
+|      `co2Content`    |       CO2 Content     |       `Number:Dimensionless`  |       `%`     |       🔓 W0 |       R/O     |       false   |
+|      `returnTempTarget`      |       Return temp target      |       `Number:Temperature`    |       `°C`   |       🔐 W1 |       R/O     |       false   |
+|      `statusCode`    |       Status code     |       `Number`        |               |       🔐 W1 |       R/O     |       false   |
+|      `efficiency`    |       Efficiency      |       `Number:Dimensionless`  |       `%`     |       🔐 W1 |       R/O     |       false   |
+|      `extractorSystem`       |       Extractor System        |       `Number:Dimensionless`  |       `%`     |       🔓 W0 |       R/O     |       false   |
+|      `feedTurbine`   |       Feed Turbine    |       `String`        |               |       🔐 W1 |       R/O     |       false   |
+|      `dischargeMotor`        |       Discharge motor |       `Number:Dimensionless`  |       `%`     |       🔓 W0 |       R/O     |       false   |
+|      `g1Target`      |       G1 Target       |       `Number:Dimensionless`  |       `%`     |       🔓 W0 |       R/O     |       false   |
+|      `bufferTop`     |       Buffer Top      |       `Number:Temperature`    |       `°C`   |       🔓 W0 |       R/O     |       false   |
+|      `bufferMid`     |       Buffer Mid      |       `Number:Temperature`    |       `°C`   |       🔓 W0 |       R/O     |       false   |
+|      `bufferBtm`     |       Buffer Btm      |       `Number:Temperature`    |       `°C`   |       🔓 W0 |       R/O     |       false   |
+|      `pumpHp0`       |       Pump HP0        |       `Switch`        |               |       🔓 W0 |       R/O     |       false   |
+|      `dhw0`  |       DHW 0   |       `Number:Temperature`    |       `°C`   |       🔓 W0 |       R/O     |       false   |
+|      `bDhw0` |       B DHW 0 |       `Switch`        |               |       🔓 W0 |       R/O     |       false   |
+|      `dhw1`  |       DHW 1   |       `Number:Temperature`    |       `°C`   |       🔓 W0 |       R/O     |       false   |
+|      `bDhw1` |       B DHW 1 |       `Switch`        |               |       🔓 W0 |       R/O     |       false   |
+|      `dhw2`  |       DHW 2   |       `Number:Temperature`    |       `°C`   |       🔓 W0 |       R/O     |       false   |
+|      `bDhw2` |       B DHW 2 |       `Switch`        |               |       🔓 W0 |       R/O     |       false   |
+|      `roomTempHc0`   |       Room Temp:HC 0  |       `Number:Temperature`    |       `°C`   |       🔓 W0 |       R/O     |       false   |
+|      `heatCirc0`     |       Heat Circ. 0    |       `Switch`        |               |       🔓 W0 |       R/O     |       false   |
+|      `roomTempHc1`   |       Room Temp:HC 1  |       `Number:Temperature`    |       `°C`   |       🔓 W0 |       R/O     |       false   |
+|      `flowTarget1`   |       Flow Target 1   |       `Number:Temperature`    |       `°C`   |       🔐 W1 |       R/O     |       false   |
+|      `flowIs1`       |       Flow is 1       |       `Number:Temperature`    |       `°C`   |       🔓 W0 |       R/O     |       false   |
+|      `mixer1`        |       Mixer 1 |       `String`        |               |       🔐 W1 |       R/O     |       false   |
+|      `heatCirc1`     |       Heat Circ. 1    |       `Switch`        |               |       🔐 W1 |       R/O     |       false   |
+|      `roomTempHc2`   |       Room Temp:HC 2  |       `Number:Temperature`    |       `°C`   |       🔓 W0 |       R/O     |       false   |
+|      `flowTarget2`   |       Flow Target 2   |       `Number:Temperature`    |       `°C`   |       🔐 W1 |       R/O     |       false   |
+|      `flowIs2`       |       Flow is 2       |       `Number:Temperature`    |       `°C`   |       🔓 W0 |       R/O     |       false   |
+|      `mixer2`        |       Mixer 2 |       `String`        |               |       🔐 W1 |       R/O     |       false   |
+|      `heatCirc2`     |       Heat Circ. 2    |       `Switch`        |               |       🔓 W0 |       R/O     |       false   |
+|      `roomTempHc3`   |       Room Temp:HC 3  |       `Number:Temperature`    |       `°C`   |       🔓 W0 |       R/O     |       false   |
+|      `heatCirc3`     |       Heat Circ. 3    |       `Switch`        |               |       🔓 W0 |       R/O     |       false   |
+|      `roomTempHc4`   |       Room Temp:HC 4  |       `Number:Temperature`    |       `°C`   |       🔓 W0 |       R/O     |       false   |
+|      `flowTarget4`   |       Flow Target 4   |       `Number:Temperature`    |       `°C`   |       🔐 W1 |       R/O     |       false   |
+|      `flowIs4`       |       Flow is 4       |       `Number:Temperature`    |       `°C`   |       🔓 W0 |       R/O     |       false   |
+|      `mixer4`        |       Mixer 4 |       `String`        |               |       🔐 W1 |       R/O     |       false   |
+|      `heatCirc4`     |       Heat Circ. 4    |       `Switch`        |               |       🔓 W0 |       R/O     |       false   |
+|      `roomTempHc5`   |       Room Temp:HC 5  |       `Number:Temperature`    |       `°C`   |       🔓 W0 |       R/O     |       false   |
+|      `flowTarget5`   |       Flow Target 5   |       `Number:Temperature`    |       `°C`   |       🔐 W1 |       R/O     |       false   |
+|      `flowIs5`       |       Flow is 5       |       `Number:Temperature`    |       `°C`   |       🔓 W0 |       R/O     |       false   |
+|      `mixer5`        |       Mixer 5 |       `String`        |               |       🔐 W1 |       R/O     |       false   |
+|      `heatCirc5`     |       Heat Circ. 5    |       `Switch`        |               |       🔓 W0 |       R/O     |       false   |
+|      `roomTempHc6`   |       Room Temp:HC 6  |       `Number:Temperature`    |       `°C`   |       🔓 W0 |       R/O     |       false   |
+|      `heatCirc6`     |       Heat Circ. 6    |       `Switch`        |               |       🔓 W0 |       R/O     |       false   |
+|      `roomTempHc7`   |       Room Temp:HC 7  |       `Number:Temperature`    |       `°C`   |       🔓 W0 |       R/O     |       false   |
+|      `flowTarget7`   |       Flow Target 7   |       `Number:Temperature`    |       `°C`   |       🔐 W1 |       R/O     |       false   |
+|      `flowIs7`       |       Flow is 7       |       `Number:Temperature`    |       `°C`   |       🔓 W0 |       R/O     |       false   |
+|      `mixer7`        |       Mixer 7 |       `String`        |               |       🔐 W1 |       R/O     |       false   |
+|      `heatCirc7`     |       Heat Circ. 7    |       `Switch`        |               |       🔓 W0 |       R/O     |       false   |
+|      `roomTempHc8`   |       Room Temp:HC 8  |       `Number:Temperature`    |       `°C`   |       🔓 W0 |       R/O     |       false   |
+|      `flowTarget8`   |       Flow Target 8   |       `Number:Temperature`    |       `°C`   |       🔐 W1 |       R/O     |       false   |
+|      `flowIs8`       |       Flow is 8       |       `Number:Temperature`    |       `°C`   |       🔓 W0 |       R/O     |       false   |
+|      `mixer8`        |       Mixer 8 |       `String`        |               |       🔐 W1 |       R/O     |       false   |
+|      `heatCirc8`     |       Heat Circ. 8    |       `Switch`        |               |       🔓 W0 |       R/O     |       false   |
+|      `fuelLevel`     |       Fuel Level      |       `String`        |               |       🔐 W1 |       R/O     |       false   |
+|      `stb`   |       STB     |       `String`        |               |       🔐 W1 |       R/O     |       false   |
+|      `tks`   |       TKS     |       `String`        |               |       🔐 W1 |       R/O     |       false   |
+|      `boilerApproval`        |       Boiler approval |       `Switch`        |               |       🔐 W1 |       R/O     |       false   |
+|      `programme`     |       Programme       |       `String`        |               |       🔓 W0 |       R/O     |       false   |
+|      `programHc0`    |       Program HC0     |       `String`        |               |       🔓 W0 |       R/O     |       false   |
+|      `programHc1`    |       Program HC1     |       `String`        |               |       🔓 W0 |       R/O     |       false   |
+|      `programHc2`    |       Program HC2     |       `String`        |               |       🔓 W0 |       R/O     |       false   |
+|      `programHc3`    |       Program HC3     |       `String`        |               |       🔓 W0 |       R/O     |       false   |
+|      `programHc4`    |       Program HC4     |       `String`        |               |       🔓 W0 |       R/O     |       false   |
+|      `programHc5`    |       Program HC5     |       `String`        |               |       🔓 W0 |       R/O     |       false   |
+|      `programHc6`    |       Program HC6     |       `String`        |               |       🔓 W0 |       R/O     |       false   |
+|      `programHc7`    |       Program HC7     |       `String`        |               |       🔓 W0 |       R/O     |       false   |
+|      `programHc8`    |       Program HC8     |       `String`        |               |       🔓 W0 |       R/O     |       false   |
+|      `interuption0`  |       Interuption 0   |       `String`        |               |       🔓 W0 |       R/O     |       false   |
+|      `interuption1`  |       Interuption 1   |       `String`        |               |       🔓 W0 |       R/O     |       false   |
+|      `serial`        |       Serial  |       `Number`        |               |       🔓 W0 |       R/O     |       false   |
+|      `version`       |       Version |       `String`        |               |       🔓 W0 |       R/O     |       false   |
+|      `runningTime`   |       Running Time    |       `Number:Time`   |       `h`     |       🔓 W0 |       R/O     |       false   |
+|      `serviceHrs`    |       Service Hrs     |       `Number:Time`   |       `d`     |       🔓 W0 |       R/O     |       false   |
+|      `emptyAshIn`    |       Empty ash in    |       `Number:Time`   |       `h`     |       🔓 W0 |       R/O     |       false   |
+|      `flowIs0`       |       Flow is 0       |       `Number:Temperature`    |       `°C`   |       🔓 W0 |       R/O     |       false   |
+|      `flowIs3`       |       Flow is 3       |       `Number:Temperature`    |       `°C`   |       🔓 W0 |       R/O     |       false   |
+|      `flowIs6`       |       Flow is 6       |       `Number:Temperature`    |       `°C`   |       🔓 W0 |       R/O     |       false   |
+|      `fuelCounter`   |       Fuel counter    |       `Number:Volume` |       `m³`   |       🔐 W1 |       R/O     |       false   |
+|      `bufferLoad`    |       Buffer load.    |       `Number:Dimensionless`  |       `%`     |       🔓 W0 |       R/O     |       false   |
+|      `bufferTop0`    |       Buffer Top 0    |       `Number:Temperature`    |       `°C`   |       🔐 W1 |       R/O     |       false   |
+|      `bufferBtm0`    |       Buffer Btm 0    |       `Number:Temperature`    |       `°C`   |       🔐 W1 |       R/O     |       false   |
+|      `bufferTop1`    |       Buffer Top 1    |       `Number:Temperature`    |       `°C`   |       🔐 W1 |       R/O     |       false   |
+|      `bufferBtm1`    |       Buffer Btm 1    |       `Number:Temperature`    |       `°C`   |       🔐 W1 |       R/O     |       false   |
+|      `bufferTop2`    |       Buffer Top 2    |       `Number:Temperature`    |       `°C`   |       🔐 W1 |       R/O     |       false   |
+|      `bufferBtm2`    |       Buffer Btm 2    |       `Number:Temperature`    |       `°C`   |       🔐 W1 |       R/O     |       false   |
+|      `bExtraWw0`     |       B extra-WW. 0   |       `Switch`        |               |       🔐 W1 |       R/O     |       false   |
+|      `bExtraWw1`     |       B extra-WW. 1   |       `Switch`        |               |       🔐 W1 |       R/O     |       false   |
+|      `bExtraWw2`     |       B extra-WW. 2   |       `Switch`        |               |       🔐 W1 |       R/O     |       false   |
+|      `auxiliaryPump0`        |       Auxiliary pump 0        |       `Switch`        |               |       🔐 W1 |       R/O     |       false   |
+|      `auxiliaryPump1`        |       Auxiliary pump 1        |       `Switch`        |               |       🔐 W1 |       R/O     |       false   |
+|      `auxiliaryPump2`        |       Auxiliary pump 2        |       `Switch`        |               |       🔐 W1 |       R/O     |       false   |
+|      `boilersConditionNo`    |       Boiler´s condition no. |       `String`        |               |       🔐 W1 |       R/O     |       false   |
+|      `bufferT5`      |       Buffer T5       |       `Number:Temperature`    |       `°C`   |       🔓 W0 |       R/O     |       false   |
+|      `bufferT6`      |       Buffer T6       |       `Number:Temperature`    |       `°C`   |       🔓 W0 |       R/O     |       false   |
+|      `bufferT7`      |       Buffer T7       |       `Number:Temperature`    |       `°C`   |       🔓 W0 |       R/O     |       false   |
+|      `extraWw0`      |       Extra-WW. 0     |       `Number:Temperature`    |       `°C`   |       🔓 W0 |       R/O     |       false   |
+|      `extraWw1`      |       Extra-WW. 1     |       `Number:Temperature`    |       `°C`   |       🔓 W0 |       R/O     |       false   |
+|      `extraWw2`      |       Extra-WW. 2     |       `Number:Temperature`    |       `°C`   |       🔓 W0 |       R/O     |       false   |
+|      `grate` |       Grate   |       `Number:Dimensionless`  |       `%`     |       🔓 W0 |       R/O     |       false   |
+
+#### Security Access Levels
+
+- 🔓 W0 ... Open
+- 🔐 W1 ... End Customer Key
+- 🔒 W2 ... Service Partner
+
+## Full Example
+
+**Thing File**
+
+```java
+Thing   guntamatic:biostar:mybiostar   "Guntamatic Biostar"    [ hostname="192.168.1.100", key="0123456789ABCDEF0123456789ABCDEF0123", refreshInterval=60, encoding="windows-1252" ]
+```
+
+**Item File**
+
+```java
+String                 Biostar_ControlBoilerApproval   "Set Boiler Approval"                   { channel="guntamatic:biostar:mybiostar:controlBoilerApproval" }
+String                 Biostar_ControlProgram          "Set Program"                           { channel="guntamatic:biostar:mybiostar:controlProgram" }
+String                 Biostar_ControlHeatCircProgram0 "Set Heat Circle 0 Program"             { channel="guntamatic:biostar:mybiostar:controlHeatCircProgram0" }
+String                 Biostar_ControlHeatCircProgram1 "Set Heat Circle 1 Program"             { channel="guntamatic:biostar:mybiostar:controlHeatCircProgram1" }
+String                 Biostar_ControlHeatCircProgram2 "Set Heat Circle 2 Program"             { channel="guntamatic:biostar:mybiostar:controlHeatCircProgram2" }
+String                 Biostar_ControlHeatCircProgram3 "Set Heat Circle 3 Program"             { channel="guntamatic:biostar:mybiostar:controlHeatCircProgram3" }
+String                 Biostar_ControlHeatCircProgram4 "Set Heat Circle 4 Program"             { channel="guntamatic:biostar:mybiostar:controlHeatCircProgram4" }
+String                 Biostar_ControlHeatCircProgram5 "Set Heat Circle 5 Program"             { channel="guntamatic:biostar:mybiostar:controlHeatCircProgram5" }
+String                 Biostar_ControlHeatCircProgram6 "Set Heat Circle 6 Program"             { channel="guntamatic:biostar:mybiostar:controlHeatCircProgram6" }
+String                 Biostar_ControlHeatCircProgram7 "Set Heat Circle 7 Program"             { channel="guntamatic:biostar:mybiostar:controlHeatCircProgram7" }
+String                 Biostar_ControlHeatCircProgram8 "Set Heat Circle 8 Program"             { channel="guntamatic:biostar:mybiostar:controlHeatCircProgram8" }
+String                 Biostar_ControlWwHeat0          "Trigger Warm Water Circle 0"           { channel="guntamatic:biostar:mybiostar:controlWwHeat0" }
+String                 Biostar_ControlWwHeat1          "Trigger Warm Water Circle 1"           { channel="guntamatic:biostar:mybiostar:controlWwHeat1" }
+String                 Biostar_ControlWwHeat2          "Trigger Warm Water Circle 2"           { channel="guntamatic:biostar:mybiostar:controlWwHeat2" }
+String                 Biostar_ControlExtraWwHeat0     "Trigger Extra Warm Water Circle 0"     { channel="guntamatic:biostar:mybiostar:controlExtraWwHeat0" }
+String                 Biostar_ControlExtraWwHeat1     "Trigger Extra Warm Water Circle 1"     { channel="guntamatic:biostar:mybiostar:controlExtraWwHeat1" }
+String                 Biostar_ControlExtraWwHeat2     "Trigger Extra Warm Water Circle 2"     { channel="guntamatic:biostar:mybiostar:controlExtraWwHeat2" }
+String                 Biostar_Running                 "Running"                               { channel="guntamatic:biostar:mybiostar:running" }
+Number:Temperature     Biostar_OutsideTemp             "Outside Temp."                         { channel="guntamatic:biostar:mybiostar:outsideTemp" }
+Number:Temperature     Biostar_BlrTargetTemp           "Blr.Target Temp"                       { channel="guntamatic:biostar:mybiostar:blrTargetTemp" }
+Number:Temperature     Biostar_BoilerTemperature       "Boiler Temperature"                    { channel="guntamatic:biostar:mybiostar:boilerTemperature" }
+Number:Dimensionless   Biostar_FlueGasUtilisation      "Flue gas utilisation"                  { channel="guntamatic:biostar:mybiostar:flueGasUtilisation" }
+Number:Dimensionless   Biostar_Output                  "Output"                                { channel="guntamatic:biostar:mybiostar:output" }
+Number:Temperature     Biostar_ReturnTemp              "Return temp"                           { channel="guntamatic:biostar:mybiostar:returnTemp" }
+Number:Dimensionless   Biostar_Co2Target               "CO2 Target"                            { channel="guntamatic:biostar:mybiostar:co2Target" }
+Number:Dimensionless   Biostar_Co2Content              "CO2 Content"                           { channel="guntamatic:biostar:mybiostar:co2Content" }
+Number:Temperature     Biostar_ReturnTempTarget        "Return temp target"                    { channel="guntamatic:biostar:mybiostar:returnTempTarget" }
+Number                 Biostar_StatusCode              "Status code"                           { channel="guntamatic:biostar:mybiostar:statusCode" }
+Number:Dimensionless   Biostar_Efficiency              "Efficiency"                            { channel="guntamatic:biostar:mybiostar:efficiency" }
+Number:Dimensionless   Biostar_ExtractorSystem         "Extractor System"                      { channel="guntamatic:biostar:mybiostar:extractorSystem" }
+String                 Biostar_FeedTurbine             "Feed Turbine"                          { channel="guntamatic:biostar:mybiostar:feedTurbine" }
+Number:Dimensionless   Biostar_DischargeMotor          "Discharge motor"                       { channel="guntamatic:biostar:mybiostar:dischargeMotor" }
+Number:Dimensionless   Biostar_G1Target                "G1 Target"                             { channel="guntamatic:biostar:mybiostar:g1Target" }
+Number:Temperature     Biostar_BufferTop               "Buffer Top"                            { channel="guntamatic:biostar:mybiostar:bufferTop" }
+Number:Temperature     Biostar_BufferMid               "Buffer Mid"                            { channel="guntamatic:biostar:mybiostar:bufferMid" }
+Number:Temperature     Biostar_BufferBtm               "Buffer Btm"                            { channel="guntamatic:biostar:mybiostar:bufferBtm" }
+Switch                 Biostar_PumpHp0                 "Pump HP0"                              { channel="guntamatic:biostar:mybiostar:pumpHp0" }
+Number:Temperature     Biostar_Dhw0                    "DHW 0"                                 { channel="guntamatic:biostar:mybiostar:dhw0" }
+Switch                 Biostar_BDhw0                   "B DHW 0"                               { channel="guntamatic:biostar:mybiostar:bDhw0" }
+Number:Temperature     Biostar_Dhw1                    "DHW 1"                                 { channel="guntamatic:biostar:mybiostar:dhw1" }
+Switch                 Biostar_BDhw1                   "B DHW 1"                               { channel="guntamatic:biostar:mybiostar:bDhw1" }
+Number:Temperature     Biostar_Dhw2                    "DHW 2"                                 { channel="guntamatic:biostar:mybiostar:dhw2" }
+Switch                 Biostar_BDhw2                   "B DHW 2"                               { channel="guntamatic:biostar:mybiostar:bDhw2" }
+Number:Temperature     Biostar_RoomTempHc0             "Room Temp:HC 0"                        { channel="guntamatic:biostar:mybiostar:roomTempHc0" }
+Switch                 Biostar_HeatCirc0               "Heat Circ. 0"                          { channel="guntamatic:biostar:mybiostar:heatCirc0" }
+Number:Temperature     Biostar_RoomTempHc1             "Room Temp:HC 1"                        { channel="guntamatic:biostar:mybiostar:roomTempHc1" }
+Number:Temperature     Biostar_FlowTarget1             "Flow Target 1"                         { channel="guntamatic:biostar:mybiostar:flowTarget1" }
+Number:Temperature     Biostar_FlowIs1                 "Flow is 1"                             { channel="guntamatic:biostar:mybiostar:flowIs1" }
+String                 Biostar_Mixer1                  "Mixer 1"                               { channel="guntamatic:biostar:mybiostar:mixer1" }
+Switch                 Biostar_HeatCirc1               "Heat Circ. 1"                          { channel="guntamatic:biostar:mybiostar:heatCirc1" }
+Number:Temperature     Biostar_RoomTempHc2             "Room Temp:HC 2"                        { channel="guntamatic:biostar:mybiostar:roomTempHc2" }
+Number:Temperature     Biostar_FlowTarget2             "Flow Target 2"                         { channel="guntamatic:biostar:mybiostar:flowTarget2" }
+Number:Temperature     Biostar_FlowIs2                 "Flow is 2"                             { channel="guntamatic:biostar:mybiostar:flowIs2" }
+String                 Biostar_Mixer2                  "Mixer 2"                               { channel="guntamatic:biostar:mybiostar:mixer2" }
+Switch                 Biostar_HeatCirc2               "Heat Circ. 2"                          { channel="guntamatic:biostar:mybiostar:heatCirc2" }
+Number:Temperature     Biostar_RoomTempHc3             "Room Temp:HC 3"                        { channel="guntamatic:biostar:mybiostar:roomTempHc3" }
+Switch                 Biostar_HeatCirc3               "Heat Circ. 3"                          { channel="guntamatic:biostar:mybiostar:heatCirc3" }
+Number:Temperature     Biostar_RoomTempHc4             "Room Temp:HC 4"                        { channel="guntamatic:biostar:mybiostar:roomTempHc4" }
+Number:Temperature     Biostar_FlowTarget4             "Flow Target 4"                         { channel="guntamatic:biostar:mybiostar:flowTarget4" }
+Number:Temperature     Biostar_FlowIs4                 "Flow is 4"                             { channel="guntamatic:biostar:mybiostar:flowIs4" }
+String                 Biostar_Mixer4                  "Mixer 4"                               { channel="guntamatic:biostar:mybiostar:mixer4" }
+Switch                 Biostar_HeatCirc4               "Heat Circ. 4"                          { channel="guntamatic:biostar:mybiostar:heatCirc4" }
+Number:Temperature     Biostar_RoomTempHc5             "Room Temp:HC 5"                        { channel="guntamatic:biostar:mybiostar:roomTempHc5" }
+Number:Temperature     Biostar_FlowTarget5             "Flow Target 5"                         { channel="guntamatic:biostar:mybiostar:flowTarget5" }
+Number:Temperature     Biostar_FlowIs5                 "Flow is 5"                             { channel="guntamatic:biostar:mybiostar:flowIs5" }
+String                 Biostar_Mixer5                  "Mixer 5"                               { channel="guntamatic:biostar:mybiostar:mixer5" }
+Switch                 Biostar_HeatCirc5               "Heat Circ. 5"                          { channel="guntamatic:biostar:mybiostar:heatCirc5" }
+Number:Temperature     Biostar_RoomTempHc6             "Room Temp:HC 6"                        { channel="guntamatic:biostar:mybiostar:roomTempHc6" }
+Switch                 Biostar_HeatCirc6               "Heat Circ. 6"                          { channel="guntamatic:biostar:mybiostar:heatCirc6" }
+Number:Temperature     Biostar_RoomTempHc7             "Room Temp:HC 7"                        { channel="guntamatic:biostar:mybiostar:roomTempHc7" }
+Number:Temperature     Biostar_FlowTarget7             "Flow Target 7"                         { channel="guntamatic:biostar:mybiostar:flowTarget7" }
+Number:Temperature     Biostar_FlowIs7                 "Flow is 7"                             { channel="guntamatic:biostar:mybiostar:flowIs7" }
+String                 Biostar_Mixer7                  "Mixer 7"                               { channel="guntamatic:biostar:mybiostar:mixer7" }
+Switch                 Biostar_HeatCirc7               "Heat Circ. 7"                          { channel="guntamatic:biostar:mybiostar:heatCirc7" }
+Number:Temperature     Biostar_RoomTempHc8             "Room Temp:HC 8"                        { channel="guntamatic:biostar:mybiostar:roomTempHc8" }
+Number:Temperature     Biostar_FlowTarget8             "Flow Target 8"                         { channel="guntamatic:biostar:mybiostar:flowTarget8" }
+Number:Temperature     Biostar_FlowIs8                 "Flow is 8"                             { channel="guntamatic:biostar:mybiostar:flowIs8" }
+String                 Biostar_Mixer8                  "Mixer 8"                               { channel="guntamatic:biostar:mybiostar:mixer8" }
+Switch                 Biostar_HeatCirc8               "Heat Circ. 8"                          { channel="guntamatic:biostar:mybiostar:heatCirc8" }
+String                 Biostar_FuelLevel               "Fuel Level"                            { channel="guntamatic:biostar:mybiostar:fuelLevel" }
+String                 Biostar_Stb                     "STB"                                   { channel="guntamatic:biostar:mybiostar:stb" }
+String                 Biostar_Tks                     "TKS"                                   { channel="guntamatic:biostar:mybiostar:tks" }
+Switch                 Biostar_BoilerApproval          "Boiler approval"                       { channel="guntamatic:biostar:mybiostar:boilerApproval" }
+String                 Biostar_Programme               "Programme"                             { channel="guntamatic:biostar:mybiostar:programme" }
+String                 Biostar_ProgramHc0              "Program HC0"                           { channel="guntamatic:biostar:mybiostar:programHc0" }
+String                 Biostar_ProgramHc1              "Program HC1"                           { channel="guntamatic:biostar:mybiostar:programHc1" }
+String                 Biostar_ProgramHc2              "Program HC2"                           { channel="guntamatic:biostar:mybiostar:programHc2" }
+String                 Biostar_ProgramHc3              "Program HC3"                           { channel="guntamatic:biostar:mybiostar:programHc3" }
+String                 Biostar_ProgramHc4              "Program HC4"                           { channel="guntamatic:biostar:mybiostar:programHc4" }
+String                 Biostar_ProgramHc5              "Program HC5"                           { channel="guntamatic:biostar:mybiostar:programHc5" }
+String                 Biostar_ProgramHc6              "Program HC6"                           { channel="guntamatic:biostar:mybiostar:programHc6" }
+String                 Biostar_ProgramHc7              "Program HC7"                           { channel="guntamatic:biostar:mybiostar:programHc7" }
+String                 Biostar_ProgramHc8              "Program HC8"                           { channel="guntamatic:biostar:mybiostar:programHc8" }
+String                 Biostar_Interuption0            "Interuption 0"                         { channel="guntamatic:biostar:mybiostar:interuption0" }
+String                 Biostar_Interuption1            "Interuption 1"                         { channel="guntamatic:biostar:mybiostar:interuption1" }
+Number                 Biostar_Serial                  "Serial"                                { channel="guntamatic:biostar:mybiostar:serial" }
+String                 Biostar_Version                 "Version"                               { channel="guntamatic:biostar:mybiostar:version" }
+Number:Time            Biostar_RunningTime             "Running Time"                          { channel="guntamatic:biostar:mybiostar:runningTime" }
+Number:Time            Biostar_ServiceHrs              "Service Hrs"                           { channel="guntamatic:biostar:mybiostar:serviceHrs" }
+Number:Time            Biostar_EmptyAshIn              "Empty ash in"                          { channel="guntamatic:biostar:mybiostar:emptyAshIn" }
+Number:Temperature     Biostar_FlowIs0                 "Flow is 0"                             { channel="guntamatic:biostar:mybiostar:flowIs0" }
+Number:Temperature     Biostar_FlowIs3                 "Flow is 3"                             { channel="guntamatic:biostar:mybiostar:flowIs3" }
+Number:Temperature     Biostar_FlowIs6                 "Flow is 6"                             { channel="guntamatic:biostar:mybiostar:flowIs6" }
+Number:Volume          Biostar_FuelCounter             "Fuel counter"                          { channel="guntamatic:biostar:mybiostar:fuelCounter" }
+Number:Dimensionless   Biostar_BufferLoad              "Buffer load."                          { channel="guntamatic:biostar:mybiostar:bufferLoad" }
+Number:Temperature     Biostar_BufferTop0              "Buffer Top 0"                          { channel="guntamatic:biostar:mybiostar:bufferTop0" }
+Number:Temperature     Biostar_BufferBtm0              "Buffer Btm 0"                          { channel="guntamatic:biostar:mybiostar:bufferBtm0" }
+Number:Temperature     Biostar_BufferTop1              "Buffer Top 1"                          { channel="guntamatic:biostar:mybiostar:bufferTop1" }
+Number:Temperature     Biostar_BufferBtm1              "Buffer Btm 1"                          { channel="guntamatic:biostar:mybiostar:bufferBtm1" }
+Number:Temperature     Biostar_BufferTop2              "Buffer Top 2"                          { channel="guntamatic:biostar:mybiostar:bufferTop2" }
+Number:Temperature     Biostar_BufferBtm2              "Buffer Btm 2"                          { channel="guntamatic:biostar:mybiostar:bufferBtm2" }
+Switch                 Biostar_BExtraWw0               "B extra-WW. 0"                         { channel="guntamatic:biostar:mybiostar:bExtraWw0" }
+Switch                 Biostar_BExtraWw1               "B extra-WW. 1"                         { channel="guntamatic:biostar:mybiostar:bExtraWw1" }
+Switch                 Biostar_BExtraWw2               "B extra-WW. 2"                         { channel="guntamatic:biostar:mybiostar:bExtraWw2" }
+Switch                 Biostar_AuxiliaryPump0          "Auxiliary pump 0"                      { channel="guntamatic:biostar:mybiostar:auxiliaryPump0" }
+Switch                 Biostar_AuxiliaryPump1          "Auxiliary pump 1"                      { channel="guntamatic:biostar:mybiostar:auxiliaryPump1" }
+Switch                 Biostar_AuxiliaryPump2          "Auxiliary pump 2"                      { channel="guntamatic:biostar:mybiostar:auxiliaryPump2" }
+String                 Biostar_BoilersConditionNo      "Boiler´s condition no."               { channel="guntamatic:biostar:mybiostar:boilersConditionNo" }
+Number:Temperature     Biostar_BufferT5                "Buffer T5"                             { channel="guntamatic:biostar:mybiostar:bufferT5" }
+Number:Temperature     Biostar_BufferT6                "Buffer T6"                             { channel="guntamatic:biostar:mybiostar:bufferT6" }
+Number:Temperature     Biostar_BufferT7                "Buffer T7"                             { channel="guntamatic:biostar:mybiostar:bufferT7" }
+Number:Temperature     Biostar_ExtraWw0                "Extra-WW. 0"                           { channel="guntamatic:biostar:mybiostar:extraWw0" }
+Number:Temperature     Biostar_ExtraWw1                "Extra-WW. 1"                           { channel="guntamatic:biostar:mybiostar:extraWw1" }
+Number:Temperature     Biostar_ExtraWw2                "Extra-WW. 2"                           { channel="guntamatic:biostar:mybiostar:extraWw2" }
+Number:Dimensionless   Biostar_Grate                   "Grate"                                 { channel="guntamatic:biostar:mybiostar:grate" }
+```
+
+**Rule**
+
+```javascript
+rule "Example Guntamatic Rule"
+when
+    Item Season changed
+then
+    if ( (Season.state != NULL) && (Season.state != UNDEF) )
+    {
+        if ( Season.state.toString == "WINTER" )
+        {
+            Biostar_ControlProgram.sendCommand("NORMAL")
+        }
+        else
+        {
+            Biostar_ControlProgram.sendCommand("OFF")
+        }
+    }
+end
+```
+
+## Your feedback is required
+
+The Guntamatic Binding was developed and tested using Guntamatic Biostar 15kW Pellets Heating System, running Firmware 3.2d.
+Please provide feedback (👍 as well as 👎) when using the Binding for other Guntamatic Heating Systems.
+
+Forum topic for feedback:
+
+ - [openHAB community #128451](https://community.openhab.org/t/guntamatic-new-binding-for-guntamatic-heating-systems-biostar-powerchip-powercorn-biocom-pro-therm/128451 "openHAB community #128451")
diff --git a/bundles/org.openhab.binding.guntamatic/pom.xml b/bundles/org.openhab.binding.guntamatic/pom.xml
new file mode 100644 (file)
index 0000000..d1d5521
--- /dev/null
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0"
+  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
+
+  <modelVersion>4.0.0</modelVersion>
+
+  <parent>
+    <groupId>org.openhab.addons.bundles</groupId>
+    <artifactId>org.openhab.addons.reactor.bundles</artifactId>
+    <version>3.3.0-SNAPSHOT</version>
+  </parent>
+
+  <artifactId>org.openhab.binding.guntamatic</artifactId>
+
+  <name>openHAB Add-ons :: Bundles :: Guntamatic Binding</name>
+
+</project>
diff --git a/bundles/org.openhab.binding.guntamatic/src/main/feature/feature.xml b/bundles/org.openhab.binding.guntamatic/src/main/feature/feature.xml
new file mode 100644 (file)
index 0000000..892beec
--- /dev/null
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<features name="org.openhab.binding.guntamatic-${project.version}" xmlns="http://karaf.apache.org/xmlns/features/v1.4.0">
+       <repository>mvn:org.openhab.core.features.karaf/org.openhab.core.features.karaf.openhab-core/${ohc.version}/xml/features</repository>
+
+       <feature name="openhab-binding-guntamatic" description="Guntamatic Binding" version="${project.version}">
+               <feature>openhab-runtime-base</feature>
+               <bundle start-level="80">mvn:org.openhab.addons.bundles/org.openhab.binding.guntamatic/${project.version}</bundle>
+       </feature>
+</features>
diff --git a/bundles/org.openhab.binding.guntamatic/src/main/java/org/openhab/binding/guntamatic/internal/GuntamaticBindingConstants.java b/bundles/org.openhab.binding.guntamatic/src/main/java/org/openhab/binding/guntamatic/internal/GuntamaticBindingConstants.java
new file mode 100644 (file)
index 0000000..1d52bcf
--- /dev/null
@@ -0,0 +1,76 @@
+/**
+ * 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.guntamatic.internal;
+
+import java.util.Arrays;
+import java.util.List;
+
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.openhab.core.thing.ThingTypeUID;
+
+/**
+ * The {@link GuntamaticBindingConstants} class defines common constants, which are
+ * used across the whole binding.
+ *
+ * @author Weger Michael - Initial contribution
+ */
+@NonNullByDefault
+public class GuntamaticBindingConstants {
+
+    public static final String BINDING_ID = "guntamatic";
+
+    // List of all Thing Type UIDs
+    public static final ThingTypeUID THING_TYPE_BIOSTAR = new ThingTypeUID(BINDING_ID, "biostar");
+    public static final ThingTypeUID THING_TYPE_POWERCHIP = new ThingTypeUID(BINDING_ID, "powerchip");
+    public static final ThingTypeUID THING_TYPE_POWERCORN = new ThingTypeUID(BINDING_ID, "powercorn");
+    public static final ThingTypeUID THING_TYPE_BIOCOM = new ThingTypeUID(BINDING_ID, "biocom");
+    public static final ThingTypeUID THING_TYPE_PRO = new ThingTypeUID(BINDING_ID, "pro");
+    public static final ThingTypeUID THING_TYPE_THERM = new ThingTypeUID(BINDING_ID, "therm");
+
+    // List of all Channel ids
+    public static final String CHANNEL_CONTROLBOILERAPPROVAL = "controlBoilerApproval";
+    public static final String CHANNEL_CONTROLPROGRAM = "controlProgram";
+    public static final String CHANNEL_CONTROLHEATCIRCPROGRAM0 = "controlHeatCircProgram0";
+    public static final String CHANNEL_CONTROLHEATCIRCPROGRAM1 = "controlHeatCircProgram1";
+    public static final String CHANNEL_CONTROLHEATCIRCPROGRAM2 = "controlHeatCircProgram2";
+    public static final String CHANNEL_CONTROLHEATCIRCPROGRAM3 = "controlHeatCircProgram3";
+    public static final String CHANNEL_CONTROLHEATCIRCPROGRAM4 = "controlHeatCircProgram4";
+    public static final String CHANNEL_CONTROLHEATCIRCPROGRAM5 = "controlHeatCircProgram5";
+    public static final String CHANNEL_CONTROLHEATCIRCPROGRAM6 = "controlHeatCircProgram6";
+    public static final String CHANNEL_CONTROLHEATCIRCPROGRAM7 = "controlHeatCircProgram7";
+    public static final String CHANNEL_CONTROLHEATCIRCPROGRAM8 = "controlHeatCircProgram8";
+    public static final String CHANNEL_CONTROLWWHEAT0 = "controlWwHeat0";
+    public static final String CHANNEL_CONTROLWWHEAT1 = "controlWwHeat1";
+    public static final String CHANNEL_CONTROLWWHEAT2 = "controlWwHeat2";
+    public static final String CHANNEL_CONTROLEXTRAWWHEAT0 = "controlExtraWwHeat0";
+    public static final String CHANNEL_CONTROLEXTRAWWHEAT1 = "controlExtraWwHeat1";
+    public static final String CHANNEL_CONTROLEXTRAWWHEAT2 = "controlExtraWwHeat2";
+
+    public static final List<String> CHANNELIDS = Arrays.asList(CHANNEL_CONTROLBOILERAPPROVAL, CHANNEL_CONTROLPROGRAM,
+            CHANNEL_CONTROLHEATCIRCPROGRAM0, CHANNEL_CONTROLHEATCIRCPROGRAM1, CHANNEL_CONTROLHEATCIRCPROGRAM2,
+            CHANNEL_CONTROLHEATCIRCPROGRAM3, CHANNEL_CONTROLHEATCIRCPROGRAM4, CHANNEL_CONTROLHEATCIRCPROGRAM5,
+            CHANNEL_CONTROLHEATCIRCPROGRAM6, CHANNEL_CONTROLHEATCIRCPROGRAM7, CHANNEL_CONTROLHEATCIRCPROGRAM8,
+            CHANNEL_CONTROLWWHEAT0, CHANNEL_CONTROLWWHEAT1, CHANNEL_CONTROLWWHEAT2, CHANNEL_CONTROLEXTRAWWHEAT0,
+            CHANNEL_CONTROLEXTRAWWHEAT1, CHANNEL_CONTROLEXTRAWWHEAT2);
+
+    public static final String PARAMETER_BOILERAPPROVAL = "boilerApproval";
+    public static final String PARAMETER_PROGRAM = "program";
+    public static final String PARAMETER_HEATCIRCPROGRAM = "heatCircProgram";
+    public static final String PARAMETER_WWHEAT = "wwHeat";
+    public static final String PARAMETER_EXTRAWWHEAT = "extraWwHeat";
+
+    public static final String DAQDATA_URL = "/daqdata.cgi";
+    public static final String DAQDESC_URL = "/daqdesc.cgi";
+    public static final String DAQEXTDESC_URL = "/ext/daqdesc.cgi";
+    public static final String PARSET_URL = "/ext/parset.cgi";
+}
diff --git a/bundles/org.openhab.binding.guntamatic/src/main/java/org/openhab/binding/guntamatic/internal/GuntamaticChannelTypeProvider.java b/bundles/org.openhab.binding.guntamatic/src/main/java/org/openhab/binding/guntamatic/internal/GuntamaticChannelTypeProvider.java
new file mode 100644 (file)
index 0000000..293fecb
--- /dev/null
@@ -0,0 +1,62 @@
+/**
+ * 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.guntamatic.internal;
+
+import java.util.Collection;
+import java.util.Locale;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.eclipse.jdt.annotation.Nullable;
+import org.openhab.core.thing.type.ChannelType;
+import org.openhab.core.thing.type.ChannelTypeBuilder;
+import org.openhab.core.thing.type.ChannelTypeProvider;
+import org.openhab.core.thing.type.ChannelTypeUID;
+import org.openhab.core.thing.type.StateChannelTypeBuilder;
+import org.openhab.core.types.StateDescriptionFragmentBuilder;
+import org.osgi.service.component.annotations.Component;
+
+/**
+ * Provide channelTypes for Guntamatic Heating Systems
+ *
+ * @author Weger Michael - Initial contribution
+ */
+@Component(service = { ChannelTypeProvider.class, GuntamaticChannelTypeProvider.class })
+@NonNullByDefault
+public class GuntamaticChannelTypeProvider implements ChannelTypeProvider {
+    private final Map<String, ChannelType> channelTypes = new ConcurrentHashMap<>();
+
+    @Override
+    public Collection<ChannelType> getChannelTypes(@Nullable Locale locale) {
+        return channelTypes.values();
+    }
+
+    @Override
+    public @Nullable ChannelType getChannelType(ChannelTypeUID channelTypeUID, @Nullable Locale locale) {
+        return channelTypes.get(channelTypeUID.getAsString()); // returns null if not found
+    }
+
+    public void addChannelType(ChannelTypeUID channelTypeUID, String label, String itemType, String description,
+            boolean advanced, String pattern) {
+        StateDescriptionFragmentBuilder stateDescriptionFragmentBuilder = StateDescriptionFragmentBuilder.create()
+                .withReadOnly(true);
+        if (!pattern.isEmpty()) {
+            stateDescriptionFragmentBuilder.withPattern(pattern);
+        }
+        StateChannelTypeBuilder stateChannelTypeBuilder = ChannelTypeBuilder.state(channelTypeUID, label, itemType)
+                .withDescription(description).isAdvanced(advanced)
+                .withStateDescriptionFragment(stateDescriptionFragmentBuilder.build());
+        channelTypes.put(channelTypeUID.getAsString(), stateChannelTypeBuilder.build());
+    }
+}
diff --git a/bundles/org.openhab.binding.guntamatic/src/main/java/org/openhab/binding/guntamatic/internal/GuntamaticConfiguration.java b/bundles/org.openhab.binding.guntamatic/src/main/java/org/openhab/binding/guntamatic/internal/GuntamaticConfiguration.java
new file mode 100644 (file)
index 0000000..e7d599d
--- /dev/null
@@ -0,0 +1,32 @@
+/**
+ * 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.guntamatic.internal;
+
+import org.eclipse.jdt.annotation.NonNullByDefault;
+
+/**
+ * The {@link GuntamaticConfiguration} class contains fields mapping thing configuration parameters.
+ *
+ * @author Weger Michael - Initial contribution
+ */
+@NonNullByDefault
+public class GuntamaticConfiguration {
+
+    /**
+     * Configuration parameters
+     */
+    public String hostname = "";
+    public String key = "";
+    public int refreshInterval = 60;
+    public String encoding = "windows-1252";
+}
diff --git a/bundles/org.openhab.binding.guntamatic/src/main/java/org/openhab/binding/guntamatic/internal/GuntamaticHandler.java b/bundles/org.openhab.binding.guntamatic/src/main/java/org/openhab/binding/guntamatic/internal/GuntamaticHandler.java
new file mode 100644 (file)
index 0000000..442c852
--- /dev/null
@@ -0,0 +1,459 @@
+/**
+ * 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.guntamatic.internal;
+
+import static org.openhab.binding.guntamatic.internal.GuntamaticBindingConstants.*;
+
+import java.nio.charset.Charset;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.ScheduledFuture;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+
+import javax.measure.Unit;
+
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.eclipse.jdt.annotation.Nullable;
+import org.eclipse.jetty.client.HttpClient;
+import org.eclipse.jetty.client.api.ContentResponse;
+import org.eclipse.jetty.client.api.Request;
+import org.eclipse.jetty.http.HttpHeader;
+import org.eclipse.jetty.http.HttpMethod;
+import org.eclipse.jetty.http.HttpStatus;
+import org.openhab.core.library.CoreItemFactory;
+import org.openhab.core.library.types.DecimalType;
+import org.openhab.core.library.types.OnOffType;
+import org.openhab.core.library.types.QuantityType;
+import org.openhab.core.library.types.StringType;
+import org.openhab.core.library.unit.ImperialUnits;
+import org.openhab.core.library.unit.SIUnits;
+import org.openhab.core.library.unit.Units;
+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.builder.ChannelBuilder;
+import org.openhab.core.thing.binding.builder.ThingBuilder;
+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.RefreshType;
+import org.openhab.core.types.State;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.gson.JsonArray;
+import com.google.gson.JsonObject;
+import com.google.gson.JsonParseException;
+import com.google.gson.JsonParser;
+
+/**
+ * The {@link GuntamaticHandler} is responsible for handling commands, which are
+ * sent to one of the channels.
+ *
+ * @author Weger Michael - Initial contribution
+ */
+@NonNullByDefault
+public class GuntamaticHandler extends BaseThingHandler {
+
+    private static final String NUMBER_TEMPERATURE = CoreItemFactory.NUMBER + ":Temperature";
+    private static final String NUMBER_VOLUME = CoreItemFactory.NUMBER + ":Volume";
+    private static final String NUMBER_TIME = CoreItemFactory.NUMBER + ":Time";
+    private static final String NUMBER_DIMENSIONLESS = CoreItemFactory.NUMBER + ":Dimensionless";
+
+    private static final Map<String, Unit<?>> MAP_UNIT = Map.of("%", Units.PERCENT, "°C", SIUnits.CELSIUS, "°F",
+            ImperialUnits.FAHRENHEIT, "m3", SIUnits.CUBIC_METRE, "d", Units.DAY, "h", Units.HOUR);
+    private static final Map<Unit<?>, String> MAP_UNIT_ITEMTYPE = Map.of(Units.PERCENT, NUMBER_DIMENSIONLESS,
+            SIUnits.CELSIUS, NUMBER_TEMPERATURE, ImperialUnits.FAHRENHEIT, NUMBER_TEMPERATURE, SIUnits.CUBIC_METRE,
+            NUMBER_VOLUME, Units.DAY, NUMBER_TIME, Units.HOUR, NUMBER_TIME);
+
+    private final Logger logger = LoggerFactory.getLogger(GuntamaticHandler.class);
+    private final HttpClient httpClient;
+
+    private @Nullable ScheduledFuture<?> pollingFuture = null;
+
+    private GuntamaticConfiguration config = new GuntamaticConfiguration();
+    private Boolean channelsInitialized = false;
+    private GuntamaticChannelTypeProvider guntamaticChannelTypeProvider;
+    private Map<Integer, String> channels = new HashMap<>();
+    private Map<Integer, String> types = new HashMap<>();
+    private Map<Integer, Unit<?>> units = new HashMap<>();
+
+    public GuntamaticHandler(Thing thing, HttpClient httpClient,
+            GuntamaticChannelTypeProvider guntamaticChannelTypeProvider) {
+        super(thing);
+        this.httpClient = httpClient;
+        this.guntamaticChannelTypeProvider = guntamaticChannelTypeProvider;
+    }
+
+    @Override
+    public void handleCommand(ChannelUID channelUID, Command command) {
+        if (!(command instanceof RefreshType)) {
+            if (!config.key.isBlank()) {
+                String param;
+                String channelID = channelUID.getId();
+                switch (channelID) {
+                    case CHANNEL_CONTROLBOILERAPPROVAL:
+                        param = getThing().getProperties().get(PARAMETER_BOILERAPPROVAL);
+                        break;
+                    case CHANNEL_CONTROLPROGRAM:
+                        param = getThing().getProperties().get(PARAMETER_PROGRAM);
+                        break;
+                    case CHANNEL_CONTROLHEATCIRCPROGRAM0:
+                    case CHANNEL_CONTROLHEATCIRCPROGRAM1:
+                    case CHANNEL_CONTROLHEATCIRCPROGRAM2:
+                    case CHANNEL_CONTROLHEATCIRCPROGRAM3:
+                    case CHANNEL_CONTROLHEATCIRCPROGRAM4:
+                    case CHANNEL_CONTROLHEATCIRCPROGRAM5:
+                    case CHANNEL_CONTROLHEATCIRCPROGRAM6:
+                    case CHANNEL_CONTROLHEATCIRCPROGRAM7:
+                    case CHANNEL_CONTROLHEATCIRCPROGRAM8:
+                        param = getThing().getProperties().get(PARAMETER_HEATCIRCPROGRAM).replace("x",
+                                channelID.substring(channelID.length() - 1));
+                        break;
+                    case CHANNEL_CONTROLWWHEAT0:
+                    case CHANNEL_CONTROLWWHEAT1:
+                    case CHANNEL_CONTROLWWHEAT2:
+                        param = getThing().getProperties().get(PARAMETER_WWHEAT).replace("x",
+                                channelID.substring(channelID.length() - 1));
+                        break;
+                    case CHANNEL_CONTROLEXTRAWWHEAT0:
+                    case CHANNEL_CONTROLEXTRAWWHEAT1:
+                    case CHANNEL_CONTROLEXTRAWWHEAT2:
+                        param = getThing().getProperties().get(PARAMETER_EXTRAWWHEAT).replace("x",
+                                channelID.substring(channelID.length() - 1));
+                        break;
+                    default:
+                        return;
+                }
+                String response = sendGetRequest(PARSET_URL, "syn=" + param, "value=" + command.toString());
+                if (response != null) {
+                    State newState = new StringType(response);
+                    updateState(channelID, newState);
+                }
+            } else {
+                logger.warn("A 'key' needs to be configured in order to control the Guntamatic Heating System");
+            }
+        }
+    }
+
+    private void parseAndUpdate(String html) {
+        String[] daqdata = html.split("\\n");
+
+        for (Integer i : channels.keySet()) {
+            String channel = channels.get(i);
+            Unit<?> unit = units.get(i);
+            if ((channel != null) && (i < daqdata.length)) {
+                String value = daqdata[i];
+                Channel chn = thing.getChannel(channel);
+                if ((chn != null) && (value != null)) {
+                    value = value.trim();
+                    String typeName = chn.getAcceptedItemType();
+                    try {
+                        State newState = null;
+                        if (typeName != null) {
+                            switch (typeName) {
+                                case CoreItemFactory.SWITCH:
+                                    // Guntamatic uses German OnOff when configured to German and English OnOff for
+                                    // all other languages
+                                    if ("ON".equals(value) || "EIN".equals(value)) {
+                                        newState = OnOffType.ON;
+                                    } else if ("OFF".equals(value) || "AUS".equals(value)) {
+                                        newState = OnOffType.OFF;
+                                    }
+                                    break;
+                                case CoreItemFactory.NUMBER:
+                                    newState = new DecimalType(value);
+                                    break;
+                                case NUMBER_DIMENSIONLESS:
+                                case NUMBER_TEMPERATURE:
+                                case NUMBER_VOLUME:
+                                case NUMBER_TIME:
+                                    if (unit != null) {
+                                        newState = new QuantityType<>(Double.parseDouble(value), unit);
+                                    }
+                                    break;
+                                case CoreItemFactory.STRING:
+                                    newState = new StringType(value);
+                                    break;
+                                default:
+                                    break;
+                            }
+                        }
+                        if (newState != null) {
+                            updateState(channel, newState);
+                        } else {
+                            logger.warn("Data for unknown typeName '{}' or unknown unit received", typeName);
+                        }
+                    } catch (NumberFormatException e) {
+                        logger.warn("NumberFormatException: {}", ((e.getMessage() != null) ? e.getMessage() : ""));
+                    }
+                }
+            } else {
+                logger.warn("Data for not intialized ChannelId '{}' received", i);
+            }
+        }
+    }
+
+    private void parseAndJsonInit(String html) {
+        try {
+            // remove non JSON compliant, empty element ",,"
+            JsonArray json = JsonParser.parseString(html.replace(",,", ",")).getAsJsonArray();
+            for (int i = 1; i < json.size(); i++) {
+                JsonObject points = json.get(i).getAsJsonObject();
+                if (points.has("id") && points.has("type")) {
+                    int id = points.get("id").getAsInt();
+                    String type = points.get("type").getAsString();
+                    types.put(id, type);
+                }
+            }
+        } catch (JsonParseException | IllegalStateException | ClassCastException e) {
+            logger.warn("Invalid JSON data will be ignored: '{}'", html.replace(",,", ","));
+        }
+    }
+
+    private void parseAndInit(String html) {
+        String[] daqdesc = html.split("\\n");
+        List<Channel> channelList = new ArrayList<>();
+
+        for (String channelID : CHANNELIDS) {
+            Channel channel = thing.getChannel(channelID);
+            if (channel == null) {
+                logger.warn("Static Channel '{}' is not present: remove and re-add Thing", channelID);
+            } else {
+                channelList.add(channel);
+            }
+        }
+
+        for (int i = 0; i < daqdesc.length; i++) {
+            String[] param = daqdesc[i].split(";");
+            String label = param[0].replace("C02", "CO2");
+
+            if (!"reserved".equals(label)) {
+                String channel = toLowerCamelCase(replaceUmlaut(label));
+                label = label.substring(0, 1).toUpperCase() + label.substring(1);
+
+                String unitStr = ((param.length == 1) || param[1].isBlank()) ? "" : param[1].trim();
+                Unit<?> unit = guessUnit(unitStr);
+
+                boolean channelInitialized = channels.containsValue(channel);
+                if (!channelInitialized) {
+                    String itemType;
+                    String pattern;
+                    String type = types.get(i);
+                    if (type == null) {
+                        type = "";
+                    }
+
+                    if ("boolean".equals(type)) {
+                        itemType = CoreItemFactory.SWITCH;
+                        pattern = "";
+                    } else if ("integer".equals(type)) {
+                        itemType = guessItemType(unit);
+                        pattern = "%d";
+                        if (unit != null) {
+                            pattern += " %unit%";
+                        }
+                    } else if ("float".equals(type)) {
+                        itemType = guessItemType(unit);
+                        pattern = "%.2f";
+                        if (unit != null) {
+                            pattern += " %unit%";
+                        }
+                    } else if ("string".equals(type)) {
+                        itemType = CoreItemFactory.STRING;
+                        pattern = "%s";
+                    } else {
+                        if (unitStr.isBlank()) {
+                            itemType = CoreItemFactory.STRING;
+                            pattern = "%s";
+                        } else {
+                            itemType = guessItemType(unit);
+                            pattern = "%.2f";
+                            if (unit != null) {
+                                pattern += " %unit%";
+                            }
+                        }
+                    }
+
+                    ChannelTypeUID channelTypeUID = new ChannelTypeUID(BINDING_ID, channel);
+                    guntamaticChannelTypeProvider.addChannelType(channelTypeUID, channel, itemType,
+                            "Guntamatic " + label, false, pattern);
+                    Channel newChannel = ChannelBuilder.create(new ChannelUID(thing.getUID(), channel), itemType)
+                            .withType(channelTypeUID).withKind(ChannelKind.STATE).withLabel(label).build();
+                    channelList.add(newChannel);
+                    channels.put(i, channel);
+                    if (unit != null) {
+                        units.put(i, unit);
+                    }
+
+                    logger.debug(
+                            "Supported Channel: Idx: '{}', Name: '{}'/'{}', Type: '{}'/'{}', Unit: '{}', Pattern '{}' ",
+                            String.format("%03d", i), label, channel, type, itemType, unitStr, pattern);
+                }
+            }
+        }
+        ThingBuilder thingBuilder = editThing();
+        thingBuilder.withChannels(channelList);
+        updateThing(thingBuilder.build());
+        channelsInitialized = true;
+    }
+
+    private @Nullable Unit<?> guessUnit(String unit) {
+        Unit<?> finalUnit = MAP_UNIT.get(unit);
+        if (!unit.isBlank() && (finalUnit == null)) {
+            logger.warn("Unsupported unit '{}' detected", unit);
+        }
+        return finalUnit;
+    }
+
+    private String guessItemType(@Nullable Unit<?> unit) {
+        String itemType = (unit != null) ? MAP_UNIT_ITEMTYPE.get(unit) : CoreItemFactory.NUMBER;
+        if (itemType == null) {
+            itemType = CoreItemFactory.NUMBER;
+            logger.warn("Unsupported unit '{}' detected: using native '{}' type", unit, itemType);
+        }
+        return itemType;
+    }
+
+    private static String replaceUmlaut(String input) {
+        // replace all lower Umlauts
+        String output = input.replace("ü", "ue").replace("ö", "oe").replace("ä", "ae").replace("ß", "ss");
+
+        // first replace all capital umlaute in a non-capitalized context (e.g. Übung)
+        output = output.replaceAll("Ü(?=[a-zäöüß ])", "Ue").replaceAll("Ö(?=[a-zäöüß ])", "Oe")
+                .replaceAll("Ä(?=[a-zäöüß ])", "Ae");
+
+        // now replace all the other capital umlaute
+        output = output.replace("Ü", "UE").replace("Ö", "OE").replace("Ä", "AE");
+
+        return output;
+    }
+
+    private String toLowerCamelCase(String input) {
+        char delimiter = ' ';
+        String output = input.replace("´", "").replaceAll("[^\\w]", String.valueOf(delimiter));
+
+        StringBuilder builder = new StringBuilder();
+        boolean nextCharLow = true;
+
+        for (int i = 0; i < output.length(); i++) {
+            char currentChar = output.charAt(i);
+            if (delimiter == currentChar) {
+                nextCharLow = false;
+            } else if (nextCharLow) {
+                builder.append(Character.toLowerCase(currentChar));
+            } else {
+                builder.append(Character.toUpperCase(currentChar));
+                nextCharLow = true;
+            }
+        }
+        return builder.toString();
+    }
+
+    private @Nullable String sendGetRequest(String url, String... params) {
+        String errorReason = "";
+        String req = "http://" + config.hostname + url;
+
+        if (!config.key.isBlank()) {
+            req += "?key=" + config.key;
+        }
+
+        for (int i = 0; i < params.length; i++) {
+            if ((i == 0) && config.key.isBlank()) {
+                req += "?";
+            } else {
+                req += "&";
+            }
+            req += params[i];
+        }
+
+        Request request = httpClient.newRequest(req);
+        request.method(HttpMethod.GET).timeout(30, TimeUnit.SECONDS).header(HttpHeader.ACCEPT_ENCODING, "gzip");
+
+        try {
+            ContentResponse contentResponse = request.send();
+            if (HttpStatus.OK_200 == contentResponse.getStatus()) {
+                if (!this.getThing().getStatus().equals(ThingStatus.ONLINE)) {
+                    updateStatus(ThingStatus.ONLINE);
+                }
+                try {
+                    String response = new String(contentResponse.getContent(), Charset.forName(config.encoding));
+                    if (url.equals(DAQEXTDESC_URL)) {
+                        parseAndJsonInit(response);
+                    } else if (url.equals(DAQDATA_URL)) {
+                        parseAndUpdate(response);
+                    } else if (url.equals(DAQDESC_URL)) {
+                        parseAndInit(response);
+                    }
+                    // PARSET_URL via return
+                    return response;
+                } catch (IllegalArgumentException e) {
+                    errorReason = String.format("IllegalArgumentException: %s",
+                            ((e.getMessage() != null) ? e.getMessage() : ""));
+                }
+            } else {
+                errorReason = String.format("Guntamatic request failed with %d: %s", contentResponse.getStatus(),
+                        ((contentResponse.getReason() != null) ? contentResponse.getReason() : ""));
+            }
+        } catch (TimeoutException e) {
+            errorReason = "TimeoutException: Guntamatic was not reachable on your network";
+        } catch (ExecutionException e) {
+            errorReason = String.format("ExecutionException: %s", ((e.getMessage() != null) ? e.getMessage() : ""));
+        } catch (InterruptedException e) {
+            Thread.currentThread().interrupt();
+            errorReason = String.format("InterruptedException: %s", ((e.getMessage() != null) ? e.getMessage() : ""));
+        }
+        updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, errorReason);
+        return null;
+    }
+
+    private void pollGuntamatic() {
+        if (!channelsInitialized) {
+            if (!config.key.isBlank()) {
+                sendGetRequest(DAQEXTDESC_URL);
+            }
+            sendGetRequest(DAQDESC_URL);
+        } else {
+            sendGetRequest(DAQDATA_URL);
+        }
+    }
+
+    @Override
+    public void initialize() {
+        config = getConfigAs(GuntamaticConfiguration.class);
+        if (config.hostname.isBlank()) {
+            updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, "Invalid hostname configuration");
+        } else {
+            updateStatus(ThingStatus.UNKNOWN);
+            pollingFuture = scheduler.scheduleWithFixedDelay(this::pollGuntamatic, 1, config.refreshInterval,
+                    TimeUnit.SECONDS);
+        }
+    }
+
+    @Override
+    public void dispose() {
+        final ScheduledFuture<?> job = pollingFuture;
+        if (job != null) {
+            job.cancel(true);
+            pollingFuture = null;
+        }
+        channelsInitialized = false;
+    }
+}
diff --git a/bundles/org.openhab.binding.guntamatic/src/main/java/org/openhab/binding/guntamatic/internal/GuntamaticHandlerFactory.java b/bundles/org.openhab.binding.guntamatic/src/main/java/org/openhab/binding/guntamatic/internal/GuntamaticHandlerFactory.java
new file mode 100644 (file)
index 0000000..6ef605a
--- /dev/null
@@ -0,0 +1,70 @@
+/**
+ * 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.guntamatic.internal;
+
+import static org.openhab.binding.guntamatic.internal.GuntamaticBindingConstants.*;
+
+import java.util.Set;
+
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.eclipse.jdt.annotation.Nullable;
+import org.eclipse.jetty.client.HttpClient;
+import org.openhab.core.io.net.http.HttpClientFactory;
+import org.openhab.core.thing.Thing;
+import org.openhab.core.thing.ThingTypeUID;
+import org.openhab.core.thing.binding.BaseThingHandlerFactory;
+import org.openhab.core.thing.binding.ThingHandler;
+import org.openhab.core.thing.binding.ThingHandlerFactory;
+import org.osgi.service.component.annotations.Activate;
+import org.osgi.service.component.annotations.Component;
+import org.osgi.service.component.annotations.Reference;
+
+/**
+ * The {@link GuntamaticHandlerFactory} is responsible for creating things and thing
+ * handlers.
+ *
+ * @author Weger Michael - Initial contribution
+ */
+@NonNullByDefault
+@Component(configurationPid = "binding.guntamatic", service = ThingHandlerFactory.class)
+public class GuntamaticHandlerFactory extends BaseThingHandlerFactory {
+
+    private static final Set<ThingTypeUID> SUPPORTED_THING_TYPES_UIDS = Set.of(THING_TYPE_BIOSTAR, THING_TYPE_POWERCHIP,
+            THING_TYPE_POWERCORN, THING_TYPE_BIOCOM, THING_TYPE_PRO, THING_TYPE_THERM);
+
+    private final HttpClient httpClient;
+    private GuntamaticChannelTypeProvider guntamaticChannelTypeProvider;
+
+    @Activate
+    public GuntamaticHandlerFactory(@Reference HttpClientFactory httpClientFactory,
+            @Reference GuntamaticChannelTypeProvider guntamaticChannelTypeProvider) {
+        this.httpClient = httpClientFactory.getCommonHttpClient();
+        this.guntamaticChannelTypeProvider = guntamaticChannelTypeProvider;
+    }
+
+    @Override
+    public boolean supportsThingType(ThingTypeUID thingTypeUID) {
+        return SUPPORTED_THING_TYPES_UIDS.contains(thingTypeUID);
+    }
+
+    @Override
+    protected @Nullable ThingHandler createHandler(Thing thing) {
+        ThingTypeUID thingTypeUID = thing.getThingTypeUID();
+
+        if (supportsThingType(thingTypeUID)) {
+            return new GuntamaticHandler(thing, httpClient, guntamaticChannelTypeProvider);
+        }
+
+        return null;
+    }
+}
diff --git a/bundles/org.openhab.binding.guntamatic/src/main/resources/OH-INF/binding/binding.xml b/bundles/org.openhab.binding.guntamatic/src/main/resources/OH-INF/binding/binding.xml
new file mode 100644 (file)
index 0000000..f43cc80
--- /dev/null
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<binding:binding id="guntamatic" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+       xmlns:binding="https://openhab.org/schemas/binding/v1.0.0"
+       xsi:schemaLocation="https://openhab.org/schemas/binding/v1.0.0 https://openhab.org/schemas/binding-1.0.0.xsd">
+
+       <name>Guntamatic Binding</name>
+       <description>Binding for Guntamatic Heating Systems.</description>
+
+</binding:binding>
diff --git a/bundles/org.openhab.binding.guntamatic/src/main/resources/OH-INF/config/config.xml b/bundles/org.openhab.binding.guntamatic/src/main/resources/OH-INF/config/config.xml
new file mode 100644 (file)
index 0000000..7962681
--- /dev/null
@@ -0,0 +1,32 @@
+<?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:guntamatic:heatingsystem">
+               <parameter name="hostname" type="text" required="true">
+                       <context>network-address</context>
+                       <label>Hostname</label>
+                       <description>Hostname or IP address of the Guntamatic Heating System</description>
+               </parameter>
+               <parameter name="key" type="text" required="false">
+                       <context>password</context>
+                       <label>Key</label>
+                       <description>Optional, but required to read protected parameters and to control the Guntamatic Heating System.
+                               The key
+                               needs to be reqested from Guntamatic support.</description>
+               </parameter>
+               <parameter name="refreshInterval" type="integer" unit="s" min="1" required="false">
+                       <default>60</default>
+                       <label>Refresh Interval</label>
+                       <description>Interval the Guntamatic Heating System is polled in seconds. Default: 60s</description>
+               </parameter>
+               <parameter name="encoding" type="text" required="false">
+                       <default>windows-1252</default>
+                       <label>Encoding</label>
+                       <description>Code page used by the Guntamatic Heating System. Default: 'windows-1252'</description>
+               </parameter>
+       </config-description>
+</config-description:config-descriptions>
diff --git a/bundles/org.openhab.binding.guntamatic/src/main/resources/OH-INF/i18n/guntamatic.properties b/bundles/org.openhab.binding.guntamatic/src/main/resources/OH-INF/i18n/guntamatic.properties
new file mode 100644 (file)
index 0000000..8d3e99c
--- /dev/null
@@ -0,0 +1,158 @@
+# binding
+
+binding.guntamatic.name = Guntamatic Binding
+binding.guntamatic.description = Binding for Guntamatic Heating Systems.
+
+# thing types
+
+thing-type.guntamatic.biocom.label = Guntamatic Biocom
+thing-type.guntamatic.biocom.description = Guntamatic Biocom Heating System. Untested! Please provide Feedback!
+thing-type.guntamatic.biocom.channel.controlBoilerApproval.label = Set Boiler Approval
+thing-type.guntamatic.biocom.channel.controlExtraWwHeat0.label = Trigger Extra Warm Water Circle 0
+thing-type.guntamatic.biocom.channel.controlExtraWwHeat1.label = Trigger Extra Warm Water Circle 1
+thing-type.guntamatic.biocom.channel.controlExtraWwHeat2.label = Trigger Extra Warm Water Circle 2
+thing-type.guntamatic.biocom.channel.controlHeatCircProgram0.label = Set Heat Circle 0 Program
+thing-type.guntamatic.biocom.channel.controlHeatCircProgram1.label = Set Heat Circle 1 Program
+thing-type.guntamatic.biocom.channel.controlHeatCircProgram2.label = Set Heat Circle 2 Program
+thing-type.guntamatic.biocom.channel.controlHeatCircProgram3.label = Set Heat Circle 3 Program
+thing-type.guntamatic.biocom.channel.controlHeatCircProgram4.label = Set Heat Circle 4 Program
+thing-type.guntamatic.biocom.channel.controlHeatCircProgram5.label = Set Heat Circle 5 Program
+thing-type.guntamatic.biocom.channel.controlHeatCircProgram6.label = Set Heat Circle 6 Program
+thing-type.guntamatic.biocom.channel.controlHeatCircProgram7.label = Set Heat Circle 7 Program
+thing-type.guntamatic.biocom.channel.controlHeatCircProgram8.label = Set Heat Circle 8 Program
+thing-type.guntamatic.biocom.channel.controlProgram.label = Set Program
+thing-type.guntamatic.biocom.channel.controlWwHeat0.label = Trigger Warm Water Circle 0
+thing-type.guntamatic.biocom.channel.controlWwHeat1.label = Trigger Warm Water Circle 1
+thing-type.guntamatic.biocom.channel.controlWwHeat2.label = Trigger Warm Water Circle 2
+thing-type.guntamatic.biostar.label = Guntamatic Biostar
+thing-type.guntamatic.biostar.description = Guntamatic Biostar Heating System
+thing-type.guntamatic.biostar.channel.controlBoilerApproval.label = Set Boiler Approval
+thing-type.guntamatic.biostar.channel.controlExtraWwHeat0.label = Trigger Extra Warm Water Circle 0
+thing-type.guntamatic.biostar.channel.controlExtraWwHeat1.label = Trigger Extra Warm Water Circle 1
+thing-type.guntamatic.biostar.channel.controlExtraWwHeat2.label = Trigger Extra Warm Water Circle 2
+thing-type.guntamatic.biostar.channel.controlHeatCircProgram0.label = Set Heat Circle 0 Program
+thing-type.guntamatic.biostar.channel.controlHeatCircProgram1.label = Set Heat Circle 1 Program
+thing-type.guntamatic.biostar.channel.controlHeatCircProgram2.label = Set Heat Circle 2 Program
+thing-type.guntamatic.biostar.channel.controlHeatCircProgram3.label = Set Heat Circle 3 Program
+thing-type.guntamatic.biostar.channel.controlHeatCircProgram4.label = Set Heat Circle 4 Program
+thing-type.guntamatic.biostar.channel.controlHeatCircProgram5.label = Set Heat Circle 5 Program
+thing-type.guntamatic.biostar.channel.controlHeatCircProgram6.label = Set Heat Circle 6 Program
+thing-type.guntamatic.biostar.channel.controlHeatCircProgram7.label = Set Heat Circle 7 Program
+thing-type.guntamatic.biostar.channel.controlHeatCircProgram8.label = Set Heat Circle 8 Program
+thing-type.guntamatic.biostar.channel.controlProgram.label = Set Program
+thing-type.guntamatic.biostar.channel.controlWwHeat0.label = Trigger Warm Water Circle 0
+thing-type.guntamatic.biostar.channel.controlWwHeat1.label = Trigger Warm Water Circle 1
+thing-type.guntamatic.biostar.channel.controlWwHeat2.label = Trigger Warm Water Circle 2
+thing-type.guntamatic.powerchip.label = Guntamatic Powerchip
+thing-type.guntamatic.powerchip.description = Guntamatic Powerchip Heating System. Untested! Please provide Feedback!
+thing-type.guntamatic.powerchip.channel.controlBoilerApproval.label = Set Boiler Approval
+thing-type.guntamatic.powerchip.channel.controlExtraWwHeat0.label = Trigger Extra Warm Water Circle 0
+thing-type.guntamatic.powerchip.channel.controlExtraWwHeat1.label = Trigger Extra Warm Water Circle 1
+thing-type.guntamatic.powerchip.channel.controlExtraWwHeat2.label = Trigger Extra Warm Water Circle 2
+thing-type.guntamatic.powerchip.channel.controlHeatCircProgram0.label = Set Heat Circle 0 Program
+thing-type.guntamatic.powerchip.channel.controlHeatCircProgram1.label = Set Heat Circle 1 Program
+thing-type.guntamatic.powerchip.channel.controlHeatCircProgram2.label = Set Heat Circle 2 Program
+thing-type.guntamatic.powerchip.channel.controlHeatCircProgram3.label = Set Heat Circle 3 Program
+thing-type.guntamatic.powerchip.channel.controlHeatCircProgram4.label = Set Heat Circle 4 Program
+thing-type.guntamatic.powerchip.channel.controlHeatCircProgram5.label = Set Heat Circle 5 Program
+thing-type.guntamatic.powerchip.channel.controlHeatCircProgram6.label = Set Heat Circle 6 Program
+thing-type.guntamatic.powerchip.channel.controlHeatCircProgram7.label = Set Heat Circle 7 Program
+thing-type.guntamatic.powerchip.channel.controlHeatCircProgram8.label = Set Heat Circle 8 Program
+thing-type.guntamatic.powerchip.channel.controlProgram.label = Set Program
+thing-type.guntamatic.powerchip.channel.controlWwHeat0.label = Trigger Warm Water Circle 0
+thing-type.guntamatic.powerchip.channel.controlWwHeat1.label = Trigger Warm Water Circle 1
+thing-type.guntamatic.powerchip.channel.controlWwHeat2.label = Trigger Warm Water Circle 2
+thing-type.guntamatic.powercorn.label = Guntamatic Powercorn
+thing-type.guntamatic.powercorn.description = Guntamatic Powercorn Heating System. Untested! Please provide Feedback!
+thing-type.guntamatic.powercorn.channel.controlBoilerApproval.label = Set Boiler Approval
+thing-type.guntamatic.powercorn.channel.controlExtraWwHeat0.label = Trigger Extra Warm Water Circle 0
+thing-type.guntamatic.powercorn.channel.controlExtraWwHeat1.label = Trigger Extra Warm Water Circle 1
+thing-type.guntamatic.powercorn.channel.controlExtraWwHeat2.label = Trigger Extra Warm Water Circle 2
+thing-type.guntamatic.powercorn.channel.controlHeatCircProgram0.label = Set Heat Circle 0 Program
+thing-type.guntamatic.powercorn.channel.controlHeatCircProgram1.label = Set Heat Circle 1 Program
+thing-type.guntamatic.powercorn.channel.controlHeatCircProgram2.label = Set Heat Circle 2 Program
+thing-type.guntamatic.powercorn.channel.controlHeatCircProgram3.label = Set Heat Circle 3 Program
+thing-type.guntamatic.powercorn.channel.controlHeatCircProgram4.label = Set Heat Circle 4 Program
+thing-type.guntamatic.powercorn.channel.controlHeatCircProgram5.label = Set Heat Circle 5 Program
+thing-type.guntamatic.powercorn.channel.controlHeatCircProgram6.label = Set Heat Circle 6 Program
+thing-type.guntamatic.powercorn.channel.controlHeatCircProgram7.label = Set Heat Circle 7 Program
+thing-type.guntamatic.powercorn.channel.controlHeatCircProgram8.label = Set Heat Circle 8 Program
+thing-type.guntamatic.powercorn.channel.controlProgram.label = Set Program
+thing-type.guntamatic.powercorn.channel.controlWwHeat0.label = Trigger Warm Water Circle 0
+thing-type.guntamatic.powercorn.channel.controlWwHeat1.label = Trigger Warm Water Circle 1
+thing-type.guntamatic.powercorn.channel.controlWwHeat2.label = Trigger Warm Water Circle 2
+thing-type.guntamatic.pro.label = Guntamatic Pro
+thing-type.guntamatic.pro.description = Guntamatic Pro Heating System. Untested! Please provide Feedback!
+thing-type.guntamatic.pro.channel.controlBoilerApproval.label = Set Boiler Approval
+thing-type.guntamatic.pro.channel.controlExtraWwHeat0.label = Trigger Extra Warm Water Circle 0
+thing-type.guntamatic.pro.channel.controlExtraWwHeat1.label = Trigger Extra Warm Water Circle 1
+thing-type.guntamatic.pro.channel.controlExtraWwHeat2.label = Trigger Extra Warm Water Circle 2
+thing-type.guntamatic.pro.channel.controlHeatCircProgram0.label = Set Heat Circle 0 Program
+thing-type.guntamatic.pro.channel.controlHeatCircProgram1.label = Set Heat Circle 1 Program
+thing-type.guntamatic.pro.channel.controlHeatCircProgram2.label = Set Heat Circle 2 Program
+thing-type.guntamatic.pro.channel.controlHeatCircProgram3.label = Set Heat Circle 3 Program
+thing-type.guntamatic.pro.channel.controlHeatCircProgram4.label = Set Heat Circle 4 Program
+thing-type.guntamatic.pro.channel.controlHeatCircProgram5.label = Set Heat Circle 5 Program
+thing-type.guntamatic.pro.channel.controlHeatCircProgram6.label = Set Heat Circle 6 Program
+thing-type.guntamatic.pro.channel.controlHeatCircProgram7.label = Set Heat Circle 7 Program
+thing-type.guntamatic.pro.channel.controlHeatCircProgram8.label = Set Heat Circle 8 Program
+thing-type.guntamatic.pro.channel.controlProgram.label = Set Program
+thing-type.guntamatic.pro.channel.controlWwHeat0.label = Trigger Warm Water Circle 0
+thing-type.guntamatic.pro.channel.controlWwHeat1.label = Trigger Warm Water Circle 1
+thing-type.guntamatic.pro.channel.controlWwHeat2.label = Trigger Warm Water Circle 2
+thing-type.guntamatic.therm.label = Guntamatic Therm
+thing-type.guntamatic.therm.description = Guntamatic Therm Heating System. Untested! Please provide Feedback!
+thing-type.guntamatic.therm.channel.controlBoilerApproval.label = Set Boiler Approval
+thing-type.guntamatic.therm.channel.controlExtraWwHeat0.label = Trigger Extra Warm Water Circle 0
+thing-type.guntamatic.therm.channel.controlExtraWwHeat1.label = Trigger Extra Warm Water Circle 1
+thing-type.guntamatic.therm.channel.controlExtraWwHeat2.label = Trigger Extra Warm Water Circle 2
+thing-type.guntamatic.therm.channel.controlHeatCircProgram0.label = Set Heat Circle 0 Program
+thing-type.guntamatic.therm.channel.controlHeatCircProgram1.label = Set Heat Circle 1 Program
+thing-type.guntamatic.therm.channel.controlHeatCircProgram2.label = Set Heat Circle 2 Program
+thing-type.guntamatic.therm.channel.controlHeatCircProgram3.label = Set Heat Circle 3 Program
+thing-type.guntamatic.therm.channel.controlHeatCircProgram4.label = Set Heat Circle 4 Program
+thing-type.guntamatic.therm.channel.controlHeatCircProgram5.label = Set Heat Circle 5 Program
+thing-type.guntamatic.therm.channel.controlHeatCircProgram6.label = Set Heat Circle 6 Program
+thing-type.guntamatic.therm.channel.controlHeatCircProgram7.label = Set Heat Circle 7 Program
+thing-type.guntamatic.therm.channel.controlHeatCircProgram8.label = Set Heat Circle 8 Program
+thing-type.guntamatic.therm.channel.controlProgram.label = Set Program
+thing-type.guntamatic.therm.channel.controlWwHeat0.label = Trigger Warm Water Circle 0
+thing-type.guntamatic.therm.channel.controlWwHeat1.label = Trigger Warm Water Circle 1
+thing-type.guntamatic.therm.channel.controlWwHeat2.label = Trigger Warm Water Circle 2
+
+# thing types config
+
+thing-type.config.guntamatic.heatingsystem.encoding.label = Encoding
+thing-type.config.guntamatic.heatingsystem.encoding.description = Code page used by the Guntamatic Heating System. Default: 'windows-1252'
+thing-type.config.guntamatic.heatingsystem.hostname.label = Hostname
+thing-type.config.guntamatic.heatingsystem.hostname.description = Hostname or IP address of the Guntamatic Heating System
+thing-type.config.guntamatic.heatingsystem.key.label = Key
+thing-type.config.guntamatic.heatingsystem.key.description = Optional, but required to read protected parameters and to control the Guntamatic Heating System. The key needs to be reqested from Guntamatic support.
+thing-type.config.guntamatic.heatingsystem.refreshInterval.label = Refresh Interval
+thing-type.config.guntamatic.heatingsystem.refreshInterval.description = Interval the Guntamatic Heating System is polled in seconds. Default: 60s
+
+# channel types
+
+channel-type.guntamatic.controlBoilerApproval.label = Set Boiler Approval
+channel-type.guntamatic.controlBoilerApproval.description = Set Boiler Approval of the Guntamatic Heating System (AUTO, OFF, ON)
+channel-type.guntamatic.controlBoilerApproval.state.option.0 = AUTO
+channel-type.guntamatic.controlBoilerApproval.state.option.1 = OFF
+channel-type.guntamatic.controlBoilerApproval.state.option.2 = ON
+channel-type.guntamatic.controlExtraWwHeat.label = Trigger Extra Warm Water Circle
+channel-type.guntamatic.controlExtraWwHeat.description = Trigger Extra Warm Water Circle of the Guntamatic Heating System (RECHARGE)
+channel-type.guntamatic.controlExtraWwHeat.state.option.0 = RECHARGE
+channel-type.guntamatic.controlHeatCircProgram.label = Set Heat Circle Program
+channel-type.guntamatic.controlHeatCircProgram.description = Set Heat Circle of the Guntamatic Heating System (OFF, NORMAL, HEAT, LOWER)
+channel-type.guntamatic.controlHeatCircProgram.state.option.0 = OFF
+channel-type.guntamatic.controlHeatCircProgram.state.option.1 = NORMAL
+channel-type.guntamatic.controlHeatCircProgram.state.option.2 = HEAT
+channel-type.guntamatic.controlHeatCircProgram.state.option.3 = LOWER
+channel-type.guntamatic.controlProgram.label = Set Program
+channel-type.guntamatic.controlProgram.description = Set Program of the Guntamatic Heating System (OFF, NORMAL, WARMWATER, MANUAL)
+channel-type.guntamatic.controlProgram.state.option.0 = OFF
+channel-type.guntamatic.controlProgram.state.option.1 = NORMAL
+channel-type.guntamatic.controlProgram.state.option.2 = WARMWATER
+channel-type.guntamatic.controlProgram.state.option.8 = MANUAL
+channel-type.guntamatic.controlWwHeat.label = Trigger Warm Water Circle
+channel-type.guntamatic.controlWwHeat.description = Trigger Warm Water Circle of the Guntamatic Heating System (RECHARGE)
+channel-type.guntamatic.controlWwHeat.state.option.0 = RECHARGE
diff --git a/bundles/org.openhab.binding.guntamatic/src/main/resources/OH-INF/thing/thing-types.xml b/bundles/org.openhab.binding.guntamatic/src/main/resources/OH-INF/thing/thing-types.xml
new file mode 100644 (file)
index 0000000..a477451
--- /dev/null
@@ -0,0 +1,470 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<thing:thing-descriptions bindingId="guntamatic"
+       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="biostar">
+
+               <label>Guntamatic Biostar</label>
+               <description>Guntamatic Biostar Heating System</description>
+
+               <channels>
+                       <channel id="controlBoilerApproval" typeId="controlBoilerApproval">
+                               <label>Set Boiler Approval</label>
+                       </channel>
+                       <channel id="controlProgram" typeId="controlProgram">
+                               <label>Set Program</label>
+                       </channel>
+                       <channel id="controlHeatCircProgram0" typeId="controlHeatCircProgram">
+                               <label>Set Heat Circle 0 Program</label>
+                       </channel>
+                       <channel id="controlHeatCircProgram1" typeId="controlHeatCircProgram">
+                               <label>Set Heat Circle 1 Program</label>
+                       </channel>
+                       <channel id="controlHeatCircProgram2" typeId="controlHeatCircProgram">
+                               <label>Set Heat Circle 2 Program</label>
+                       </channel>
+                       <channel id="controlHeatCircProgram3" typeId="controlHeatCircProgram">
+                               <label>Set Heat Circle 3 Program</label>
+                       </channel>
+                       <channel id="controlHeatCircProgram4" typeId="controlHeatCircProgram">
+                               <label>Set Heat Circle 4 Program</label>
+                       </channel>
+                       <channel id="controlHeatCircProgram5" typeId="controlHeatCircProgram">
+                               <label>Set Heat Circle 5 Program</label>
+                       </channel>
+                       <channel id="controlHeatCircProgram6" typeId="controlHeatCircProgram">
+                               <label>Set Heat Circle 6 Program</label>
+                       </channel>
+                       <channel id="controlHeatCircProgram7" typeId="controlHeatCircProgram">
+                               <label>Set Heat Circle 7 Program</label>
+                       </channel>
+                       <channel id="controlHeatCircProgram8" typeId="controlHeatCircProgram">
+                               <label>Set Heat Circle 8 Program</label>
+                       </channel>
+                       <channel id="controlWwHeat0" typeId="controlWwHeat">
+                               <label>Trigger Warm Water Circle 0</label>
+                       </channel>
+                       <channel id="controlWwHeat1" typeId="controlWwHeat">
+                               <label>Trigger Warm Water Circle 1</label>
+                       </channel>
+                       <channel id="controlWwHeat2" typeId="controlWwHeat">
+                               <label>Trigger Warm Water Circle 2</label>
+                       </channel>
+                       <channel id="controlExtraWwHeat0" typeId="controlExtraWwHeat">
+                               <label>Trigger Extra Warm Water Circle 0</label>
+                       </channel>
+                       <channel id="controlExtraWwHeat1" typeId="controlExtraWwHeat">
+                               <label>Trigger Extra Warm Water Circle 1</label>
+                       </channel>
+                       <channel id="controlExtraWwHeat2" typeId="controlExtraWwHeat">
+                               <label>Trigger Extra Warm Water Circle 2</label>
+                       </channel>
+               </channels>
+               <properties>
+                       <property name="boilerApproval">K0010</property>
+                       <property name="program">PR001</property>
+                       <property name="heatCircProgram">HKx01</property>
+                       <property name="wwHeat">BKx06</property>
+                       <property name="extraWwHeat">ZKx06</property>
+               </properties>
+               <config-description-ref uri="thing-type:guntamatic:heatingsystem"/>
+       </thing-type>
+       <thing-type id="powerchip">
+
+               <label>Guntamatic Powerchip</label>
+               <description>Guntamatic Powerchip Heating System. Untested! Please provide Feedback!</description>
+
+               <channels>
+                       <channel id="controlBoilerApproval" typeId="controlBoilerApproval">
+                               <label>Set Boiler Approval</label>
+                       </channel>
+                       <channel id="controlProgram" typeId="controlProgram">
+                               <label>Set Program</label>
+                       </channel>
+                       <channel id="controlHeatCircProgram0" typeId="controlHeatCircProgram">
+                               <label>Set Heat Circle 0 Program</label>
+                       </channel>
+                       <channel id="controlHeatCircProgram1" typeId="controlHeatCircProgram">
+                               <label>Set Heat Circle 1 Program</label>
+                       </channel>
+                       <channel id="controlHeatCircProgram2" typeId="controlHeatCircProgram">
+                               <label>Set Heat Circle 2 Program</label>
+                       </channel>
+                       <channel id="controlHeatCircProgram3" typeId="controlHeatCircProgram">
+                               <label>Set Heat Circle 3 Program</label>
+                       </channel>
+                       <channel id="controlHeatCircProgram4" typeId="controlHeatCircProgram">
+                               <label>Set Heat Circle 4 Program</label>
+                       </channel>
+                       <channel id="controlHeatCircProgram5" typeId="controlHeatCircProgram">
+                               <label>Set Heat Circle 5 Program</label>
+                       </channel>
+                       <channel id="controlHeatCircProgram6" typeId="controlHeatCircProgram">
+                               <label>Set Heat Circle 6 Program</label>
+                       </channel>
+                       <channel id="controlHeatCircProgram7" typeId="controlHeatCircProgram">
+                               <label>Set Heat Circle 7 Program</label>
+                       </channel>
+                       <channel id="controlHeatCircProgram8" typeId="controlHeatCircProgram">
+                               <label>Set Heat Circle 8 Program</label>
+                       </channel>
+                       <channel id="controlWwHeat0" typeId="controlWwHeat">
+                               <label>Trigger Warm Water Circle 0</label>
+                       </channel>
+                       <channel id="controlWwHeat1" typeId="controlWwHeat">
+                               <label>Trigger Warm Water Circle 1</label>
+                       </channel>
+                       <channel id="controlWwHeat2" typeId="controlWwHeat">
+                               <label>Trigger Warm Water Circle 2</label>
+                       </channel>
+                       <channel id="controlExtraWwHeat0" typeId="controlExtraWwHeat">
+                               <label>Trigger Extra Warm Water Circle 0</label>
+                       </channel>
+                       <channel id="controlExtraWwHeat1" typeId="controlExtraWwHeat">
+                               <label>Trigger Extra Warm Water Circle 1</label>
+                       </channel>
+                       <channel id="controlExtraWwHeat2" typeId="controlExtraWwHeat">
+                               <label>Trigger Extra Warm Water Circle 2</label>
+                       </channel>
+               </channels>
+               <properties>
+                       <property name="boilerApproval">PK002</property>
+                       <property name="program">PR001</property>
+                       <property name="heatCircProgram">HKx01</property>
+                       <property name="wwHeat">BKx06</property>
+                       <property name="extraWwHeat">ZKx06</property>
+               </properties>
+               <config-description-ref uri="thing-type:guntamatic:heatingsystem"/>
+       </thing-type>
+       <thing-type id="powercorn">
+
+               <label>Guntamatic Powercorn</label>
+               <description>Guntamatic Powercorn Heating System. Untested! Please provide Feedback!</description>
+
+               <channels>
+                       <channel id="controlBoilerApproval" typeId="controlBoilerApproval">
+                               <label>Set Boiler Approval</label>
+                       </channel>
+                       <channel id="controlProgram" typeId="controlProgram">
+                               <label>Set Program</label>
+                       </channel>
+                       <channel id="controlHeatCircProgram0" typeId="controlHeatCircProgram">
+                               <label>Set Heat Circle 0 Program</label>
+                       </channel>
+                       <channel id="controlHeatCircProgram1" typeId="controlHeatCircProgram">
+                               <label>Set Heat Circle 1 Program</label>
+                       </channel>
+                       <channel id="controlHeatCircProgram2" typeId="controlHeatCircProgram">
+                               <label>Set Heat Circle 2 Program</label>
+                       </channel>
+                       <channel id="controlHeatCircProgram3" typeId="controlHeatCircProgram">
+                               <label>Set Heat Circle 3 Program</label>
+                       </channel>
+                       <channel id="controlHeatCircProgram4" typeId="controlHeatCircProgram">
+                               <label>Set Heat Circle 4 Program</label>
+                       </channel>
+                       <channel id="controlHeatCircProgram5" typeId="controlHeatCircProgram">
+                               <label>Set Heat Circle 5 Program</label>
+                       </channel>
+                       <channel id="controlHeatCircProgram6" typeId="controlHeatCircProgram">
+                               <label>Set Heat Circle 6 Program</label>
+                       </channel>
+                       <channel id="controlHeatCircProgram7" typeId="controlHeatCircProgram">
+                               <label>Set Heat Circle 7 Program</label>
+                       </channel>
+                       <channel id="controlHeatCircProgram8" typeId="controlHeatCircProgram">
+                               <label>Set Heat Circle 8 Program</label>
+                       </channel>
+                       <channel id="controlWwHeat0" typeId="controlWwHeat">
+                               <label>Trigger Warm Water Circle 0</label>
+                       </channel>
+                       <channel id="controlWwHeat1" typeId="controlWwHeat">
+                               <label>Trigger Warm Water Circle 1</label>
+                       </channel>
+                       <channel id="controlWwHeat2" typeId="controlWwHeat">
+                               <label>Trigger Warm Water Circle 2</label>
+                       </channel>
+                       <channel id="controlExtraWwHeat0" typeId="controlExtraWwHeat">
+                               <label>Trigger Extra Warm Water Circle 0</label>
+                       </channel>
+                       <channel id="controlExtraWwHeat1" typeId="controlExtraWwHeat">
+                               <label>Trigger Extra Warm Water Circle 1</label>
+                       </channel>
+                       <channel id="controlExtraWwHeat2" typeId="controlExtraWwHeat">
+                               <label>Trigger Extra Warm Water Circle 2</label>
+                       </channel>
+               </channels>
+               <properties>
+                       <property name="boilerApproval">PK002</property>
+                       <property name="program">PR001</property>
+                       <property name="heatCircProgram">HKx01</property>
+                       <property name="wwHeat">BKx06</property>
+                       <property name="extraWwHeat">ZKx06</property>
+               </properties>
+               <config-description-ref uri="thing-type:guntamatic:heatingsystem"/>
+       </thing-type>
+       <thing-type id="biocom">
+
+               <label>Guntamatic Biocom</label>
+               <description>Guntamatic Biocom Heating System. Untested! Please provide Feedback!</description>
+
+               <channels>
+                       <channel id="controlBoilerApproval" typeId="controlBoilerApproval">
+                               <label>Set Boiler Approval</label>
+                       </channel>
+                       <channel id="controlProgram" typeId="controlProgram">
+                               <label>Set Program</label>
+                       </channel>
+                       <channel id="controlHeatCircProgram0" typeId="controlHeatCircProgram">
+                               <label>Set Heat Circle 0 Program</label>
+                       </channel>
+                       <channel id="controlHeatCircProgram1" typeId="controlHeatCircProgram">
+                               <label>Set Heat Circle 1 Program</label>
+                       </channel>
+                       <channel id="controlHeatCircProgram2" typeId="controlHeatCircProgram">
+                               <label>Set Heat Circle 2 Program</label>
+                       </channel>
+                       <channel id="controlHeatCircProgram3" typeId="controlHeatCircProgram">
+                               <label>Set Heat Circle 3 Program</label>
+                       </channel>
+                       <channel id="controlHeatCircProgram4" typeId="controlHeatCircProgram">
+                               <label>Set Heat Circle 4 Program</label>
+                       </channel>
+                       <channel id="controlHeatCircProgram5" typeId="controlHeatCircProgram">
+                               <label>Set Heat Circle 5 Program</label>
+                       </channel>
+                       <channel id="controlHeatCircProgram6" typeId="controlHeatCircProgram">
+                               <label>Set Heat Circle 6 Program</label>
+                       </channel>
+                       <channel id="controlHeatCircProgram7" typeId="controlHeatCircProgram">
+                               <label>Set Heat Circle 7 Program</label>
+                       </channel>
+                       <channel id="controlHeatCircProgram8" typeId="controlHeatCircProgram">
+                               <label>Set Heat Circle 8 Program</label>
+                       </channel>
+                       <channel id="controlWwHeat0" typeId="controlWwHeat">
+                               <label>Trigger Warm Water Circle 0</label>
+                       </channel>
+                       <channel id="controlWwHeat1" typeId="controlWwHeat">
+                               <label>Trigger Warm Water Circle 1</label>
+                       </channel>
+                       <channel id="controlWwHeat2" typeId="controlWwHeat">
+                               <label>Trigger Warm Water Circle 2</label>
+                       </channel>
+                       <channel id="controlExtraWwHeat0" typeId="controlExtraWwHeat">
+                               <label>Trigger Extra Warm Water Circle 0</label>
+                       </channel>
+                       <channel id="controlExtraWwHeat1" typeId="controlExtraWwHeat">
+                               <label>Trigger Extra Warm Water Circle 1</label>
+                       </channel>
+                       <channel id="controlExtraWwHeat2" typeId="controlExtraWwHeat">
+                               <label>Trigger Extra Warm Water Circle 2</label>
+                       </channel>
+               </channels>
+               <properties>
+                       <property name="boilerApproval">PK002</property>
+                       <property name="program">PR001</property>
+                       <property name="heatCircProgram">HKx01</property>
+                       <property name="wwHeat">BKx06</property>
+                       <property name="extraWwHeat">ZKx06</property>
+               </properties>
+               <config-description-ref uri="thing-type:guntamatic:heatingsystem"/>
+       </thing-type>
+       <thing-type id="pro">
+
+               <label>Guntamatic Pro</label>
+               <description>Guntamatic Pro Heating System. Untested! Please provide Feedback!</description>
+
+               <channels>
+                       <channel id="controlBoilerApproval" typeId="controlBoilerApproval">
+                               <label>Set Boiler Approval</label>
+                       </channel>
+                       <channel id="controlProgram" typeId="controlProgram">
+                               <label>Set Program</label>
+                       </channel>
+                       <channel id="controlHeatCircProgram0" typeId="controlHeatCircProgram">
+                               <label>Set Heat Circle 0 Program</label>
+                       </channel>
+                       <channel id="controlHeatCircProgram1" typeId="controlHeatCircProgram">
+                               <label>Set Heat Circle 1 Program</label>
+                       </channel>
+                       <channel id="controlHeatCircProgram2" typeId="controlHeatCircProgram">
+                               <label>Set Heat Circle 2 Program</label>
+                       </channel>
+                       <channel id="controlHeatCircProgram3" typeId="controlHeatCircProgram">
+                               <label>Set Heat Circle 3 Program</label>
+                       </channel>
+                       <channel id="controlHeatCircProgram4" typeId="controlHeatCircProgram">
+                               <label>Set Heat Circle 4 Program</label>
+                       </channel>
+                       <channel id="controlHeatCircProgram5" typeId="controlHeatCircProgram">
+                               <label>Set Heat Circle 5 Program</label>
+                       </channel>
+                       <channel id="controlHeatCircProgram6" typeId="controlHeatCircProgram">
+                               <label>Set Heat Circle 6 Program</label>
+                       </channel>
+                       <channel id="controlHeatCircProgram7" typeId="controlHeatCircProgram">
+                               <label>Set Heat Circle 7 Program</label>
+                       </channel>
+                       <channel id="controlHeatCircProgram8" typeId="controlHeatCircProgram">
+                               <label>Set Heat Circle 8 Program</label>
+                       </channel>
+                       <channel id="controlWwHeat0" typeId="controlWwHeat">
+                               <label>Trigger Warm Water Circle 0</label>
+                       </channel>
+                       <channel id="controlWwHeat1" typeId="controlWwHeat">
+                               <label>Trigger Warm Water Circle 1</label>
+                       </channel>
+                       <channel id="controlWwHeat2" typeId="controlWwHeat">
+                               <label>Trigger Warm Water Circle 2</label>
+                       </channel>
+                       <channel id="controlExtraWwHeat0" typeId="controlExtraWwHeat">
+                               <label>Trigger Extra Warm Water Circle 0</label>
+                       </channel>
+                       <channel id="controlExtraWwHeat1" typeId="controlExtraWwHeat">
+                               <label>Trigger Extra Warm Water Circle 1</label>
+                       </channel>
+                       <channel id="controlExtraWwHeat2" typeId="controlExtraWwHeat">
+                               <label>Trigger Extra Warm Water Circle 2</label>
+                       </channel>
+               </channels>
+               <properties>
+                       <property name="boilerApproval">PK002</property>
+                       <property name="program">PR001</property>
+                       <property name="heatCircProgram">HKx01</property>
+                       <property name="wwHeat">BKx06</property>
+                       <property name="extraWwHeat">ZKx06</property>
+               </properties>
+               <config-description-ref uri="thing-type:guntamatic:heatingsystem"/>
+       </thing-type>
+       <thing-type id="therm">
+
+               <label>Guntamatic Therm</label>
+               <description>Guntamatic Therm Heating System. Untested! Please provide Feedback!</description>
+
+               <channels>
+                       <channel id="controlBoilerApproval" typeId="controlBoilerApproval">
+                               <label>Set Boiler Approval</label>
+                       </channel>
+                       <channel id="controlProgram" typeId="controlProgram">
+                               <label>Set Program</label>
+                       </channel>
+                       <channel id="controlHeatCircProgram0" typeId="controlHeatCircProgram">
+                               <label>Set Heat Circle 0 Program</label>
+                       </channel>
+                       <channel id="controlHeatCircProgram1" typeId="controlHeatCircProgram">
+                               <label>Set Heat Circle 1 Program</label>
+                       </channel>
+                       <channel id="controlHeatCircProgram2" typeId="controlHeatCircProgram">
+                               <label>Set Heat Circle 2 Program</label>
+                       </channel>
+                       <channel id="controlHeatCircProgram3" typeId="controlHeatCircProgram">
+                               <label>Set Heat Circle 3 Program</label>
+                       </channel>
+                       <channel id="controlHeatCircProgram4" typeId="controlHeatCircProgram">
+                               <label>Set Heat Circle 4 Program</label>
+                       </channel>
+                       <channel id="controlHeatCircProgram5" typeId="controlHeatCircProgram">
+                               <label>Set Heat Circle 5 Program</label>
+                       </channel>
+                       <channel id="controlHeatCircProgram6" typeId="controlHeatCircProgram">
+                               <label>Set Heat Circle 6 Program</label>
+                       </channel>
+                       <channel id="controlHeatCircProgram7" typeId="controlHeatCircProgram">
+                               <label>Set Heat Circle 7 Program</label>
+                       </channel>
+                       <channel id="controlHeatCircProgram8" typeId="controlHeatCircProgram">
+                               <label>Set Heat Circle 8 Program</label>
+                       </channel>
+                       <channel id="controlWwHeat0" typeId="controlWwHeat">
+                               <label>Trigger Warm Water Circle 0</label>
+                       </channel>
+                       <channel id="controlWwHeat1" typeId="controlWwHeat">
+                               <label>Trigger Warm Water Circle 1</label>
+                       </channel>
+                       <channel id="controlWwHeat2" typeId="controlWwHeat">
+                               <label>Trigger Warm Water Circle 2</label>
+                       </channel>
+                       <channel id="controlExtraWwHeat0" typeId="controlExtraWwHeat">
+                               <label>Trigger Extra Warm Water Circle 0</label>
+                       </channel>
+                       <channel id="controlExtraWwHeat1" typeId="controlExtraWwHeat">
+                               <label>Trigger Extra Warm Water Circle 1</label>
+                       </channel>
+                       <channel id="controlExtraWwHeat2" typeId="controlExtraWwHeat">
+                               <label>Trigger Extra Warm Water Circle 2</label>
+                       </channel>
+               </channels>
+               <properties>
+                       <property name="boilerApproval">K0010</property>
+                       <property name="program">PR001</property>
+                       <property name="heatCircProgram">HKx01</property>
+                       <property name="wwHeat">BKx06</property>
+                       <property name="extraWwHeat">ZKx06</property>
+               </properties>
+               <config-description-ref uri="thing-type:guntamatic:heatingsystem"/>
+       </thing-type>
+
+
+       <channel-type id="controlProgram" advanced="false">
+               <item-type>String</item-type>
+               <label>Set Program</label>
+               <description>Set Program of the Guntamatic Heating System (OFF, NORMAL, WARMWATER, MANUAL)</description>
+               <state>
+                       <options>
+                               <option value="0">OFF</option>
+                               <option value="1">NORMAL</option>
+                               <option value="2">WARMWATER</option>
+                               <option value="8">MANUAL</option>
+                       </options>
+               </state>
+       </channel-type>
+       <channel-type id="controlBoilerApproval" advanced="true">
+               <item-type>String</item-type>
+               <label>Set Boiler Approval</label>
+               <description>Set Boiler Approval of the Guntamatic Heating System (AUTO, OFF, ON)</description>
+               <state>
+                       <options>
+                               <option value="0">AUTO</option>
+                               <option value="1">OFF</option>
+                               <option value="2">ON</option>
+                       </options>
+               </state>
+       </channel-type>
+       <channel-type id="controlHeatCircProgram" advanced="true">
+               <item-type>String</item-type>
+               <label>Set Heat Circle Program</label>
+               <description>Set Heat Circle of the Guntamatic Heating System (OFF, NORMAL, HEAT, LOWER)</description>
+               <state>
+                       <options>
+                               <option value="0">OFF</option>
+                               <option value="1">NORMAL</option>
+                               <option value="2">HEAT</option>
+                               <option value="3">LOWER</option>
+                       </options>
+               </state>
+       </channel-type>
+       <channel-type id="controlWwHeat" advanced="true">
+               <item-type>String</item-type>
+               <label>Trigger Warm Water Circle</label>
+               <description>Trigger Warm Water Circle of the Guntamatic Heating System (RECHARGE)</description>
+               <state>
+                       <options>
+                               <option value="0">RECHARGE</option>
+                       </options>
+               </state>
+       </channel-type>
+       <channel-type id="controlExtraWwHeat" advanced="true">
+               <item-type>String</item-type>
+               <label>Trigger Extra Warm Water Circle</label>
+               <description>Trigger Extra Warm Water Circle of the Guntamatic Heating System (RECHARGE)</description>
+               <state>
+                       <options>
+                               <option value="0">RECHARGE</option>
+                       </options>
+               </state>
+       </channel-type>
+
+</thing:thing-descriptions>
index 6f3981daa9d02ebe34fcfd235f69d8f3c0bdb265..dd18d0850e93f2543088b728dca6b5bb148fa982 100644 (file)
     <module>org.openhab.binding.gpstracker</module>
     <module>org.openhab.binding.gree</module>
     <module>org.openhab.binding.groheondus</module>
+    <module>org.openhab.binding.guntamatic</module>
     <module>org.openhab.binding.haassohnpelletstove</module>
     <module>org.openhab.binding.harmonyhub</module>
     <module>org.openhab.binding.haywardomnilogic</module>