added migrated 2.x add-ons
Signed-off-by: Kai Kreuzer <kai@openhab.org>
This commit is contained in:
32
bundles/org.openhab.binding.valloxmv/.classpath
Normal file
32
bundles/org.openhab.binding.valloxmv/.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.valloxmv/.project
Normal file
23
bundles/org.openhab.binding.valloxmv/.project
Normal file
@@ -0,0 +1,23 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<projectDescription>
|
||||
<name>org.openhab.binding.valloxmv</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.valloxmv/NOTICE
Normal file
13
bundles/org.openhab.binding.valloxmv/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
|
||||
89
bundles/org.openhab.binding.valloxmv/README.md
Normal file
89
bundles/org.openhab.binding.valloxmv/README.md
Normal file
@@ -0,0 +1,89 @@
|
||||
# ValloxMV Binding
|
||||
|
||||
This binding is designed to connect to the web interface of Vallox MV series of ventilation unit.
|
||||
It has been tested so far only with Vallox 350 MV and 510 MV.
|
||||
|
||||
## Supported Things
|
||||
|
||||
There is one thing (valloxmv) supporting the connection via the web interface of the Vallox MV. There is NO support of former modbus connected devices.
|
||||
|
||||
## Discovery
|
||||
|
||||
This binding does not support any discovery, IP address has to be provided.
|
||||
|
||||
## Thing Configuration
|
||||
|
||||
The Thing needs the information at which IP the web interface could be reached and how often the values should be updated.
|
||||
Minimum update interval is limited to 15 sec in order to avoid polling again before results have been evaluated.
|
||||
|
||||
| Config | Description | Type | Default |
|
||||
| :-------------------- |:------------------------------------------------------|:-----:|:-------:|
|
||||
| ip | IP address of web interface |string | n/a |
|
||||
| updateinterval | Interval in seconds in which the interface is polled |int | 60 |
|
||||
|
||||
## Channels
|
||||
|
||||
Overview of provided channels
|
||||
|
||||
| Channel ID | Vallox Name | Description | Read/Write | Values |
|
||||
| :------------------------- | :--------------------------- |:-----------------------------------|:-:|:----------------------:|
|
||||
| onoff | A_CYC_MODE | On off switch |rw| On/Off |
|
||||
| state | _several_ | Current state of ventilation unit |rw| 1=FIREPLACE, 2=AWAY, 3=ATHOME, 4=BOOST |
|
||||
| fanspeed | A_CYC_FAN_SPEED | Fan speed |r | 0 - 100 (%) |
|
||||
| fanspeedextract | A_CYC_EXTR_FAN_SPEED | Fan speed of extracting fan |r | 1/min |
|
||||
| fanspeedsupply | A_CYC_SUPP_FAN_SPEED | Fan speed of supplying fan |r | 1/min |
|
||||
| tempinside | A_CYC_TEMP_EXTRACT_AIR | Extracted air temp |r | Number (°C) |
|
||||
| tempoutside | A_CYC_TEMP_OUTDOOR_AIR | Outside air temp |r | Number (°C) |
|
||||
| tempexhaust | A_CYC_TEMP_EXHAUST_AIR | Exhausted air temp |r | Number (°C) |
|
||||
| tempincomingbeforeheating | A_CYC_TEMP_SUPPLY_CELL_AIR | Incoming air temp (pre heating) |r | Number (°C) |
|
||||
| tempincoming | A_CYC_TEMP_SUPPLY_AIR | Incoming air temp |r | Number (°C) |
|
||||
| humidity | A_CYC_RH_VALUE | Extracted air humidity |r | 0 - 100 (%) |
|
||||
| cellstate | A_CYC_CELL_STATE | Current cell state |r | 0=heat recovery, 1=cool recovery, 2=bypass, 3=defrosting |
|
||||
| uptimeyears | A_CYC_TOTAL_UP_TIME_YEARS | Total uptime years |r | Y |
|
||||
| uptimehours | A_CYC_TOTAL_UP_TIME_HOURS | Total uptime hours |r | h |
|
||||
| uptimehourscurrent | A_CYC_CURRENT_UP_TIME_HOURS | Current uptime in hours |r | h |
|
||||
| filterchangeddate | A\_CYC\_FILTER\_CHANGED\_DAY/MONTH/YEAR | Last filter change |r | date |
|
||||
| remainingfilterdays | A_CYC_CURRENT_UP_TIME_HOURS | Days until filter change |r | d |
|
||||
| extrfanbalancebase | A_CYC_EXTR_FAN_BALANCE_BASE | Extract fan base speed |rw| 0 - 100 (%) |
|
||||
| suppfanbalancebase | A_CYC_SUPP_FAN_BALANCE_BASE | Supply fan base speed |rw| 0 - 100 (%) |
|
||||
| homespeedsetting | A_CYC_HOME_SPEED_SETTING | Home fan speed |rw| 0 - 100 (%) |
|
||||
| awayspeedsetting | A_CYC_AWAY_SPEED_SETTING | Away fan speed |rw| 0 - 100 (%) |
|
||||
| boostspeedsetting | A_CYC_BOOST_SPEED_SETTING | Boost fan speed |rw| 0 - 100 (%) |
|
||||
| homeairtemptarget | A_CYC_HOME_AIR_TEMP_TARGET | Target temperature in home state |rw| Number (°C) |
|
||||
| awayairtemptarget | A_CYC_AWAY_AIR_TEMP_TARGET | Target temperature in away state |rw| Number (°C) |
|
||||
| boostairtemptarget | A_CYC_BOOST_AIR_TEMP_TARGET | Target temperature in boost state |rw| Number (°C) |
|
||||
| boosttime | A_CYC_BOOST_TIME | Timer value in boost profile |rw| 1 - 65535 (min) |
|
||||
| boosttimerenabled | A_CYC_BOOST_TIMER_ENABLED | Timer enabled setting in boost profile |rw| On/Off |
|
||||
| fireplaceextrfan | A_CYC_FIREPLACE_EXTR_FAN | Fireplace profile extract fan speed |rw| 0 - 100 (%) |
|
||||
| fireplacesuppfan | A_CYC_FIREPLACE_SUPP_FAN | Fireplace profile supply fan speed |rw| 0 - 100 (%) |
|
||||
| fireplacetime | A_CYC_FIREPLACE_TIME | Timer value in fireplace profile |rw| 1 - 65535 (min) |
|
||||
| fireplacetimerenabled | A_CYC_FIREPLACE_TIMER_ENABLED | Timer enabled setting in fireplace profile |rw| On/Off |
|
||||
| extraairtemptarget | A_CYC_EXTRA_AIR_TEMP_TARGET | Target temperature in extra profile |rw| Number (°C) |
|
||||
| extraextrfan | A_CYC_EXTRA_EXTR_FAN | Extra profile extract fan speed |rw| 0 - 100 (%) |
|
||||
| extrasuppfan | A_CYC_EXTRA_EXTR_FAN | Extra profile supply fan speed |rw| 0 - 100 (%) |
|
||||
| extratime | A_CYC_EXTRA_TIME | Timer value in extra profile |rw| 1 - 65535 (min) |
|
||||
| extratimerenabled | A_CYC_EXTRA_TIMER_ENABLED | Timer enabled setting in extra profile |rw| On/Off |
|
||||
| weeklytimerenabled | A_CYC_WEEKLY_TIMER_ENABLED | Weekly timer enabled setting |rw| On/Off |
|
||||
|
||||
## Example
|
||||
|
||||
### Things file ###
|
||||
|
||||
```
|
||||
Thing valloxmv:valloxmv:lueftung [ip="192.168.1.3", updateinterval=60]
|
||||
```
|
||||
|
||||
|
||||
### Items file ###
|
||||
|
||||
```
|
||||
Number State "Current state: [%d]" {channel="valloxmv:valloxmv:lueftung:state"}
|
||||
Number FanSpeed "Fanspeed [%d %%]" {channel="valloxmv:valloxmv:lueftung:fanspeed"}
|
||||
|
||||
Number Temp_TempInside "Temp inside [%.1f °C]" <temperature> {channel="valloxmv:valloxmv:lueftung:tempinside"}
|
||||
Number Temp_TempOutside "Temp outside [%.1f °C]" <temperature> {channel="valloxmv:valloxmv:lueftung:tempoutside"}
|
||||
Number Temp_TempExhaust "Temp outgoing [%.1f °C]" <temperature> {channel="valloxmv:valloxmv:lueftung:tempexhaust"}
|
||||
Number Temp_TempIncoming "Temp incoming [%.1f °C]" <temperature> {channel="valloxmv:valloxmv:lueftung:tempincoming"}
|
||||
|
||||
Number Humidity "Humidity [%d %%]" {channel="valloxmv:valloxmv:lueftung:humidity"}
|
||||
```
|
||||
1838
bundles/org.openhab.binding.valloxmv/README_DEV.md
Normal file
1838
bundles/org.openhab.binding.valloxmv/README_DEV.md
Normal file
File diff suppressed because it is too large
Load Diff
17
bundles/org.openhab.binding.valloxmv/pom.xml
Normal file
17
bundles/org.openhab.binding.valloxmv/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.valloxmv</artifactId>
|
||||
|
||||
<name>openHAB Add-ons :: Bundles :: ValloxMV Binding</name>
|
||||
|
||||
</project>
|
||||
@@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<features name="org.openhab.binding.valloxmv-${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-valloxmv" description="ValloxMV Binding" version="${project.version}">
|
||||
<feature>openhab-runtime-base</feature>
|
||||
<bundle start-level="80">mvn:org.openhab.addons.bundles/org.openhab.binding.valloxmv/${project.version}</bundle>
|
||||
</feature>
|
||||
</features>
|
||||
@@ -0,0 +1,268 @@
|
||||
/**
|
||||
* 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.valloxmv.internal;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.core.thing.ThingTypeUID;
|
||||
|
||||
/**
|
||||
* The {@link ValloxMVBindingConstants} class defines common constants, which are
|
||||
* used across the whole binding.
|
||||
*
|
||||
* @author Björn Brings - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class ValloxMVBindingConstants {
|
||||
|
||||
private static final String BINDING_ID = "valloxmv";
|
||||
|
||||
// List of all Thing Type UIDs
|
||||
public static final ThingTypeUID THING_TYPE_VALLOXMV = new ThingTypeUID(BINDING_ID, "valloxmv");
|
||||
|
||||
// 4 states of ventilation unit (Fireplace = 1, Away = 2, At home = 3, Boost = 4)
|
||||
public static final int STATE_FIREPLACE = 1;
|
||||
public static final int STATE_AWAY = 2;
|
||||
public static final int STATE_ATHOME = 3;
|
||||
public static final int STATE_BOOST = 4;
|
||||
|
||||
// List of all Channel ids
|
||||
/**
|
||||
* Ventilation unit powered on
|
||||
*/
|
||||
public static final String CHANNEL_ONOFF = "onoff";
|
||||
|
||||
/**
|
||||
* Current state ventilation unit (Fireplace = 1, Away = 2, At home = 3, Boost = 4)
|
||||
*/
|
||||
public static final String CHANNEL_STATE = "state";
|
||||
|
||||
/**
|
||||
* Current fan speed (0 - 100)
|
||||
*/
|
||||
public static final String CHANNEL_FAN_SPEED = "fanspeed";
|
||||
|
||||
/**
|
||||
* Current fan speed of extracting fan (1/min)
|
||||
*/
|
||||
public static final String CHANNEL_FAN_SPEED_EXTRACT = "fanspeedextract";
|
||||
|
||||
/**
|
||||
* Current fan speed of supplying fan (1/min)
|
||||
*/
|
||||
public static final String CHANNEL_FAN_SPEED_SUPPLY = "fanspeedsupply";
|
||||
|
||||
/**
|
||||
* Current temperature inside the building
|
||||
*/
|
||||
public static final String CHANNEL_TEMPERATURE_INSIDE = "tempinside";
|
||||
|
||||
/**
|
||||
* Current temperature outside the building
|
||||
*/
|
||||
public static final String CHANNEL_TEMPERATURE_OUTSIDE = "tempoutside";
|
||||
|
||||
/**
|
||||
* Current temperature of the air flow exhausting the building.
|
||||
*/
|
||||
public static final String CHANNEL_TEMPERATURE_EXHAUST = "tempexhaust";
|
||||
|
||||
/**
|
||||
* Current temperature of the air flow incoming to the building before heating (if optional heating module included
|
||||
* in ventilation unit).
|
||||
*/
|
||||
public static final String CHANNEL_TEMPERATURE_INCOMING_BEFORE_HEATING = "tempincomingbeforeheating";
|
||||
|
||||
/**
|
||||
* Current temperature of the air flow incoming to the building.
|
||||
*/
|
||||
public static final String CHANNEL_TEMPERATURE_INCOMING = "tempincoming";
|
||||
|
||||
/**
|
||||
* Current humidity of the air flow exhausting the building.
|
||||
*/
|
||||
public static final String CHANNEL_HUMIDITY = "humidity";
|
||||
|
||||
/**
|
||||
* Current cell state (0=heat recovery, 1=cool recovery, 2=bypass, 3=defrosting).
|
||||
*/
|
||||
public static final String CHANNEL_CELLSTATE = "cellstate";
|
||||
|
||||
/**
|
||||
* Total uptime in years (+ uptime in hours = total uptime).
|
||||
*/
|
||||
public static final String CHANNEL_UPTIME_YEARS = "uptimeyears";
|
||||
|
||||
/**
|
||||
* Total uptime in hours (+ uptime in years = total uptime).
|
||||
*/
|
||||
public static final String CHANNEL_UPTIME_HOURS = "uptimehours";
|
||||
|
||||
/**
|
||||
* Current uptime in hours.
|
||||
*/
|
||||
public static final String CHANNEL_UPTIME_HOURS_CURRENT = "uptimehourscurrent";
|
||||
|
||||
/**
|
||||
* Date filter was changed last time.
|
||||
*/
|
||||
public static final String CHANNEL_FILTER_CHANGED_DATE = "filterchangeddate";
|
||||
|
||||
/**
|
||||
* Days until filter has to be changed.
|
||||
*/
|
||||
public static final String CHANNEL_REMAINING_FILTER_DAYS = "remainingfilterdays";
|
||||
|
||||
/**
|
||||
* Extract fan base speed in % (0-100).
|
||||
*/
|
||||
public static final String CHANNEL_EXTR_FAN_BALANCE_BASE = "extrfanbalancebase";
|
||||
|
||||
/**
|
||||
* Supply fan base speed in % (0-100).
|
||||
*/
|
||||
public static final String CHANNEL_SUPP_FAN_BALANCE_BASE = "suppfanbalancebase";
|
||||
|
||||
/**
|
||||
* Home fan speed in % (0-100).
|
||||
*/
|
||||
public static final String CHANNEL_HOME_SPEED_SETTING = "homespeedsetting";
|
||||
|
||||
/**
|
||||
* Away fan speed in % (0-100).
|
||||
*/
|
||||
public static final String CHANNEL_AWAY_SPEED_SETTING = "awayspeedsetting";
|
||||
|
||||
/**
|
||||
* Boost fan speed in % (0-100).
|
||||
*/
|
||||
public static final String CHANNEL_BOOST_SPEED_SETTING = "boostspeedsetting";
|
||||
|
||||
/**
|
||||
* Target temperature in home state.
|
||||
*/
|
||||
public static final String CHANNEL_HOME_AIR_TEMP_TARGET = "homeairtemptarget";
|
||||
|
||||
/**
|
||||
* Target temperature in away state.
|
||||
*/
|
||||
public static final String CHANNEL_AWAY_AIR_TEMP_TARGET = "awayairtemptarget";
|
||||
|
||||
/**
|
||||
* Target temperature in boost state.
|
||||
*/
|
||||
public static final String CHANNEL_BOOST_AIR_TEMP_TARGET = "boostairtemptarget";
|
||||
|
||||
/**
|
||||
* Timer value setting in minutes of boost profile (1-65535).
|
||||
*/
|
||||
public static final String CHANNEL_BOOST_TIME = "boosttime";
|
||||
|
||||
/**
|
||||
* Timer enabled setting in boost profile (Enabled = 1, Disabled = 0).
|
||||
*/
|
||||
public static final String CHANNEL_BOOST_TIMER_ENABLED = "boosttimerenabled";
|
||||
|
||||
/**
|
||||
* Fireplace profile extract fan speed setting in % (0-100).
|
||||
*/
|
||||
public static final String CHANNEL_FIREPLACE_EXTR_FAN = "fireplaceextrfan";
|
||||
|
||||
/**
|
||||
* Fireplace profile supply fan speed setting in % (0-100).
|
||||
*/
|
||||
public static final String CHANNEL_FIREPLACE_SUPP_FAN = "fireplacesuppfan";
|
||||
|
||||
/**
|
||||
* Timer value setting in minutes of fireplace profile (1-65535).
|
||||
*/
|
||||
public static final String CHANNEL_FIREPLACE_TIME = "fireplacetime";
|
||||
|
||||
/**
|
||||
* Timer enabled setting in fireplace profile (Enabled = 1, Disabled = 0).
|
||||
*/
|
||||
public static final String CHANNEL_FIREPLACE_TIMER_ENABLED = "fireplacetimerenabled";
|
||||
|
||||
/**
|
||||
* Programmable profile enabled
|
||||
* Not sure if this is needed at all, Vallox modbus document does not list this.
|
||||
*/
|
||||
// public static final String CHANNEL_EXTRA_ENABLED = "extraenabled";
|
||||
|
||||
/**
|
||||
* Target temperature in programmable profile.
|
||||
*/
|
||||
public static final String CHANNEL_EXTRA_AIR_TEMP_TARGET = "extraairtemptarget";
|
||||
|
||||
/**
|
||||
* Programmable profile extract fan speed setting in % (0-100).
|
||||
*/
|
||||
public static final String CHANNEL_EXTRA_EXTR_FAN = "extraextrfan";
|
||||
|
||||
/**
|
||||
* Programmable profile supply fan speed setting in % (0-100).
|
||||
*/
|
||||
public static final String CHANNEL_EXTRA_SUPP_FAN = "extrasuppfan";
|
||||
|
||||
/**
|
||||
* Timer value setting in minutes of programmable profile (1-65535).
|
||||
*/
|
||||
public static final String CHANNEL_EXTRA_TIME = "extratime";
|
||||
|
||||
/**
|
||||
* Timer enabled setting in programmable profile (Enabled = 1, Disabled = 0).
|
||||
*/
|
||||
public static final String CHANNEL_EXTRA_TIMER_ENABLED = "extratimerenabled";
|
||||
|
||||
/**
|
||||
* Weekly Timer enabled setting (Enabled = 1, Disabled = 0).
|
||||
*/
|
||||
public static final String CHANNEL_WEEKLY_TIMER_ENABLED = "weeklytimerenabled";
|
||||
|
||||
/**
|
||||
* Set of writable channels that are Switches
|
||||
*/
|
||||
public static final Set<String> WRITABLE_CHANNELS_SWITCHES = Collections
|
||||
.unmodifiableSet(new HashSet<>(Arrays.asList(CHANNEL_ONOFF, CHANNEL_BOOST_TIMER_ENABLED,
|
||||
CHANNEL_FIREPLACE_TIMER_ENABLED, CHANNEL_EXTRA_TIMER_ENABLED, CHANNEL_WEEKLY_TIMER_ENABLED)));
|
||||
|
||||
/**
|
||||
*
|
||||
* Set of writable channels that are dimensionless
|
||||
*/
|
||||
public static final Set<String> WRITABLE_CHANNELS_DIMENSIONLESS = Collections
|
||||
.unmodifiableSet(new HashSet<>(Arrays.asList(CHANNEL_EXTR_FAN_BALANCE_BASE, CHANNEL_SUPP_FAN_BALANCE_BASE,
|
||||
CHANNEL_HOME_SPEED_SETTING, CHANNEL_AWAY_SPEED_SETTING, CHANNEL_BOOST_SPEED_SETTING,
|
||||
CHANNEL_BOOST_TIME, CHANNEL_BOOST_TIMER_ENABLED, CHANNEL_FIREPLACE_EXTR_FAN,
|
||||
CHANNEL_FIREPLACE_SUPP_FAN, CHANNEL_FIREPLACE_TIME, CHANNEL_FIREPLACE_TIMER_ENABLED,
|
||||
CHANNEL_EXTRA_EXTR_FAN, CHANNEL_EXTRA_SUPP_FAN, CHANNEL_EXTRA_TIME, CHANNEL_EXTRA_TIMER_ENABLED,
|
||||
CHANNEL_WEEKLY_TIMER_ENABLED)));
|
||||
|
||||
/**
|
||||
* Set of writable channels that are temperatures
|
||||
*/
|
||||
public static final Set<String> WRITABLE_CHANNELS_TEMPERATURE = Collections
|
||||
.unmodifiableSet(new HashSet<>(Arrays.asList(CHANNEL_HOME_AIR_TEMP_TARGET, CHANNEL_AWAY_AIR_TEMP_TARGET,
|
||||
CHANNEL_BOOST_AIR_TEMP_TARGET, CHANNEL_EXTRA_AIR_TEMP_TARGET)));
|
||||
|
||||
// Thing configuration
|
||||
/**
|
||||
* Name of the configuration parameters
|
||||
*/
|
||||
public static final String CONFIG_UPDATE_INTERVAL = "updateinterval";
|
||||
public static final String CONFIG_IP = "ip";
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
/**
|
||||
* 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.valloxmv.internal;
|
||||
|
||||
/**
|
||||
* The {@link ValloxMVConfig} class holds the configuration properties of the thing.
|
||||
*
|
||||
* @author Björn Brings - Initial contribution
|
||||
*/
|
||||
|
||||
public class ValloxMVConfig {
|
||||
private String ip;
|
||||
private int updateinterval;
|
||||
|
||||
public String getIp() {
|
||||
return ip;
|
||||
}
|
||||
|
||||
public void setIp(String ip) {
|
||||
this.ip = ip;
|
||||
}
|
||||
|
||||
public int getUpdateinterval() {
|
||||
return updateinterval;
|
||||
}
|
||||
|
||||
public void setUpdateinterval(int updateinterval) {
|
||||
this.updateinterval = updateinterval;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,208 @@
|
||||
/**
|
||||
* 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.valloxmv.internal;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.concurrent.ScheduledFuture;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import javax.measure.quantity.Dimensionless;
|
||||
import javax.measure.quantity.Temperature;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.eclipse.jetty.websocket.client.WebSocketClient;
|
||||
import org.openhab.core.library.types.OnOffType;
|
||||
import org.openhab.core.library.types.QuantityType;
|
||||
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.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 ValloxMVHandler} is responsible for handling commands, which are
|
||||
* sent to one of the channels.
|
||||
*
|
||||
* @author Björn Brings - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class ValloxMVHandler extends BaseThingHandler {
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(ValloxMVHandler.class);
|
||||
private @Nullable ScheduledFuture<?> readDataJob;
|
||||
private @Nullable ValloxMVWebSocket valloxSocket;
|
||||
private @Nullable WebSocketClient webSocketClient;
|
||||
|
||||
/**
|
||||
* Refresh interval in seconds.
|
||||
*/
|
||||
private int readDataInterval;
|
||||
|
||||
/**
|
||||
* IP of vallox ventilation unit web interface.
|
||||
*/
|
||||
public ValloxMVHandler(Thing thing, @Nullable WebSocketClient webSocketClient) {
|
||||
super(thing);
|
||||
this.webSocketClient = webSocketClient;
|
||||
}
|
||||
|
||||
@SuppressWarnings({ "null", "unchecked" })
|
||||
@Override
|
||||
public void handleCommand(ChannelUID channelUID, Command command) {
|
||||
if (valloxSocket == null) {
|
||||
return;
|
||||
}
|
||||
if (command instanceof RefreshType) {
|
||||
// We don't have Vallox device values in memory - we cannot update channel with value
|
||||
// We can re-schedule readDataJob in case next read is more than 5 seconds away
|
||||
if (readDataJob != null) {
|
||||
if ((!readDataJob.isDone()) && (readDataJob.getDelay(TimeUnit.MILLISECONDS) > 5000)) {
|
||||
// Next read is more than 5 seconds away, re-schedule
|
||||
// Cancel read data job
|
||||
cancelReadDataJob();
|
||||
// Schedule read data job with 2 seconds initial delay
|
||||
scheduleReadDataJob(2);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
String strUpdateValue = "";
|
||||
if (ValloxMVBindingConstants.CHANNEL_STATE.equals(channelUID.getId())) {
|
||||
try {
|
||||
int cmd = Integer.parseInt(command.toString());
|
||||
if ((cmd == ValloxMVBindingConstants.STATE_FIREPLACE)
|
||||
|| (cmd == ValloxMVBindingConstants.STATE_ATHOME)
|
||||
|| (cmd == ValloxMVBindingConstants.STATE_AWAY)
|
||||
|| (cmd == ValloxMVBindingConstants.STATE_BOOST)) {
|
||||
// logger.debug("Changing state to: {}", command);
|
||||
strUpdateValue = command.toString();
|
||||
}
|
||||
} catch (NumberFormatException nfe) {
|
||||
// Other commands like refresh
|
||||
return;
|
||||
}
|
||||
} else if (ValloxMVBindingConstants.WRITABLE_CHANNELS_SWITCHES.contains(channelUID.getId())) {
|
||||
if (ValloxMVBindingConstants.CHANNEL_ONOFF.equals(channelUID.getId())) {
|
||||
// Vallox MV MODE: Normal mode = 0, Switch off = 5
|
||||
strUpdateValue = (OnOffType.ON.equals(command)) ? "0" : "5";
|
||||
} else {
|
||||
// Switches with ON = 1, OFF = 0
|
||||
strUpdateValue = (OnOffType.ON.equals(command)) ? "1" : "0";
|
||||
}
|
||||
} else if (ValloxMVBindingConstants.WRITABLE_CHANNELS_DIMENSIONLESS.contains(channelUID.getId())) {
|
||||
if (command instanceof QuantityType) {
|
||||
QuantityType<Dimensionless> quantity = (QuantityType<Dimensionless>) command;
|
||||
strUpdateValue = Integer.toString(quantity.intValue());
|
||||
}
|
||||
} else if (ValloxMVBindingConstants.WRITABLE_CHANNELS_TEMPERATURE.contains(channelUID.getId())) {
|
||||
if (command instanceof QuantityType) {
|
||||
// Convert temperature to centiKelvin (= (Celsius * 100) + 27315 )
|
||||
QuantityType<Temperature> quantity = ((QuantityType<Temperature>) command)
|
||||
.toUnit(SmartHomeUnits.KELVIN);
|
||||
if (quantity == null) {
|
||||
return;
|
||||
}
|
||||
int centiKelvin = quantity.multiply(new BigDecimal(100)).intValue();
|
||||
strUpdateValue = Integer.toString(centiKelvin);
|
||||
}
|
||||
} else {
|
||||
// Not writable channel
|
||||
return;
|
||||
}
|
||||
if (strUpdateValue != "") {
|
||||
if (readDataJob != null) {
|
||||
// Re-schedule readDataJob to read device values after data write
|
||||
// Avoid re-scheduling job several times in case of subsequent data writes
|
||||
long timeToRead = readDataJob.getDelay(TimeUnit.MILLISECONDS);
|
||||
if ((!readDataJob.isDone()) && ((timeToRead < 2000) || (timeToRead > 5000))) {
|
||||
// Next read is not within the next 2 to 5 seconds, cancel read data job
|
||||
cancelReadDataJob();
|
||||
// Schedule read data job with 5 seconds initial delay
|
||||
scheduleReadDataJob(5);
|
||||
}
|
||||
}
|
||||
// Send command and process response
|
||||
valloxSocket.request(channelUID, strUpdateValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initialize() {
|
||||
logger.debug("Initializing thing {}", getThing().getUID());
|
||||
|
||||
updateStatus(ThingStatus.UNKNOWN);
|
||||
|
||||
String ip = getConfigAs(ValloxMVConfig.class).getIp();
|
||||
valloxSocket = new ValloxMVWebSocket(webSocketClient, ValloxMVHandler.this, ip);
|
||||
|
||||
logger.debug("Vallox MV IP address : {}", ip);
|
||||
// Schedule read data job with 2 seconds initial delay
|
||||
scheduleReadDataJob(2);
|
||||
|
||||
logger.debug("Thing {} initialized", getThing().getUID());
|
||||
}
|
||||
|
||||
private void scheduleReadDataJob(int initialDelay) {
|
||||
if (initialDelay < 0)
|
||||
initialDelay = 0;
|
||||
|
||||
readDataInterval = getConfigAs(ValloxMVConfig.class).getUpdateinterval();
|
||||
if (readDataInterval < 15)
|
||||
readDataInterval = 60;
|
||||
|
||||
logger.debug("Data table request interval {} seconds, Request in {} seconds", readDataInterval, initialDelay);
|
||||
|
||||
readDataJob = scheduler.scheduleWithFixedDelay(() -> {
|
||||
// Read all device values
|
||||
valloxSocket.request(null, null);
|
||||
}, initialDelay, readDataInterval, TimeUnit.SECONDS);
|
||||
}
|
||||
|
||||
private void cancelReadDataJob() {
|
||||
if (readDataJob != null) {
|
||||
if (!readDataJob.isDone()) {
|
||||
readDataJob.cancel(true);
|
||||
logger.debug("Scheduled data table requests cancelled");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
logger.debug("Disposing thing {}", getThing().getUID());
|
||||
cancelReadDataJob();
|
||||
logger.debug("Thing {} disposed", getThing().getUID());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void updateState(String strChannelName, State dt) {
|
||||
super.updateState(strChannelName, dt);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void updateStatus(ThingStatus ts, ThingStatusDetail statusDetail) {
|
||||
super.updateStatus(ts, statusDetail);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void updateStatus(ThingStatus ts) {
|
||||
super.updateStatus(ts);
|
||||
}
|
||||
}
|
||||
@@ -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.valloxmv.internal;
|
||||
|
||||
import static org.openhab.binding.valloxmv.internal.ValloxMVBindingConstants.THING_TYPE_VALLOXMV;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Set;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.eclipse.jetty.websocket.client.WebSocketClient;
|
||||
import org.openhab.core.io.net.http.WebSocketFactory;
|
||||
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 ValloxMVHandlerFactory} is responsible for creating things and thing
|
||||
* handlers.
|
||||
*
|
||||
* @author Björn Brings - Initial contribution
|
||||
*/
|
||||
@Component(service = ThingHandlerFactory.class, configurationPid = "binding.valloxmv")
|
||||
@NonNullByDefault()
|
||||
public class ValloxMVHandlerFactory extends BaseThingHandlerFactory {
|
||||
|
||||
private static final Set<ThingTypeUID> SUPPORTED_THING_TYPES_UIDS = Collections.singleton(THING_TYPE_VALLOXMV);
|
||||
|
||||
private final WebSocketClient webSocketClient;
|
||||
|
||||
@Activate
|
||||
public ValloxMVHandlerFactory(@Reference final WebSocketFactory webSocketFactory) {
|
||||
this.webSocketClient = webSocketFactory.getCommonWebSocketClient();
|
||||
}
|
||||
|
||||
@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_VALLOXMV.equals(thingTypeUID)) {
|
||||
return new ValloxMVHandler(thing, webSocketClient);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,590 @@
|
||||
/**
|
||||
* 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.valloxmv.internal;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.math.BigDecimal;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.time.ZonedDateTime;
|
||||
import java.util.Calendar;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.TimeZone;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.eclipse.jetty.websocket.api.Session;
|
||||
import org.eclipse.jetty.websocket.api.annotations.OnWebSocketClose;
|
||||
import org.eclipse.jetty.websocket.api.annotations.OnWebSocketConnect;
|
||||
import org.eclipse.jetty.websocket.api.annotations.OnWebSocketError;
|
||||
import org.eclipse.jetty.websocket.api.annotations.OnWebSocketMessage;
|
||||
import org.eclipse.jetty.websocket.api.annotations.WebSocket;
|
||||
import org.eclipse.jetty.websocket.client.ClientUpgradeRequest;
|
||||
import org.eclipse.jetty.websocket.client.WebSocketClient;
|
||||
import org.openhab.core.library.types.DateTimeType;
|
||||
import org.openhab.core.library.types.DecimalType;
|
||||
import org.openhab.core.library.types.OnOffType;
|
||||
import org.openhab.core.library.types.QuantityType;
|
||||
import org.openhab.core.library.unit.MetricPrefix;
|
||||
import org.openhab.core.library.unit.SIUnits;
|
||||
import org.openhab.core.library.unit.SmartHomeUnits;
|
||||
import org.openhab.core.thing.ChannelUID;
|
||||
import org.openhab.core.thing.ThingStatus;
|
||||
import org.openhab.core.thing.ThingStatusDetail;
|
||||
import org.openhab.core.types.State;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* The {@link ValloxMVWebSocket} is responsible for socket communication with the vallox ventilation unit
|
||||
*
|
||||
* @author Björn Brings - Initial contribution
|
||||
*/
|
||||
public class ValloxMVWebSocket {
|
||||
private final ValloxMVHandler voHandler;
|
||||
private final WebSocketClient client;
|
||||
private final URI destUri;
|
||||
private ValloxMVWebSocketListener socket;
|
||||
|
||||
private int iBoostTime;
|
||||
private OnOffType ooBoostTimerEnabled;
|
||||
private int iFireplaceTime;
|
||||
private OnOffType ooFireplaceTimerEnabled;
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(ValloxMVWebSocket.class);
|
||||
|
||||
public ValloxMVWebSocket(WebSocketClient webSocketClient, ValloxMVHandler voHandler, String ip) {
|
||||
this.voHandler = voHandler;
|
||||
this.client = webSocketClient;
|
||||
URI tempUri;
|
||||
try {
|
||||
tempUri = new URI("ws://" + ip + ":80");
|
||||
} catch (URISyntaxException e) {
|
||||
tempUri = null;
|
||||
connectionError(e);
|
||||
}
|
||||
destUri = tempUri;
|
||||
}
|
||||
|
||||
public void request(ChannelUID channelUID, String updateState) {
|
||||
Future<?> sessionFuture = null;
|
||||
try {
|
||||
socket = new ValloxMVWebSocketListener(channelUID, updateState);
|
||||
|
||||
ClientUpgradeRequest request = new ClientUpgradeRequest();
|
||||
logger.debug("Connecting to: {}", destUri);
|
||||
sessionFuture = client.connect(socket, destUri, request);
|
||||
socket.awaitClose(2, TimeUnit.SECONDS);
|
||||
} catch (InterruptedException | IOException e) {
|
||||
connectionError(e);
|
||||
} catch (Exception e) {
|
||||
logger.debug("Unexpected error");
|
||||
connectionError(e);
|
||||
} finally {
|
||||
if (sessionFuture != null && !sessionFuture.isDone()) {
|
||||
sessionFuture.cancel(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void connectionError(Exception e) {
|
||||
logger.debug("Error connecting vallox unit.", e);
|
||||
voHandler.updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.OFFLINE.COMMUNICATION_ERROR);
|
||||
}
|
||||
|
||||
@WebSocket
|
||||
public class ValloxMVWebSocketListener {
|
||||
private final CountDownLatch closeLatch = new CountDownLatch(1);
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(ValloxMVWebSocketListener.class);
|
||||
private final String updateState;
|
||||
private ChannelUID channelUID;
|
||||
private int iValloxCmd;
|
||||
|
||||
public ValloxMVWebSocketListener(ChannelUID channelUID, String updateState) {
|
||||
this.updateState = updateState;
|
||||
this.channelUID = channelUID;
|
||||
}
|
||||
|
||||
@OnWebSocketConnect
|
||||
public void onConnect(Session session) {
|
||||
try {
|
||||
logger.debug("Connected to: {}", session.getRemoteAddress().getAddress());
|
||||
ByteBuffer buf = generateRequest();
|
||||
session.getRemote().sendBytes(buf);
|
||||
} catch (IOException e) {
|
||||
connectionError(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to generate ByteBuffer request to be sent to vallox online websocket
|
||||
* to request or set data
|
||||
*
|
||||
* @param mode 246 for data request, 249 for setting data
|
||||
* @param hmParameters HashMap for setting data with register as key and value as value
|
||||
* @return ByteBuffer to be sent to websocket
|
||||
*/
|
||||
public ByteBuffer generateCustomRequest(Integer mode, Map<Integer, Integer> hmParameters) {
|
||||
// If we just want data the format is different so its just hardcoded here
|
||||
if (mode == 246) {
|
||||
// requestData (Length 3, Command to get data 246, 0, checksum [sum of everything before])
|
||||
return ByteBuffer.wrap(new byte[] { 3, 0, (byte) 246, 0, 0, 0, (byte) 249, 0 });
|
||||
}
|
||||
|
||||
int numberParameters = (hmParameters.size() * 2) + 2; // Parameters (key + value) + Mode + Checksum
|
||||
int checksum = numberParameters;
|
||||
// Allocate for bytebuffer incl. Length
|
||||
ByteBuffer bb = ByteBuffer.allocate((numberParameters + 1) * 2)
|
||||
.put(convertIntegerIntoByteBuffer(numberParameters));
|
||||
|
||||
// Put Mode, HashMap and checksum to ByteArray
|
||||
bb.put(convertIntegerIntoByteBuffer(mode));
|
||||
checksum += mode;
|
||||
|
||||
for (Map.Entry<Integer, Integer> i : hmParameters.entrySet()) {
|
||||
bb.put(convertIntegerIntoByteBuffer(i.getKey()));
|
||||
bb.put(convertIntegerIntoByteBuffer(i.getValue()));
|
||||
checksum += i.getKey() + i.getValue();
|
||||
}
|
||||
|
||||
// We have to make sure that checksum is within the range
|
||||
// Checksum may hold larger value than 65535 from the above loop
|
||||
// We will never reach integer max value in the loop so it is ok to do this after the loop
|
||||
// This is not needed if we make sure that conversion to bytes will take care of it
|
||||
// bitwise AND inside convertIntegerIntoByteBuffer() takes care of this
|
||||
// checksum = checksum & 0xffff;
|
||||
|
||||
bb.put(convertIntegerIntoByteBuffer(checksum));
|
||||
bb.position(0);
|
||||
return bb;
|
||||
}
|
||||
|
||||
// Convert Integer to ByteBuffer in Little-endian
|
||||
public ByteBuffer convertIntegerIntoByteBuffer(Integer i) {
|
||||
// Use bitwise operators to extract two rightmost bytes from the integer
|
||||
byte b1 = (byte) (i & 0xff); // Rightmost byte
|
||||
byte b2 = (byte) ((i >> 8) & 0xff); // Second rightmost byte
|
||||
return ByteBuffer.wrap(new byte[] { b1, b2 });
|
||||
}
|
||||
|
||||
public ByteBuffer generateRequest() {
|
||||
if ((updateState == null) || (channelUID == null)) {
|
||||
// requestData (Length 3, Command to get data 246, empty set, checksum [sum of everything before])
|
||||
iValloxCmd = 246;
|
||||
return generateCustomRequest(246, new HashMap<>());
|
||||
}
|
||||
String strChannelUIDid = channelUID.getId();
|
||||
int iUpdateState = Integer.parseInt(updateState);
|
||||
Map<Integer, Integer> request = new HashMap<>();
|
||||
switch (strChannelUIDid) {
|
||||
case ValloxMVBindingConstants.CHANNEL_STATE:
|
||||
switch (iUpdateState) {
|
||||
case ValloxMVBindingConstants.STATE_FIREPLACE:
|
||||
// Fireplace (Length 6, Command to set data 249, CYC_BOOST_TIMER (4612) = 0,
|
||||
// CYC_FIREPLACE_TIMER (4613) = value from CYC_FIREPLACE_TIME, checksum)
|
||||
// CYC_FIREPLACE_TIME is read during READ_TABLES and stored into outer class variable
|
||||
if (iFireplaceTime < 1) {
|
||||
// use 15 minutes in case not initialized (should never happen)
|
||||
iFireplaceTime = 15;
|
||||
}
|
||||
if (OnOffType.ON.equals(ooFireplaceTimerEnabled)) {
|
||||
logger.debug("Changing to Fireplace profile, timer {} minutes", iFireplaceTime);
|
||||
} else {
|
||||
logger.debug("Changing to Fireplace profile, timer not enabled");
|
||||
}
|
||||
request.put(4612, 0);
|
||||
request.put(4613, iFireplaceTime);
|
||||
break;
|
||||
case ValloxMVBindingConstants.STATE_ATHOME:
|
||||
// At Home (Length 8, Command to set data 249, CYC_STATE (4609) = 0,
|
||||
// CYC_BOOST_TIMER (4612) = 0, CYC_FIREPLACE_TIMER (4613) = 0, checksum)
|
||||
logger.debug("Changing to At Home profile");
|
||||
request.put(4609, 0);
|
||||
request.put(4612, 0);
|
||||
request.put(4613, 0);
|
||||
break;
|
||||
case ValloxMVBindingConstants.STATE_AWAY:
|
||||
// Away (Length 8, Command to set data 249, CYC_STATE (4609) = 1,
|
||||
// CYC_BOOST_TIMER (4612) = 0, CYC_FIREPLACE_TIMER (4613) = 0, checksum)
|
||||
logger.debug("Changing to Away profile");
|
||||
request.put(4609, 1);
|
||||
request.put(4612, 0);
|
||||
request.put(4613, 0);
|
||||
break;
|
||||
case ValloxMVBindingConstants.STATE_BOOST:
|
||||
// Boost (Length 6, Command to set data 249,
|
||||
// CYC_BOOST_TIMER (4612) = value from CYC_BOOST_TIME,
|
||||
// CYC_FIREPLACE_TIMER (4613) = 0, checksum)
|
||||
// CYC_BOOST_TIME is read during READ_TABLES and stored into outer class variable
|
||||
if (iBoostTime < 1) {
|
||||
// use 30 minutes in case not initialized (should never happen)
|
||||
iBoostTime = 30;
|
||||
}
|
||||
if (OnOffType.ON.equals(ooBoostTimerEnabled)) {
|
||||
logger.debug("Changing to Boost profile, timer {} minutes", iBoostTime);
|
||||
} else {
|
||||
logger.debug("Changing to Boost profile, timer not enabled");
|
||||
}
|
||||
request.put(4612, iBoostTime);
|
||||
request.put(4613, 0);
|
||||
break;
|
||||
default:
|
||||
// This should never happen. Let's get back to basic profile.
|
||||
// Clearing boost and fireplace timers.
|
||||
logger.debug("Incorrect profile requested, changing back to basic profile");
|
||||
request.put(4612, 0);
|
||||
request.put(4613, 0);
|
||||
}
|
||||
break;
|
||||
case ValloxMVBindingConstants.CHANNEL_ONOFF:
|
||||
request.put(4610, iUpdateState);
|
||||
break;
|
||||
case ValloxMVBindingConstants.CHANNEL_EXTR_FAN_BALANCE_BASE:
|
||||
request.put(20485, iUpdateState);
|
||||
break;
|
||||
case ValloxMVBindingConstants.CHANNEL_SUPP_FAN_BALANCE_BASE:
|
||||
request.put(20486, iUpdateState);
|
||||
break;
|
||||
case ValloxMVBindingConstants.CHANNEL_HOME_SPEED_SETTING:
|
||||
request.put(20507, iUpdateState);
|
||||
break;
|
||||
case ValloxMVBindingConstants.CHANNEL_AWAY_SPEED_SETTING:
|
||||
request.put(20501, iUpdateState);
|
||||
break;
|
||||
case ValloxMVBindingConstants.CHANNEL_BOOST_SPEED_SETTING:
|
||||
request.put(20513, iUpdateState);
|
||||
break;
|
||||
case ValloxMVBindingConstants.CHANNEL_HOME_AIR_TEMP_TARGET:
|
||||
request.put(20508, iUpdateState);
|
||||
break;
|
||||
case ValloxMVBindingConstants.CHANNEL_AWAY_AIR_TEMP_TARGET:
|
||||
request.put(20502, iUpdateState);
|
||||
break;
|
||||
case ValloxMVBindingConstants.CHANNEL_BOOST_AIR_TEMP_TARGET:
|
||||
request.put(20514, iUpdateState);
|
||||
break;
|
||||
case ValloxMVBindingConstants.CHANNEL_BOOST_TIME:
|
||||
iBoostTime = iUpdateState;
|
||||
request.put(20544, iUpdateState);
|
||||
break;
|
||||
case ValloxMVBindingConstants.CHANNEL_BOOST_TIMER_ENABLED:
|
||||
ooBoostTimerEnabled = OnOffType.from(Integer.toString(iUpdateState));
|
||||
request.put(21766, iUpdateState);
|
||||
break;
|
||||
case ValloxMVBindingConstants.CHANNEL_FIREPLACE_EXTR_FAN:
|
||||
request.put(20487, iUpdateState);
|
||||
break;
|
||||
case ValloxMVBindingConstants.CHANNEL_FIREPLACE_SUPP_FAN:
|
||||
request.put(20488, iUpdateState);
|
||||
break;
|
||||
case ValloxMVBindingConstants.CHANNEL_FIREPLACE_TIME:
|
||||
iFireplaceTime = iUpdateState;
|
||||
request.put(20545, iUpdateState);
|
||||
break;
|
||||
case ValloxMVBindingConstants.CHANNEL_FIREPLACE_TIMER_ENABLED:
|
||||
ooFireplaceTimerEnabled = OnOffType.from(Integer.toString(iUpdateState));
|
||||
request.put(21767, iUpdateState);
|
||||
break;
|
||||
case ValloxMVBindingConstants.CHANNEL_EXTRA_AIR_TEMP_TARGET:
|
||||
request.put(20493, iUpdateState);
|
||||
break;
|
||||
case ValloxMVBindingConstants.CHANNEL_EXTRA_EXTR_FAN:
|
||||
request.put(20494, iUpdateState);
|
||||
break;
|
||||
case ValloxMVBindingConstants.CHANNEL_EXTRA_SUPP_FAN:
|
||||
request.put(20495, iUpdateState);
|
||||
break;
|
||||
case ValloxMVBindingConstants.CHANNEL_EXTRA_TIME:
|
||||
request.put(20496, iUpdateState);
|
||||
break;
|
||||
case ValloxMVBindingConstants.CHANNEL_EXTRA_TIMER_ENABLED:
|
||||
request.put(21772, iUpdateState);
|
||||
break;
|
||||
case ValloxMVBindingConstants.CHANNEL_WEEKLY_TIMER_ENABLED:
|
||||
request.put(4615, iUpdateState);
|
||||
break;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
iValloxCmd = 249;
|
||||
return generateCustomRequest(249, request);
|
||||
}
|
||||
|
||||
@OnWebSocketMessage
|
||||
public void onMessage(String message) {
|
||||
logger.debug("Message from Server: {}", message);
|
||||
}
|
||||
|
||||
@OnWebSocketError
|
||||
public void onError(Throwable cause) {
|
||||
voHandler.updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR);
|
||||
logger.debug("Connection failed: {}", cause.getMessage());
|
||||
}
|
||||
|
||||
@OnWebSocketMessage
|
||||
public void onBinary(InputStream in) {
|
||||
logger.debug("Got binary message");
|
||||
try {
|
||||
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
|
||||
|
||||
int nRead;
|
||||
byte[] data = new byte[16384];
|
||||
|
||||
while ((nRead = in.read(data, 0, data.length)) != -1) {
|
||||
buffer.write(data, 0, nRead);
|
||||
}
|
||||
|
||||
buffer.flush();
|
||||
|
||||
byte[] bytes = buffer.toByteArray();
|
||||
|
||||
if ((bytes.length > 5) && (bytes.length % 2 == 0)) {
|
||||
logger.debug("Response length: {} bytes", bytes.length);
|
||||
} else {
|
||||
logger.debug("Response corrupted, length: {} bytes", bytes.length);
|
||||
return;
|
||||
}
|
||||
|
||||
int iDataLength = bytes.length / 2;
|
||||
|
||||
// Verify responses to requests
|
||||
if ((iValloxCmd == 249) || (iValloxCmd == 250)) {
|
||||
// COMMAND_WRITE_DATA (249) or COMMAND_READ_DATA (250)
|
||||
int iChecksum = 0;
|
||||
int[] arriData = new int[iDataLength];
|
||||
for (int i = 0; i < iDataLength; i++) {
|
||||
arriData[i] = getNumberLE(bytes, (i * 2));
|
||||
}
|
||||
for (int i = 0; i < (iDataLength - 1); i++) {
|
||||
iChecksum += arriData[i];
|
||||
}
|
||||
iChecksum &= 0xffff;
|
||||
if ((arriData[0] != (iDataLength - 1)) || (arriData[iDataLength - 1] != iChecksum)) {
|
||||
// Data length or Checksum do not match
|
||||
logger.debug("Response corrupted, Data length or Checksum do not match");
|
||||
return;
|
||||
}
|
||||
// COMMAND_WRITE_DATA (249)
|
||||
if (iValloxCmd == 249) {
|
||||
String strChannelUIDid = channelUID.getId();
|
||||
if (arriData[1] == 245) {
|
||||
// ACK
|
||||
logger.debug("Channel {} successfully updated to {}", strChannelUIDid, updateState);
|
||||
} else {
|
||||
logger.debug("Channel {} could not be updated", strChannelUIDid);
|
||||
}
|
||||
return;
|
||||
}
|
||||
// COMMAND_READ_DATA (250)
|
||||
/* Read data command is not implemented, response check is ready for future implementation
|
||||
// @formatter:off
|
||||
if ((((iDataLength - 1) % 2) != 0) || (iDataLength < 5)) {
|
||||
logger.debug("Response corrupted, data length is wrong");
|
||||
return;
|
||||
}
|
||||
// number of data pairs (address, value) = (iDataLength - 3) / 2
|
||||
// First data pair (address, value) is in positions 2 and 3
|
||||
// (address, value) pairs could be put into array or hashmap
|
||||
// @formatter:on
|
||||
*/
|
||||
logger.debug("Vallox command {} not implemented", iValloxCmd);
|
||||
return;
|
||||
} else if (iValloxCmd == 246) {
|
||||
// COMMAND_READ_TABLES (246)
|
||||
if (iDataLength > 704) {
|
||||
logger.debug("Data table response with {} values, updating to channels", iDataLength);
|
||||
} else {
|
||||
logger.debug("Response corrupted, data table response not complete");
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
logger.debug("Vallox command {} not implemented", iValloxCmd);
|
||||
return;
|
||||
}
|
||||
|
||||
// COMMAND_READ_TABLES (246)
|
||||
// Read values from received tables
|
||||
int iFanspeed = getNumberBE(bytes, 128);
|
||||
int iFanspeedExtract = getNumberBE(bytes, 144);
|
||||
int iFanspeedSupply = getNumberBE(bytes, 146);
|
||||
BigDecimal bdTempInside = getTemperature(bytes, 130);
|
||||
BigDecimal bdTempExhaust = getTemperature(bytes, 132);
|
||||
BigDecimal bdTempOutside = getTemperature(bytes, 134);
|
||||
BigDecimal bdTempIncomingBeforeHeating = getTemperature(bytes, 136);
|
||||
BigDecimal bdTempIncoming = getTemperature(bytes, 138);
|
||||
int iHumidity = getNumberBE(bytes, 166);
|
||||
|
||||
int iStateOrig = getNumberBE(bytes, 214);
|
||||
int iBoostTimer = getNumberBE(bytes, 220);
|
||||
int iFireplaceTimer = getNumberBE(bytes, 222);
|
||||
|
||||
int iCellstate = getNumberBE(bytes, 228);
|
||||
int iUptimeYears = getNumberBE(bytes, 230);
|
||||
int iUptimeHours = getNumberBE(bytes, 232);
|
||||
int iUptimeHoursCurrent = getNumberBE(bytes, 234);
|
||||
|
||||
int iRemainingTimeForFilter = getNumberBE(bytes, 236);
|
||||
int iFilterChangedDateDay = getNumberBE(bytes, 496);
|
||||
int iFilterChangedDateMonth = getNumberBE(bytes, 498);
|
||||
int iFilterChangedDateYear = getNumberBE(bytes, 500);
|
||||
|
||||
Calendar cFilterChangedDate = Calendar.getInstance();
|
||||
cFilterChangedDate.set(iFilterChangedDateYear + 2000,
|
||||
iFilterChangedDateMonth - 1 /* Month is 0-based */, iFilterChangedDateDay, 0, 0, 0);
|
||||
|
||||
int iExtrFanBalanceBase = getNumberBE(bytes, 374);
|
||||
int iSuppFanBalanceBase = getNumberBE(bytes, 376);
|
||||
|
||||
int iHomeSpeedSetting = getNumberBE(bytes, 418);
|
||||
int iAwaySpeedSetting = getNumberBE(bytes, 406);
|
||||
int iBoostSpeedSetting = getNumberBE(bytes, 430);
|
||||
BigDecimal bdHomeAirTempTarget = getTemperature(bytes, 420);
|
||||
BigDecimal bdAwayAirTempTarget = getTemperature(bytes, 408);
|
||||
BigDecimal bdBoostAirTempTarget = getTemperature(bytes, 432);
|
||||
|
||||
// Using outer class variable for boost time and timer enabled
|
||||
iBoostTime = getNumberBE(bytes, 492);
|
||||
ooBoostTimerEnabled = OnOffType.from(Integer.toString(getNumberBE(bytes, 528)));
|
||||
int iFireplaceExtrFan = getNumberBE(bytes, 378);
|
||||
int iFireplaceSuppFan = getNumberBE(bytes, 380);
|
||||
// Using outer class variable for fireplace time and timer enabled
|
||||
iFireplaceTime = getNumberBE(bytes, 494);
|
||||
ooFireplaceTimerEnabled = OnOffType.from(Integer.toString(getNumberBE(bytes, 530)));
|
||||
BigDecimal bdExtraAirTempTarget = getTemperature(bytes, 390);
|
||||
int iExtraExtrFan = getNumberBE(bytes, 392);
|
||||
int iExtraSuppFan = getNumberBE(bytes, 394);
|
||||
int iExtraTime = getNumberBE(bytes, 396);
|
||||
OnOffType ooExtraTimerEnabled = OnOffType.from(Integer.toString(getNumberBE(bytes, 540)));
|
||||
OnOffType ooWeeklyTimerEnabled = OnOffType.from(Integer.toString(getNumberBE(bytes, 226)));
|
||||
|
||||
BigDecimal bdState;
|
||||
if (iFireplaceTimer > 0) {
|
||||
bdState = new BigDecimal(ValloxMVBindingConstants.STATE_FIREPLACE);
|
||||
} else if (iBoostTimer > 0) {
|
||||
bdState = new BigDecimal(ValloxMVBindingConstants.STATE_BOOST);
|
||||
} else if (iStateOrig == 1) {
|
||||
bdState = new BigDecimal(ValloxMVBindingConstants.STATE_AWAY);
|
||||
} else {
|
||||
bdState = new BigDecimal(ValloxMVBindingConstants.STATE_ATHOME);
|
||||
}
|
||||
|
||||
OnOffType ooOnOff = OnOffType.from(bytes[217] != 5);
|
||||
|
||||
// Update channels with read values
|
||||
updateChannel(ValloxMVBindingConstants.CHANNEL_ONOFF, ooOnOff);
|
||||
updateChannel(ValloxMVBindingConstants.CHANNEL_STATE, new DecimalType(bdState));
|
||||
updateChannel(ValloxMVBindingConstants.CHANNEL_FAN_SPEED,
|
||||
new QuantityType<>(iFanspeed, SmartHomeUnits.PERCENT));
|
||||
updateChannel(ValloxMVBindingConstants.CHANNEL_FAN_SPEED_EXTRACT, new DecimalType(iFanspeedExtract));
|
||||
updateChannel(ValloxMVBindingConstants.CHANNEL_FAN_SPEED_SUPPLY, new DecimalType(iFanspeedSupply));
|
||||
updateChannel(ValloxMVBindingConstants.CHANNEL_TEMPERATURE_INSIDE,
|
||||
new QuantityType<>(bdTempInside, SIUnits.CELSIUS));
|
||||
updateChannel(ValloxMVBindingConstants.CHANNEL_TEMPERATURE_OUTSIDE,
|
||||
new QuantityType<>(bdTempOutside, SIUnits.CELSIUS));
|
||||
updateChannel(ValloxMVBindingConstants.CHANNEL_TEMPERATURE_EXHAUST,
|
||||
new QuantityType<>(bdTempExhaust, SIUnits.CELSIUS));
|
||||
updateChannel(ValloxMVBindingConstants.CHANNEL_TEMPERATURE_INCOMING_BEFORE_HEATING,
|
||||
new QuantityType<>(bdTempIncomingBeforeHeating, SIUnits.CELSIUS));
|
||||
updateChannel(ValloxMVBindingConstants.CHANNEL_TEMPERATURE_INCOMING,
|
||||
new QuantityType<>(bdTempIncoming, SIUnits.CELSIUS));
|
||||
updateChannel(ValloxMVBindingConstants.CHANNEL_HUMIDITY,
|
||||
new QuantityType<>(iHumidity, SmartHomeUnits.PERCENT));
|
||||
updateChannel(ValloxMVBindingConstants.CHANNEL_CELLSTATE, new DecimalType(iCellstate));
|
||||
updateChannel(ValloxMVBindingConstants.CHANNEL_UPTIME_YEARS, new DecimalType(iUptimeYears));
|
||||
updateChannel(ValloxMVBindingConstants.CHANNEL_UPTIME_HOURS, new DecimalType(iUptimeHours));
|
||||
updateChannel(ValloxMVBindingConstants.CHANNEL_UPTIME_HOURS_CURRENT,
|
||||
new DecimalType(iUptimeHoursCurrent));
|
||||
updateChannel(ValloxMVBindingConstants.CHANNEL_FILTER_CHANGED_DATE, new DateTimeType(
|
||||
ZonedDateTime.ofInstant(cFilterChangedDate.toInstant(), TimeZone.getDefault().toZoneId())));
|
||||
updateChannel(ValloxMVBindingConstants.CHANNEL_REMAINING_FILTER_DAYS,
|
||||
new QuantityType<>(iRemainingTimeForFilter, SmartHomeUnits.DAY));
|
||||
updateChannel(ValloxMVBindingConstants.CHANNEL_EXTR_FAN_BALANCE_BASE,
|
||||
new QuantityType<>(iExtrFanBalanceBase, SmartHomeUnits.PERCENT));
|
||||
updateChannel(ValloxMVBindingConstants.CHANNEL_SUPP_FAN_BALANCE_BASE,
|
||||
new QuantityType<>(iSuppFanBalanceBase, SmartHomeUnits.PERCENT));
|
||||
updateChannel(ValloxMVBindingConstants.CHANNEL_HOME_SPEED_SETTING,
|
||||
new QuantityType<>(iHomeSpeedSetting, SmartHomeUnits.PERCENT));
|
||||
updateChannel(ValloxMVBindingConstants.CHANNEL_AWAY_SPEED_SETTING,
|
||||
new QuantityType<>(iAwaySpeedSetting, SmartHomeUnits.PERCENT));
|
||||
updateChannel(ValloxMVBindingConstants.CHANNEL_BOOST_SPEED_SETTING,
|
||||
new QuantityType<>(iBoostSpeedSetting, SmartHomeUnits.PERCENT));
|
||||
updateChannel(ValloxMVBindingConstants.CHANNEL_HOME_AIR_TEMP_TARGET,
|
||||
new QuantityType<>(bdHomeAirTempTarget, SIUnits.CELSIUS));
|
||||
updateChannel(ValloxMVBindingConstants.CHANNEL_AWAY_AIR_TEMP_TARGET,
|
||||
new QuantityType<>(bdAwayAirTempTarget, SIUnits.CELSIUS));
|
||||
updateChannel(ValloxMVBindingConstants.CHANNEL_BOOST_AIR_TEMP_TARGET,
|
||||
new QuantityType<>(bdBoostAirTempTarget, SIUnits.CELSIUS));
|
||||
updateChannel(ValloxMVBindingConstants.CHANNEL_BOOST_TIME, new DecimalType(iBoostTime));
|
||||
updateChannel(ValloxMVBindingConstants.CHANNEL_BOOST_TIMER_ENABLED, ooBoostTimerEnabled);
|
||||
updateChannel(ValloxMVBindingConstants.CHANNEL_FIREPLACE_EXTR_FAN,
|
||||
new QuantityType<>(iFireplaceExtrFan, SmartHomeUnits.PERCENT));
|
||||
updateChannel(ValloxMVBindingConstants.CHANNEL_FIREPLACE_SUPP_FAN,
|
||||
new QuantityType<>(iFireplaceSuppFan, SmartHomeUnits.PERCENT));
|
||||
updateChannel(ValloxMVBindingConstants.CHANNEL_FIREPLACE_TIME, new DecimalType(iFireplaceTime));
|
||||
updateChannel(ValloxMVBindingConstants.CHANNEL_FIREPLACE_TIMER_ENABLED, ooFireplaceTimerEnabled);
|
||||
updateChannel(ValloxMVBindingConstants.CHANNEL_EXTRA_AIR_TEMP_TARGET,
|
||||
new QuantityType<>(bdExtraAirTempTarget, SIUnits.CELSIUS));
|
||||
updateChannel(ValloxMVBindingConstants.CHANNEL_EXTRA_EXTR_FAN,
|
||||
new QuantityType<>(iExtraExtrFan, SmartHomeUnits.PERCENT));
|
||||
updateChannel(ValloxMVBindingConstants.CHANNEL_EXTRA_SUPP_FAN,
|
||||
new QuantityType<>(iExtraSuppFan, SmartHomeUnits.PERCENT));
|
||||
updateChannel(ValloxMVBindingConstants.CHANNEL_EXTRA_TIME, new DecimalType(iExtraTime));
|
||||
updateChannel(ValloxMVBindingConstants.CHANNEL_EXTRA_TIMER_ENABLED, ooExtraTimerEnabled);
|
||||
updateChannel(ValloxMVBindingConstants.CHANNEL_WEEKLY_TIMER_ENABLED, ooWeeklyTimerEnabled);
|
||||
|
||||
voHandler.updateStatus(ThingStatus.ONLINE);
|
||||
logger.debug("Data updated successfully");
|
||||
|
||||
} catch (IOException e) {
|
||||
connectionError(e);
|
||||
}
|
||||
}
|
||||
|
||||
private void updateChannel(String strChannelName, State state) {
|
||||
voHandler.updateState(strChannelName, state);
|
||||
}
|
||||
|
||||
private int getNumberBE(byte[] bytes, int pos) {
|
||||
return ((bytes[pos] & 0xff) << 8) | (bytes[pos + 1] & 0xff);
|
||||
}
|
||||
|
||||
private int getNumberLE(byte[] bytes, int pos) {
|
||||
return (bytes[pos] & 0xff) | ((bytes[pos + 1] & 0xff) << 8);
|
||||
}
|
||||
|
||||
@SuppressWarnings("null")
|
||||
private BigDecimal getTemperature(byte[] bytes, int pos) {
|
||||
// Fetch 2 byte number out of bytearray representing the temperature in centiKelvin
|
||||
BigDecimal bdTemperatureCentiKelvin = new BigDecimal(getNumberBE(bytes, pos));
|
||||
// Return number converted to degree celsius (= (centiKelvin - 27315) / 100 )
|
||||
return (new QuantityType<>(bdTemperatureCentiKelvin, MetricPrefix.CENTI(SmartHomeUnits.KELVIN))
|
||||
.toUnit(SIUnits.CELSIUS)).toBigDecimal();
|
||||
}
|
||||
|
||||
@OnWebSocketClose
|
||||
public void onClose(int statusCode, String reason) {
|
||||
logger.debug("WebSocket Closed. Code: {}; Reason: {}", statusCode, reason);
|
||||
this.closeLatch.countDown();
|
||||
}
|
||||
|
||||
public boolean awaitClose(int duration, TimeUnit unit) throws InterruptedException {
|
||||
return this.closeLatch.await(duration, unit);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<binding:binding id="valloxmv" 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>ValloxMV Binding</name>
|
||||
<description>Binding for online interface of Vallox ventilation unit</description>
|
||||
<author>Björn Brings</author>
|
||||
|
||||
</binding:binding>
|
||||
@@ -0,0 +1,71 @@
|
||||
# binding
|
||||
binding.valloxmv.name = Vallox Lüftungsanlagen
|
||||
binding.valloxmv.description = Binding für das Online-Interface von Vallox Lüftungsanlagen
|
||||
|
||||
# thing types
|
||||
thing-type.valloxmv.valloxmv.label = Vallox Lüftungsanlage
|
||||
thing-type.valloxmv.valloxmv.description = Anbindung an das Online-Interface einer Vallox Lüftungsanlage
|
||||
thing-type.config.valloxmv.valloxmv.ip.label = IP
|
||||
thing-type.config.valloxmv.valloxmv.ip.description = IP Adresse oder DNS-Name des Online-Interface der Lüftungsanlage
|
||||
thing-type.config.valloxmv.valloxmv.updateinterval.label = Update Intervall
|
||||
thing-type.config.valloxmv.valloxmv.updateinterval.description = Intervall in dem die Daten aktualisiert werden in Sekunden (Standard: 60s)
|
||||
|
||||
# channel types
|
||||
channel-type.valloxmv.onoff.label = An/Aus
|
||||
channel-type.valloxmv.onoff.description = An/Aus-Schalter der Lüftungsanlage
|
||||
channel-type.valloxmv.state.label = Profil
|
||||
channel-type.valloxmv.state.description = Aktuell aktives Profil der Lüftungsanlage
|
||||
channel-type.valloxmv.state.state.option.1 = Kaminfunktion
|
||||
channel-type.valloxmv.state.state.option.2 = Abwesend
|
||||
channel-type.valloxmv.state.state.option.3 = Anwesend
|
||||
channel-type.valloxmv.state.state.option.4 = Stoßlüftung
|
||||
channel-type.valloxmv.fanspeed.label = Ventilatorleistung
|
||||
channel-type.valloxmv.fanspeed.description = Leistung in % (0-100)
|
||||
channel-type.valloxmv.fanspeedextract.label = Ventilatorleistung Abluft
|
||||
channel-type.valloxmv.fanspeedextract.description = Leistung Abluft in (1/min)
|
||||
channel-type.valloxmv.fanspeedsupply.label = Ventilatorleistung Zuluft
|
||||
channel-type.valloxmv.fanspeedsupply.description = Leistung Zuluft in (1/min)
|
||||
channel-type.valloxmv.tempinside.label = Temperatur innen
|
||||
channel-type.valloxmv.tempinside.description = Aktuelle Temperatur im Gebäude
|
||||
channel-type.valloxmv.tempoutside.label = Temperatur außen
|
||||
channel-type.valloxmv.tempoutside.description = Aktuelle Temperatur außerhalb des Gebäudes
|
||||
channel-type.valloxmv.tempexhaust.label = Temperatur Abluft
|
||||
channel-type.valloxmv.tempexhaust.description = Aktuelle Temperatur der ausgestoßenen Luft
|
||||
channel-type.valloxmv.tempincomingbeforeheating.label = Temperatur Zuluft vor Heizung
|
||||
channel-type.valloxmv.tempincomingbeforeheating.description = Aktuelle Temperatur der Zuluft vor Erwärmung durch Heizung (optionales Zubehör)
|
||||
channel-type.valloxmv.tempincoming.label = Temperatur Zuluft
|
||||
channel-type.valloxmv.tempincoming.description = Aktuelle Temperatur der Zuluft
|
||||
channel-type.valloxmv.humidity.label = Luftfeuchtigkeit
|
||||
channel-type.valloxmv.humidity.description = Aktuelle Luftfeuchtigkeit der Abluft
|
||||
channel-type.valloxmv.cellstate.label = Status Wärmetauscher
|
||||
channel-type.valloxmv.cellstate.description = Status Wärmetauscher
|
||||
channel-type.valloxmv.cellstate.state.option.0 = Wärmerückgewinnung
|
||||
channel-type.valloxmv.cellstate.state.option.1 = Kälterückgewinnung
|
||||
channel-type.valloxmv.cellstate.state.option.2 = Deaktiviert (bypass)
|
||||
channel-type.valloxmv.cellstate.state.option.3 = Enteisung
|
||||
channel-type.valloxmv.uptimeyears.label = Zeit in Betrieb (Jahre)
|
||||
channel-type.valloxmv.uptimeyears.description = Betriebszeit in Jahren (+ Betriebszeit in Stunden = Gesamtbetriebszeit)
|
||||
channel-type.valloxmv.uptimehours.label = Zeit in Betrieb (Stunden)
|
||||
channel-type.valloxmv.uptimehours.description = Betriebszeit in Stunden (+ Betriebszeit in Jahren = Gesamtbetriebszeit)
|
||||
channel-type.valloxmv.uptimehourscurrent.label = Betriebszeit seit letztem Stromausfall (Stunden)
|
||||
channel-type.valloxmv.uptimehourscurrent.description = Betriebszeit seit letztem Stromausfall in Stunden
|
||||
channel-type.valloxmv.filterchangeddate.label = Letzter Filterwechsel
|
||||
channel-type.valloxmv.filterchangeddate.description = Datum des letzten Filterwechsels
|
||||
channel-type.valloxmv.remainingfilterdays.label = Tage bis Filtertausch
|
||||
channel-type.valloxmv.remainingfilterdays.description = Anzahl an Tagen bis zum nächsten Filtertausch
|
||||
channel-type.valloxmv.extrfanbalancebase.label = Abluft Basis Leistung
|
||||
channel-type.valloxmv.extrfanbalancebase.description = Abluft Basis Leistung in % (0-100)
|
||||
channel-type.valloxmv.suppfanbalancebase.label = Zuluft Basis Leistung
|
||||
channel-type.valloxmv.suppfanbalancebase.description = Zuluft Basis Leistung in % (0-100)
|
||||
channel-type.valloxmv.homespeedsetting.label = Ventilatorleistung Anwesend
|
||||
channel-type.valloxmv.homespeedsetting.description = Ventilatorleistung im Profil Anwesend in % (0-100)
|
||||
channel-type.valloxmv.awayspeedsetting.label = Ventilatorleistung Abwesend
|
||||
channel-type.valloxmv.awayspeedsetting.description = Ventilatorleistung im Profil Abwesend in % (0-100)
|
||||
channel-type.valloxmv.boostspeedsetting.label = Ventilatorleistung Stoßlüftung
|
||||
channel-type.valloxmv.boostspeedsetting.description = Ventilatorleistung im Profil Stoßlüftung in % (0-100)
|
||||
channel-type.valloxmv.homeairtemptarget.label = Zieltemperatur Anwesend
|
||||
channel-type.valloxmv.homeairtemptarget.description = Zieltemperatur im Profil Anwesend
|
||||
channel-type.valloxmv.awayairtemptarget.label = Zieltemperatur Abwesend
|
||||
channel-type.valloxmv.awayairtemptarget.description = Zieltemperatur im Profil Abwesend
|
||||
channel-type.valloxmv.boostairtemptarget.label = Zieltemperatur Stoßlüftung
|
||||
channel-type.valloxmv.boostairtemptarget.description = Zieltemperatur im Profil Stoßlüftung
|
||||
@@ -0,0 +1,343 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<thing:thing-descriptions bindingId="valloxmv"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:thing="https://openhab.org/schemas/thing-description/v1.0.0"
|
||||
xsi:schemaLocation="https://openhab.org/schemas/thing-description/v1.0.0 https://openhab.org/schemas/thing-description-1.0.0.xsd">
|
||||
<thing-type id="valloxmv">
|
||||
<label>Vallox Ventilation Unit</label>
|
||||
<description>Interface to online interface of Vallox ventilation unit</description>
|
||||
<channels>
|
||||
<channel id="onoff" typeId="onoff"/>
|
||||
<channel id="state" typeId="state"/>
|
||||
<channel id="fanspeed" typeId="fanspeed"/>
|
||||
<channel id="fanspeedextract" typeId="fanspeedextract"/>
|
||||
<channel id="fanspeedsupply" typeId="fanspeedsupply"/>
|
||||
<channel id="tempinside" typeId="tempinside"/>
|
||||
<channel id="tempoutside" typeId="tempoutside"/>
|
||||
<channel id="tempexhaust" typeId="tempexhaust"/>
|
||||
<channel id="tempincomingbeforeheating" typeId="tempincomingbeforeheating"/>
|
||||
<channel id="tempincoming" typeId="tempincoming"/>
|
||||
<channel id="humidity" typeId="humidity"/>
|
||||
<channel id="cellstate" typeId="cellstate"/>
|
||||
<channel id="uptimeyears" typeId="uptimeyears"/>
|
||||
<channel id="uptimehours" typeId="uptimehours"/>
|
||||
<channel id="uptimehourscurrent" typeId="uptimehourscurrent"/>
|
||||
<channel id="filterchangeddate" typeId="filterchangeddate"/>
|
||||
<channel id="remainingfilterdays" typeId="remainingfilterdays"/>
|
||||
<channel id="extrfanbalancebase" typeId="extrfanbalancebase"/>
|
||||
<channel id="suppfanbalancebase" typeId="suppfanbalancebase"/>
|
||||
<channel id="homespeedsetting" typeId="homespeedsetting"/>
|
||||
<channel id="awayspeedsetting" typeId="awayspeedsetting"/>
|
||||
<channel id="boostspeedsetting" typeId="boostspeedsetting"/>
|
||||
<channel id="homeairtemptarget" typeId="homeairtemptarget"/>
|
||||
<channel id="awayairtemptarget" typeId="awayairtemptarget"/>
|
||||
<channel id="boostairtemptarget" typeId="boostairtemptarget"/>
|
||||
<channel id="boosttime" typeId="boosttime"/>
|
||||
<channel id="boosttimerenabled" typeId="boosttimerenabled"/>
|
||||
<channel id="fireplaceextrfan" typeId="fireplaceextrfan"/>
|
||||
<channel id="fireplacesuppfan" typeId="fireplacesuppfan"/>
|
||||
<channel id="fireplacetime" typeId="fireplacetime"/>
|
||||
<channel id="fireplacetimerenabled" typeId="fireplacetimerenabled"/>
|
||||
<channel id="extraairtemptarget" typeId="extraairtemptarget"/>
|
||||
<channel id="extraextrfan" typeId="extraextrfan"/>
|
||||
<channel id="extrasuppfan" typeId="extrasuppfan"/>
|
||||
<channel id="extratime" typeId="extratime"/>
|
||||
<channel id="extratimerenabled" typeId="extratimerenabled"/>
|
||||
<channel id="weeklytimerenabled" typeId="weeklytimerenabled"/>
|
||||
</channels>
|
||||
<config-description>
|
||||
<parameter name="ip" type="text" required="true">
|
||||
<label>IP Address</label>
|
||||
<context>network-address</context>
|
||||
<description>IP address or host name of online interface of ventilation unit</description>
|
||||
</parameter>
|
||||
<parameter name="updateinterval" type="integer" required="false">
|
||||
<label>Update Interval</label>
|
||||
<description>Data update interval in seconds (default: 60s)</description>
|
||||
<required>false</required>
|
||||
<default>60</default>
|
||||
</parameter>
|
||||
</config-description>
|
||||
</thing-type>
|
||||
|
||||
<channel-type id="onoff">
|
||||
<item-type>Switch</item-type>
|
||||
<label>On</label>
|
||||
<description>Power switch for ventilation unit</description>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="state">
|
||||
<item-type>Number</item-type>
|
||||
<label>State</label>
|
||||
<description>Current state of ventilation unit</description>
|
||||
<state readOnly="false">
|
||||
<options>
|
||||
<option value="1">Fireplace</option>
|
||||
<option value="2">Away</option>
|
||||
<option value="3">At home</option>
|
||||
<option value="4">Boost</option>
|
||||
</options>
|
||||
</state>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="fanspeed">
|
||||
<item-type>Number:Dimensionless</item-type>
|
||||
<label>Fan Speed</label>
|
||||
<description>Fan speed in % (0-100)</description>
|
||||
<state readOnly="true" min="0" max="1" pattern="%d %unit%"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="fanspeedextract" advanced="true">
|
||||
<item-type>Number</item-type>
|
||||
<label>Fan Speed Extracting</label>
|
||||
<description>Fan speed of extracting fan (1/min)</description>
|
||||
<state pattern="%d 1/min" readOnly="true"></state>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="fanspeedsupply" advanced="true">
|
||||
<item-type>Number</item-type>
|
||||
<label>Fan Speed Supplying</label>
|
||||
<description>Fan speed of supplying fan (1/min)</description>
|
||||
<state pattern="%d 1/min" readOnly="true"></state>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="tempinside">
|
||||
<item-type>Number:Temperature</item-type>
|
||||
<label>Temperature Inside</label>
|
||||
<description>Current temperature inside the building.</description>
|
||||
<category>Temperature</category>
|
||||
<state pattern="%.2f %unit%" readOnly="true"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="tempoutside">
|
||||
<item-type>Number:Temperature</item-type>
|
||||
<label>Temperature Outside</label>
|
||||
<description>Current temperature outside the building.</description>
|
||||
<category>Temperature</category>
|
||||
<state pattern="%.2f %unit%" readOnly="true"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="tempexhaust">
|
||||
<item-type>Number:Temperature</item-type>
|
||||
<label>Temperature Exhaust</label>
|
||||
<description>Current temperature of the air flow exhausting the building.</description>
|
||||
<category>Temperature</category>
|
||||
<state pattern="%.2f %unit%" readOnly="true"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="tempincomingbeforeheating" advanced="true">
|
||||
<item-type>Number:Temperature</item-type>
|
||||
<label>Temperature Incoming Before Heating</label>
|
||||
<description>
|
||||
Current temperature of the air flow incoming to the building before heating (if optional heating module
|
||||
included in ventilation unit).
|
||||
</description>
|
||||
<category>Temperature</category>
|
||||
<state pattern="%.2f %unit%" readOnly="true"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="tempincoming">
|
||||
<item-type>Number:Temperature</item-type>
|
||||
<label>Temperature Incoming</label>
|
||||
<description>Current temperature of the air flow incoming to the building.</description>
|
||||
<category>Temperature</category>
|
||||
<state pattern="%.2f %unit%" readOnly="true"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="humidity">
|
||||
<item-type>Number:Dimensionless</item-type>
|
||||
<label>Humidity</label>
|
||||
<description>Current humidity of the air flow exhausting the building.</description>
|
||||
<state readOnly="true" min="0" max="100" pattern="%d %unit%"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="cellstate">
|
||||
<item-type>Number</item-type>
|
||||
<label>Cell State</label>
|
||||
<description>Current cell state</description>
|
||||
<state readOnly="true">
|
||||
<options>
|
||||
<option value="0">Heat recovery</option>
|
||||
<option value="1">Cool recovery</option>
|
||||
<option value="2">Bypass</option>
|
||||
<option value="3">Defrosting</option>
|
||||
</options>
|
||||
</state>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="uptimeyears">
|
||||
<item-type>Number</item-type>
|
||||
<label>Total Uptime Years</label>
|
||||
<description>Total uptime in years (+ uptime in hours = total uptime)</description>
|
||||
<state pattern="%d Y" readOnly="true"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="uptimehours">
|
||||
<item-type>Number</item-type>
|
||||
<label>Total Uptime Hours</label>
|
||||
<description>Total uptime in hours (+ uptime in years = total uptime)</description>
|
||||
<state pattern="%d h" readOnly="true"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="uptimehourscurrent">
|
||||
<item-type>Number</item-type>
|
||||
<label>Current Uptime Hours</label>
|
||||
<description>Current uptime in hours</description>
|
||||
<state pattern="%d h" readOnly="true"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="filterchangeddate" advanced="true">
|
||||
<item-type>DateTime</item-type>
|
||||
<label>Last Filter Change</label>
|
||||
<description>Date filter was changed last time</description>
|
||||
<state readOnly="true"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="remainingfilterdays" advanced="true">
|
||||
<item-type>Number:Time</item-type>
|
||||
<label>Next Filter Change</label>
|
||||
<description>Days until filter has to be changed</description>
|
||||
<state pattern="%d d" readOnly="true"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="extrfanbalancebase" advanced="true">
|
||||
<item-type>Number:Dimensionless</item-type>
|
||||
<label>Extract Fan Base Speed</label>
|
||||
<description>Extract fan base speed in % (0-100)</description>
|
||||
<state readOnly="false" min="0" max="100" pattern="%d %%"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="suppfanbalancebase" advanced="true">
|
||||
<item-type>Number:Dimensionless</item-type>
|
||||
<label>Supply Fan Base Speed</label>
|
||||
<description>Supply fan base speed in % (0-100)</description>
|
||||
<state readOnly="false" min="0" max="100" pattern="%d %%"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="homespeedsetting" advanced="true">
|
||||
<item-type>Number:Dimensionless</item-type>
|
||||
<label>Home Fan Speed</label>
|
||||
<description>Home fan speed in % (0-100)</description>
|
||||
<state readOnly="false" min="0" max="100" pattern="%d %%"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="awayspeedsetting" advanced="true">
|
||||
<item-type>Number:Dimensionless</item-type>
|
||||
<label>Away Fan Speed</label>
|
||||
<description>Away fan speed in % (0-100)</description>
|
||||
<state readOnly="false" min="0" max="100" pattern="%d %%"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="boostspeedsetting" advanced="true">
|
||||
<item-type>Number:Dimensionless</item-type>
|
||||
<label>Boost Fan Speed</label>
|
||||
<description>Boost fan speed in % (0-100)</description>
|
||||
<state readOnly="false" min="0" max="100" pattern="%d %%"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="homeairtemptarget" advanced="true">
|
||||
<item-type>Number:Temperature</item-type>
|
||||
<label>Home Target Temperature</label>
|
||||
<description>Target temperature in home state</description>
|
||||
<category>Temperature</category>
|
||||
<state pattern="%.2f %unit%" readOnly="false"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="awayairtemptarget" advanced="true">
|
||||
<item-type>Number:Temperature</item-type>
|
||||
<label>Away Target Temperature</label>
|
||||
<description>Target temperature in away state</description>
|
||||
<category>Temperature</category>
|
||||
<state pattern="%.2f %unit%" readOnly="false"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="boostairtemptarget" advanced="true">
|
||||
<item-type>Number:Temperature</item-type>
|
||||
<label>Boost Target Temperature</label>
|
||||
<description>Target temperature in boost state</description>
|
||||
<category>Temperature</category>
|
||||
<state pattern="%.2f %unit%" readOnly="false"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="boosttime" advanced="true">
|
||||
<item-type>Number:Dimensionless</item-type>
|
||||
<label>Boost Timer</label>
|
||||
<description>Boost profile timer value in minutes</description>
|
||||
<state readOnly="false" min="1" max="65535" pattern="%d min"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="boosttimerenabled" advanced="true">
|
||||
<item-type>Switch</item-type>
|
||||
<label>Boost Timer Enabled</label>
|
||||
<description>Timer enabled setting in boost profile</description>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="fireplaceextrfan" advanced="true">
|
||||
<item-type>Number:Dimensionless</item-type>
|
||||
<label>Fireplace Extract Fan Speed</label>
|
||||
<description>Fireplace profile extract fan speed in % (0-100)</description>
|
||||
<state readOnly="false" min="0" max="100" pattern="%d %%"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="fireplacesuppfan" advanced="true">
|
||||
<item-type>Number:Dimensionless</item-type>
|
||||
<label>Fireplace Supply Fan Speed</label>
|
||||
<description>Fireplace profile supply fan speed in % (0-100)</description>
|
||||
<state readOnly="false" min="0" max="100" pattern="%d %%"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="fireplacetime" advanced="true">
|
||||
<item-type>Number:Dimensionless</item-type>
|
||||
<label>Fireplace Timer</label>
|
||||
<description>Fireplace profile timer value in minutes</description>
|
||||
<state readOnly="false" min="1" max="65535" pattern="%d min"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="fireplacetimerenabled" advanced="true">
|
||||
<item-type>Switch</item-type>
|
||||
<label>Fireplace Timer Enabled</label>
|
||||
<description>Timer enabled setting in fireplace profile</description>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="extraairtemptarget" advanced="true">
|
||||
<item-type>Number:Temperature</item-type>
|
||||
<label>Extra Target Temperature</label>
|
||||
<description>Target temperature in extra profile</description>
|
||||
<category>Temperature</category>
|
||||
<state readOnly="false" min="5" max="25" pattern="%.2f %unit%"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="extraextrfan" advanced="true">
|
||||
<item-type>Number:Dimensionless</item-type>
|
||||
<label>Extra Extract Fan Speed</label>
|
||||
<description>Extra profile extract fan speed in % (0-100)</description>
|
||||
<state readOnly="false" min="0" max="100" pattern="%d %%"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="extrasuppfan" advanced="true">
|
||||
<item-type>Number:Dimensionless</item-type>
|
||||
<label>Extra Supply Fan Speed</label>
|
||||
<description>Extra profile supply fan speed in % (0-100)</description>
|
||||
<state readOnly="false" min="0" max="100" pattern="%d %%"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="extratime" advanced="true">
|
||||
<item-type>Number:Dimensionless</item-type>
|
||||
<label>Extra Timer</label>
|
||||
<description>Extra profile timer value in minutes</description>
|
||||
<state readOnly="false" min="1" max="65535" pattern="%d min"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="extratimerenabled" advanced="true">
|
||||
<item-type>Switch</item-type>
|
||||
<label>Extra Timer Enabled</label>
|
||||
<description>Timer enabled setting in extra profile</description>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="weeklytimerenabled" advanced="true">
|
||||
<item-type>Switch</item-type>
|
||||
<label>Weekly Timer Enabled</label>
|
||||
<description>Weekly timer enabled setting</description>
|
||||
</channel-type>
|
||||
|
||||
</thing:thing-descriptions>
|
||||
Reference in New Issue
Block a user