added migrated 2.x add-ons
Signed-off-by: Kai Kreuzer <kai@openhab.org>
This commit is contained in:
32
bundles/org.openhab.binding.heliosventilation/.classpath
Normal file
32
bundles/org.openhab.binding.heliosventilation/.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="test" value="true"/>
|
||||
<attribute name="optional" value="true"/>
|
||||
<attribute name="maven.pomderived" 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 exported="true" 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.heliosventilation/.project
Normal file
23
bundles/org.openhab.binding.heliosventilation/.project
Normal file
@@ -0,0 +1,23 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<projectDescription>
|
||||
<name>org.openhab.binding.heliosventilation</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.heliosventilation/NOTICE
Normal file
13
bundles/org.openhab.binding.heliosventilation/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
|
||||
111
bundles/org.openhab.binding.heliosventilation/README.md
Normal file
111
bundles/org.openhab.binding.heliosventilation/README.md
Normal file
@@ -0,0 +1,111 @@
|
||||
# HeliosVentilation Binding
|
||||
|
||||
This is the binding for Helios Ventilation Systems KWL EC 200/300/500 Pro.
|
||||
It requires a connection to the RS485 bus used by the original remote controls KWL-FB (9417) and does not use the Modbus/TCP interface of the newer EasyControl devices.
|
||||
|
||||
For electrical connection it is recommended to use an USB-RS485 interface, but any RS485 interface that shows up as a serial port will do.
|
||||
Setup the device as described in https://www.openhab.org/docs/administration/serial.html.
|
||||
|
||||
The binding will use the remote control address 15 for communication, so make sure that this is not assigned to a physically present remote control.
|
||||
|
||||
## Supported Things
|
||||
|
||||
There is only one thing type supported by this binding: a Helios Ventilation System KWL EC 200/300/500 Pro from Helios.
|
||||
The binding was developed and test on a KWL EC 200 Pro device.
|
||||
|
||||
## Binding Configuration
|
||||
|
||||
The binding requires access to the serial device connecting to the RS485 bus as described in https://www.openhab.org/docs/administration/serial.html.
|
||||
Otherwise only thing configuration is needed.
|
||||
|
||||
## Thing Configuration
|
||||
|
||||
The binding supports only one thing and requires the configuration of the serial port (typically /dev/ttyUSB0 on Linux and COM3 on Windows) and optionally the polling time which is the cycle time after which the binding tries to reconnect to the bus and requests data updates.
|
||||
|
||||
## Channels
|
||||
|
||||
Supported operation channels:
|
||||
|
||||
| channel | type | description |
|
||||
|--------------------|----------------------|-----------------------------------------------|
|
||||
| outsideTemp | Number:Temperature | Temperature sensor in the outside air flow |
|
||||
| outgoingTemp | Number:Temperature | Temperature sensor in the outgoing air flow |
|
||||
| extractTemp | Number:Temperature | Temperature sensor in the extract air flow |
|
||||
| supplyTemp | Number:Temperature | Temperature sensor in the supply air flow |
|
||||
| setTemp | Number:Temperature | Set temperature for supply (not always used) |
|
||||
| fanspeed | Number | Level of the fanspeed (1-8) |
|
||||
| powerState | Switch | Main power switch |
|
||||
| co2State | Switch | Switch for CO2 regulation |
|
||||
| rhState | Switch | Switch for humidity regulation |
|
||||
| winterMode | Switch | Switch to set winter mode |
|
||||
|
||||
Supported configuration channels:
|
||||
|
||||
| channel | type | description |
|
||||
|--------------------|----------------------|-----------------------------------------------|
|
||||
| bypassTemp | Number:Temperature | Temperature to disable the bypass function |
|
||||
| supplyStopTemp | Number:Temperature | Temperature to stop supply fan for defrosting |
|
||||
| preheatTemp | Number:Temperature | Temperature to enable the preheater |
|
||||
| minFanspeed | Number | Minimal level of the fanspeed (1-8) |
|
||||
| maxFanspeed | Number | Maximal level of the fanspeed (1-8) |
|
||||
| rhLimit | Number:Dimensionless | Limit for relative humidity sensor |
|
||||
| hysteresis | Number:Temperature | Hysteresis on defroster temperature |
|
||||
| DCFanExtract | Number:Dimensionless | Speed reduction for the extract fan |
|
||||
| DCFanSupply | Number:Dimensionless | Speed reduction for the supply fan |
|
||||
| maintenanceInterval| Number:Dimensionless | Maintenance interval in months |
|
||||
| adjustInveral | Number:Dimensionless | Adjust interval in minutes for air quality |
|
||||
| RHLevelAuto | Switch | Automatic base humidity determination |
|
||||
| switchType | Switch | External Switch type (Boost or Fireplace) |
|
||||
| radiatorType | Switch | Use water (ON) or electric (OFF) radiator |
|
||||
| cascade | Switch | System is cascaded |
|
||||
|
||||
Note: the configuration channels are not intended to be written regularly.
|
||||
|
||||
## Full Example
|
||||
|
||||
Things:
|
||||
|
||||
```
|
||||
heliosventilation:ventilation:MyKWL [ serialPort="/dev/ttyUSB0" ]
|
||||
```
|
||||
|
||||
Items:
|
||||
|
||||
```
|
||||
Switch KWLOnOff { channel="heliosventilation:ventilation:MyKWL:powerState" }
|
||||
Switch KWLWinter { channel="heliosventilation:ventilation:MyKWL:winterMode" }
|
||||
|
||||
Group VentilationTemp "Measured Temperatures in Ventilation System"
|
||||
|
||||
Number:Temperature Outside_Temperature "Outside Temperature [%.1f °C]" <temperature> (VentilationTemp) { channel="heliosventilation:ventilation:MyKWL:outsideTemp" }
|
||||
Number:Temperature Outgoing_Temperature "Outgoing Temperature [%.1f °C]" <temperature> (VentilationTemp) { channel="heliosventilation:ventilation:MyKWL:outgoingTemp" }
|
||||
Number:Temperature Extract_Temperature "Extract Temperature [%.1f °C]" <temperature> (VentilationTemp) { channel="heliosventilation:ventilation:MyKWL:extractTemp" }
|
||||
Number:Temperature Supply_Temperature "Supply Temperature [%.1f °C]" <temperature> (VentilationTemp) { channel="heliosventilation:ventilation:MyKWL:supplyTemp" }
|
||||
|
||||
Number Fan_Speed "Fan Speed" <fan> { channel="heliosventilation:ventilation:MyKWL:fanspeed" }
|
||||
Number Min_Fan_Speed "Min Fan Speed" <fan> { channel="heliosventilation:ventilation:MyKWL:minFanspeed" }
|
||||
Number Max_Fan_Speed "Max Fan Speed" <fan> { channel="heliosventilation:ventilation:MyKWL:maxFanspeed" }
|
||||
|
||||
```
|
||||
|
||||
Sitemap:
|
||||
|
||||
```
|
||||
sitemap helios_kwl label="Helios Ventilation" {
|
||||
Frame label="Temperatures" {
|
||||
Text item=Outside_Temperature
|
||||
Text item=Outgoing_Temperature
|
||||
Text item=Extract_Temperature
|
||||
Text item=Supply_Temperature
|
||||
}
|
||||
Frame label="Control" {
|
||||
Switch item=KWLOnOff
|
||||
Switch item=KWLWinter
|
||||
Slider item=Fan_Speed icon="fan" minValue=1 maxValue=8 step=1
|
||||
}
|
||||
Frame label="Configuration" {
|
||||
Slider item=Min_Fan_Speed
|
||||
Setpoint item=Max_Fan_Speed icon="fan"
|
||||
}
|
||||
}
|
||||
```
|
||||
17
bundles/org.openhab.binding.heliosventilation/pom.xml
Normal file
17
bundles/org.openhab.binding.heliosventilation/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.heliosventilation</artifactId>
|
||||
|
||||
<name>openHAB Add-ons :: Bundles :: HeliosVentilation Binding</name>
|
||||
|
||||
</project>
|
||||
@@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<features name="org.openhab.binding.heliosventilation-${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-heliosventilation" description="HeliosVentilation 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.heliosventilation/${project.version}</bundle>
|
||||
</feature>
|
||||
</features>
|
||||
@@ -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.heliosventilation.internal;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
|
||||
/**
|
||||
* The {@link HeliosPropertiesFormatException} class defines an exception to describe parsing format errors
|
||||
*
|
||||
* @author Raphael Mack - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class HeliosPropertiesFormatException extends Exception {
|
||||
private static final long serialVersionUID = 8051109351111509577L;
|
||||
private final String channelName;
|
||||
private final String fullSpec;
|
||||
private final String reason;
|
||||
|
||||
public HeliosPropertiesFormatException(String reason, String channelName, String fullSpec) {
|
||||
this.channelName = channelName;
|
||||
this.fullSpec = fullSpec;
|
||||
this.reason = reason;
|
||||
}
|
||||
|
||||
public String getChannelName() {
|
||||
return channelName;
|
||||
}
|
||||
|
||||
public String getFullSpec() {
|
||||
return fullSpec;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getMessage() {
|
||||
return "Cannot parse '" + fullSpec + "' for datapoint '" + channelName + "': " + reason;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
/**
|
||||
* 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.heliosventilation.internal;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URL;
|
||||
import java.util.Enumeration;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.core.thing.ThingTypeUID;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* The {@link HeliosVentilationBindingConstants} class defines common constants, which are
|
||||
* used across the whole binding.
|
||||
*
|
||||
* @author Raphael Mack - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class HeliosVentilationBindingConstants {
|
||||
|
||||
public static final String BINDING_ID = "heliosventilation";
|
||||
|
||||
public static final String DATAPOINT_FILE = "datapoints.properties";
|
||||
|
||||
// List of all Thing Type UIDs
|
||||
public static final ThingTypeUID THING_TYPE_HELIOS_VENTILATION = new ThingTypeUID(BINDING_ID, "ventilation");
|
||||
|
||||
public static final Map<Byte, HeliosVentilationDataPoint> DATAPOINTS;
|
||||
|
||||
private static final Logger LOGGER;
|
||||
static {
|
||||
/* logger is used by readChannelProperties() so we need to initialize logger first. */
|
||||
LOGGER = LoggerFactory.getLogger(HeliosVentilationBindingConstants.class);
|
||||
DATAPOINTS = readChannelProperties();
|
||||
}
|
||||
// List of all Channel ids
|
||||
// Channel ids are only in datapoints.properties and thing-types.xml
|
||||
|
||||
/**
|
||||
* parse datapoints from properties
|
||||
*
|
||||
*/
|
||||
private static Map<Byte, HeliosVentilationDataPoint> readChannelProperties() {
|
||||
HashMap<Byte, HeliosVentilationDataPoint> result = new HashMap<Byte, HeliosVentilationDataPoint>();
|
||||
|
||||
URL resource = Thread.currentThread().getContextClassLoader().getResource(DATAPOINT_FILE);
|
||||
Properties properties = new Properties();
|
||||
try {
|
||||
properties.load(resource.openStream());
|
||||
|
||||
Enumeration<Object> keys = properties.keys();
|
||||
while (keys.hasMoreElements()) {
|
||||
String channel = (String) keys.nextElement();
|
||||
HeliosVentilationDataPoint dp;
|
||||
try {
|
||||
dp = new HeliosVentilationDataPoint(channel, properties.getProperty(channel));
|
||||
if (result.containsKey(dp.address())) {
|
||||
result.get(dp.address()).append(dp);
|
||||
} else {
|
||||
result.put(dp.address(), dp);
|
||||
}
|
||||
} catch (HeliosPropertiesFormatException e) {
|
||||
LOGGER.warn("could not read resource file {}, binding will probably fail: {}", DATAPOINT_FILE,
|
||||
e.getMessage());
|
||||
}
|
||||
}
|
||||
} catch (IOException e) {
|
||||
LOGGER.warn("could not read resource file {}, binding will probably fail: {}", DATAPOINT_FILE,
|
||||
e.getMessage());
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
/**
|
||||
* 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.heliosventilation.internal;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
|
||||
/**
|
||||
* The {@link HeliosVentilationConfiguration} class contains fields mapping thing configuration parameters.
|
||||
*
|
||||
* @author Raphael Mack - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class HeliosVentilationConfiguration {
|
||||
|
||||
/**
|
||||
* Port name for a serial connection to RS485 bus. Valid values are e.g. COM1 for Windows and /dev/ttyS0 or
|
||||
* /dev/ttyUSB0 for Linux.
|
||||
*/
|
||||
public String serialPort = "";
|
||||
|
||||
/**
|
||||
* The Panel Poll Period. Default is 60 sec. = 1 minute;
|
||||
*/
|
||||
public int pollPeriod = 60;
|
||||
}
|
||||
@@ -0,0 +1,334 @@
|
||||
/**
|
||||
* 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.heliosventilation.internal;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.core.library.types.DecimalType;
|
||||
import org.openhab.core.library.types.OnOffType;
|
||||
import org.openhab.core.library.types.QuantityType;
|
||||
import org.openhab.core.library.unit.SIUnits;
|
||||
import org.openhab.core.library.unit.SmartHomeUnits;
|
||||
import org.openhab.core.types.State;
|
||||
import org.openhab.core.types.UnDefType;
|
||||
|
||||
/**
|
||||
* The {@next HeliosVentilationDataPoint} is a description of a datapoint in the Helios ventilation system.
|
||||
*
|
||||
* @author Raphael Mack - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class HeliosVentilationDataPoint {
|
||||
public enum DataType {
|
||||
TEMPERATURE,
|
||||
HYSTERESIS,
|
||||
FANSPEED,
|
||||
SWITCH,
|
||||
BYTE_PERCENT,
|
||||
PERCENT,
|
||||
NUMBER
|
||||
}
|
||||
|
||||
/**
|
||||
* mapping from temperature byte values to °C
|
||||
*/
|
||||
private static final int[] TEMP_MAP = { -74, -70, -66, -62, -59, -56, -54, -52, -50, -48, -47, -46, -44, -43, -42,
|
||||
-41, -40, -39, -38, -37, -36, -35, -34, -33, -33, -32, -31, -30, -30, -29, -28, -28, -27, -27, -26, -25,
|
||||
-25, -24, -24, -23, -23, -22, -22, -21, -21, -20, -20, -19, -19, -19, -18, -18, -17, -17, -16, -16, -16,
|
||||
-15, -15, -14, -14, -14, -13, -13, -12, -12, -12, -11, -11, -11, -10, -10, -9, -9, -9, -8, -8, -8, -7, -7,
|
||||
-7, -6, -6, -6, -5, -5, -5, -4, -4, -4, -3, -3, -3, -2, -2, -2, -1, -1, -1, -1, 0, 0, 0, 1, 1, 1, 2, 2, 2,
|
||||
3, 3, 3, 4, 4, 4, 5, 5, 5, 5, 6, 6, 6, 7, 7, 7, 8, 8, 8, 9, 9, 9, 10, 10, 10, 11, 11, 11, 12, 12, 12, 13,
|
||||
13, 13, 14, 14, 14, 15, 15, 15, 16, 16, 16, 17, 17, 18, 18, 18, 19, 19, 19, 20, 20, 21, 21, 21, 22, 22, 22,
|
||||
23, 23, 24, 24, 24, 25, 25, 26, 26, 27, 27, 27, 28, 28, 29, 29, 30, 30, 31, 31, 32, 32, 33, 33, 34, 34, 35,
|
||||
35, 36, 36, 37, 37, 38, 38, 39, 40, 40, 41, 41, 42, 43, 43, 44, 45, 45, 46, 47, 48, 48, 49, 50, 51, 52, 53,
|
||||
53, 54, 55, 56, 57, 59, 60, 61, 62, 63, 65, 66, 68, 69, 71, 73, 75, 77, 79, 81, 82, 86, 90, 93, 97, 100,
|
||||
100, 100, 100, 100, 100, 100, 100, 100 };
|
||||
|
||||
/**
|
||||
* mapping from human readable fanspeed to raw value
|
||||
*/
|
||||
private static final int[] FANSPEED_MAP = { 0, 1, 3, 7, 15, 31, 63, 127, 255 };
|
||||
|
||||
private static final int BYTE_PERCENT_OFFSET = 52;
|
||||
|
||||
private String name;
|
||||
private boolean writable;
|
||||
private DataType datatype;
|
||||
private byte address;
|
||||
private int bitStart;
|
||||
private int bitLength;
|
||||
|
||||
private @Nullable HeliosVentilationDataPoint next;
|
||||
|
||||
/**
|
||||
* parse fullSpec in the properties format to declare a datapoint
|
||||
*
|
||||
* @param name the name of the datapoint
|
||||
* @param fullSpec datapoint specification, see format in datapoints.properties
|
||||
* @throws HeliosPropertiesFormatException in case fullSpec is not parsable
|
||||
*/
|
||||
public HeliosVentilationDataPoint(String name, String fullSpec) throws HeliosPropertiesFormatException {
|
||||
String specWithoutComment;
|
||||
if (fullSpec.contains("#")) {
|
||||
specWithoutComment = fullSpec.substring(0, fullSpec.indexOf("#"));
|
||||
} else {
|
||||
specWithoutComment = fullSpec;
|
||||
}
|
||||
String[] tokens = specWithoutComment.split(",");
|
||||
this.name = name;
|
||||
if (tokens.length != 3) {
|
||||
throw new HeliosPropertiesFormatException("invalid length", name, fullSpec);
|
||||
}
|
||||
try {
|
||||
String addr = tokens[0];
|
||||
String[] addrTokens;
|
||||
if (addr.contains(":")) {
|
||||
addrTokens = addr.split(":");
|
||||
} else {
|
||||
addrTokens = new String[] { addr };
|
||||
}
|
||||
bitLength = 8;
|
||||
bitStart = 0;
|
||||
this.address = (byte) (int) Integer.decode(addrTokens[0]);
|
||||
if (addrTokens.length > 1) {
|
||||
bitStart = (byte) (int) Integer.decode(addrTokens[1]);
|
||||
bitLength = 1;
|
||||
}
|
||||
if (addrTokens.length > 2) {
|
||||
bitLength = (byte) (int) Integer.decode(addrTokens[2]) - bitStart + 1;
|
||||
}
|
||||
if (addrTokens.length > 3) {
|
||||
throw new HeliosPropertiesFormatException(
|
||||
"invalid address spec: too many separators in bit specification", name, fullSpec);
|
||||
}
|
||||
} catch (NumberFormatException e) {
|
||||
throw new HeliosPropertiesFormatException("invalid address spec", name, fullSpec);
|
||||
}
|
||||
|
||||
this.writable = Boolean.parseBoolean(tokens[1]);
|
||||
try {
|
||||
this.datatype = DataType.valueOf(tokens[2].replaceAll("\\s+", ""));
|
||||
} catch (IllegalArgumentException e) {
|
||||
throw new HeliosPropertiesFormatException("invalid type spec", name, fullSpec);
|
||||
}
|
||||
}
|
||||
|
||||
public HeliosVentilationDataPoint(String name, byte address, boolean writable, DataType datatype) {
|
||||
this.datatype = datatype;
|
||||
this.writable = writable;
|
||||
this.name = name;
|
||||
this.address = address;
|
||||
}
|
||||
|
||||
public boolean isWritable() {
|
||||
return writable;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return the name of the variable, which is also the channel name
|
||||
*/
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return address of the variable
|
||||
*/
|
||||
public byte address() {
|
||||
return address;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the bit mask of the data point. 0xFF in case the full byte is used.
|
||||
*/
|
||||
public byte bitMask() {
|
||||
byte mask = (byte) 0xff;
|
||||
if (datatype == DataType.NUMBER || datatype == DataType.SWITCH) {
|
||||
mask = (byte) (((1 << bitLength) - 1) << bitStart);
|
||||
}
|
||||
return mask;
|
||||
}
|
||||
|
||||
/**
|
||||
* interpret the given byte b and return the value as State.
|
||||
*
|
||||
* @param b
|
||||
* @return state representation of byte value b in current datatype
|
||||
*/
|
||||
public State asState(byte b) {
|
||||
int val = b & 0xff;
|
||||
switch (datatype) {
|
||||
case TEMPERATURE:
|
||||
return new QuantityType<>(TEMP_MAP[val], SIUnits.CELSIUS);
|
||||
case BYTE_PERCENT:
|
||||
return new QuantityType<>((int) ((val - BYTE_PERCENT_OFFSET) * 100.0 / (255 - BYTE_PERCENT_OFFSET)),
|
||||
SmartHomeUnits.PERCENT);
|
||||
case SWITCH:
|
||||
if (bitLength != 1) {
|
||||
return UnDefType.UNDEF;
|
||||
} else if ((b & (1 << bitStart)) != 0) {
|
||||
return OnOffType.ON;
|
||||
} else {
|
||||
return OnOffType.OFF;
|
||||
}
|
||||
case NUMBER:
|
||||
int value = (b & bitMask()) >> bitStart;
|
||||
return new DecimalType(value);
|
||||
case PERCENT:
|
||||
return new QuantityType<>(val, SmartHomeUnits.PERCENT);
|
||||
case FANSPEED:
|
||||
int i = 1;
|
||||
while (i < FANSPEED_MAP.length && FANSPEED_MAP[i] < val) {
|
||||
i++;
|
||||
}
|
||||
return new DecimalType(i);
|
||||
case HYSTERESIS:
|
||||
return new QuantityType<>(val / 3, SIUnits.CELSIUS);
|
||||
default:
|
||||
return UnDefType.UNDEF;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* interpret the given byte b and return the value as string.
|
||||
*
|
||||
* @param b
|
||||
* @return sting representation of byte value b in current datatype
|
||||
*/
|
||||
public String asString(byte b) {
|
||||
State ste = asState(b);
|
||||
String str = ste.toString();
|
||||
if (ste instanceof UnDefType) {
|
||||
return String.format("<unknown type> %02X ", b);
|
||||
} else {
|
||||
return str;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* generate byte data to transmit
|
||||
*
|
||||
* @param val is the state of a channel
|
||||
* @return byte value with RS485 representation. Bit level values are returned in the correct location, but other
|
||||
* bits/datapoints in the same address are zero.
|
||||
*/
|
||||
public byte getTransmitDataFor(State val) {
|
||||
byte result = 0;
|
||||
DecimalType value = val.as(DecimalType.class);
|
||||
if (value == null) {
|
||||
/*
|
||||
* if value is not convertible to a numeric type we cannot do anything reasonable with it, let's use the
|
||||
* initial value for it
|
||||
*/
|
||||
} else {
|
||||
QuantityType<?> quantvalue;
|
||||
switch (datatype) {
|
||||
case TEMPERATURE:
|
||||
quantvalue = ((QuantityType<?>) val);
|
||||
quantvalue = quantvalue.toUnit(SIUnits.CELSIUS);
|
||||
if (quantvalue != null) {
|
||||
value = quantvalue.as(DecimalType.class);
|
||||
if (value != null) {
|
||||
int temp = (int) Math.round(value.doubleValue());
|
||||
int i = 0;
|
||||
while (i < TEMP_MAP.length && TEMP_MAP[i] < temp) {
|
||||
i++;
|
||||
}
|
||||
result = (byte) i;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case FANSPEED:
|
||||
int i = value.intValue();
|
||||
if (i < 0) {
|
||||
i = 0;
|
||||
} else if (i > 8) {
|
||||
i = 8;
|
||||
}
|
||||
result = (byte) FANSPEED_MAP[i];
|
||||
break;
|
||||
case BYTE_PERCENT:
|
||||
result = (byte) ((value.doubleValue() / 100.0) * (255 - BYTE_PERCENT_OFFSET) + BYTE_PERCENT_OFFSET);
|
||||
break;
|
||||
case PERCENT:
|
||||
double d = (Math.round(value.doubleValue()));
|
||||
if (d < 0.0) {
|
||||
d = 0.0;
|
||||
} else if (d > 100.0) {
|
||||
d = 100.0;
|
||||
}
|
||||
result = (byte) d;
|
||||
break;
|
||||
case HYSTERESIS:
|
||||
quantvalue = ((QuantityType<?>) val).toUnit(SIUnits.CELSIUS);
|
||||
if (quantvalue != null) {
|
||||
result = (byte) (quantvalue.intValue() * 3);
|
||||
}
|
||||
break;
|
||||
case SWITCH:
|
||||
case NUMBER:
|
||||
// those are the types supporting bit level specification
|
||||
// output only the relevant bits
|
||||
result = (byte) (value.intValue() << bitStart);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get further datapoint linked to the same address.
|
||||
*
|
||||
* @return sister datapoint
|
||||
*/
|
||||
public @Nullable HeliosVentilationDataPoint next() {
|
||||
return next;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a next to a datapoint on the same address.
|
||||
* Caller has to ensure that identical datapoints are not added several times.
|
||||
*
|
||||
* @param next is the sister datapoint
|
||||
*/
|
||||
public void append(HeliosVentilationDataPoint next) {
|
||||
HeliosVentilationDataPoint existing = this.next;
|
||||
if (this == next) {
|
||||
// this datapoint is already there, so we do nothing and return
|
||||
return;
|
||||
} else if (existing != null) {
|
||||
existing.append(next);
|
||||
} else {
|
||||
this.next = next;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if writing to this datapoint requires a read-modify-write on the address
|
||||
*/
|
||||
public boolean requiresReadModifyWrite() {
|
||||
/*
|
||||
* the address either has multiple datapoints linked to it or is a bit-level point
|
||||
* this means we need to do read-modify-write on udpate and therefore we store the data in memory
|
||||
*/
|
||||
return (bitMask() != (byte) 0xFF || next != null);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,455 @@
|
||||
/**
|
||||
* 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.heliosventilation.internal;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.TooManyListenersException;
|
||||
import java.util.concurrent.ScheduledFuture;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.core.io.transport.serial.PortInUseException;
|
||||
import org.openhab.core.io.transport.serial.SerialPort;
|
||||
import org.openhab.core.io.transport.serial.SerialPortEvent;
|
||||
import org.openhab.core.io.transport.serial.SerialPortEventListener;
|
||||
import org.openhab.core.io.transport.serial.SerialPortIdentifier;
|
||||
import org.openhab.core.io.transport.serial.SerialPortManager;
|
||||
import org.openhab.core.io.transport.serial.UnsupportedCommOperationException;
|
||||
import org.openhab.core.library.types.DecimalType;
|
||||
import org.openhab.core.library.types.OnOffType;
|
||||
import org.openhab.core.library.types.QuantityType;
|
||||
import org.openhab.core.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.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* The {@link HeliosVentilationHandler} is responsible for handling commands, which are
|
||||
* sent to one of the channels.
|
||||
*
|
||||
* @author Raphael Mack - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class HeliosVentilationHandler extends BaseThingHandler implements SerialPortEventListener {
|
||||
private static final int BUSMEMBER_MAINBOARD = 0x11;
|
||||
private static final int BUSMEMBER_SLAVEBOARDS = 0x10;
|
||||
private static final byte BUSMEMBER_CONTROLBOARDS = (byte) 0x20;
|
||||
private static final int BUSMEMBER_REC_MASK = 0xF0; // interpreting frames delivered to BUSMEMBER_ME &
|
||||
// BUSMEMBER_REC_MASK
|
||||
private static final int BUSMEMBER_ME = 0x2F; // used as sender when communicating with the helios system
|
||||
private static final int POLL_OFFLINE_THRESHOLD = 3;
|
||||
|
||||
/** Logger Instance */
|
||||
private final Logger logger = LoggerFactory.getLogger(HeliosVentilationHandler.class);
|
||||
|
||||
/**
|
||||
* store received data for read-modify-write operations on bitlevel
|
||||
*/
|
||||
private final Map<Byte, Byte> memory = new HashMap<Byte, Byte>();
|
||||
|
||||
private final SerialPortManager serialPortManager;
|
||||
|
||||
/**
|
||||
* init to default to avoid NPE in case handleCommand() is called before initialize()
|
||||
*/
|
||||
private HeliosVentilationConfiguration config = new HeliosVentilationConfiguration();
|
||||
|
||||
private @Nullable SerialPort serialPort;
|
||||
private @Nullable InputStream inputStream;
|
||||
private @Nullable OutputStream outputStream;
|
||||
|
||||
private @Nullable ScheduledFuture<?> pollingTask;
|
||||
private int pollCounter;
|
||||
|
||||
public HeliosVentilationHandler(Thing thing, final SerialPortManager serialPortManager) {
|
||||
super(thing);
|
||||
this.serialPortManager = serialPortManager;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initialize() {
|
||||
config = getConfigAs(HeliosVentilationConfiguration.class);
|
||||
|
||||
logger.debug("Serial Port: {}, 9600 baud, PollPeriod: {}", config.serialPort, config.pollPeriod);
|
||||
|
||||
if (config.serialPort.length() < 1) {
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.OFFLINE.CONFIGURATION_ERROR, "Port must be set!");
|
||||
return;
|
||||
} else {
|
||||
SerialPortIdentifier portId = serialPortManager.getIdentifier(config.serialPort);
|
||||
if (portId == null) {
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.OFFLINE.CONFIGURATION_ERROR,
|
||||
"Port " + config.serialPort + " is not known!");
|
||||
serialPort = null;
|
||||
} else {
|
||||
updateStatus(ThingStatus.UNKNOWN);
|
||||
if (this.config.pollPeriod > 0) {
|
||||
startPolling();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
scheduler.execute(this::connect);
|
||||
}
|
||||
|
||||
private synchronized void connect() {
|
||||
logger.debug("HeliosVentilation: connecting...");
|
||||
// parse ports and if the port is found, initialize the reader
|
||||
SerialPortIdentifier portId = serialPortManager.getIdentifier(config.serialPort);
|
||||
if (portId == null) {
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.OFFLINE.CONFIGURATION_ERROR,
|
||||
"Port " + config.serialPort + " is not known!");
|
||||
serialPort = null;
|
||||
|
||||
disconnect();
|
||||
} else if (!isConnected()) {
|
||||
// initialize serial port
|
||||
try {
|
||||
SerialPort serial = portId.open(getThing().getUID().toString(), 2000);
|
||||
serial.setSerialPortParams(9600, SerialPort.DATABITS_8, SerialPort.STOPBITS_1, SerialPort.PARITY_NONE);
|
||||
serial.addEventListener(this);
|
||||
|
||||
try {
|
||||
if (inputStream != null) {
|
||||
inputStream.close();
|
||||
}
|
||||
} catch (IOException e) {
|
||||
// ignore the exception on close
|
||||
inputStream = null;
|
||||
}
|
||||
try {
|
||||
if (outputStream != null) {
|
||||
outputStream.close();
|
||||
}
|
||||
} catch (IOException e) {
|
||||
// ignore the exception on close
|
||||
outputStream = null;
|
||||
}
|
||||
|
||||
inputStream = serial.getInputStream();
|
||||
outputStream = serial.getOutputStream();
|
||||
|
||||
// activate the DATA_AVAILABLE notifier
|
||||
serial.notifyOnDataAvailable(true);
|
||||
serialPort = serial;
|
||||
updateStatus(ThingStatus.UNKNOWN);
|
||||
} catch (final IOException ex) {
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.OFFLINE.COMMUNICATION_ERROR, "I/O error!");
|
||||
} catch (PortInUseException e) {
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.OFFLINE.COMMUNICATION_ERROR, "Port is in use!");
|
||||
} catch (TooManyListenersException e) {
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.OFFLINE.COMMUNICATION_ERROR,
|
||||
"Cannot attach listener to port!");
|
||||
} catch (UnsupportedCommOperationException e) {
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.OFFLINE.COMMUNICATION_ERROR,
|
||||
"Serial port does not support the RS485 parameters of the Helios remote protocol.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
stopPolling();
|
||||
disconnect();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
/**
|
||||
* Start the polling task.
|
||||
*/
|
||||
public synchronized void startPolling() {
|
||||
final ScheduledFuture<?> task = pollingTask;
|
||||
if (task != null && task.isCancelled()) {
|
||||
task.cancel(true);
|
||||
}
|
||||
if (config.pollPeriod > 0) {
|
||||
pollingTask = scheduler.scheduleWithFixedDelay(this::polling, 10, config.pollPeriod, TimeUnit.SECONDS);
|
||||
} else {
|
||||
pollingTask = null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Stop the polling task.
|
||||
*/
|
||||
public synchronized void stopPolling() {
|
||||
final ScheduledFuture<?> task = pollingTask;
|
||||
if (task != null && !task.isCancelled()) {
|
||||
task.cancel(true);
|
||||
pollingTask = null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Method for polling the RS485 Helios RemoteContol bus
|
||||
*/
|
||||
public synchronized void polling() {
|
||||
if (logger.isTraceEnabled()) {
|
||||
logger.trace("HeliosVentilation Polling data for '{}'", getThing().getUID());
|
||||
}
|
||||
pollCounter++;
|
||||
if (pollCounter > POLL_OFFLINE_THRESHOLD) {
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.OFFLINE.GONE, "No data received!");
|
||||
logger.info("No data received for '{}' disconnecting now...", getThing().getUID());
|
||||
disconnect();
|
||||
}
|
||||
|
||||
if (!isConnected()) {
|
||||
connect(); // let's try to reconnect if the connection failed or was never established before
|
||||
}
|
||||
|
||||
HeliosVentilationBindingConstants.DATAPOINTS.values().forEach((v) -> {
|
||||
if (isLinked(v.getName())) {
|
||||
poll(v);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void disconnect() {
|
||||
if (thing.getStatus() != ThingStatus.REMOVING) {
|
||||
updateStatus(ThingStatus.OFFLINE);
|
||||
}
|
||||
synchronized (this) {
|
||||
try {
|
||||
if (inputStream != null) {
|
||||
inputStream.close();
|
||||
}
|
||||
} catch (IOException e) {
|
||||
// ignore the exception on close
|
||||
inputStream = null;
|
||||
}
|
||||
try {
|
||||
if (outputStream != null) {
|
||||
outputStream.close();
|
||||
}
|
||||
} catch (IOException e) {
|
||||
// ignore the exception on close
|
||||
outputStream = null;
|
||||
}
|
||||
|
||||
SerialPort serial = serialPort;
|
||||
if (serial != null) {
|
||||
serial.close();
|
||||
}
|
||||
serialPort = null;
|
||||
}
|
||||
}
|
||||
|
||||
private void poll(HeliosVentilationDataPoint v) {
|
||||
byte[] txFrame = { 0x01, BUSMEMBER_ME, BUSMEMBER_MAINBOARD, 0x00, v.address(), 0x00 };
|
||||
txFrame[5] = (byte) checksum(txFrame);
|
||||
|
||||
tx(txFrame);
|
||||
}
|
||||
|
||||
/*
|
||||
* transmit a frame
|
||||
*/
|
||||
private void tx(byte[] txFrame) {
|
||||
try {
|
||||
OutputStream out = outputStream;
|
||||
if (out != null) {
|
||||
if (logger.isTraceEnabled()) {
|
||||
logger.trace("HeliosVentilation: Write to serial port: {}",
|
||||
String.format("%02x %02x %02x %02x", txFrame[1], txFrame[2], txFrame[3], txFrame[4]));
|
||||
}
|
||||
|
||||
out.write(txFrame);
|
||||
out.flush();
|
||||
// after each frame we have to wait.
|
||||
// 30 ms is taken from what we roughly see the original remote control is doing
|
||||
Thread.sleep(30);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
// in case we cannot write the connection is somehow broken, let's officially disconnect
|
||||
disconnect();
|
||||
connect();
|
||||
} catch (InterruptedException e) {
|
||||
// ignore if we got interrupted
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check connection status
|
||||
*
|
||||
* @return true if currently connected
|
||||
*/
|
||||
private boolean isConnected() {
|
||||
return serialPort != null && inputStream != null && outputStream != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void serialEvent(SerialPortEvent event) {
|
||||
switch (event.getEventType()) {
|
||||
case SerialPortEvent.DATA_AVAILABLE:
|
||||
// we get here if data has been received
|
||||
|
||||
try {
|
||||
// Wait roughly a frame length to ensure that the complete frame is already buffered. This improves
|
||||
// the robustness for RS485/USB converters which sometimes duplicate bytes otherwise.
|
||||
Thread.sleep(8);
|
||||
} catch (InterruptedException e) {
|
||||
// ignore interruption
|
||||
}
|
||||
|
||||
byte[] frame = { 0, 0, 0, 0, 0, 0 };
|
||||
InputStream in = inputStream;
|
||||
if (in != null) {
|
||||
try {
|
||||
do {
|
||||
int cnt = 0;
|
||||
// read data from serial device
|
||||
while (cnt < 6 && in.available() > 0) {
|
||||
final int bytes = in.read(frame, cnt, 1);
|
||||
if (cnt > 0 || frame[0] == 0x01) {
|
||||
// only proceed if the first byte was 0x01
|
||||
cnt += bytes;
|
||||
}
|
||||
}
|
||||
int sum = checksum(frame);
|
||||
if (sum == (frame[5] & 0xff)) {
|
||||
if (logger.isTraceEnabled()) {
|
||||
logger.trace("HeliosVentilation: Read from serial port: {}", String
|
||||
.format("%02x %02x %02x %02x", frame[1], frame[2], frame[3], frame[4]));
|
||||
}
|
||||
interpretFrame(frame);
|
||||
|
||||
} else {
|
||||
if (logger.isTraceEnabled()) {
|
||||
logger.trace(
|
||||
"HeliosVentilation: Read frame with not matching checksum from serial port: {}",
|
||||
String.format("%02x %02x %02x %02x %02x %02x (expected %02x)", frame[0],
|
||||
frame[1], frame[2], frame[3], frame[4], frame[5], sum));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
} while (in.available() > 0);
|
||||
|
||||
} catch (IOException e1) {
|
||||
logger.debug("Error reading from serial port: {}", e1.getMessage(), e1);
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleCommand(ChannelUID channelUID, Command command) {
|
||||
if (command instanceof RefreshType) {
|
||||
scheduler.execute(this::polling);
|
||||
} else if (command instanceof DecimalType || command instanceof QuantityType || command instanceof OnOffType) {
|
||||
scheduler.execute(() -> update(channelUID, command));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the variable corresponding to given channel/command
|
||||
*
|
||||
* @param channelUID UID of the channel to update
|
||||
* @param command data element to write
|
||||
*
|
||||
*/
|
||||
public void update(ChannelUID channelUID, Command command) {
|
||||
HeliosVentilationBindingConstants.DATAPOINTS.values().forEach((outer) -> {
|
||||
HeliosVentilationDataPoint v = outer;
|
||||
do {
|
||||
if (channelUID.getThingUID().equals(thing.getUID()) && v.getName().equals(channelUID.getId())) {
|
||||
if (v.isWritable()) {
|
||||
byte[] txFrame = { 0x01, BUSMEMBER_ME, BUSMEMBER_CONTROLBOARDS, v.address(), 0x00, 0x00 };
|
||||
txFrame[4] = v.getTransmitDataFor((State) command);
|
||||
if (v.requiresReadModifyWrite()) {
|
||||
txFrame[4] |= memory.get(v.address()) & ~v.bitMask();
|
||||
memory.put(v.address(), txFrame[4]);
|
||||
}
|
||||
txFrame[5] = (byte) checksum(txFrame);
|
||||
tx(txFrame);
|
||||
|
||||
txFrame[2] = BUSMEMBER_SLAVEBOARDS;
|
||||
txFrame[5] = (byte) checksum(txFrame);
|
||||
tx(txFrame);
|
||||
|
||||
txFrame[2] = BUSMEMBER_MAINBOARD;
|
||||
txFrame[5] = (byte) checksum(txFrame);
|
||||
tx(txFrame);
|
||||
}
|
||||
}
|
||||
v = v.next();
|
||||
} while (v != null);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* calculate checksum of a frame
|
||||
*
|
||||
* @param frame filled with 5 bytes
|
||||
* @return checksum of the first 5 bytes of frame
|
||||
*/
|
||||
private int checksum(byte[] frame) {
|
||||
int sum = 0;
|
||||
for (int a = 0; a < 5; a++) {
|
||||
sum += frame[a] & 0xff;
|
||||
}
|
||||
sum %= 256;
|
||||
return sum;
|
||||
}
|
||||
|
||||
/**
|
||||
* interpret a frame, which is already validated to be in correct format with valid checksum
|
||||
*
|
||||
* @param frame 6 bytes long data with 0x01, sender, receiver, address, value, checksum
|
||||
*/
|
||||
private void interpretFrame(byte[] frame) {
|
||||
if ((frame[2] & BUSMEMBER_REC_MASK) == (BUSMEMBER_ME & BUSMEMBER_REC_MASK)) {
|
||||
// something to read for us
|
||||
byte var = frame[3];
|
||||
byte val = frame[4];
|
||||
if (HeliosVentilationBindingConstants.DATAPOINTS.containsKey(var)) {
|
||||
HeliosVentilationDataPoint datapoint = HeliosVentilationBindingConstants.DATAPOINTS.get(var);
|
||||
if (datapoint.requiresReadModifyWrite()) {
|
||||
memory.put(var, val);
|
||||
}
|
||||
do {
|
||||
if (logger.isTraceEnabled()) {
|
||||
String t = datapoint.asString(val);
|
||||
logger.trace("Received {} = {}", datapoint, t);
|
||||
}
|
||||
updateStatus(ThingStatus.ONLINE);
|
||||
pollCounter = 0;
|
||||
|
||||
updateState(datapoint.getName(), datapoint.asState(val));
|
||||
datapoint = datapoint.next();
|
||||
} while (datapoint != null);
|
||||
|
||||
} else {
|
||||
if (logger.isTraceEnabled()) {
|
||||
logger.trace("Received unkown data @{} = {}", String.format("%02X ", var),
|
||||
String.format("%02X ", val));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
/**
|
||||
* 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.heliosventilation.internal;
|
||||
|
||||
import static org.openhab.binding.heliosventilation.internal.HeliosVentilationBindingConstants.THING_TYPE_HELIOS_VENTILATION;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Set;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
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 HeliosVentilationHandlerFactory} is responsible for creating things and thing
|
||||
* handlers.
|
||||
*
|
||||
* @author Raphael Mack - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
@Component(configurationPid = "binding.heliosventilation", service = ThingHandlerFactory.class)
|
||||
public class HeliosVentilationHandlerFactory extends BaseThingHandlerFactory {
|
||||
|
||||
private static final Set<ThingTypeUID> SUPPORTED_THING_TYPES_UIDS = Collections
|
||||
.singleton(THING_TYPE_HELIOS_VENTILATION);
|
||||
|
||||
private final SerialPortManager serialPortManager;
|
||||
|
||||
@Activate
|
||||
public HeliosVentilationHandlerFactory(@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 (THING_TYPE_HELIOS_VENTILATION.equals(thingTypeUID)) {
|
||||
return new HeliosVentilationHandler(thing, serialPortManager);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<binding:binding id="heliosventilation" 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>HeliosVentilation Binding</name>
|
||||
<description>This is the binding for Helios Ventilation Systems KWL EC 200/300/500 Pro. It requires a connection to the
|
||||
RS485 bus used by the original remote controls KWL-FB (9417).</description>
|
||||
<author>Raphael Mack</author>
|
||||
|
||||
</binding:binding>
|
||||
@@ -0,0 +1,85 @@
|
||||
# binding
|
||||
binding.heliosventilation.name = Helios KWL Binding
|
||||
binding.heliosventilation.description = Dies ist das Binding für Helios KWL Systeme KWL EC 200/300/500 Pro. Es benötigt eine Verbindung zum RS485 Bus für die Fernbedienung KWL-FB (9417).
|
||||
|
||||
# thing types
|
||||
thing-type.heliosventilation.ventilation.label = KWL
|
||||
thing-type.heliosventilation.ventilation.description = Lüftungsgerät zur kontrollierten Wohnraumlüftung.
|
||||
|
||||
# thing type config description
|
||||
thing-type.config.heliosventilation.ventilation.serialPort.label = Serielle Schnittstelle
|
||||
thing-type.config.heliosventilation.ventilation.serialPort.description = Die Betreibssystembezeichnung des Gerätes für die serielle Schnittstelle. Gültige Werte sind z. B. COM1 unter Windows und /dev/ttyS0 oder /dev/ttyUSB0 unter GNU/Linux.
|
||||
thing-type.config.heliosventilation.ventilation.pollPeriod.label = Poll-Zyklus
|
||||
thing-type.config.heliosventilation.ventilation.pollPeriod.description = Der Poll-Zyklus in Sekunden, 0 für keine wiederkehrende Aktualisierung.
|
||||
|
||||
# channel types
|
||||
channel-type.heliosventilation.outside_temperature.label = Außenlufttemperatur
|
||||
channel-type.heliosventilation.outside_temperature.description = Temperatur gemessen im Außenluftstrom.
|
||||
|
||||
channel-type.heliosventilation.outgoing_temperature.label = Fortlufttemperatur
|
||||
channel-type.heliosventilation.outgoing_temperature.description = Temperatur gemessen im Fortluftstrom (das Haus verlassend).
|
||||
|
||||
channel-type.heliosventilation.extract_temperature.label = Ablufttemperatur
|
||||
channel-type.heliosventilation.extract_temperature.description = Temperatur gemessen im Abluftstrom (Raumluft).
|
||||
|
||||
channel-type.heliosventilation.supply_temperature.label = Zulufttemperatur
|
||||
channel-type.heliosventilation.supply_temperature.description = Temperatur gemessen im Zuluftstrom (in den Raum einströhmend).
|
||||
|
||||
channel-type.heliosventilation.bypass_temperature.label = WRG Bypasstemperatur
|
||||
channel-type.heliosventilation.bypass_temperature.description = Temperaturwert der von der Außenlufttemperatur überschritten werden muss um im Sommerbetrieb die Wärmetauscherumgehung zu aktivieren.
|
||||
|
||||
channel-type.heliosventilation.supply_stop_temperature.label = Frostschutztemperatur
|
||||
channel-type.heliosventilation.supply_stop_temperature.description = Abschalttemperatur des Zuluftventilators zur Entfrostung des Wärmetauschers.
|
||||
|
||||
channel-type.heliosventilation.preheat_temperature.label = Vorheizregister
|
||||
channel-type.heliosventilation.preheat_temperature.description = Solltemperatur der Vorheizung für die Entfrosterfunktion des Wärmetauschers.
|
||||
|
||||
channel-type.heliosventilation.supply_stop_temperature.label = Frostschutztemperatur
|
||||
channel-type.heliosventilation.supply_stop_temperature.description = Abschalttemperatur des Zuluftventilators zur Entfrostung des Wärmetauschers.
|
||||
|
||||
channel-type.heliosventilation.preheat_temperature.label = Vorheizregister
|
||||
channel-type.heliosventilation.preheat_temperature.description = Solltemperatur der Vorheizung für die Entforsterfunktion des Wärmetauschers.
|
||||
|
||||
channel-type.heliosventilation.fanspeed.label = Ventilator-Drehzahlstufe
|
||||
channel-type.heliosventilation.min_fanspeed.label = Grundlüftungsstufe
|
||||
channel-type.heliosventilation.max_fanspeed.label = Maximale Drehzahlstufe
|
||||
|
||||
channel-type.heliosventilation.rh_limit.label = Feuchtegrenzwert
|
||||
|
||||
channel-type.heliosventilation.hysteresis.label = Entfrosterhysterese
|
||||
channel-type.heliosventilation.hysteresis.description = Hysterese der Entfrosterfunktion
|
||||
|
||||
channel-type.heliosventilation.set_temperature.label = Vorgabetemperatur
|
||||
channel-type.heliosventilation.set_temperature.description = Vorgabe für die Raumtemperatur. Wird nicht von allen Helios KWLs verwendet.
|
||||
|
||||
channel-type.heliosventilation.dc_fan_extract.label = Ablufventilator
|
||||
channel-type.heliosventilation.dc_fan_extract.description = Drehzahlreduktion des Abluftventilators.
|
||||
|
||||
channel-type.heliosventilation.dc_fan_supply.label = Zulufventilator
|
||||
channel-type.heliosventilation.dc_fan_supply.description = Drehzahlreduktion des Zuluftventilators.
|
||||
|
||||
channel-type.heliosventilation.maintenance_interval.label = Wartungsinterval
|
||||
|
||||
channel-type.heliosventilation.radiator_type.label = Wasser-Nachheizregister
|
||||
channel-type.heliosventilation.radiator_type.description = An für wasserbetriebenes, aus für elektrisches Nachheizregister.
|
||||
|
||||
channel-type.heliosventilation.switch_type.label = Stoßlüftungstaste
|
||||
channel-type.heliosventilation.switch_type.description = An: Externer Taster wird als Stoßlüftungstaste verwendet. Aus: Taste ist in Funktion "Kamintaste".
|
||||
|
||||
channel-type.heliosventilation.cascade_mode.label = Kaskadensteuerung
|
||||
|
||||
channel-type.heliosventilation.rh_level_auto.label = Automatische Basisfeuchtebestimmung
|
||||
|
||||
channel-type.heliosventilation.power_state.label = Hauptschalter
|
||||
channel-type.heliosventilation.power_state.description = Schaltet die KWL an/aus.
|
||||
|
||||
channel-type.heliosventilation.co2_state.label = CO2-Regelung
|
||||
channel-type.heliosventilation.co2_state.description = Schaltet die CO2-Sensor-basierte Regelung an/aus.
|
||||
|
||||
channel-type.heliosventilation.rh_state.label = Feuchteregelung
|
||||
channel-type.heliosventilation.rh_state.description = Schaltet die Feuchte-basierte Regelung an/aus.
|
||||
|
||||
channel-type.heliosventilation.winter_state.label = Winterbetrieb
|
||||
channel-type.heliosventilation.winter_state.description = Schaltet die KWL in Winterbetrieb um die Bypass-Funktion zu deaktivieren. Falls Winterbetrieb aus ist, wird zur Kühlung der Wärmetauscher umgangen, falls die Außenluft kälter als die Abluft ist.
|
||||
|
||||
channel-type.heliosventilation.adjust_interval.label = Regelintervall
|
||||
@@ -0,0 +1,236 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<thing:thing-descriptions bindingId="heliosventilation"
|
||||
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">
|
||||
|
||||
<!-- Ventilation Thing Type -->
|
||||
<thing-type id="ventilation">
|
||||
<label>HeliosVentilation (KWL)</label>
|
||||
<description>A domestic ventilation system (KWL) from Helios.</description>
|
||||
|
||||
<channels>
|
||||
<channel id="outsideTemp" typeId="outside_temperature"/>
|
||||
<channel id="outgoingTemp" typeId="outgoing_temperature"/>
|
||||
<channel id="extractTemp" typeId="extract_temperature"/>
|
||||
<channel id="supplyTemp" typeId="supply_temperature"/>
|
||||
<channel id="setTemp" typeId="set_temperature"/>
|
||||
<channel id="bypassTemp" typeId="bypass_temperature"/>
|
||||
<channel id="supplyStopTemp" typeId="supply_stop_temperature"/>
|
||||
<channel id="preheatTemp" typeId="preheat_temperature"/>
|
||||
<channel id="minFanspeed" typeId="min_fanspeed"/>
|
||||
<channel id="maxFanspeed" typeId="max_fanspeed"/>
|
||||
<channel id="fanspeed" typeId="fanspeed"/>
|
||||
<channel id="rhLimit" typeId="rh_limit"/>
|
||||
<channel id="hysteresis" typeId="hysteresis"/>
|
||||
<channel id="DCFanExtract" typeId="dc_fan_extract"/>
|
||||
<channel id="DCFanSupply" typeId="dc_fan_supply"/>
|
||||
<channel id="maintenanceInterval" typeId="maintenance_interval"/>
|
||||
|
||||
<channel id="radiatorType" typeId="radiator_type"/>
|
||||
<channel id="switchType" typeId="switch_type"/>
|
||||
<channel id="cascade" typeId="cascade_mode"/>
|
||||
<channel id="RHLevelAuto" typeId="rh_level_auto"/>
|
||||
<channel id="powerState" typeId="power_state"/>
|
||||
<channel id="co2State" typeId="co2_state"/>
|
||||
<channel id="rhState" typeId="rh_state"/>
|
||||
<channel id="winterMode" typeId="winter_state"/>
|
||||
<channel id="adjustInveral" typeId="adjust_interval"/>
|
||||
</channels>
|
||||
|
||||
<config-description>
|
||||
<parameter name="serialPort" type="text" required="true">
|
||||
<context>serial-port</context>
|
||||
<label>RS485 Interface Serial Port</label>
|
||||
<description>The serial port name for the RS485 interfaces. Valid values are e.g. COM1 for Windows and /dev/ttyS0 or
|
||||
/dev/ttyUSB0 for Linux.</description>
|
||||
</parameter>
|
||||
|
||||
<parameter name="pollPeriod" type="integer" min="0" unit="s">
|
||||
<label>Poll Period</label>
|
||||
<description>The poll period in seconds use 0 for no polling.</description>
|
||||
<default>60</default>
|
||||
</parameter>
|
||||
</config-description>
|
||||
</thing-type>
|
||||
|
||||
<channel-type id="outside_temperature" advanced="false">
|
||||
<item-type>Number:Temperature</item-type>
|
||||
<label>Outside Temperature</label>
|
||||
<description>Temperature measured in the outdoor air flow.</description>
|
||||
<category>Temperature</category>
|
||||
<state pattern="%d %unit%" readOnly="true"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="extract_temperature" advanced="false">
|
||||
<item-type>Number:Temperature</item-type>
|
||||
<label>Extract Temperature</label>
|
||||
<description>Temperature measured in the extract (indoor, room temperature) air flow.</description>
|
||||
<category>Temperature</category>
|
||||
<state pattern="%d %unit%" readOnly="true"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="supply_temperature" advanced="false">
|
||||
<item-type>Number:Temperature</item-type>
|
||||
<label>Supply Temperature</label>
|
||||
<description>Temperature measured in the supply (incoming) air flow.</description>
|
||||
<category>Temperature</category>
|
||||
<state pattern="%d %unit%" readOnly="true"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="outgoing_temperature" advanced="false">
|
||||
<item-type>Number:Temperature</item-type>
|
||||
<label>Outgoing Temperature</label>
|
||||
<description>Temperature measured in the outgoing air flow.</description>
|
||||
<category>Temperature</category>
|
||||
<state pattern="%d %unit%" readOnly="true"/>
|
||||
</channel-type>
|
||||
|
||||
|
||||
<channel-type id="set_temperature" advanced="true">
|
||||
<item-type>Number:Temperature</item-type>
|
||||
<label>Temperature</label>
|
||||
<description>Set temperature for the supply air. Not used in all ventilation systems.</description>
|
||||
<category>Temperature</category>
|
||||
<state pattern="%d %unit%" readOnly="false"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="fanspeed" advanced="false">
|
||||
<item-type>Number</item-type>
|
||||
<label>Fanspeed</label>
|
||||
<category>HVAC</category>
|
||||
<state min="1" max="8" pattern="%d" readOnly="false"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="min_fanspeed" advanced="true">
|
||||
<item-type>Number</item-type>
|
||||
<label>Minimal Fanspeed</label>
|
||||
<category>HVAC</category>
|
||||
<state min="1" max="8" pattern="%d" readOnly="false"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="max_fanspeed" advanced="true">
|
||||
<item-type>Number</item-type>
|
||||
<label>Maximum Fanspeed</label>
|
||||
<category>HVAC</category>
|
||||
<state min="1" max="8" pattern="%d" readOnly="false"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="bypass_temperature" advanced="true">
|
||||
<item-type>Number:Temperature</item-type>
|
||||
<label>Cell Bypass Temperature</label>
|
||||
<description>Bypass temperature to disable the bypass function if outside temperature is below this threshold even if
|
||||
ventilation system is in summer mode.</description>
|
||||
<category>Temperature</category>
|
||||
<state pattern="%d %unit%" readOnly="false"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="supply_stop_temperature" advanced="true">
|
||||
<item-type>Number:Temperature</item-type>
|
||||
<label>Supply Stop Temperature</label>
|
||||
<description>Stop the supply fan if outside temperature is below this threshold.</description>
|
||||
<category>Temperature</category>
|
||||
<state pattern="%d %unit%" readOnly="false"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="preheat_temperature" advanced="true">
|
||||
<item-type>Number:Temperature</item-type>
|
||||
<label>Preheat Temperature</label>
|
||||
<description>Set temperature for preheater.</description>
|
||||
<category>Temperature</category>
|
||||
<state pattern="%d %unit%" readOnly="false"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="rh_limit" advanced="true">
|
||||
<item-type>Number:Dimensionless</item-type>
|
||||
<label>RH Limit</label>
|
||||
<description>Limit for relative humidity sensor.</description>
|
||||
<category>Humidity</category>
|
||||
<state pattern="%f %unit%" min="0" max="100" readOnly="false"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="dc_fan_supply" advanced="true">
|
||||
<item-type>Number:Dimensionless</item-type>
|
||||
<label>Supply Fan</label>
|
||||
<description>Speed of the supply air fan (incoming air).</description>
|
||||
<category>HVAC</category>
|
||||
<state pattern="%f %unit%" min="0" max="100" readOnly="false"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="dc_fan_extract" advanced="true">
|
||||
<item-type>Number:Dimensionless</item-type>
|
||||
<label>Extract Fan</label>
|
||||
<description>Speed of the extract air fan (outgoing air).</description>
|
||||
<category>HVAC</category>
|
||||
<state pattern="%f %unit%" min="0" max="100" readOnly="false"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="hysteresis" advanced="true">
|
||||
<item-type>Number:Temperature</item-type>
|
||||
<label>Hysteresis</label>
|
||||
<description>Hysteresis on defroster temperature.</description>
|
||||
<state pattern="%d %unit%" min="1" max="10" readOnly="false"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="power_state" advanced="false">
|
||||
<item-type>Switch</item-type>
|
||||
<label>Power</label>
|
||||
<description>State of the ventilation system.</description>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="co2_state" advanced="false">
|
||||
<item-type>Switch</item-type>
|
||||
<label>CO2 Control</label>
|
||||
<description>Control the ventilation system by CO2 sensor.</description>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="rh_state" advanced="false">
|
||||
<item-type>Switch</item-type>
|
||||
<label>Humidity Control</label>
|
||||
<description>Control the ventilation system by humidity sensor.</description>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="winter_state" advanced="false">
|
||||
<item-type>Switch</item-type>
|
||||
<label>Winter Mode</label>
|
||||
<description>Ventilation system is in winter mode and will not use bypass for cooling. If OFF, the bypass function
|
||||
will be used for cooling if the outside temperature is above the Cell Bypass Temperature.</description>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="rh_level_auto" advanced="true">
|
||||
<item-type>Switch</item-type>
|
||||
<label>Auto Humidity level</label>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="radiator_type" advanced="true">
|
||||
<item-type>Switch</item-type>
|
||||
<label>Water radiator</label>
|
||||
<description>Ventilation system with water radiator (ON) or electric radiator (OFF).</description>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="switch_type" advanced="true">
|
||||
<item-type>Switch</item-type>
|
||||
<label>Boost switch</label>
|
||||
<description>External switch is used for boost (ON) or fireplace (OFF).</description>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="cascade_mode" advanced="true">
|
||||
<item-type>Switch</item-type>
|
||||
<label>Cascaded ventilation system</label>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="adjust_interval" advanced="true">
|
||||
<item-type>Number:Dimensionless</item-type>
|
||||
<label>Adjust Interval</label>
|
||||
<category>HVAC</category>
|
||||
<state pattern="%f %unit%" min="1" max="15" readOnly="false"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="maintenance_interval" advanced="true">
|
||||
<item-type>Number:Dimensionless</item-type>
|
||||
<label>Maintenance Interval</label>
|
||||
<category>HVAC</category>
|
||||
<state pattern="%f %unit%" min="1" max="15" readOnly="false"/>
|
||||
</channel-type>
|
||||
|
||||
</thing:thing-descriptions>
|
||||
@@ -0,0 +1,48 @@
|
||||
#
|
||||
# datapoints.properties - This file defines the datapoints of the Helios ventilation system
|
||||
#
|
||||
# Format: <name> = <address(:bitspec)>,writable,type
|
||||
#
|
||||
# bitspec is
|
||||
# - a single digit in range 0-7 or
|
||||
# - start:end (where start is the number of the LSB and end the number of the MSB of the field)
|
||||
#
|
||||
# type is one of
|
||||
# - TEMPERATURE
|
||||
# - FANSPEED
|
||||
# - PERCENT
|
||||
# - BYTE_PERCENT
|
||||
# - SWITCH
|
||||
# - NUMBER
|
||||
# - HYSTERESIS
|
||||
#
|
||||
# on change of this file, ensure that the thing-types.xml is consistent
|
||||
|
||||
fanspeed = 0x29,true,FANSPEED
|
||||
|
||||
outsideTemp = 0x32,false,TEMPERATURE
|
||||
outgoingTemp = 0x33,false,TEMPERATURE
|
||||
extractTemp = 0x34,false,TEMPERATURE
|
||||
supplyTemp = 0x35,false,TEMPERATURE
|
||||
|
||||
DCFanSupply = 0xB0,true,PERCENT
|
||||
DCFanExtract = 0xB1,true,PERCENT
|
||||
hysteresis = 0xB2,true,HYSTERESIS
|
||||
setTemp = 0xA4,true,TEMPERATURE
|
||||
maxFanspeed = 0xA5,true,FANSPEED
|
||||
maintenanceInterval = 0xA6:0:3,true,NUMBER
|
||||
preheatTemp = 0xA7,true,TEMPERATURE
|
||||
supplyStopTemp = 0xA8,true,TEMPERATURE
|
||||
minFanspeed = 0xA9,true,FANSPEED
|
||||
rhLimit = 0xAE,true,BYTE_PERCENT
|
||||
bypassTemp = 0xAF,true,TEMPERATURE
|
||||
adjustInveral = 0xAA:0:3,true,NUMBER
|
||||
RHLevelAuto = 0xAA:4,true,SWITCH
|
||||
switchType = 0xAA:5,true,SWITCH # ON = boost, OFF = fireplace
|
||||
radiatorType = 0xAA:6,true,SWITCH # ON = water, OFF = electric
|
||||
cascade = 0xAA:7,true,SWITCH
|
||||
|
||||
powerState = 0xA3:0,true,SWITCH
|
||||
co2State = 0xA3:1,true,SWITCH
|
||||
rhState = 0xA3:2,true,SWITCH
|
||||
winterMode = 0xA3:3,true,SWITCH # ON = bypass disabled
|
||||
Reference in New Issue
Block a user