added migrated 2.x add-ons
Signed-off-by: Kai Kreuzer <kai@openhab.org>
This commit is contained in:
32
bundles/org.openhab.binding.regoheatpump/.classpath
Normal file
32
bundles/org.openhab.binding.regoheatpump/.classpath
Normal file
@@ -0,0 +1,32 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<classpath>
|
||||
<classpathentry kind="src" output="target/classes" path="src/main/java">
|
||||
<attributes>
|
||||
<attribute name="optional" value="true"/>
|
||||
<attribute name="maven.pomderived" value="true"/>
|
||||
</attributes>
|
||||
</classpathentry>
|
||||
<classpathentry excluding="**" kind="src" output="target/classes" path="src/main/resources">
|
||||
<attributes>
|
||||
<attribute name="maven.pomderived" value="true"/>
|
||||
</attributes>
|
||||
</classpathentry>
|
||||
<classpathentry kind="src" output="target/test-classes" path="src/test/java">
|
||||
<attributes>
|
||||
<attribute name="optional" value="true"/>
|
||||
<attribute name="maven.pomderived" value="true"/>
|
||||
<attribute name="test" value="true"/>
|
||||
</attributes>
|
||||
</classpathentry>
|
||||
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-11">
|
||||
<attributes>
|
||||
<attribute name="maven.pomderived" value="true"/>
|
||||
</attributes>
|
||||
</classpathentry>
|
||||
<classpathentry kind="con" path="org.eclipse.m2e.MAVEN2_CLASSPATH_CONTAINER">
|
||||
<attributes>
|
||||
<attribute name="maven.pomderived" value="true"/>
|
||||
</attributes>
|
||||
</classpathentry>
|
||||
<classpathentry kind="output" path="target/classes"/>
|
||||
</classpath>
|
||||
23
bundles/org.openhab.binding.regoheatpump/.project
Normal file
23
bundles/org.openhab.binding.regoheatpump/.project
Normal file
@@ -0,0 +1,23 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<projectDescription>
|
||||
<name>org.openhab.binding.regoheatpump</name>
|
||||
<comment></comment>
|
||||
<projects>
|
||||
</projects>
|
||||
<buildSpec>
|
||||
<buildCommand>
|
||||
<name>org.eclipse.jdt.core.javabuilder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
<buildCommand>
|
||||
<name>org.eclipse.m2e.core.maven2Builder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
</buildSpec>
|
||||
<natures>
|
||||
<nature>org.eclipse.jdt.core.javanature</nature>
|
||||
<nature>org.eclipse.m2e.core.maven2Nature</nature>
|
||||
</natures>
|
||||
</projectDescription>
|
||||
13
bundles/org.openhab.binding.regoheatpump/NOTICE
Normal file
13
bundles/org.openhab.binding.regoheatpump/NOTICE
Normal file
@@ -0,0 +1,13 @@
|
||||
This content is produced and maintained by the openHAB project.
|
||||
|
||||
* Project home: https://www.openhab.org
|
||||
|
||||
== Declared Project Licenses
|
||||
|
||||
This program and the accompanying materials are made available under the terms
|
||||
of the Eclipse Public License 2.0 which is available at
|
||||
https://www.eclipse.org/legal/epl-2.0/.
|
||||
|
||||
== Source Code
|
||||
|
||||
https://github.com/openhab/openhab-addons
|
||||
238
bundles/org.openhab.binding.regoheatpump/README.md
Normal file
238
bundles/org.openhab.binding.regoheatpump/README.md
Normal file
@@ -0,0 +1,238 @@
|
||||
# RegoHeatPump Binding
|
||||
|
||||
The Rego heat pump binding supports:
|
||||
|
||||
* Rego 6xx controllers family and
|
||||
* Husdata interface.
|
||||
|
||||
## The Rego 6xx family
|
||||
|
||||
The Rego 6xx controllers family is used in many heat pumps such as IVT/Bosch/Autotherm/Carrier and others.
|
||||
|
||||
Rego 6xx unit contain an interface marked as service.
|
||||
Header of this interface is close to the control unit. This is 5V (TTL) serial interface and is connected by a 9 pin can/d-sub connector. Pinout:
|
||||
|
||||
2 - RxD
|
||||
3 - TxD
|
||||
4 - +5V
|
||||
5 - GND
|
||||
|
||||
Serial communication is using 19200 bps, 8 bit, no parity, 1 stop bit.
|
||||
|
||||
### Thing configuration
|
||||
|
||||
Two connection types are supported:
|
||||
|
||||
* TCP/IP and
|
||||
* serial (RS232).
|
||||
|
||||
#### TCP/IP connection
|
||||
|
||||
A transparent bridge between the serial interface of the heat pump and network (i.e. wifi) is used.
|
||||
This way no additional wires are required between heat pump and computer, running openHAB.
|
||||
|
||||
There are many existing project providing such functionality, i.e. [ser2net](http://ser2net.sourceforge.net/).
|
||||
|
||||
For my setup, I used a low budget (~5€) circuit, that is integrated into the heat pump and connects to a wifi using an ESP8266 based module.
|
||||
|
||||
Board:
|
||||
|
||||

|
||||
|
||||
The code running on the ESP module can be found [here](https://github.com/crnjan/esp8266-bridge).
|
||||
There are other projects providing ESP firmware with similar functionality, i.e. [ESP-LINK](https://github.com/jeelabs/esp-link), but did not test with those.
|
||||
|
||||
Configuration of the TCP/IP thing:
|
||||
|
||||
- address: the hostname/IP address of the transparent bridge on the local network - mandatory,
|
||||
- tcpPort: the port number to use to connect to the transparent bridge - optional, defaults to 9265,
|
||||
- refreshInterval: refresh interval in seconds, used to fetch new values from the heat pump - optional, defaults to 60 seconds.
|
||||
|
||||
Example thing definition:
|
||||
|
||||
```
|
||||
regoheatpump:ipRego6xx:ivtIP [ address="192.168.2.50", tcpPort="9265" ]
|
||||
```
|
||||
|
||||
#### Serial connection
|
||||
|
||||
In order to connect directly to the rego 6xx controller, one needs to adjust the TTL levels coming from the rego unit to levels used by a RS232 serial port, used within computers, using MAX232 or similar.
|
||||
|
||||
Parameters:
|
||||
|
||||
- portName: the name of the serial port on your computer - mandatory,
|
||||
- refreshInterval: refresh interval in seconds, used to fetch new values from the heat pump - optional, defaults to 60 seconds.
|
||||
|
||||
Example thing definition:
|
||||
|
||||
```
|
||||
regoheatpump:serialRego6xx:ivtSerial [ portName="COM3" ]
|
||||
```
|
||||
|
||||
### Channels
|
||||
|
||||
Below is the list of supported channels:
|
||||
|
||||
| Channel Type ID | Item Type | Access |
|
||||
|---------------------------------------|-------------|--------|
|
||||
| sensorValues#radiatorReturn | Temperature | R |
|
||||
| sensorValues#outdoor | Temperature | R |
|
||||
| sensorValues#hotWater | Temperature | R |
|
||||
| sensors#radiatorForward | Temperature | R |
|
||||
| sensorValues#indoor | Temperature | R |
|
||||
| sensorValues#compressor | Temperature | R |
|
||||
| sensorValues#heatFluidOut | Temperature | R |
|
||||
| sensorValues#heatFluidIn | Temperature | R |
|
||||
| sensorValues#coldFluidIn | Temperature | R |
|
||||
| sensorValues#coldFluidOut | Temperature | R |
|
||||
| sensorValues#externalHotWater | Temperature | R |
|
||||
| status#lastErrorTimestamp | DateTime | R |
|
||||
| status#lastErrorType | String | R |
|
||||
| frontPanel#powerLamp | Switch | R |
|
||||
| frontPanel#heatPumpLamp | Switch | R |
|
||||
| frontPanel#additionalHeatLamp | Switch | R |
|
||||
| frontPanel#hotWaterLamp | Switch | R |
|
||||
| frontPanel#alarmLamp | Switch | R |
|
||||
| controlData#radiatorReturnTarget | Temperature | R |
|
||||
| controlData#radiatorReturnOn | Temperature | R |
|
||||
| controlData#radiatorReturnOff | Temperature | R |
|
||||
| controlData#hotWaterOn | Temperature | R |
|
||||
| controlData#hotWaterOff | Temperature | R |
|
||||
| controlData#radiatorForwardTarget | Temperature | R |
|
||||
| controlData#addHeatPower | Number (%) | R |
|
||||
| deviceValues#coldFluidPump | Switch | R |
|
||||
| deviceValues#compressor | Switch | R |
|
||||
| deviceValues#additionalHeat3kW | Switch | R |
|
||||
| deviceValues#additionalHeat6kW | Switch | R |
|
||||
| deviceValues#radiatorPump | Switch | R |
|
||||
| deviceValues#heatFluidPump | Switch | R |
|
||||
| deviceValues#switchValue | Switch | R |
|
||||
| deviceValues#alarm | Switch | R |
|
||||
| settings#hotWaterTarget | Temperature | RW |
|
||||
| settings#hotWaterTargetHysteresis | Temperature | RW |
|
||||
| settings#heatCurve | Number | RW |
|
||||
| settings#heatCurveFineAdj | Temperature | RW |
|
||||
| settings#heatCurve2 | Number | RW |
|
||||
| settings#heatCurve2FineAdj | Temperature | RW |
|
||||
| settings#indoorTempSetting | Temperature | RW |
|
||||
| settings#curveInflByInTemp | Number | RW |
|
||||
| settings#adjCurveAt20 | Temperature | RW |
|
||||
| settings#adjCurveAt15 | Temperature | RW |
|
||||
| settings#adjCurveAt10 | Temperature | RW |
|
||||
| settings#adjCurveAt5 | Temperature | RW |
|
||||
| settings#adjCurveAt0 | Temperature | RW |
|
||||
| settings#adjCurveAtMinus5 | Temperature | RW |
|
||||
| settings#adjCurveAtMinus10 | Temperature | RW |
|
||||
| settings#adjCurveAtMinus15 | Temperature | RW |
|
||||
| settings#adjCurveAtMinus20 | Temperature | RW |
|
||||
| settings#adjCurveAtMinus25 | Temperature | RW |
|
||||
| settings#adjCurveAtMinus30 | Temperature | RW |
|
||||
| settings#adjCurveAtMinus35 | Temperature | RW |
|
||||
| settings#heatCurveCouplingDiff | Temperature | RW |
|
||||
| settings#summerDisconnection | Temperature | RW |
|
||||
| operatingTimes#heatPumpInOperationRAD | Hours | R |
|
||||
| operatingTimes#heatPumpInOperationDHW | Hours | R |
|
||||
| operatingTimes#addHeatInOperationRAD | Hours | R |
|
||||
| operatingTimes#addHeatInOperationDHW | Hours | R |
|
||||
|
||||
Access: R = read only; RW = read write
|
||||
|
||||
**Note - breaking change:** to have all writable channels within the settings group, hotWaterTarget channel was moved from controlData to the setting group.
|
||||
|
||||
## The Husdata interface
|
||||
|
||||
The [Husdata](https://www.husdata.se/) interface bridges the often complex communication methods with a heat pump controller and provides access through a simple standard interface over RS-232.
|
||||
|
||||
Supported heat pump models
|
||||
|
||||
| Heat pump models | Technical |
|
||||
|-----------------------------------|--------------------|
|
||||
| IVT Greenline / Optima 900 | Rego 600 Serial |
|
||||
| IVT 490 | Rego 400 Serial |
|
||||
| IVT Premiumline X, Optima/290-AW | Rego 800, Can bus |
|
||||
| IVT Greenline HE/HC/HA+Prem HQ/EQ | Rego 1000, Can bus |
|
||||
| NIBE xx45 | EB100, RS-485 |
|
||||
| NIBE Fighter series | Styr 2002, RS-485 |
|
||||
| Thermia Diplomat series | 901510, i2c |
|
||||
|
||||
Above list is informational, please consult with the Husdata interface provider for further details.
|
||||
|
||||
### Thing configuration
|
||||
|
||||
Two connection types are supported:
|
||||
|
||||
* TCP/IP and
|
||||
* serial (RS232).
|
||||
|
||||
#### TCP/IP connection
|
||||
|
||||
A transparent bridge between the Husdata interface and network (i.e. wifi) is used.
|
||||
|
||||
There are many existing project providing such functionality, i.e. [ser2net](http://ser2net.sourceforge.net/).
|
||||
|
||||
Configuration of the TCP/IP thing:
|
||||
|
||||
- address: the hostname/IP address of the transparent bridge on the local network - mandatory,
|
||||
- tcpPort: the port number to use to connect to the transparent bridge - optional, defaults to 9265.
|
||||
|
||||
Example thing definition:
|
||||
|
||||
```
|
||||
regoheatpump:ipHusdata:ivtIP [ address="192.168.2.50", tcpPort="9265" ]
|
||||
```
|
||||
|
||||
#### Serial connection
|
||||
|
||||
One can connect the Husdata interface directly to a computer that runs openHAB.
|
||||
|
||||
Parameters:
|
||||
|
||||
- portName: the name of the serial port on your computer - mandatory.
|
||||
|
||||
Example thing definition:
|
||||
|
||||
```
|
||||
regoheatpump:serialHusdata:ivtSerial [ portName="COM3" ]
|
||||
```
|
||||
|
||||
### Channels
|
||||
|
||||
Below is the list of supported channels, all values are read only:
|
||||
|
||||
| H1 ID | Name | Channel Type ID | Item Type |
|
||||
|-------|-----------------------|----------------------------------|------------------|
|
||||
| 001 | Radiator Return | sensorValues#radiatorReturn | Temperature |
|
||||
| 002 | Radiator Forward | sensorValues#radiatorForward | Temperature |
|
||||
| 003 | Heat carrier Return | sensorValues#heatFluidIn | Temperature |
|
||||
| 004 | Heat carrier Forward | sensorValues#heatFluidOut | Temperature |
|
||||
| 005 | Brine In / Evaporator | sensorValues#coldFluidIn | Temperature |
|
||||
| 006 | Brine Out / Condenser | sensorValues#coldFluidOut | Temperature |
|
||||
| 007 | Outdoor | sensorValues#outdoor | Temperature |
|
||||
| 008 | Indoor | sensorValues#indoor | Temperature |
|
||||
| 009 | Hot water 1 / Top | sensorValues#hotWater | Temperature |
|
||||
| 00A | Hot water 2 / Mid | sensorValues#externalHotWater | Temperature |
|
||||
| 00B | Hot gas / Compressor | sensorValues#compressor | Temperature |
|
||||
| 00E | Air intake | sensorValues#airIntake | Temperature |
|
||||
| 011 | Pool | sensorValues#pool | Temperature |
|
||||
| 104 | Add heat status | controlData#addHeatPowerPercent | Number - % |
|
||||
| 104 | Add heat status | controlData#addHeatPowerEnergy | Number - kW |
|
||||
| 107 | Heating setpoint | controlData#radiatorReturnTarget | Temperature |
|
||||
| 108 | Compressor speed | controlData#compressorSpeed | Number - % |
|
||||
| 203 | Room temp setpoint | settings#indoorTempSetting | Temperature |
|
||||
| 204 | Room sensor influence | settings#curveInflByInTemp | Number |
|
||||
| 205 | Heat set 1, CurveL | settings#heatCurve | Number |
|
||||
| 206 | Heat set 2, CurveR | settings#heatCurve2 | Number |
|
||||
| A01 | Compressor | deviceValues#compressor | Switch |
|
||||
| A04 | Pump Cold circuit | deviceValues#coldFluidPump | Switch |
|
||||
| A05 | Pump Heat circuit | deviceValues#heatFluidPump | Switch |
|
||||
| A06 | Pump Radiator | deviceValues#radiatorPump | Switch |
|
||||
| A07 | Switch valve 1 | deviceValues#switchValve | Switch |
|
||||
| A08 | Switch valve 2 | deviceValues#switchValve2 | Switch |
|
||||
| A09 | Fan | deviceValues#fan | Switch |
|
||||
| A0A | High Pressostat | deviceValues#highPressostat | Switch |
|
||||
| A0B | Low Pressostat | deviceValues#lowPressostat | Switch |
|
||||
| A0C | Heating cable | deviceValues#heatingCable | Switch |
|
||||
| A0D | Crank case heater | deviceValues#crankCaseHeater | Switch |
|
||||
| A20 | Alarm | deviceValues#alarm | Switch |
|
||||
| FF1 | EL-Meter 1 | deviceValues#elMeter1 | Number - pulses |
|
||||
| FF2 | EL-Meter 2 | deviceValues#elMeter2 | Number - pulses |
|
||||
BIN
bundles/org.openhab.binding.regoheatpump/doc/board.png
Normal file
BIN
bundles/org.openhab.binding.regoheatpump/doc/board.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 57 KiB |
17
bundles/org.openhab.binding.regoheatpump/pom.xml
Normal file
17
bundles/org.openhab.binding.regoheatpump/pom.xml
Normal file
@@ -0,0 +1,17 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<parent>
|
||||
<groupId>org.openhab.addons.bundles</groupId>
|
||||
<artifactId>org.openhab.addons.reactor.bundles</artifactId>
|
||||
<version>3.0.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>org.openhab.binding.regoheatpump</artifactId>
|
||||
|
||||
<name>openHAB Add-ons :: Bundles :: RegoHeatPump Binding</name>
|
||||
|
||||
</project>
|
||||
@@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<features name="org.openhab.binding.regoheatpump-${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-regoheatpump" description="RegoHeatPump Binding" version="${project.version}">
|
||||
<feature>openhab-runtime-base</feature>
|
||||
<feature>openhab-transport-serial</feature>
|
||||
<bundle start-level="80">mvn:org.openhab.addons.bundles/org.openhab.binding.regoheatpump/${project.version}</bundle>
|
||||
</feature>
|
||||
</features>
|
||||
@@ -0,0 +1,58 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.regoheatpump.internal;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.core.thing.ThingTypeUID;
|
||||
|
||||
/**
|
||||
* The {@link RegoHeatPumpBinding} class defines common constants, which are
|
||||
* used across the whole binding.
|
||||
*
|
||||
* @author Boris Krivonog - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class RegoHeatPumpBindingConstants {
|
||||
|
||||
public static final String BINDING_ID = "regoheatpump";
|
||||
|
||||
// List of all Thing Type UIDs
|
||||
public static final ThingTypeUID THING_TYPE_IP_REGO6XX = new ThingTypeUID(BINDING_ID, "ipRego6xx");
|
||||
public static final ThingTypeUID THING_TYPE_SERIAL_REGO6XX = new ThingTypeUID(BINDING_ID, "serialRego6xx");
|
||||
public static final ThingTypeUID THING_TYPE_IP_HUSDATA = new ThingTypeUID(BINDING_ID, "ipHusdata");
|
||||
public static final ThingTypeUID THING_TYPE_SERIAL_HUSDATA = new ThingTypeUID(BINDING_ID, "serialHusdata");
|
||||
|
||||
// List of all Channel ids
|
||||
public static final String CHANNEL_GROUP_SENSOR_VALUES = "sensorValues#";
|
||||
public static final String CHANNEL_GROUP_CONTROL_DATA = "controlData#";
|
||||
public static final String CHANNEL_GROUP_DEVICE_VALUES = "deviceValues#";
|
||||
public static final String CHANNEL_GROUP_SETTINGS = "settings#";
|
||||
public static final String CHANNEL_GROUP_OPERATING_TIMES = "operatingTimes#";
|
||||
public static final String CHANNEL_LAST_ERROR = "status#lastError";
|
||||
public static final String CHANNEL_LAST_ERROR_TIMESTAMP = CHANNEL_LAST_ERROR + "Timestamp";
|
||||
public static final String CHANNEL_LAST_ERROR_TYPE = CHANNEL_LAST_ERROR + "Type";
|
||||
public static final String CHANNEL_FRONT_PANEL_POWER_LAMP = "frontPanel#powerLamp";
|
||||
public static final String CHANNEL_FRONT_PANEL_PUMP_LAMP = "frontPanel#heatPumpLamp";
|
||||
public static final String CHANNEL_FRONT_PANEL_ADDITIONAL_HEAT_LAMP = "frontPanel#additionalHeatLamp";
|
||||
public static final String CHANNEL_FRONT_PANEL_WATER_HEATER_LAMP = "frontPanel#hotWaterLamp";
|
||||
public static final String CHANNEL_FRONT_PANEL_ALARM_LAMP = "frontPanel#alarmLamp";
|
||||
|
||||
public static final String REFRESH_INTERVAL = "refreshInterval";
|
||||
|
||||
// TCP/IP thing
|
||||
public static final String HOST_PARAMETER = "address";
|
||||
public static final String TCP_PORT_PARAMETER = "tcpPort";
|
||||
|
||||
// Serial thing
|
||||
public static final String PORT_NAME = "portName";
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.regoheatpump.internal;
|
||||
|
||||
import static org.openhab.binding.regoheatpump.internal.RegoHeatPumpBindingConstants.*;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.binding.regoheatpump.internal.handler.IpHusdataHandler;
|
||||
import org.openhab.binding.regoheatpump.internal.handler.IpRego6xxHeatPumpHandler;
|
||||
import org.openhab.binding.regoheatpump.internal.handler.SerialHusdataHandler;
|
||||
import org.openhab.binding.regoheatpump.internal.handler.SerialRego6xxHeatPumpHandler;
|
||||
import org.openhab.core.io.transport.serial.SerialPortManager;
|
||||
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 RegoHeatPumpHandlerFactory} is responsible for creating things and thing
|
||||
* handlers.
|
||||
*
|
||||
* @author Boris Krivonog - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
@Component(service = ThingHandlerFactory.class, configurationPid = "binding.regoheatpump")
|
||||
public class RegoHeatPumpHandlerFactory extends BaseThingHandlerFactory {
|
||||
|
||||
private static final Set<ThingTypeUID> SUPPORTED_THING_TYPES_UIDS = Collections.unmodifiableSet(Stream
|
||||
.of(THING_TYPE_IP_REGO6XX, THING_TYPE_SERIAL_REGO6XX, THING_TYPE_IP_HUSDATA, THING_TYPE_SERIAL_HUSDATA)
|
||||
.collect(Collectors.toSet()));
|
||||
|
||||
private final SerialPortManager serialPortManager;
|
||||
|
||||
@Activate
|
||||
public RegoHeatPumpHandlerFactory(final @Reference SerialPortManager serialPortManager) {
|
||||
this.serialPortManager = serialPortManager;
|
||||
}
|
||||
|
||||
@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 (thingTypeUID.equals(THING_TYPE_IP_REGO6XX)) {
|
||||
return new IpRego6xxHeatPumpHandler(thing);
|
||||
}
|
||||
|
||||
if (thingTypeUID.equals(THING_TYPE_SERIAL_REGO6XX)) {
|
||||
return new SerialRego6xxHeatPumpHandler(thing, serialPortManager);
|
||||
}
|
||||
|
||||
if (thingTypeUID.equals(THING_TYPE_IP_HUSDATA)) {
|
||||
return new IpHusdataHandler(thing);
|
||||
}
|
||||
|
||||
if (thingTypeUID.equals(THING_TYPE_SERIAL_HUSDATA)) {
|
||||
return new SerialHusdataHandler(thing, serialPortManager);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,284 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.regoheatpump.internal.handler;
|
||||
|
||||
import static org.openhab.binding.regoheatpump.internal.RegoHeatPumpBindingConstants.*;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.EOFException;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.OutputStream;
|
||||
import java.net.SocketTimeoutException;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ScheduledFuture;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.openhab.binding.regoheatpump.internal.protocol.RegoConnection;
|
||||
import org.openhab.core.library.types.DecimalType;
|
||||
import org.openhab.core.library.types.QuantityType;
|
||||
import org.openhab.core.library.unit.MetricPrefix;
|
||||
import org.openhab.core.library.unit.SmartHomeUnits;
|
||||
import org.openhab.core.thing.ChannelUID;
|
||||
import org.openhab.core.thing.Thing;
|
||||
import org.openhab.core.thing.ThingStatus;
|
||||
import org.openhab.core.thing.binding.BaseThingHandler;
|
||||
import org.openhab.core.types.Command;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* The {@link HusdataHandler} is responsible for handling commands, which are
|
||||
* sent to one of the channels.
|
||||
*
|
||||
* @author Boris Krivonog - Initial contribution
|
||||
*/
|
||||
abstract class HusdataHandler extends BaseThingHandler {
|
||||
|
||||
private static final Map<Integer, String> MAPPINGS;
|
||||
private final Logger logger = LoggerFactory.getLogger(HusdataHandler.class);
|
||||
private RegoConnection connection;
|
||||
private ScheduledFuture<?> scheduledRefreshFuture;
|
||||
private BufferedReader bufferedReader;
|
||||
|
||||
static {
|
||||
MAPPINGS = mappings();
|
||||
}
|
||||
|
||||
protected HusdataHandler(Thing thing) {
|
||||
super(thing);
|
||||
}
|
||||
|
||||
protected abstract RegoConnection createConnection();
|
||||
|
||||
@Override
|
||||
public void initialize() {
|
||||
bufferedReader = null;
|
||||
connection = createConnection();
|
||||
|
||||
updateStatus(ThingStatus.UNKNOWN);
|
||||
|
||||
scheduledRefreshFuture = scheduler.scheduleWithFixedDelay(this::handleDataFromHusdataInterface, 2, 1,
|
||||
TimeUnit.SECONDS);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
super.dispose();
|
||||
|
||||
if (scheduledRefreshFuture != null) {
|
||||
scheduledRefreshFuture.cancel(true);
|
||||
scheduledRefreshFuture = null;
|
||||
}
|
||||
|
||||
if (connection != null) {
|
||||
connection.close();
|
||||
connection = null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleCommand(ChannelUID channelUID, Command command) {
|
||||
}
|
||||
|
||||
private synchronized void handleDataFromHusdataInterface() {
|
||||
RegoConnection connection = this.connection;
|
||||
if (connection == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
while (!Thread.interrupted()) {
|
||||
try {
|
||||
if (!connection.isConnected()) {
|
||||
bufferedReader = null;
|
||||
connection.connect();
|
||||
|
||||
// Request real-time registers.
|
||||
logger.debug("Requesting read and dump of real-time registers.");
|
||||
final OutputStream outputStream = connection.outputStream();
|
||||
outputStream.write(new String("XR\r\n").getBytes());
|
||||
outputStream.flush();
|
||||
}
|
||||
|
||||
if (bufferedReader == null) {
|
||||
bufferedReader = new BufferedReader(new InputStreamReader(connection.inputStream()));
|
||||
}
|
||||
|
||||
final String line = bufferedReader.readLine();
|
||||
if (line == null) {
|
||||
throw new EOFException();
|
||||
}
|
||||
|
||||
if (line.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
logger.debug("Got '{}'", line);
|
||||
|
||||
processReceivedData(line);
|
||||
} catch (SocketTimeoutException e) {
|
||||
// Do nothing. Just happen to allow the thread to check if it has to stop.
|
||||
break;
|
||||
} catch (IOException e) {
|
||||
logger.warn("Processing request failed", e);
|
||||
|
||||
bufferedReader = null;
|
||||
|
||||
if (!Thread.interrupted()) {
|
||||
connection.close();
|
||||
updateStatus(ThingStatus.OFFLINE);
|
||||
}
|
||||
|
||||
break;
|
||||
} catch (Exception e) {
|
||||
logger.warn("Error occurred during message waiting", e);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// If state here is still unknown, than something went wrong so set thing status to OFFLINE.
|
||||
if (thing.getStatus() == ThingStatus.UNKNOWN) {
|
||||
updateStatus(ThingStatus.OFFLINE);
|
||||
}
|
||||
}
|
||||
|
||||
private void processReceivedData(final String line) {
|
||||
if (line.length() != 10) {
|
||||
logger.debug("Unexpected length for '{}'", line);
|
||||
return;
|
||||
}
|
||||
|
||||
if (line.charAt(0) != 'X' || line.charAt(1) != 'R') {
|
||||
logger.debug("Expecting XRxxxxxxxx but got '{}'", line);
|
||||
return;
|
||||
}
|
||||
|
||||
int dataType = Integer.parseInt(line.substring(2, 3), 16);
|
||||
int register = Integer.parseInt(line.substring(3, 6), 16);
|
||||
int value = (short) (Integer.parseInt(line.substring(6, 8), 16) * 256
|
||||
+ Integer.parseInt(line.substring(8, 10), 16));
|
||||
|
||||
logger.debug("dataType = {}, register = {}, value = {}", dataType, register, value);
|
||||
|
||||
updateStatus(ThingStatus.ONLINE);
|
||||
|
||||
int channel = ((dataType & 0x0f) << 12) | (register & 0x0fff);
|
||||
String channelID = MAPPINGS.get(channel);
|
||||
if (channelID == null) {
|
||||
logger.debug("Unsupported register {}.", register);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!isLinked(channelID)) {
|
||||
logger.debug("Ignoring channel {} since it is not linked.", channelID);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (dataType) {
|
||||
case 0x00: // Degrees
|
||||
updateState(channelID, new QuantityType<>(value / 10.0, SmartHomeUnits.DEGREE_ANGLE));
|
||||
break;
|
||||
|
||||
case 0x02: // Number
|
||||
updateState(channelID, new DecimalType(value / 10.0));
|
||||
break;
|
||||
|
||||
case 0x03: // Percent
|
||||
updateState(channelID, new QuantityType<>(value / 10.0, SmartHomeUnits.PERCENT));
|
||||
break;
|
||||
|
||||
case 0x04: // Ampere
|
||||
updateState(channelID, new QuantityType<>(value / 10.0, SmartHomeUnits.AMPERE));
|
||||
break;
|
||||
|
||||
case 0x05: // kWh
|
||||
updateState(channelID, new QuantityType<>(value / 10.0, SmartHomeUnits.KILOWATT_HOUR));
|
||||
break;
|
||||
|
||||
case 0x06: // Hours
|
||||
updateState(channelID, new QuantityType<>(value, SmartHomeUnits.HOUR));
|
||||
break;
|
||||
|
||||
case 0x07: // Minutes
|
||||
updateState(channelID, new QuantityType<>(value, SmartHomeUnits.MINUTE));
|
||||
break;
|
||||
|
||||
case 0x09: // kw
|
||||
updateState(channelID, new QuantityType<>(value, MetricPrefix.KILO(SmartHomeUnits.WATT)));
|
||||
break;
|
||||
|
||||
case 0x01: // Switch
|
||||
case 0x08: // Degree minutes
|
||||
case 0x0A: // Pulses (For S0 El-meter pulse counter)
|
||||
updateState(channelID, new DecimalType(value));
|
||||
break;
|
||||
|
||||
default:
|
||||
logger.debug("Ignoring {} due unsupported data type {}.", channelID, dataType);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private static Map<Integer, String> mappings() {
|
||||
final Map<Integer, String> mappings = new HashMap<>();
|
||||
{
|
||||
// Sensor values
|
||||
mappings.put(0x0001, CHANNEL_GROUP_SENSOR_VALUES + "radiatorReturn");
|
||||
mappings.put(0x0002, CHANNEL_GROUP_SENSOR_VALUES + "radiatorForward");
|
||||
mappings.put(0x0003, CHANNEL_GROUP_SENSOR_VALUES + "heatFluidIn");
|
||||
mappings.put(0x0004, CHANNEL_GROUP_SENSOR_VALUES + "heatFluidOut");
|
||||
mappings.put(0x0005, CHANNEL_GROUP_SENSOR_VALUES + "coldFluidIn");
|
||||
mappings.put(0x0006, CHANNEL_GROUP_SENSOR_VALUES + "coldFluidOut");
|
||||
mappings.put(0x0007, CHANNEL_GROUP_SENSOR_VALUES + "outdoor");
|
||||
mappings.put(0x0008, CHANNEL_GROUP_SENSOR_VALUES + "indoor");
|
||||
mappings.put(0x0009, CHANNEL_GROUP_SENSOR_VALUES + "hotWater");
|
||||
mappings.put(0x000A, CHANNEL_GROUP_SENSOR_VALUES + "externalHotWater");
|
||||
mappings.put(0x000B, CHANNEL_GROUP_SENSOR_VALUES + "compressor");
|
||||
mappings.put(0x000E, CHANNEL_GROUP_SENSOR_VALUES + "airIntake");
|
||||
mappings.put(0x0011, CHANNEL_GROUP_SENSOR_VALUES + "pool");
|
||||
|
||||
// Control data
|
||||
mappings.put(0x3104, CHANNEL_GROUP_CONTROL_DATA + "addHeatPowerPercent"); // %
|
||||
mappings.put(0x5104, CHANNEL_GROUP_CONTROL_DATA + "addHeatPowerEnergy"); // kWh
|
||||
mappings.put(0x0107, CHANNEL_GROUP_CONTROL_DATA + "radiatorReturnTarget");
|
||||
mappings.put(0x2108, CHANNEL_GROUP_CONTROL_DATA + "compressorSpeed");
|
||||
|
||||
// Device values
|
||||
mappings.put(0x1A01, CHANNEL_GROUP_DEVICE_VALUES + "compressor");
|
||||
mappings.put(0x1A04, CHANNEL_GROUP_DEVICE_VALUES + "coldFluidPump");
|
||||
mappings.put(0x1A05, CHANNEL_GROUP_DEVICE_VALUES + "heatFluidPump");
|
||||
mappings.put(0x1A06, CHANNEL_GROUP_DEVICE_VALUES + "radiatorPump");
|
||||
mappings.put(0x1A07, CHANNEL_GROUP_DEVICE_VALUES + "switchValve");
|
||||
mappings.put(0x1A08, CHANNEL_GROUP_DEVICE_VALUES + "switchValve2");
|
||||
mappings.put(0x1A09, CHANNEL_GROUP_DEVICE_VALUES + "fan");
|
||||
mappings.put(0x1A0A, CHANNEL_GROUP_DEVICE_VALUES + "highPressostat");
|
||||
mappings.put(0x1A0B, CHANNEL_GROUP_DEVICE_VALUES + "lowPressostat");
|
||||
mappings.put(0x1A0C, CHANNEL_GROUP_DEVICE_VALUES + "heatingCable");
|
||||
mappings.put(0x1A0D, CHANNEL_GROUP_DEVICE_VALUES + "crankCaseHeater");
|
||||
mappings.put(0x1A20, CHANNEL_GROUP_DEVICE_VALUES + "alarm");
|
||||
mappings.put(0xAFF1, CHANNEL_GROUP_DEVICE_VALUES + "elMeter1");
|
||||
mappings.put(0xAFF2, CHANNEL_GROUP_DEVICE_VALUES + "elMeter2");
|
||||
|
||||
// Settings
|
||||
mappings.put(0x0203, CHANNEL_GROUP_SETTINGS + "indoorTempSetting");
|
||||
mappings.put(0x2204, CHANNEL_GROUP_SETTINGS + "curveInflByInTemp");
|
||||
mappings.put(0x0205, CHANNEL_GROUP_SETTINGS + "heatCurve");
|
||||
mappings.put(0x0206, CHANNEL_GROUP_SETTINGS + "heatCurve2");
|
||||
mappings.put(0x0207, CHANNEL_GROUP_SETTINGS + "heatCurveFineAdj");
|
||||
}
|
||||
|
||||
return Collections.unmodifiableMap(mappings);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.regoheatpump.internal.handler;
|
||||
|
||||
import org.openhab.binding.regoheatpump.internal.RegoHeatPumpBindingConstants;
|
||||
import org.openhab.binding.regoheatpump.internal.protocol.IpRegoConnection;
|
||||
import org.openhab.binding.regoheatpump.internal.protocol.RegoConnection;
|
||||
import org.openhab.core.thing.Thing;
|
||||
|
||||
/**
|
||||
* The {@link IpHusdataHandler} is responsible for handling commands, which are
|
||||
* sent to one of the channels.
|
||||
*
|
||||
* @author Boris Krivonog - Initial contribution
|
||||
*/
|
||||
public class IpHusdataHandler extends HusdataHandler {
|
||||
public IpHusdataHandler(Thing thing) {
|
||||
super(thing);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected RegoConnection createConnection() {
|
||||
String host = (String) getConfig().get(RegoHeatPumpBindingConstants.HOST_PARAMETER);
|
||||
Integer port = ((Number) getConfig().get(RegoHeatPumpBindingConstants.TCP_PORT_PARAMETER)).intValue();
|
||||
|
||||
return new IpRegoConnection(host, port);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.regoheatpump.internal.handler;
|
||||
|
||||
import org.openhab.binding.regoheatpump.internal.RegoHeatPumpBindingConstants;
|
||||
import org.openhab.binding.regoheatpump.internal.protocol.IpRegoConnection;
|
||||
import org.openhab.binding.regoheatpump.internal.protocol.RegoConnection;
|
||||
import org.openhab.core.thing.Thing;
|
||||
|
||||
/**
|
||||
* The {@link IpRego6xxHeatPumpHandler} is responsible for handling commands, which are
|
||||
* sent to one of the channels.
|
||||
*
|
||||
* @author Boris Krivonog - Initial contribution
|
||||
*/
|
||||
public class IpRego6xxHeatPumpHandler extends Rego6xxHeatPumpHandler {
|
||||
public IpRego6xxHeatPumpHandler(Thing thing) {
|
||||
super(thing);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected RegoConnection createConnection() {
|
||||
String host = (String) getConfig().get(RegoHeatPumpBindingConstants.HOST_PARAMETER);
|
||||
Integer port = ((Number) getConfig().get(RegoHeatPumpBindingConstants.TCP_PORT_PARAMETER)).intValue();
|
||||
|
||||
return new IpRegoConnection(host, port);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,413 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.regoheatpump.internal.handler;
|
||||
|
||||
import static org.openhab.binding.regoheatpump.internal.RegoHeatPumpBindingConstants.*;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.util.Collection;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ScheduledFuture;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import javax.measure.Unit;
|
||||
|
||||
import org.openhab.binding.regoheatpump.internal.protocol.RegoConnection;
|
||||
import org.openhab.binding.regoheatpump.internal.rego6xx.CommandFactory;
|
||||
import org.openhab.binding.regoheatpump.internal.rego6xx.ErrorLine;
|
||||
import org.openhab.binding.regoheatpump.internal.rego6xx.Rego6xxProtocolException;
|
||||
import org.openhab.binding.regoheatpump.internal.rego6xx.RegoRegisterMapper;
|
||||
import org.openhab.binding.regoheatpump.internal.rego6xx.ResponseParser;
|
||||
import org.openhab.binding.regoheatpump.internal.rego6xx.ResponseParserFactory;
|
||||
import org.openhab.core.library.types.DateTimeType;
|
||||
import org.openhab.core.library.types.DecimalType;
|
||||
import org.openhab.core.library.types.QuantityType;
|
||||
import org.openhab.core.library.types.StringType;
|
||||
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.types.Command;
|
||||
import org.openhab.core.types.RefreshType;
|
||||
import org.openhab.core.types.State;
|
||||
import org.openhab.core.types.UnDefType;
|
||||
import org.openhab.core.util.HexUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* The {@link Rego6xxHeatPumpHandler} is responsible for handling commands, which are
|
||||
* sent to one of the channels.
|
||||
*
|
||||
* @author Boris Krivonog - Initial contribution
|
||||
*/
|
||||
abstract class Rego6xxHeatPumpHandler extends BaseThingHandler {
|
||||
|
||||
private static final class ChannelDescriptor {
|
||||
private Date lastUpdate;
|
||||
private byte[] cachedValue;
|
||||
|
||||
public byte[] cachedValueIfNotExpired(int refreshTime) {
|
||||
if (lastUpdate == null || (lastUpdate.getTime() + refreshTime * 900 < new Date().getTime())) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return cachedValue;
|
||||
}
|
||||
|
||||
public void setValue(byte[] value) {
|
||||
lastUpdate = new Date();
|
||||
cachedValue = value;
|
||||
}
|
||||
}
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(Rego6xxHeatPumpHandler.class);
|
||||
private final Map<String, ChannelDescriptor> channelDescriptors = new HashMap<>();
|
||||
private int refreshInterval;
|
||||
private RegoConnection connection;
|
||||
private RegoRegisterMapper mapper;
|
||||
private ScheduledFuture<?> scheduledRefreshFuture;
|
||||
|
||||
protected Rego6xxHeatPumpHandler(Thing thing) {
|
||||
super(thing);
|
||||
}
|
||||
|
||||
protected abstract RegoConnection createConnection();
|
||||
|
||||
@Override
|
||||
public void initialize() {
|
||||
mapper = RegoRegisterMapper.REGO600;
|
||||
refreshInterval = ((Number) getConfig().get(REFRESH_INTERVAL)).intValue();
|
||||
|
||||
connection = createConnection();
|
||||
|
||||
scheduledRefreshFuture = scheduler.scheduleWithFixedDelay(this::refresh, 2, refreshInterval, TimeUnit.SECONDS);
|
||||
|
||||
updateStatus(ThingStatus.UNKNOWN);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
super.dispose();
|
||||
|
||||
if (connection != null) {
|
||||
connection.close();
|
||||
}
|
||||
|
||||
if (scheduledRefreshFuture != null) {
|
||||
scheduledRefreshFuture.cancel(true);
|
||||
scheduledRefreshFuture = null;
|
||||
}
|
||||
|
||||
synchronized (channelDescriptors) {
|
||||
channelDescriptors.clear();
|
||||
}
|
||||
|
||||
connection = null;
|
||||
mapper = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleCommand(ChannelUID channelUID, Command command) {
|
||||
if (command instanceof RefreshType) {
|
||||
processChannelReadRequest(channelUID.getId());
|
||||
} else {
|
||||
RegoRegisterMapper.Channel channel = mapper.map(channelUID.getId());
|
||||
if (channel != null) {
|
||||
logger.debug("Executing command '{}' for channel '{}'", command, channelUID.getId());
|
||||
processChannelWriteRequest(channel, command);
|
||||
} else {
|
||||
logger.debug("Unsupported channel {}", channelUID.getId());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static double commandToValue(Command command) {
|
||||
if (command instanceof QuantityType<?>) {
|
||||
return ((QuantityType<?>) command).doubleValue();
|
||||
}
|
||||
|
||||
if (command instanceof DecimalType) {
|
||||
return ((DecimalType) command).doubleValue();
|
||||
}
|
||||
|
||||
throw new NumberFormatException("Command '" + command + "' not supported");
|
||||
}
|
||||
|
||||
private void processChannelWriteRequest(RegoRegisterMapper.Channel channel, Command command) {
|
||||
short value = (short) Math.round(commandToValue(command) / channel.scaleFactor());
|
||||
byte[] commandPayload = CommandFactory.createWriteToSystemRegisterCommand(channel.address(), value);
|
||||
executeCommand(null, commandPayload, ResponseParserFactory.WRITE, result -> {
|
||||
// Ignore result since it is a write command.
|
||||
});
|
||||
}
|
||||
|
||||
private void processChannelReadRequest(String channelIID) {
|
||||
switch (channelIID) {
|
||||
case CHANNEL_LAST_ERROR_TYPE:
|
||||
readAndUpdateLastErrorType();
|
||||
break;
|
||||
case CHANNEL_LAST_ERROR_TIMESTAMP:
|
||||
readAndUpdateLastErrorTimestamp();
|
||||
break;
|
||||
case CHANNEL_FRONT_PANEL_POWER_LAMP:
|
||||
readAndUpdateFrontPanel(channelIID, (short) 0x0012);
|
||||
break;
|
||||
case CHANNEL_FRONT_PANEL_PUMP_LAMP:
|
||||
readAndUpdateFrontPanel(channelIID, (short) 0x0013);
|
||||
break;
|
||||
case CHANNEL_FRONT_PANEL_ADDITIONAL_HEAT_LAMP:
|
||||
readAndUpdateFrontPanel(channelIID, (short) 0x0014);
|
||||
break;
|
||||
case CHANNEL_FRONT_PANEL_WATER_HEATER_LAMP:
|
||||
readAndUpdateFrontPanel(channelIID, (short) 0x0015);
|
||||
break;
|
||||
case CHANNEL_FRONT_PANEL_ALARM_LAMP:
|
||||
readAndUpdateFrontPanel(channelIID, (short) 0x0016);
|
||||
break;
|
||||
default:
|
||||
readAndUpdateSystemRegister(channelIID);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private Collection<String> linkedChannels() {
|
||||
return thing.getChannels().stream().map(Channel::getUID).map(ChannelUID::getId).filter(this::isLinked)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
private void refresh() {
|
||||
for (String channelIID : linkedChannels()) {
|
||||
if (Thread.interrupted()) {
|
||||
break;
|
||||
}
|
||||
|
||||
processChannelReadRequest(channelIID);
|
||||
|
||||
if (thing.getStatus() != ThingStatus.ONLINE) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void readAndUpdateLastErrorType() {
|
||||
readAndUpdateLastError(CHANNEL_LAST_ERROR_TYPE, e -> new StringType(Byte.toString(e.error())));
|
||||
}
|
||||
|
||||
private void readAndUpdateLastErrorTimestamp() {
|
||||
readAndUpdateLastError(CHANNEL_LAST_ERROR_TIMESTAMP, e -> new DateTimeType(e.timestamp()));
|
||||
}
|
||||
|
||||
private void readAndUpdateLastError(String channelIID, Function<ErrorLine, State> converter) {
|
||||
executeCommandAndUpdateState(channelIID, CommandFactory.createReadLastErrorCommand(),
|
||||
ResponseParserFactory.ERROR_LINE, e -> {
|
||||
return e == null ? UnDefType.NULL : converter.apply(e);
|
||||
});
|
||||
}
|
||||
|
||||
private void readAndUpdateFrontPanel(String channelIID, short address) {
|
||||
byte[] command = CommandFactory.createReadFromFrontPanelCommand(address);
|
||||
executeCommandAndUpdateState(channelIID, command, ResponseParserFactory.SHORT, DecimalType::new);
|
||||
}
|
||||
|
||||
private void readAndUpdateSystemRegister(String channelIID) {
|
||||
RegoRegisterMapper.Channel channel = mapper.map(channelIID);
|
||||
if (channel != null) {
|
||||
byte[] command = CommandFactory.createReadFromSystemRegisterCommand(channel.address());
|
||||
executeCommandAndUpdateState(channelIID, command, ResponseParserFactory.SHORT, value -> {
|
||||
Unit<?> unit = channel.unit();
|
||||
double result = Math.round(channel.convertValue(value) * channel.scaleFactor() * 10.0) / 10.0;
|
||||
return unit != null ? new QuantityType<>(result, unit) : new DecimalType(result);
|
||||
});
|
||||
} else {
|
||||
logger.debug("Unsupported channel {}", channelIID);
|
||||
}
|
||||
}
|
||||
|
||||
private <T> void executeCommandAndUpdateState(String channelIID, byte[] command, ResponseParser<T> parser,
|
||||
Function<T, State> converter) {
|
||||
logger.debug("Reading value for channel '{}' ...", channelIID);
|
||||
executeCommand(channelIID, command, parser, result -> {
|
||||
logger.debug("Got value for '{}' = {}", channelIID, result);
|
||||
updateState(channelIID, converter.apply(result));
|
||||
});
|
||||
}
|
||||
|
||||
private synchronized <T> void executeCommand(String channelIID, byte[] command, ResponseParser<T> parser,
|
||||
Consumer<T> resultProcessor) {
|
||||
try {
|
||||
T result = executeCommandWithRetry(channelIID, command, parser, 5);
|
||||
resultProcessor.accept(result);
|
||||
} catch (IOException e) {
|
||||
logger.warn("Executing command for channel '{}' failed.", channelIID, e);
|
||||
|
||||
synchronized (channelDescriptors) {
|
||||
channelDescriptors.clear();
|
||||
}
|
||||
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, e.getMessage());
|
||||
} catch (Rego6xxProtocolException e) {
|
||||
logger.warn("Executing command for channel '{}' failed.", channelIID, e);
|
||||
updateState(channelIID, UnDefType.UNDEF);
|
||||
} catch (InterruptedException e) {
|
||||
logger.debug("Execution interrupted when accessing value for channel '{}'.", channelIID, e);
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
}
|
||||
|
||||
private <T> T executeCommandWithRetry(String channelIID, byte[] command, ResponseParser<T> parser, int retry)
|
||||
throws Rego6xxProtocolException, IOException, InterruptedException {
|
||||
try {
|
||||
checkRegoDevice();
|
||||
return executeCommand(channelIID, command, parser);
|
||||
} catch (IOException | Rego6xxProtocolException e) {
|
||||
if (retry > 0) {
|
||||
logger.debug("Executing command for channel '{}' failed, retry {}.", channelIID, retry, e);
|
||||
Thread.sleep(200);
|
||||
return executeCommandWithRetry(channelIID, command, parser, retry - 1);
|
||||
}
|
||||
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
private void checkRegoDevice() throws Rego6xxProtocolException, IOException, InterruptedException {
|
||||
if (thing.getStatus() != ThingStatus.ONLINE) {
|
||||
logger.debug("Reading Rego device version...");
|
||||
Short regoVersion = executeCommand(null, CommandFactory.createReadRegoVersionCommand(),
|
||||
ResponseParserFactory.SHORT);
|
||||
|
||||
if (regoVersion != 600) {
|
||||
throw new IOException("Invalid rego version received " + regoVersion.toString());
|
||||
}
|
||||
|
||||
updateStatus(ThingStatus.ONLINE);
|
||||
logger.debug("Connected to Rego version {}.", regoVersion);
|
||||
}
|
||||
}
|
||||
|
||||
private ChannelDescriptor channelDescriptorForChannel(String channelIID) {
|
||||
synchronized (channelDescriptors) {
|
||||
ChannelDescriptor descriptor = channelDescriptors.get(channelIID);
|
||||
if (descriptor == null) {
|
||||
descriptor = new ChannelDescriptor();
|
||||
channelDescriptors.put(channelIID, descriptor);
|
||||
}
|
||||
return descriptor;
|
||||
}
|
||||
}
|
||||
|
||||
private <T> T executeCommand(String channelIID, byte[] command, ResponseParser<T> parser)
|
||||
throws Rego6xxProtocolException, IOException, InterruptedException {
|
||||
try {
|
||||
return executeCommandInternal(channelIID, command, parser);
|
||||
} catch (IOException e) {
|
||||
if (connection != null) {
|
||||
connection.close();
|
||||
}
|
||||
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
private <T> T executeCommandInternal(String channelIID, byte[] command, ResponseParser<T> parser)
|
||||
throws Rego6xxProtocolException, IOException, InterruptedException {
|
||||
// CHANNEL_LAST_ERROR_CODE and CHANNEL_LAST_ERROR_TIMESTAMP are read from same
|
||||
// register. To prevent accessing same register twice when both channels are linked,
|
||||
// use same name for both so only a single fetch will be triggered.
|
||||
String mappedChannelIID = (CHANNEL_LAST_ERROR_TYPE.equals(channelIID)
|
||||
|| CHANNEL_LAST_ERROR_TIMESTAMP.equals(channelIID)) ? CHANNEL_LAST_ERROR : channelIID;
|
||||
|
||||
// Use transient channel descriptor for null (not cached) channels.
|
||||
ChannelDescriptor descriptor = channelIID == null ? new ChannelDescriptor()
|
||||
: channelDescriptorForChannel(mappedChannelIID);
|
||||
|
||||
byte[] cachedValue = descriptor.cachedValueIfNotExpired(refreshInterval);
|
||||
if (cachedValue != null) {
|
||||
logger.debug("Cache did not yet expire, using cached value for {}", mappedChannelIID);
|
||||
return parser.parse(cachedValue);
|
||||
}
|
||||
|
||||
// Send command to device and wait for response.
|
||||
if (!connection.isConnected()) {
|
||||
connection.connect();
|
||||
}
|
||||
|
||||
// Give heat pump some time between commands. Feeding commands too quickly
|
||||
// might cause heat pump not to respond.
|
||||
Thread.sleep(80);
|
||||
|
||||
// Protocol is request driven so there should be no data available before sending
|
||||
// a command to the heat pump.
|
||||
InputStream inputStream = connection.inputStream();
|
||||
int available = inputStream.available();
|
||||
if (available > 0) {
|
||||
// Limit to max 64 bytes, fuse.
|
||||
byte[] buffer = new byte[Math.min(64, available)];
|
||||
inputStream.read(buffer);
|
||||
logger.debug("There are {} unexpected bytes available. Skipping {}.", available, buffer);
|
||||
}
|
||||
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Sending {}", HexUtils.bytesToHex(command));
|
||||
}
|
||||
|
||||
// Send command
|
||||
OutputStream outputStream = connection.outputStream();
|
||||
outputStream.write(command);
|
||||
outputStream.flush();
|
||||
|
||||
// Read response, wait for max 2 second for data to arrive.
|
||||
byte[] response = new byte[parser.responseLength()];
|
||||
long timeout = System.currentTimeMillis() + 2000;
|
||||
int pos = 0;
|
||||
|
||||
do {
|
||||
int len = inputStream.read(response, pos, response.length - pos);
|
||||
if (len > 0) {
|
||||
pos += len;
|
||||
} else {
|
||||
// Give some time for response to arrive...
|
||||
Thread.sleep(50);
|
||||
}
|
||||
|
||||
} while (pos < response.length && timeout > System.currentTimeMillis());
|
||||
|
||||
if (pos < response.length) {
|
||||
logger.debug("Response not received, read {} bytes => {}", pos, response);
|
||||
|
||||
throw new IOException("Response not received - got " + Integer.toString(pos) + " bytes of "
|
||||
+ Integer.toString(response.length));
|
||||
}
|
||||
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Received {}", HexUtils.bytesToHex(response));
|
||||
}
|
||||
|
||||
T result = parser.parse(response);
|
||||
|
||||
// If reading/parsing was done successfully, cache response payload.
|
||||
descriptor.setValue(response);
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.regoheatpump.internal.handler;
|
||||
|
||||
import org.openhab.binding.regoheatpump.internal.RegoHeatPumpBindingConstants;
|
||||
import org.openhab.binding.regoheatpump.internal.protocol.RegoConnection;
|
||||
import org.openhab.binding.regoheatpump.internal.protocol.SerialRegoConnection;
|
||||
import org.openhab.core.io.transport.serial.SerialPortIdentifier;
|
||||
import org.openhab.core.io.transport.serial.SerialPortManager;
|
||||
import org.openhab.core.thing.Thing;
|
||||
import org.openhab.core.thing.ThingStatus;
|
||||
import org.openhab.core.thing.ThingStatusDetail;
|
||||
|
||||
/**
|
||||
* The {@link SerialHusdataHandler} is responsible for handling commands, which are
|
||||
* sent to one of the channels.
|
||||
*
|
||||
* @author Boris Krivonog - Initial contribution
|
||||
*/
|
||||
public class SerialHusdataHandler extends HusdataHandler {
|
||||
private final SerialPortManager serialPortManager;
|
||||
private SerialPortIdentifier serialPortIdentifier;
|
||||
|
||||
public SerialHusdataHandler(Thing thing, SerialPortManager serialPortManager) {
|
||||
super(thing);
|
||||
this.serialPortManager = serialPortManager;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initialize() {
|
||||
String portName = (String) getConfig().get(RegoHeatPumpBindingConstants.PORT_NAME);
|
||||
serialPortIdentifier = serialPortManager.getIdentifier(portName);
|
||||
if (serialPortIdentifier == null) {
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
|
||||
"Serial port does not exist: " + portName);
|
||||
} else {
|
||||
super.initialize();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected RegoConnection createConnection() {
|
||||
return new SerialRegoConnection(serialPortIdentifier, 19200);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.regoheatpump.internal.handler;
|
||||
|
||||
import org.openhab.binding.regoheatpump.internal.RegoHeatPumpBindingConstants;
|
||||
import org.openhab.binding.regoheatpump.internal.protocol.RegoConnection;
|
||||
import org.openhab.binding.regoheatpump.internal.protocol.SerialRegoConnection;
|
||||
import org.openhab.core.io.transport.serial.SerialPortIdentifier;
|
||||
import org.openhab.core.io.transport.serial.SerialPortManager;
|
||||
import org.openhab.core.thing.Thing;
|
||||
import org.openhab.core.thing.ThingStatus;
|
||||
import org.openhab.core.thing.ThingStatusDetail;
|
||||
|
||||
/**
|
||||
* The {@link SerialRego6xxHeatPumpHandler} is responsible for handling commands, which are
|
||||
* sent to one of the channels.
|
||||
*
|
||||
* @author Boris Krivonog - Initial contribution
|
||||
*/
|
||||
public class SerialRego6xxHeatPumpHandler extends Rego6xxHeatPumpHandler {
|
||||
private final SerialPortManager serialPortManager;
|
||||
private SerialPortIdentifier serialPortIdentifier;
|
||||
|
||||
public SerialRego6xxHeatPumpHandler(Thing thing, SerialPortManager serialPortManager) {
|
||||
super(thing);
|
||||
this.serialPortManager = serialPortManager;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initialize() {
|
||||
String portName = (String) getConfig().get(RegoHeatPumpBindingConstants.PORT_NAME);
|
||||
serialPortIdentifier = serialPortManager.getIdentifier(portName);
|
||||
if (serialPortIdentifier == null) {
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
|
||||
"Serial port does not exist: " + portName);
|
||||
} else {
|
||||
super.initialize();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected RegoConnection createConnection() {
|
||||
return new SerialRegoConnection(serialPortIdentifier, 19200);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.regoheatpump.internal.protocol;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.Socket;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* The {@link IpRegoConnection} is responsible for creating TCP/IP connections to clients.
|
||||
*
|
||||
* @author Boris Krivonog - Initial contribution
|
||||
*/
|
||||
public class IpRegoConnection implements RegoConnection {
|
||||
/**
|
||||
* Connection timeout in milliseconds
|
||||
**/
|
||||
private static final int CONNECTION_TIMEOUT = 3000;
|
||||
|
||||
/**
|
||||
* Socket read timeout in milliseconds
|
||||
**/
|
||||
private static final int SOCKET_READ_TIMEOUT = 2000;
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(IpRegoConnection.class);
|
||||
private final String address;
|
||||
private final int port;
|
||||
private Socket clientSocket;
|
||||
|
||||
public IpRegoConnection(String address, int port) {
|
||||
this.address = address;
|
||||
this.port = port;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void connect() throws IOException {
|
||||
logger.debug("Connecting to '{}', port = {}.", address, port);
|
||||
if (clientSocket == null) {
|
||||
clientSocket = new Socket();
|
||||
clientSocket.setSoTimeout(SOCKET_READ_TIMEOUT);
|
||||
clientSocket.setKeepAlive(true);
|
||||
}
|
||||
clientSocket.connect(new InetSocketAddress(address, port), CONNECTION_TIMEOUT);
|
||||
logger.debug("Connected to '{}', port = {}.", address, port);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isConnected() {
|
||||
return clientSocket != null && clientSocket.isConnected();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
try {
|
||||
if (clientSocket != null) {
|
||||
clientSocket.close();
|
||||
}
|
||||
} catch (IOException e) {
|
||||
// There is really not much we can do here, ignore the error and continue execution.
|
||||
logger.warn("Closing socket failed", e);
|
||||
}
|
||||
|
||||
clientSocket = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public OutputStream outputStream() throws IOException {
|
||||
return clientSocket.getOutputStream();
|
||||
}
|
||||
|
||||
@Override
|
||||
public InputStream inputStream() throws IOException {
|
||||
return clientSocket.getInputStream();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.regoheatpump.internal.protocol;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
|
||||
/**
|
||||
* The {@link RegoConnection} is responsible for creating connections to clients.
|
||||
*
|
||||
* @author Boris Krivonog - Initial contribution
|
||||
*/
|
||||
public interface RegoConnection {
|
||||
/**
|
||||
* Connect to the receiver. Return true if the connection has succeeded or if already connected.
|
||||
*
|
||||
**/
|
||||
public void connect() throws IOException;
|
||||
|
||||
/**
|
||||
* Return true if this manager is connected to the AVR.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public boolean isConnected();
|
||||
|
||||
/**
|
||||
* Closes the connection.
|
||||
**/
|
||||
public void close();
|
||||
|
||||
/**
|
||||
* Returns an output stream for this connection.
|
||||
*/
|
||||
public OutputStream outputStream() throws IOException;
|
||||
|
||||
/**
|
||||
* Returns an input stream for this connection.
|
||||
*/
|
||||
public InputStream inputStream() throws IOException;
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.regoheatpump.internal.protocol;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
|
||||
import org.openhab.core.io.transport.serial.PortInUseException;
|
||||
import org.openhab.core.io.transport.serial.SerialPort;
|
||||
import org.openhab.core.io.transport.serial.SerialPortIdentifier;
|
||||
import org.openhab.core.io.transport.serial.UnsupportedCommOperationException;
|
||||
|
||||
/**
|
||||
* The {@link SerialRegoConnection} is responsible for creating serial connections to clients.
|
||||
*
|
||||
* @author Boris Krivonog - Initial contribution
|
||||
*/
|
||||
public class SerialRegoConnection implements RegoConnection {
|
||||
private final int baudRate;
|
||||
private final String portName;
|
||||
private SerialPort serialPort;
|
||||
private final SerialPortIdentifier serialPortIdentifier;
|
||||
|
||||
public SerialRegoConnection(SerialPortIdentifier serialPortIdentifier, int baudRate) {
|
||||
this.serialPortIdentifier = serialPortIdentifier;
|
||||
this.portName = serialPortIdentifier.getName();
|
||||
this.baudRate = baudRate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void connect() throws IOException {
|
||||
try {
|
||||
serialPort = serialPortIdentifier.open(SerialRegoConnection.class.getCanonicalName(), 2000);
|
||||
serialPort.enableReceiveTimeout(100);
|
||||
serialPort.setSerialPortParams(baudRate, SerialPort.DATABITS_8, SerialPort.STOPBITS_1,
|
||||
SerialPort.PARITY_NONE);
|
||||
} catch (PortInUseException e) {
|
||||
throw new IOException("Serial port already used: " + portName, e);
|
||||
} catch (UnsupportedCommOperationException e) {
|
||||
throw new IOException("Unsupported operation on '" + portName + "': " + e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isConnected() {
|
||||
return serialPort != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
if (serialPort != null) {
|
||||
serialPort.close();
|
||||
serialPort = null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public OutputStream outputStream() throws IOException {
|
||||
return serialPort.getOutputStream();
|
||||
}
|
||||
|
||||
@Override
|
||||
public InputStream inputStream() throws IOException {
|
||||
return serialPort.getInputStream();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.regoheatpump.internal.rego6xx;
|
||||
|
||||
/**
|
||||
* The {@link AbstractLongResponseParser} is responsible for parsing long form responses.
|
||||
*
|
||||
* @author Boris Krivonog - Initial contribution
|
||||
*/
|
||||
abstract class AbstractLongResponseParser<T> extends AbstractResponseParser<T> {
|
||||
@Override
|
||||
public int responseLength() {
|
||||
return 42;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.regoheatpump.internal.rego6xx;
|
||||
|
||||
import org.openhab.core.util.HexUtils;
|
||||
|
||||
/**
|
||||
* The {@link AbstractResponseParser} is responsible for parsing responses coming from
|
||||
* rego6xx controllers.
|
||||
*
|
||||
* @author Boris Krivonog - Initial contribution
|
||||
*/
|
||||
abstract class AbstractResponseParser<T> implements ResponseParser<T> {
|
||||
private static final byte COMPUTER_ADDRESS = (byte) 0x01;
|
||||
|
||||
@Override
|
||||
public abstract int responseLength();
|
||||
|
||||
protected abstract T convert(byte[] responseBytes);
|
||||
|
||||
@Override
|
||||
public T parse(byte[] buffer) throws Rego6xxProtocolException {
|
||||
if (buffer.length != responseLength()) {
|
||||
throw new Rego6xxProtocolException(
|
||||
"Expected size does not match: " + buffer.length + " != " + responseLength());
|
||||
}
|
||||
|
||||
if (buffer[0] != COMPUTER_ADDRESS) {
|
||||
throw new Rego6xxProtocolException("Invalid header " + HexUtils.bytesToHex(buffer));
|
||||
}
|
||||
|
||||
if (responseLength() > 1
|
||||
&& Checksum.calculate(buffer, 1, responseLength() - 2) != buffer[responseLength() - 1]) {
|
||||
throw new Rego6xxProtocolException("Invalid crc - " + HexUtils.bytesToHex(buffer));
|
||||
}
|
||||
|
||||
return convert(buffer);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.regoheatpump.internal.rego6xx;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* The {@link Checksum} is responsible for calculating checksum of given data.
|
||||
*
|
||||
* @author Boris Krivonog - Initial contribution
|
||||
*/
|
||||
class Checksum {
|
||||
static byte calculate(byte[]... lists) {
|
||||
return Arrays.stream(lists).reduce((byte) 0, Checksum::calculate, (a, b) -> b);
|
||||
}
|
||||
|
||||
static byte calculate(byte[] buffer, int offset, int count) {
|
||||
return calculate((byte) 0, buffer, offset, count);
|
||||
}
|
||||
|
||||
private static byte calculate(byte checksum, byte[] buffer) {
|
||||
return calculate(checksum, buffer, 0, buffer.length);
|
||||
}
|
||||
|
||||
private static byte calculate(byte checksum, byte[] buffer, int offset, int count) {
|
||||
byte result = checksum;
|
||||
int end = count + offset;
|
||||
for (int index = offset; index < end; ++index) {
|
||||
result = (byte) (result ^ buffer[index]);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.regoheatpump.internal.rego6xx;
|
||||
|
||||
/**
|
||||
* The {@link CommandFactory} is responsible for creating different commands that can
|
||||
* be send to a rego 6xx unit.
|
||||
*
|
||||
* @author Boris Krivonog - Initial contribution
|
||||
*/
|
||||
public class CommandFactory {
|
||||
private static final byte DEVICE_ADDRESS = (byte) 0x81;
|
||||
|
||||
public static byte[] createReadRegoVersionCommand() {
|
||||
return createReadCommand((byte) 0x7f, (short) 0);
|
||||
}
|
||||
|
||||
public static byte[] createReadFromSystemRegisterCommand(short address) {
|
||||
return createReadCommand((byte) 0x02, address);
|
||||
}
|
||||
|
||||
public static byte[] createWriteToSystemRegisterCommand(short address, short data) {
|
||||
return createCommand((byte) 0x03, address, data);
|
||||
}
|
||||
|
||||
public static byte[] createReadFromDisplayCommand(short displayLine) {
|
||||
return createReadCommand((byte) 0x20, displayLine);
|
||||
}
|
||||
|
||||
public static byte[] createReadLastErrorCommand() {
|
||||
return createReadCommand((byte) 0x40, (short) 0);
|
||||
}
|
||||
|
||||
public static byte[] createReadFromFrontPanelCommand(short address) {
|
||||
return createReadCommand((byte) 0x00, address);
|
||||
}
|
||||
|
||||
private static byte[] createReadCommand(byte source, short address) {
|
||||
return createCommand(source, address, (short) 0);
|
||||
}
|
||||
|
||||
private static byte[] createCommand(byte source, short address, short data) {
|
||||
byte[] addressBytes = ValueConverter.shortToSevenBitFormat(address);
|
||||
byte[] dataBytes = ValueConverter.shortToSevenBitFormat(data);
|
||||
return new byte[] { DEVICE_ADDRESS, source, addressBytes[0], addressBytes[1], addressBytes[2], dataBytes[0],
|
||||
dataBytes[1], dataBytes[2], Checksum.calculate(addressBytes, dataBytes) };
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.regoheatpump.internal.rego6xx;
|
||||
|
||||
import java.time.ZoneId;
|
||||
import java.time.ZonedDateTime;
|
||||
|
||||
/**
|
||||
* The {@link ErrorLine} is responsible for holding information about a single error line.
|
||||
*
|
||||
* @author Boris Krivonog - Initial contribution
|
||||
*/
|
||||
public class ErrorLine {
|
||||
private final byte error;
|
||||
private final String timestamp;
|
||||
|
||||
public ErrorLine(byte error, String timestamp) {
|
||||
this.error = error;
|
||||
this.timestamp = timestamp;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format("%d @ %s", error, timestamp);
|
||||
}
|
||||
|
||||
public byte error() {
|
||||
return error;
|
||||
}
|
||||
|
||||
public String timestampAsString() {
|
||||
return timestamp;
|
||||
}
|
||||
|
||||
public ZonedDateTime timestamp() {
|
||||
int year = Integer.parseInt(timestamp.substring(0, 2)) + 1000;
|
||||
if (year < 1950) {
|
||||
year += 1000;
|
||||
}
|
||||
int month = Integer.parseInt(timestamp.substring(2, 4));
|
||||
int day = Integer.parseInt(timestamp.substring(4, 6));
|
||||
int hour = Integer.parseInt(timestamp.substring(7, 9));
|
||||
int min = Integer.parseInt(timestamp.substring(10, 12));
|
||||
int sec = Integer.parseInt(timestamp.substring(13, 15));
|
||||
|
||||
return ZonedDateTime.of(year, month, day, hour, min, sec, 0, ZoneId.systemDefault());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.regoheatpump.internal.rego6xx;
|
||||
|
||||
/**
|
||||
* The {@link ErrorLineResponseParser} is responsible for parsing error information (log) entry.
|
||||
*
|
||||
* @author Boris Krivonog - Initial contribution
|
||||
*/
|
||||
class ErrorLineResponseParser extends AbstractLongResponseParser<ErrorLine> {
|
||||
|
||||
@Override
|
||||
protected ErrorLine convert(byte[] responseBytes) {
|
||||
// 255 marks no error.
|
||||
if (responseBytes[1] == (byte) 255) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return new ErrorLine(ValueConverter.arrayToByte(responseBytes, 1),
|
||||
ValueConverter.stringFromBytes(responseBytes, 3, 15));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.regoheatpump.internal.rego6xx;
|
||||
|
||||
/**
|
||||
* The {@link Rego6xxProtocolException} is responsible for holding information about an Rego6xx protocol error.
|
||||
*
|
||||
* @author Boris Krivonog - Initial contribution
|
||||
*/
|
||||
public class Rego6xxProtocolException extends Exception {
|
||||
|
||||
private static final long serialVersionUID = 7556083982084149686L;
|
||||
|
||||
public Rego6xxProtocolException(String message) {
|
||||
super(message);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,180 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.regoheatpump.internal.rego6xx;
|
||||
|
||||
import static org.openhab.binding.regoheatpump.internal.RegoHeatPumpBindingConstants.*;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.measure.Unit;
|
||||
|
||||
import org.openhab.core.library.unit.SIUnits;
|
||||
import org.openhab.core.library.unit.SmartHomeUnits;
|
||||
|
||||
/**
|
||||
* The {@link RegoRegisterMapper} is responsible for mapping rego 6xx registers into channels.
|
||||
*
|
||||
* @author Boris Krivonog - Initial contribution
|
||||
*/
|
||||
public class RegoRegisterMapper {
|
||||
public static final RegoRegisterMapper REGO600;
|
||||
|
||||
public static interface Channel {
|
||||
public short address();
|
||||
|
||||
public double scaleFactor();
|
||||
|
||||
public Unit<?> unit();
|
||||
|
||||
public int convertValue(short value);
|
||||
}
|
||||
|
||||
private static class ChannelFactory {
|
||||
private static class ChannelImpl implements Channel {
|
||||
private final short address;
|
||||
private final double scaleFactor;
|
||||
private final Unit<?> unit;
|
||||
|
||||
private ChannelImpl(short address, double scaleFactor, Unit<?> unit) {
|
||||
this.address = address;
|
||||
this.scaleFactor = scaleFactor;
|
||||
this.unit = unit;
|
||||
}
|
||||
|
||||
@Override
|
||||
public short address() {
|
||||
return address;
|
||||
}
|
||||
|
||||
@Override
|
||||
public double scaleFactor() {
|
||||
return scaleFactor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Unit<?> unit() {
|
||||
return unit;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int convertValue(short value) {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
private ChannelFactory() {
|
||||
}
|
||||
|
||||
static Channel temperature(short address) {
|
||||
return new ChannelImpl(address, 0.1, SIUnits.CELSIUS);
|
||||
}
|
||||
|
||||
static Channel hours(short address) {
|
||||
return new ChannelImpl(address, 1, SmartHomeUnits.HOUR) {
|
||||
@Override
|
||||
public int convertValue(short value) {
|
||||
return Short.toUnsignedInt(value);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
static Channel percent(short address) {
|
||||
return new ChannelImpl(address, 0.1, SmartHomeUnits.PERCENT);
|
||||
}
|
||||
|
||||
static Channel unitless(short address, double scaleFactor) {
|
||||
return new ChannelImpl(address, scaleFactor, null);
|
||||
}
|
||||
}
|
||||
|
||||
private final Map<String, Channel> mappings;
|
||||
|
||||
private RegoRegisterMapper(Map<String, Channel> mappings) {
|
||||
this.mappings = mappings;
|
||||
}
|
||||
|
||||
public Channel map(String channelIID) {
|
||||
return mappings.get(channelIID);
|
||||
}
|
||||
|
||||
static {
|
||||
final Map<String, Channel> mappings = new HashMap<>();
|
||||
{
|
||||
// Sensor values
|
||||
mappings.put(CHANNEL_GROUP_SENSOR_VALUES + "radiatorReturn", ChannelFactory.temperature((short) 521));
|
||||
mappings.put(CHANNEL_GROUP_SENSOR_VALUES + "outdoor", ChannelFactory.temperature((short) 522));
|
||||
mappings.put(CHANNEL_GROUP_SENSOR_VALUES + "hotWater", ChannelFactory.temperature((short) 523));
|
||||
mappings.put(CHANNEL_GROUP_SENSOR_VALUES + "radiatorForward", ChannelFactory.temperature((short) 524));
|
||||
mappings.put(CHANNEL_GROUP_SENSOR_VALUES + "indoor", ChannelFactory.temperature((short) 525));
|
||||
mappings.put(CHANNEL_GROUP_SENSOR_VALUES + "compressor", ChannelFactory.temperature((short) 526));
|
||||
mappings.put(CHANNEL_GROUP_SENSOR_VALUES + "heatFluidOut", ChannelFactory.temperature((short) 527));
|
||||
mappings.put(CHANNEL_GROUP_SENSOR_VALUES + "heatFluidIn", ChannelFactory.temperature((short) 528));
|
||||
mappings.put(CHANNEL_GROUP_SENSOR_VALUES + "coldFluidIn", ChannelFactory.temperature((short) 529));
|
||||
mappings.put(CHANNEL_GROUP_SENSOR_VALUES + "coldFluidOut", ChannelFactory.temperature((short) 530));
|
||||
mappings.put(CHANNEL_GROUP_SENSOR_VALUES + "externalHotWater", ChannelFactory.temperature((short) 531));
|
||||
|
||||
// Control data
|
||||
mappings.put(CHANNEL_GROUP_CONTROL_DATA + "radiatorReturnTarget", ChannelFactory.temperature((short) 110));
|
||||
mappings.put(CHANNEL_GROUP_CONTROL_DATA + "radiatorReturnOn", ChannelFactory.temperature((short) 111));
|
||||
mappings.put(CHANNEL_GROUP_CONTROL_DATA + "radiatorReturnOff", ChannelFactory.temperature((short) 112));
|
||||
mappings.put(CHANNEL_GROUP_CONTROL_DATA + "hotWaterOn", ChannelFactory.temperature((short) 115));
|
||||
mappings.put(CHANNEL_GROUP_CONTROL_DATA + "hotWaterOff", ChannelFactory.temperature((short) 116));
|
||||
mappings.put(CHANNEL_GROUP_CONTROL_DATA + "radiatorForwardTarget", ChannelFactory.temperature((short) 109));
|
||||
mappings.put(CHANNEL_GROUP_CONTROL_DATA + "addHeatPowerPercent", ChannelFactory.percent((short) 108));
|
||||
|
||||
// Device values
|
||||
mappings.put(CHANNEL_GROUP_DEVICE_VALUES + "coldFluidPump", ChannelFactory.unitless((short) 509, 1));
|
||||
mappings.put(CHANNEL_GROUP_DEVICE_VALUES + "compressor", ChannelFactory.unitless((short) 510, 1));
|
||||
mappings.put(CHANNEL_GROUP_DEVICE_VALUES + "additionalHeat3kW", ChannelFactory.unitless((short) 511, 1));
|
||||
mappings.put(CHANNEL_GROUP_DEVICE_VALUES + "additionalHeat6kW", ChannelFactory.unitless((short) 512, 1));
|
||||
mappings.put(CHANNEL_GROUP_DEVICE_VALUES + "radiatorPump", ChannelFactory.unitless((short) 515, 1));
|
||||
mappings.put(CHANNEL_GROUP_DEVICE_VALUES + "heatFluidPump", ChannelFactory.unitless((short) 516, 1));
|
||||
mappings.put(CHANNEL_GROUP_DEVICE_VALUES + "switchValve", ChannelFactory.unitless((short) 517, 1));
|
||||
mappings.put(CHANNEL_GROUP_DEVICE_VALUES + "alarm", ChannelFactory.unitless((short) 518, 1));
|
||||
|
||||
// Settings
|
||||
mappings.put(CHANNEL_GROUP_SETTINGS + "heatCurve", ChannelFactory.unitless((short) 0x0000, 0.1));
|
||||
mappings.put(CHANNEL_GROUP_SETTINGS + "heatCurveFineAdj", ChannelFactory.temperature((short) 0x0001));
|
||||
mappings.put(CHANNEL_GROUP_SETTINGS + "heatCurveCouplingDiff", ChannelFactory.temperature((short) 0x0002));
|
||||
mappings.put(CHANNEL_GROUP_SETTINGS + "heatCurve2", ChannelFactory.unitless((short) 0x0003, 0.1));
|
||||
mappings.put(CHANNEL_GROUP_SETTINGS + "heatCurve2FineAdj", ChannelFactory.temperature((short) 0x0004));
|
||||
mappings.put(CHANNEL_GROUP_SETTINGS + "adjCurveAt20", ChannelFactory.temperature((short) 0x001e));
|
||||
mappings.put(CHANNEL_GROUP_SETTINGS + "adjCurveAt15", ChannelFactory.temperature((short) 0x001c));
|
||||
mappings.put(CHANNEL_GROUP_SETTINGS + "adjCurveAt10", ChannelFactory.temperature((short) 0x001a));
|
||||
mappings.put(CHANNEL_GROUP_SETTINGS + "adjCurveAt5", ChannelFactory.temperature((short) 0x0018));
|
||||
mappings.put(CHANNEL_GROUP_SETTINGS + "adjCurveAt0", ChannelFactory.temperature((short) 0x0016));
|
||||
mappings.put(CHANNEL_GROUP_SETTINGS + "adjCurveAtMinus5", ChannelFactory.temperature((short) 0x0014));
|
||||
mappings.put(CHANNEL_GROUP_SETTINGS + "adjCurveAtMinus10", ChannelFactory.temperature((short) 0x0012));
|
||||
mappings.put(CHANNEL_GROUP_SETTINGS + "adjCurveAtMinus15", ChannelFactory.temperature((short) 0x0010));
|
||||
mappings.put(CHANNEL_GROUP_SETTINGS + "adjCurveAtMinus20", ChannelFactory.temperature((short) 0x000e));
|
||||
mappings.put(CHANNEL_GROUP_SETTINGS + "adjCurveAtMinus25", ChannelFactory.temperature((short) 0x000c));
|
||||
mappings.put(CHANNEL_GROUP_SETTINGS + "adjCurveAtMinus30", ChannelFactory.temperature((short) 0x000a));
|
||||
mappings.put(CHANNEL_GROUP_SETTINGS + "adjCurveAtMinus35", ChannelFactory.temperature((short) 0x0008));
|
||||
mappings.put(CHANNEL_GROUP_SETTINGS + "indoorTempSetting", ChannelFactory.temperature((short) 0x0021));
|
||||
mappings.put(CHANNEL_GROUP_SETTINGS + "curveInflByInTemp", ChannelFactory.unitless((short) 0x0022, 0.1));
|
||||
mappings.put(CHANNEL_GROUP_SETTINGS + "summerDisconnection", ChannelFactory.temperature((short) 0x0024));
|
||||
mappings.put(CHANNEL_GROUP_SETTINGS + "hotWaterTarget", ChannelFactory.temperature((short) 0x002b));
|
||||
mappings.put(CHANNEL_GROUP_SETTINGS + "hotWaterTargetHysteresis",
|
||||
ChannelFactory.temperature((short) 0x002c));
|
||||
|
||||
// Operating times
|
||||
mappings.put(CHANNEL_GROUP_OPERATING_TIMES + "heatPumpInOperationRAD", ChannelFactory.hours((short) 72));
|
||||
mappings.put(CHANNEL_GROUP_OPERATING_TIMES + "heatPumpInOperationDHW", ChannelFactory.hours((short) 74));
|
||||
mappings.put(CHANNEL_GROUP_OPERATING_TIMES + "addHeatInOperationRAD", ChannelFactory.hours((short) 76));
|
||||
mappings.put(CHANNEL_GROUP_OPERATING_TIMES + "addHeatInOperationDHW", ChannelFactory.hours((short) 78));
|
||||
}
|
||||
|
||||
REGO600 = new RegoRegisterMapper(mappings);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.regoheatpump.internal.rego6xx;
|
||||
|
||||
/**
|
||||
* The {@link ResponseParser} is responsible for parsing arbitrary data coming from a rego 6xx unit.
|
||||
*
|
||||
* @author Boris Krivonog - Initial contribution
|
||||
*/
|
||||
public interface ResponseParser<T> {
|
||||
public int responseLength();
|
||||
|
||||
public T parse(byte[] buffer) throws Rego6xxProtocolException;
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.regoheatpump.internal.rego6xx;
|
||||
|
||||
/**
|
||||
* The {@link ResponseParserFactory} is responsible for providing parsers for all known data
|
||||
* forms coming from the rego 6xx unit.
|
||||
*
|
||||
* @author Boris Krivonog - Initial contribution
|
||||
*/
|
||||
public class ResponseParserFactory {
|
||||
public static final ResponseParser<Short> SHORT = new ShortResponseParser();
|
||||
public static final ResponseParser<String> STRING = new StringResponseParser();
|
||||
public static final ResponseParser<ErrorLine> ERROR_LINE = new ErrorLineResponseParser();
|
||||
public static final ResponseParser<Void> WRITE = new WriteResponse();
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.regoheatpump.internal.rego6xx;
|
||||
|
||||
/**
|
||||
* The {@link ShortResponseParser} is responsible for parsing short form data format
|
||||
* coming from the rego 6xx unit.
|
||||
*
|
||||
* @author Boris Krivonog - Initial contribution
|
||||
*/
|
||||
class ShortResponseParser extends AbstractResponseParser<Short> {
|
||||
|
||||
@Override
|
||||
public int responseLength() {
|
||||
return 5;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Short convert(byte[] responseBytes) {
|
||||
return ValueConverter.sevenBitFormatToShort(responseBytes, 1);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.regoheatpump.internal.rego6xx;
|
||||
|
||||
/**
|
||||
* The {@link StringResponseParser} is responsible for parsing long (text) form data format
|
||||
* coming from the rego 6xx unit.
|
||||
*
|
||||
* @author Boris Krivonog - Initial contribution
|
||||
*/
|
||||
class StringResponseParser extends AbstractLongResponseParser<String> {
|
||||
|
||||
@Override
|
||||
protected String convert(byte[] responseBytes) {
|
||||
return ValueConverter.stringFromBytes(responseBytes, 1, 20);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.regoheatpump.internal.rego6xx;
|
||||
|
||||
/**
|
||||
* The {@link ValueConverter} is responsible for converting various rego 6xx specific data types.
|
||||
*
|
||||
* @author Boris Krivonog - Initial contribution
|
||||
*/
|
||||
class ValueConverter {
|
||||
public static byte[] shortToSevenBitFormat(short value) {
|
||||
byte b1 = (byte) ((value & 0xC000) >> 14);
|
||||
byte b2 = (byte) ((value & 0x3F80) >> 7);
|
||||
byte b3 = (byte) (value & 0x007F);
|
||||
|
||||
return new byte[] { b1, b2, b3 };
|
||||
}
|
||||
|
||||
public static short sevenBitFormatToShort(byte[] buffer, int offset) {
|
||||
return (short) (buffer[offset] << 14 | buffer[offset + 1] << 7 | buffer[offset + 2]);
|
||||
}
|
||||
|
||||
public static byte arrayToByte(byte[] buffer, int offset) {
|
||||
return (byte) (buffer[offset] << 4 | buffer[offset + 1]);
|
||||
}
|
||||
|
||||
public static String stringFromBytes(byte[] buffer, int offset, int charCount) {
|
||||
StringBuilder builder = new StringBuilder(charCount);
|
||||
|
||||
int length = offset + charCount * 2;
|
||||
for (int i = offset; i < length; i += 2) {
|
||||
builder.append((char) arrayToByte(buffer, i));
|
||||
}
|
||||
|
||||
return builder.toString();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.regoheatpump.internal.rego6xx;
|
||||
|
||||
/**
|
||||
* The {@link WriteResponse} is responsible for parsing write responses
|
||||
* coming from the rego 6xx unit.
|
||||
*
|
||||
* @author Boris Krivonog - Initial contribution
|
||||
*/
|
||||
class WriteResponse extends AbstractResponseParser<Void> {
|
||||
@Override
|
||||
public int responseLength() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Void convert(byte[] responseBytes) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<binding:binding id="regoheatpump" 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>RegoHeatPump Binding</name>
|
||||
<description>The Rego controller based heat pumps binding.</description>
|
||||
<author>Boris Krivonog</author>
|
||||
|
||||
</binding:binding>
|
||||
@@ -0,0 +1,817 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<thing:thing-descriptions bindingId="regoheatpump"
|
||||
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">
|
||||
|
||||
<!-- Manage Rego 6xx based Heat Pump over IP -->
|
||||
<thing-type id="ipRego6xx">
|
||||
<label>Heat Pump</label>
|
||||
<description>Manage Rego 6xx based heat pump over TCP/IP</description>
|
||||
|
||||
<channel-groups>
|
||||
<channel-group id="sensorValues" typeId="sensorValues"/>
|
||||
<channel-group id="controlData" typeId="controlData"/>
|
||||
<channel-group id="deviceValues" typeId="deviceValues"/>
|
||||
<channel-group id="settings" typeId="settings"/>
|
||||
<channel-group id="frontPanel" typeId="frontPanel"/>
|
||||
<channel-group id="status" typeId="status"/>
|
||||
<channel-group id="operatingTimes" typeId="operatingTimes"/>
|
||||
</channel-groups>
|
||||
|
||||
<config-description>
|
||||
<parameter name="address" type="text" required="true">
|
||||
<context>network-address</context>
|
||||
<label>Address</label>
|
||||
<description>The IP address of the Rego to control.</description>
|
||||
</parameter>
|
||||
<parameter name="tcpPort" type="integer" max="65535" min="1" required="false">
|
||||
<default>9265</default>
|
||||
<label>TCP Port</label>
|
||||
<description>The TCP port number used to connect to the Rego controller.</description>
|
||||
</parameter>
|
||||
<parameter name="refreshInterval" type="integer" max="65535" min="10" required="false">
|
||||
<default>60</default>
|
||||
<label>Refresh Interval</label>
|
||||
<description>Refresh interval in seconds.</description>
|
||||
</parameter>
|
||||
</config-description>
|
||||
</thing-type>
|
||||
|
||||
<!-- Manage Rego 6xx based Heat Pump over serial -->
|
||||
<thing-type id="serialRego6xx">
|
||||
<label>Heat Pump</label>
|
||||
<description>Manage Rego 6xx based heat pump over serial port</description>
|
||||
|
||||
<channel-groups>
|
||||
<channel-group id="sensorValues" typeId="sensorValues"/>
|
||||
<channel-group id="controlData" typeId="controlData"/>
|
||||
<channel-group id="deviceValues" typeId="deviceValues"/>
|
||||
<channel-group id="settings" typeId="settings"/>
|
||||
<channel-group id="frontPanel" typeId="frontPanel"/>
|
||||
<channel-group id="status" typeId="status"/>
|
||||
<channel-group id="operatingTimes" typeId="operatingTimes"/>
|
||||
</channel-groups>
|
||||
|
||||
<config-description>
|
||||
<parameter name="portName" type="text" required="true">
|
||||
<label>Port</label>
|
||||
<context>serial-port</context>
|
||||
<limitToOptions>false</limitToOptions>
|
||||
<description>The serial port used to connect to the Rego controller.</description>
|
||||
</parameter>
|
||||
<parameter name="refreshInterval" type="integer" max="65535" min="10" required="false">
|
||||
<default>60</default>
|
||||
<label>Refresh Interval</label>
|
||||
<description>Refresh interval in seconds.</description>
|
||||
</parameter>
|
||||
</config-description>
|
||||
</thing-type>
|
||||
|
||||
<!-- Manage Husdata interface over IP -->
|
||||
<thing-type id="ipHusdata">
|
||||
<label>Husdata Interface</label>
|
||||
<description>Access heat pump over Husdata interface connected via TCP/IP</description>
|
||||
|
||||
<channel-groups>
|
||||
<channel-group id="sensorValues" typeId="sensorValues"/>
|
||||
<channel-group id="controlData" typeId="controlData"/>
|
||||
<channel-group id="deviceValues" typeId="deviceValues"/>
|
||||
<channel-group id="settings" typeId="settings"/>
|
||||
</channel-groups>
|
||||
|
||||
<config-description>
|
||||
<parameter name="address" type="text" required="true">
|
||||
<context>network-address</context>
|
||||
<label>Address</label>
|
||||
<description>The IP address of the Rego to control.</description>
|
||||
</parameter>
|
||||
<parameter name="tcpPort" type="integer" max="65535" min="1" required="false">
|
||||
<default>9265</default>
|
||||
<label>TCP Port</label>
|
||||
<description>The TCP port number used to connect to the Rego controller.</description>
|
||||
</parameter>
|
||||
</config-description>
|
||||
</thing-type>
|
||||
|
||||
<!-- Manage Husdata interface over serial -->
|
||||
<thing-type id="serialHusdata">
|
||||
<label>Husdata Interface</label>
|
||||
<description>Access heat pump over Husdata interface connected via serial port</description>
|
||||
|
||||
<channel-groups>
|
||||
<channel-group id="sensorValues" typeId="sensorValues"/>
|
||||
<channel-group id="controlData" typeId="controlData"/>
|
||||
<channel-group id="deviceValues" typeId="deviceValues"/>
|
||||
<channel-group id="settings" typeId="settings"/>
|
||||
</channel-groups>
|
||||
|
||||
<config-description>
|
||||
<parameter name="portName" type="text" required="true">
|
||||
<label>Port</label>
|
||||
<context>serial-port</context>
|
||||
<limitToOptions>false</limitToOptions>
|
||||
<description>The serial port used to connect to the Husdata interface.</description>
|
||||
</parameter>
|
||||
</config-description>
|
||||
</thing-type>
|
||||
|
||||
<channel-group-type id="sensorValues">
|
||||
<label>Sensor Values</label>
|
||||
<channels>
|
||||
<channel id="radiatorReturn" typeId="radiatorReturnTemp"/>
|
||||
<channel id="outdoor" typeId="outdoorTemp"/>
|
||||
<channel id="hotWater" typeId="hotWaterTemp"/>
|
||||
<channel id="radiatorForward" typeId="radiatorForwardTemp"/>
|
||||
<channel id="indoor" typeId="indoorTemp"/>
|
||||
<channel id="compressor" typeId="compressorTemp"/>
|
||||
<channel id="heatFluidOut" typeId="heatFluidOutTemp"/>
|
||||
<channel id="heatFluidIn" typeId="heatFluidInTemp"/>
|
||||
<channel id="coldFluidIn" typeId="coldFluidInTemp"/>
|
||||
<channel id="coldFluidOut" typeId="coldFluidOutTemp"/>
|
||||
<channel id="externalHotWater" typeId="externalHotWaterTemp"/>
|
||||
<channel id="airIntake" typeId="airIntakeTemp"/>
|
||||
<channel id="pool" typeId="poolTemp"/>
|
||||
</channels>
|
||||
</channel-group-type>
|
||||
|
||||
<channel-group-type id="controlData">
|
||||
<label>Control Data</label>
|
||||
<channels>
|
||||
<channel id="radiatorReturnTarget" typeId="radiatorReturnTarget"/>
|
||||
<channel id="radiatorReturnOn" typeId="radiatorReturnOn"/>
|
||||
<channel id="radiatorReturnOff" typeId="radiatorReturnOff"/>
|
||||
<channel id="hotWaterOn" typeId="hotWaterOn"/>
|
||||
<channel id="hotWaterOff" typeId="hotWaterOff"/>
|
||||
<channel id="radiatorForwardTarget" typeId="radiatorForwardTarget"/>
|
||||
<channel id="addHeatPowerPercent" typeId="addHeatPowerPercent"/>
|
||||
<channel id="addHeatPowerEnergy" typeId="addHeatPowerEnergy"/>
|
||||
<channel id="compressorSpeed" typeId="compressorSpeed"/>
|
||||
</channels>
|
||||
</channel-group-type>
|
||||
|
||||
<channel-group-type id="deviceValues">
|
||||
<label>Device Values</label>
|
||||
<channels>
|
||||
<channel id="radiatorPump" typeId="radiatorPumpState"/>
|
||||
<channel id="heatFluidPump" typeId="heatFluidPumpState"/>
|
||||
<channel id="coldFluidPump" typeId="coldFluidPumpState"/>
|
||||
<channel id="compressor" typeId="compressorState"/>
|
||||
<channel id="additionalHeat3kW" typeId="additionalHeat3kWState"/>
|
||||
<channel id="additionalHeat6kW" typeId="additionalHeat6kWState"/>
|
||||
<channel id="alarm" typeId="alarmState"/>
|
||||
<channel id="switchValve" typeId="switchValveState"/>
|
||||
<channel id="switchValve2" typeId="switchValve2State"/>
|
||||
<channel id="fan" typeId="fanState"/>
|
||||
<channel id="highPressostat" typeId="highPressostatState"/>
|
||||
<channel id="lowPressostat" typeId="lowPressostatState"/>
|
||||
<channel id="heatingCable" typeId="heatingCableState"/>
|
||||
<channel id="crankCaseHeater" typeId="crankCaseHeaterState"/>
|
||||
<channel id="elMeter1" typeId="elMeter1"/>
|
||||
<channel id="elMeter2" typeId="elMeter2"/>
|
||||
</channels>
|
||||
</channel-group-type>
|
||||
|
||||
<channel-group-type id="settings">
|
||||
<label>Settings</label>
|
||||
<channels>
|
||||
<channel id="hotWaterTarget" typeId="hotWaterTarget"/>
|
||||
<channel id="hotWaterTargetHysteresis" typeId="hotWaterTargetHysteresis"/>
|
||||
<channel id="heatCurve" typeId="heatCurve"/>
|
||||
<channel id="heatCurveFineAdj" typeId="heatCurveFineAdj"/>
|
||||
<channel id="indoorTempSetting" typeId="indoorTempSetting"/>
|
||||
<channel id="curveInflByInTemp" typeId="curveInflByInTemp"/>
|
||||
<channel id="adjCurveAt20" typeId="adjCurveAt20"/>
|
||||
<channel id="adjCurveAt15" typeId="adjCurveAt15"/>
|
||||
<channel id="adjCurveAt10" typeId="adjCurveAt10"/>
|
||||
<channel id="adjCurveAt5" typeId="adjCurveAt5"/>
|
||||
<channel id="adjCurveAt0" typeId="adjCurveAt0"/>
|
||||
<channel id="adjCurveAtMinus5" typeId="adjCurveAtMinus5"/>
|
||||
<channel id="adjCurveAtMinus10" typeId="adjCurveAtMinus10"/>
|
||||
<channel id="adjCurveAtMinus15" typeId="adjCurveAtMinus15"/>
|
||||
<channel id="adjCurveAtMinus20" typeId="adjCurveAtMinus20"/>
|
||||
<channel id="adjCurveAtMinus25" typeId="adjCurveAtMinus25"/>
|
||||
<channel id="adjCurveAtMinus30" typeId="adjCurveAtMinus30"/>
|
||||
<channel id="adjCurveAtMinus35" typeId="adjCurveAtMinus35"/>
|
||||
<channel id="heatCurveCouplingDiff" typeId="heatCurveCouplingDiff"/>
|
||||
<channel id="heatCurve2" typeId="heatCurve2"/>
|
||||
<channel id="heatCurve2FineAdj" typeId="heatCurve2FineAdj"/>
|
||||
<channel id="summerDisconnection" typeId="summerDisconnection"/>
|
||||
</channels>
|
||||
</channel-group-type>
|
||||
|
||||
<channel-group-type id="status">
|
||||
<label>Status</label>
|
||||
<channels>
|
||||
<channel id="lastErrorTimestamp" typeId="lastErrorTimestamp"/>
|
||||
<channel id="lastErrorType" typeId="lastErrorType"/>
|
||||
</channels>
|
||||
</channel-group-type>
|
||||
|
||||
<channel-group-type id="frontPanel">
|
||||
<label>Front Panel</label>
|
||||
<channels>
|
||||
<channel id="powerLamp" typeId="powerLamp"/>
|
||||
<channel id="heatPumpLamp" typeId="heatPumpLamp"/>
|
||||
<channel id="additionalHeatLamp" typeId="additionalHeatLamp"/>
|
||||
<channel id="hotWaterLamp" typeId="hotWaterLamp"/>
|
||||
<channel id="alarmLamp" typeId="alarmLamp"/>
|
||||
</channels>
|
||||
</channel-group-type>
|
||||
|
||||
<channel-group-type id="operatingTimes">
|
||||
<label>Operating Times</label>
|
||||
<channels>
|
||||
<channel id="heatPumpInOperationRAD" typeId="heatPumpInOperationRAD"/>
|
||||
<channel id="heatPumpInOperationDHW" typeId="heatPumpInOperationDHW"/>
|
||||
<channel id="addHeatInOperationRAD" typeId="addHeatInOperationRAD"/>
|
||||
<channel id="addHeatInOperationDHW" typeId="addHeatInOperationDHW"/>
|
||||
</channels>
|
||||
</channel-group-type>
|
||||
|
||||
<channel-type id="radiatorReturnTemp">
|
||||
<item-type>Number:Temperature</item-type>
|
||||
<label>Radiator Return</label>
|
||||
<description>Temperature of the water that returns to the heat pump from the radiators</description>
|
||||
<category>Temperature</category>
|
||||
<state readOnly="true" pattern="%.1f %unit%"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="outdoorTemp">
|
||||
<item-type>Number:Temperature</item-type>
|
||||
<label>Outdoor</label>
|
||||
<description>The outdoor temperature. Determines how much heating the heat pump should produce</description>
|
||||
<category>Temperature</category>
|
||||
<state readOnly="true" pattern="%.1f %unit%"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="hotWaterTemp" advanced="true">
|
||||
<item-type>Number:Temperature</item-type>
|
||||
<label>Hot Water</label>
|
||||
<description>Temperature in the hot water cylinder</description>
|
||||
<category>Temperature</category>
|
||||
<state readOnly="true" pattern="%.1f %unit%"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="radiatorForwardTemp" advanced="true">
|
||||
<item-type>Number:Temperature</item-type>
|
||||
<label>Radiator Forward</label>
|
||||
<description>Temperature on the flow water in the circuit</description>
|
||||
<category>Temperature</category>
|
||||
<state readOnly="true" pattern="%.1f %unit%"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="indoorTemp" advanced="true">
|
||||
<item-type>Number:Temperature</item-type>
|
||||
<label>Indoor</label>
|
||||
<description>Present temperature in the room where the sensor is fitted</description>
|
||||
<category>Temperature</category>
|
||||
<state readOnly="true" pattern="%.1f %unit%"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="compressorTemp">
|
||||
<item-type>Number:Temperature</item-type>
|
||||
<label>Compressor</label>
|
||||
<description>Compressor’s working temperature</description>
|
||||
<category>Temperature</category>
|
||||
<state readOnly="true" pattern="%.1f %unit%"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="heatFluidOutTemp">
|
||||
<item-type>Number:Temperature</item-type>
|
||||
<label>Heat Fluid Out</label>
|
||||
<description>Temperature of the radiator water as it leaves the heat pump</description>
|
||||
<category>Temperature</category>
|
||||
<state readOnly="true" pattern="%.1f %unit%"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="heatFluidInTemp">
|
||||
<item-type>Number:Temperature</item-type>
|
||||
<label>Heat Fluid In</label>
|
||||
<description>Temperature of the water that is led into the heat pump</description>
|
||||
<category>Temperature</category>
|
||||
<state readOnly="true" pattern="%.1f %unit%"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="coldFluidInTemp">
|
||||
<item-type>Number:Temperature</item-type>
|
||||
<label>Cold Fluid In</label>
|
||||
<description>Temperature of the heat transfer fluid that is led into the heat pump from the bore hole or the ground</description>
|
||||
<category>Temperature</category>
|
||||
<state readOnly="true" pattern="%.1f %unit%"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="coldFluidOutTemp">
|
||||
<item-type>Number:Temperature</item-type>
|
||||
<label>Cold Fluid Out</label>
|
||||
<description>Temperature of the heat transfer fluid that is led out of the heat pump to the bore hole or the ground</description>
|
||||
<category>Temperature</category>
|
||||
<state readOnly="true" pattern="%.1f %unit%"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="externalHotWaterTemp" advanced="true">
|
||||
<item-type>Number:Temperature</item-type>
|
||||
<label>External Hot Water</label>
|
||||
<description>Temperature in the external hot water cylinder</description>
|
||||
<category>Temperature</category>
|
||||
<state readOnly="true" pattern="%.1f %unit%"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="lastErrorType">
|
||||
<item-type>String</item-type>
|
||||
<label>Last Error Type</label>
|
||||
<description>Information about the alarm type that occured last</description>
|
||||
<category>Error</category>
|
||||
<state readOnly="true" pattern="%s">
|
||||
<options>
|
||||
<option value="0">Sensor radiator return (GT1)</option>
|
||||
<option value="1">Outdoor sensor (GT2)</option>
|
||||
<option value="2">Sensor hot water (GT3)</option>
|
||||
<option value="3">Mixing valve sensor (GT4)</option>
|
||||
<option value="4">Room sensor (GT5)</option>
|
||||
<option value="5">Sensor compressor (GT6)</option>
|
||||
<option value="6">Sensor heat transfer fluid out (GT8)</option>
|
||||
<option value="7">Sensor heat transfer fluid in (GT9)</option>
|
||||
<option value="8">Sensor cold transfer fluid in (GT10)</option>
|
||||
<option value="9">Sensor cold transfer fluid in (GT11)</option>
|
||||
<option value="10">Compressor circuit switch</option>
|
||||
<option value="11">Electrical cassette</option>
|
||||
<option value="12">HTF C=pump switch (MB2)</option>
|
||||
<option value="13">Low pressure switch (LP)</option>
|
||||
<option value="14">High pressure switch (HP)</option>
|
||||
<option value="15">High return HP (GT9)</option>
|
||||
<option value="16">HTF out max (GT8)</option>
|
||||
<option value="17">HTF in under limit (GT10)</option>
|
||||
<option value="18">HTF out under limit (GT11)</option>
|
||||
<option value="19">Compressor superheat (GT6)</option>
|
||||
<option value="20">Three phase incorrect order</option>
|
||||
<option value="21">Power failure</option>
|
||||
<option value="22">High delta GT8/GT9</option>
|
||||
</options>
|
||||
</state>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="lastErrorTimestamp">
|
||||
<item-type>DateTime</item-type>
|
||||
<label>Last Error Date</label>
|
||||
<description>Information about when last alarm occurred</description>
|
||||
<category>Time</category>
|
||||
<state readOnly="true" pattern="%1$td.%1$tm.%1$tY %1$tH:%1$tM:%1$tS"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="powerLamp" advanced="true">
|
||||
<item-type>Switch</item-type>
|
||||
<label>Power Lamp</label>
|
||||
<description>Lamp on when the heat pump is on</description>
|
||||
<category>Switch</category>
|
||||
<state readOnly="true"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="heatPumpLamp">
|
||||
<item-type>Switch</item-type>
|
||||
<label>Heat Pump Lamp</label>
|
||||
<description>Lamp on when the heat pump (compressor) is operational</description>
|
||||
<category>Switch</category>
|
||||
<state readOnly="true"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="additionalHeatLamp">
|
||||
<item-type>Switch</item-type>
|
||||
<label>Additional Heat Lamp</label>
|
||||
<description>Lamp on when the heat pump is using additional heat from an electric cassette</description>
|
||||
<category>Switch</category>
|
||||
<state readOnly="true"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="hotWaterLamp">
|
||||
<item-type>Switch</item-type>
|
||||
<label>Hot Water Lamp</label>
|
||||
<description>Lamp on when the heat pump is heating water in the heater</description>
|
||||
<category>Switch</category>
|
||||
<state readOnly="true"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="alarmLamp">
|
||||
<item-type>Switch</item-type>
|
||||
<label>Alarm Lamp</label>
|
||||
<description>Lamp indicates that a fault has occurred in the heat pump</description>
|
||||
<category>Siren</category>
|
||||
<state readOnly="true"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="coldFluidPumpState" advanced="true">
|
||||
<item-type>Switch</item-type>
|
||||
<label>Cold Fluid Pump</label>
|
||||
<category>Switch</category>
|
||||
<state readOnly="true"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="compressorState" advanced="true">
|
||||
<item-type>Switch</item-type>
|
||||
<label>Compressor</label>
|
||||
<category>Switch</category>
|
||||
<state readOnly="true"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="radiatorPumpState" advanced="true">
|
||||
<item-type>Switch</item-type>
|
||||
<label>Radiator Pump</label>
|
||||
<category>Switch</category>
|
||||
<state readOnly="true"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="heatFluidPumpState" advanced="true">
|
||||
<item-type>Switch</item-type>
|
||||
<label>Heat Fluid Pump</label>
|
||||
<category>Switch</category>
|
||||
<state readOnly="true"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="additionalHeat3kWState" advanced="true">
|
||||
<item-type>Switch</item-type>
|
||||
<label>Additional Heat 3kW</label>
|
||||
<category>Switch</category>
|
||||
<state readOnly="true"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="additionalHeat6kWState" advanced="true">
|
||||
<item-type>Switch</item-type>
|
||||
<label>Additional Heat 6kW</label>
|
||||
<category>Switch</category>
|
||||
<state readOnly="true"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="switchValveState" advanced="true">
|
||||
<item-type>Switch</item-type>
|
||||
<label>Switch Valve</label>
|
||||
<description>The valve switches between heating the heating water and hot water</description>
|
||||
<category>Heating</category>
|
||||
<state readOnly="true"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="alarmState" advanced="true">
|
||||
<item-type>Switch</item-type>
|
||||
<label>Alarm</label>
|
||||
<category>Siren</category>
|
||||
<state readOnly="true"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="radiatorReturnTarget" advanced="true">
|
||||
<item-type>Number:Temperature</item-type>
|
||||
<label>Radiator Return Target</label>
|
||||
<description>Calculated desired radiator return temperature</description>
|
||||
<category>Temperature</category>
|
||||
<state readOnly="true" pattern="%.1f %unit%"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="radiatorReturnOn" advanced="true">
|
||||
<item-type>Number:Temperature</item-type>
|
||||
<label>Minimal Radiator Return</label>
|
||||
<description>Calculated minimal (start) radiator return temperature</description>
|
||||
<category>Temperature</category>
|
||||
<state readOnly="true" pattern="%.1f %unit%"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="radiatorReturnOff" advanced="true">
|
||||
<item-type>Number:Temperature</item-type>
|
||||
<label>Maximal Radiator Return</label>
|
||||
<description>Calculated maximal (stop) radiator return temperature</description>
|
||||
<category>Temperature</category>
|
||||
<state readOnly="true" pattern="%.1f %unit%"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="hotWaterTarget" advanced="true">
|
||||
<item-type>Number:Temperature</item-type>
|
||||
<label>Hot Water Target</label>
|
||||
<description>Desired radiator return temperature</description>
|
||||
<category>Temperature</category>
|
||||
<state min="35" max="54" step="0.1" pattern="%.1f %unit%"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="hotWaterTargetHysteresis" advanced="true">
|
||||
<item-type>Number:Temperature</item-type>
|
||||
<label>Hot Water Hysteresis</label>
|
||||
<description> The function measures below and above the value set in hotWaterTarget</description>
|
||||
<category>Temperature</category>
|
||||
<state min="2" max="15" step="0.1" pattern="%.1f %unit%"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="hotWaterOn" advanced="true">
|
||||
<item-type>Number:Temperature</item-type>
|
||||
<label>Minimal Hot Water</label>
|
||||
<description>Minimal (start) hot water temperature</description>
|
||||
<category>Temperature</category>
|
||||
<state readOnly="true" pattern="%.1f %unit%"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="hotWaterOff" advanced="true">
|
||||
<item-type>Number:Temperature</item-type>
|
||||
<label>Maximal Hot Water</label>
|
||||
<description>Maximal (stop) hot water temperature</description>
|
||||
<category>Temperature</category>
|
||||
<state readOnly="true" pattern="%.1f %unit%"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="radiatorForwardTarget" advanced="true">
|
||||
<item-type>Number:Temperature</item-type>
|
||||
<label>Radiator Forward Target</label>
|
||||
<description>Calculated desired radiator forward temperature</description>
|
||||
<category>Temperature</category>
|
||||
<state readOnly="true" pattern="%.1f %unit%"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="addHeatPowerPercent" advanced="true">
|
||||
<item-type>Number:Dimensionless</item-type>
|
||||
<label>Additional Heat Power</label>
|
||||
<category>Energy</category>
|
||||
<state readOnly="true" pattern="%.1f %unit%"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="addHeatPowerEnergy" advanced="true">
|
||||
<item-type>Number:Energy</item-type>
|
||||
<label>Additional Heat Power</label>
|
||||
<category>Energy</category>
|
||||
<state readOnly="true" pattern="%.1f %unit%"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="heatCurve" advanced="true">
|
||||
<item-type>Number</item-type>
|
||||
<label>Heat Curve</label>
|
||||
<description>Heat curve influences the heat pump’s production of heat</description>
|
||||
<category>Line</category>
|
||||
<state min="0" max="10" step="0.1" pattern="%.1f"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="heatCurveFineAdj" advanced="true">
|
||||
<item-type>Number:Temperature</item-type>
|
||||
<label>Heat Curve Fine Tune</label>
|
||||
<description>Fine-tuning means that you offset the heat curve in parallel</description>
|
||||
<category>Temperature</category>
|
||||
<state min="-10" max="10" step="0.1" pattern="%.1f %unit%"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="indoorTempSetting" advanced="true">
|
||||
<item-type>Number:Temperature</item-type>
|
||||
<label>Indoor Target</label>
|
||||
<description>Desired temperature in the room where the sensor is fitted</description>
|
||||
<category>Temperature</category>
|
||||
<state step="0.1" pattern="%.1f %unit%"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="curveInflByInTemp" advanced="true">
|
||||
<item-type>Number</item-type>
|
||||
<label>Room Sensor Influence</label>
|
||||
<description>Set how much the room sensor should influence the heat curve</description>
|
||||
<category>Line</category>
|
||||
<state step="0.1" pattern="%.1f"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="adjCurveAt20" advanced="true">
|
||||
<item-type>Number:Temperature</item-type>
|
||||
<label>Adjust Heat Curve At 20 °C</label>
|
||||
<description>Heat curve can be adjusted up or down every fifth outdoor degree. The purpose of breaking the curve is to
|
||||
be able to influence the heat pump's heat production at extra sensitive outdoor temperatures</description>
|
||||
<category>Temperature</category>
|
||||
<state step="0.1" pattern="%.1f %unit%"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="adjCurveAt15" advanced="true">
|
||||
<item-type>Number:Temperature</item-type>
|
||||
<label>Adjust Heat Curve At 15 °C</label>
|
||||
<description>Heat curve can be adjusted up or down every fifth outdoor degree. The purpose of breaking the curve is to
|
||||
be able to influence the heat pump's heat production at extra sensitive outdoor temperatures</description>
|
||||
<category>Temperature</category>
|
||||
<state step="0.1" pattern="%.1f %unit%"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="adjCurveAt10" advanced="true">
|
||||
<item-type>Number:Temperature</item-type>
|
||||
<label>Adjust Heat Curve At 10 °C</label>
|
||||
<description>Heat curve can be adjusted up or down every fifth outdoor degree. The purpose of breaking the curve is to
|
||||
be able to influence the heat pump's heat production at extra sensitive outdoor temperatures</description>
|
||||
<category>Temperature</category>
|
||||
<state step="0.1" pattern="%.1f %unit%"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="adjCurveAt5" advanced="true">
|
||||
<item-type>Number:Temperature</item-type>
|
||||
<label>Adjust Heat Curve At 5 °C</label>
|
||||
<description>Heat curve can be adjusted up or down every fifth outdoor degree. The purpose of breaking the curve is to
|
||||
be able to influence the heat pump's heat production at extra sensitive outdoor temperatures</description>
|
||||
<category>Temperature</category>
|
||||
<state step="0.1" pattern="%.1f %unit%"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="adjCurveAt0" advanced="true">
|
||||
<item-type>Number:Temperature</item-type>
|
||||
<label>Adjust Heat Curve At 0 °C</label>
|
||||
<description>Heat curve can be adjusted up or down every fifth outdoor degree. The purpose of breaking the curve is to
|
||||
be able to influence the heat pump's heat production at extra sensitive outdoor temperatures</description>
|
||||
<category>Temperature</category>
|
||||
<state step="0.1" pattern="%.1f %unit%"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="adjCurveAtMinus5" advanced="true">
|
||||
<item-type>Number:Temperature</item-type>
|
||||
<label>Adjust Heat Curve At -5 °C</label>
|
||||
<description>Heat curve can be adjusted up or down every fifth outdoor degree. The purpose of breaking the curve is to
|
||||
be able to influence the heat pump's heat production at extra sensitive outdoor temperatures</description>
|
||||
<category>Temperature</category>
|
||||
<state step="0.1" pattern="%.1f %unit%"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="adjCurveAtMinus10" advanced="true">
|
||||
<item-type>Number:Temperature</item-type>
|
||||
<label>Adjust Heat Curve At -10 °C</label>
|
||||
<description>Heat curve can be adjusted up or down every fifth outdoor degree. The purpose of breaking the curve is to
|
||||
be able to influence the heat pump's heat production at extra sensitive outdoor temperatures</description>
|
||||
<category>Temperature</category>
|
||||
<state step="0.1" pattern="%.1f %unit%"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="adjCurveAtMinus15" advanced="true">
|
||||
<item-type>Number:Temperature</item-type>
|
||||
<label>Adjust Heat Curve At -15 °C</label>
|
||||
<description>Heat curve can be adjusted up or down every fifth outdoor degree. The purpose of breaking the curve is to
|
||||
be able to influence the heat pump's heat production at extra sensitive outdoor temperatures</description>
|
||||
<category>Temperature</category>
|
||||
<state step="0.1" pattern="%.1f %unit%"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="adjCurveAtMinus20" advanced="true">
|
||||
<item-type>Number:Temperature</item-type>
|
||||
<label>Adjust Heat Curve At -20 °C</label>
|
||||
<description>Heat curve can be adjusted up or down every fifth outdoor degree. The purpose of breaking the curve is to
|
||||
be able to influence the heat pump's heat production at extra sensitive outdoor temperatures</description>
|
||||
<category>Temperature</category>
|
||||
<state step="0.1" pattern="%.1f %unit%"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="adjCurveAtMinus25" advanced="true">
|
||||
<item-type>Number:Temperature</item-type>
|
||||
<label>Adjust Heat Curve At -25 °C</label>
|
||||
<description>Heat curve can be adjusted up or down every fifth outdoor degree. The purpose of breaking the curve is to
|
||||
be able to influence the heat pump's heat production at extra sensitive outdoor temperatures</description>
|
||||
<category>Temperature</category>
|
||||
<state step="0.1" pattern="%.1f %unit%"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="adjCurveAtMinus30" advanced="true">
|
||||
<item-type>Number:Temperature</item-type>
|
||||
<label>Adjust Heat Curve At -30 °C</label>
|
||||
<description>Heat curve can be adjusted up or down every fifth outdoor degree. The purpose of breaking the curve is to
|
||||
be able to influence the heat pump's heat production at extra sensitive outdoor temperatures</description>
|
||||
<category>Temperature</category>
|
||||
<state step="0.1" pattern="%.1f %unit%"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="adjCurveAtMinus35" advanced="true">
|
||||
<item-type>Number:Temperature</item-type>
|
||||
<label>Adjust Heat Curve At -35 °C</label>
|
||||
<description>Heat curve can be adjusted up or down every fifth outdoor degree. The purpose of breaking the curve is to
|
||||
be able to influence the heat pump's heat production at extra sensitive outdoor temperatures</description>
|
||||
<category>Temperature</category>
|
||||
<state step="0.1" pattern="%.1f %unit%"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="heatCurveCouplingDiff" advanced="true">
|
||||
<item-type>Number:Temperature</item-type>
|
||||
<label>Heat Curve Coupling Diff</label>
|
||||
<category>Temperature</category>
|
||||
<state step="0.1" pattern="%.1f %unit%"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="airIntakeTemp" advanced="true">
|
||||
<item-type>Number:Temperature</item-type>
|
||||
<label>Air Intake</label>
|
||||
<category>Temperature</category>
|
||||
<state readOnly="true" pattern="%.1f %unit%"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="poolTemp" advanced="true">
|
||||
<item-type>Number:Temperature</item-type>
|
||||
<label>Pool</label>
|
||||
<category>Temperature</category>
|
||||
<state readOnly="true" pattern="%.1f %unit%"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="compressorSpeed" advanced="true">
|
||||
<item-type>Number:Dimensionless</item-type>
|
||||
<label>Compressor Speed</label>
|
||||
<category>Pump</category>
|
||||
<state readOnly="true" pattern="%.1f %unit%"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="heatCurve2" advanced="true">
|
||||
<item-type>Number</item-type>
|
||||
<label>Heat Curve 2</label>
|
||||
<category>Line</category>
|
||||
<state min="0" max="10" step="0.1" pattern="%.1f"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="heatCurve2FineAdj" advanced="true">
|
||||
<item-type>Number:Temperature</item-type>
|
||||
<label>Heat Curve 2 Fine Tune</label>
|
||||
<description>Fine-tuning means that you offset the heat curve 2 in parallel</description>
|
||||
<category>Temperature</category>
|
||||
<state min="-10" max="10" step="0.1" pattern="%.1f %unit%"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="switchValve2State" advanced="true">
|
||||
<item-type>Switch</item-type>
|
||||
<label>Switch Valve 2</label>
|
||||
<category>Heating</category>
|
||||
<state readOnly="true"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="fanState" advanced="true">
|
||||
<item-type>Switch</item-type>
|
||||
<label>Fan</label>
|
||||
<category>Fan</category>
|
||||
<state readOnly="true"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="highPressostatState" advanced="true">
|
||||
<item-type>Switch</item-type>
|
||||
<label>High Pressostat</label>
|
||||
<category>Switch</category>
|
||||
<state readOnly="true"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="lowPressostatState" advanced="true">
|
||||
<item-type>Switch</item-type>
|
||||
<label>Low Pressostat</label>
|
||||
<category>Switch</category>
|
||||
<state readOnly="true"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="heatingCableState" advanced="true">
|
||||
<item-type>Switch</item-type>
|
||||
<label>Heating Cable</label>
|
||||
<category>Switch</category>
|
||||
<state readOnly="true"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="crankCaseHeaterState" advanced="true">
|
||||
<item-type>Switch</item-type>
|
||||
<label>Crank Case Heater</label>
|
||||
<category>Switch</category>
|
||||
<state readOnly="true"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="elMeter1" advanced="true">
|
||||
<item-type>Number</item-type>
|
||||
<label>Collected Pulses Meter 1</label>
|
||||
<category>Switch</category>
|
||||
<state readOnly="true" pattern="%d"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="elMeter2" advanced="true">
|
||||
<item-type>Number</item-type>
|
||||
<label>Collected Pulses Meter 2</label>
|
||||
<category>Switch</category>
|
||||
<state readOnly="true" pattern="%d"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="heatPumpInOperationDHW" advanced="true">
|
||||
<item-type>Number:Time</item-type>
|
||||
<label>Heat Pump in Oper. - DHW</label>
|
||||
<description>Heat pump in operation while heating DHW - number of hours</description>
|
||||
<category>Time</category>
|
||||
<state readOnly="true" pattern="%d %unit%"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="heatPumpInOperationRAD" advanced="true">
|
||||
<item-type>Number:Time</item-type>
|
||||
<label>Heat Pump in Oper. - Radiators</label>
|
||||
<description>Heat pump in operation while heating radiators - number of hours</description>
|
||||
<category>Time</category>
|
||||
<state readOnly="true" pattern="%d %unit%"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="addHeatInOperationDHW" advanced="true">
|
||||
<item-type>Number:Time</item-type>
|
||||
<label>Add. Heat in Oper. - DHW</label>
|
||||
<description>Additional heat in operation heating DHW - number of hours</description>
|
||||
<category>Time</category>
|
||||
<state readOnly="true" pattern="%d %unit%"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="addHeatInOperationRAD" advanced="true">
|
||||
<item-type>Number:Time</item-type>
|
||||
<label>Add. Heat in Oper. - Radiators</label>
|
||||
<description>Additional heat in operation heating radiators - number of hours</description>
|
||||
<category>Time</category>
|
||||
<state readOnly="true" pattern="%d %unit%"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="summerDisconnection" advanced="true">
|
||||
<item-type>Number:Temperature</item-type>
|
||||
<label>Summer Disconnection</label>
|
||||
<description>The function means the heat pump only produces hot water when the outdoor temperature rises above the set
|
||||
value</description>
|
||||
<category>Temperature</category>
|
||||
<state min="10" max="30" step="0.1" pattern="%.1f %unit%"/>
|
||||
</channel-type>
|
||||
|
||||
</thing:thing-descriptions>
|
||||
Reference in New Issue
Block a user