added migrated 2.x add-ons

Signed-off-by: Kai Kreuzer <kai@openhab.org>
This commit is contained in:
Kai Kreuzer
2020-09-21 01:58:32 +02:00
parent bbf1a7fd29
commit 6df6783b60
11662 changed files with 1302875 additions and 11 deletions

View File

@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<features name="org.openhab.binding.comfoair-${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-comfoair" description="ComfoAir 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.comfoair/${project.version}</bundle>
</feature>
</features>

View File

@@ -0,0 +1,202 @@
/**
* 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.comfoair.internal;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.core.thing.ThingTypeUID;
/**
* The {@link ComfoAirBindingConstants} class defines common constants, which are
* used across the whole binding.
*
* @author Hans Böhm - Initial contribution
*/
@NonNullByDefault
public class ComfoAirBindingConstants {
private static final String BINDING_ID = "comfoair";
public static final ThingTypeUID THING_TYPE_COMFOAIR_GENERIC = new ThingTypeUID(BINDING_ID, "comfoair");
// Thing properties
// General properties
public static final String PROPERTY_SOFTWARE_MAIN_VERSION = "SOFTWARE_VERSION_MAIN";
public static final String PROPERTY_SOFTWARE_MINOR_VERSION = "SOFTWARE_VERSION_MINOR";
public static final String PROPERTY_DEVICE_NAME = "DEVICE_NAME";
// Installed options
public static final String PROPERTY_OPTION_PREHEATER = "OPTION_PREHEATER";
public static final String PROPERTY_OPTION_BYPASS = "OPTION_BYPASS";
public static final String PROPERTY_OPTION_RECU_TYPE = "DEVICE_TYPE";
public static final String PROPERTY_OPTION_RECU_SIZE = "DEVICE_SIZE";
public static final String PROPERTY_OPTION_CHIMNEY = "OPTION_CHIMNEY";
public static final String PROPERTY_OPTION_COOKERHOOD = "OPTION_COOKERHOOD";
public static final String PROPERTY_OPTION_HEATER = "OPTION_HEATER";
public static final String PROPERTY_OPTION_ENTHALPY = "OPTION_ENTHALPY";
public static final String PROPERTY_OPTION_EWT = "OPTION_EWT";
// Common option states
public static final String[] COMMON_OPTION_STATES = { "Not installed", "Installed" };
// Channel groups
public static final String CG_CONTROL_PREFIX = "bindingControl#";
public static final String CG_VENTILATION_PREFIX = "ventilation#";
public static final String CG_TEMPS_PREFIX = "temperatures#";
public static final String CG_TIMES_PREFIX = "times#";
public static final String CG_BYPASS_PREFIX = "bypass#";
public static final String CG_PREHEATER_PREFIX = "preheater#";
public static final String CG_EWT_PREFIX = "ewt#";
public static final String CG_HEATER_PREFIX = "heater#";
public static final String CG_COOKERHOOD_PREFIX = "cookerhood#";
public static final String CG_ENTHALPY_PREFIX = "enthalpy#";
public static final String CG_OPTIONS_PREFIX = "options#";
public static final String CG_MENUP1_PREFIX = "menuP1#";
public static final String CG_MENUP2_PREFIX = "menuP2#";
public static final String CG_MENUP9_PREFIX = "menuP9#";
public static final String CG_INPUTS_PREFIX = "inputs#";
public static final String CG_ANALOG1_PREFIX = "analog1#";
public static final String CG_ANALOG2_PREFIX = "analog2#";
public static final String CG_ANALOG3_PREFIX = "analog3#";
public static final String CG_ANALOG4_PREFIX = "analog4#";
public static final String CG_ANALOGRF_PREFIX = "analogRF#";
public static final String CG_ERRORS_PREFIX = "errors#";
public static final String CG_RESETS_PREFIX = "resets#";
// Channels
// Control channels
public static final String CHANNEL_ACTIVATE = "activate";
// Ventilation channels
public static final String CHANNEL_FAN_LEVEL = "fanLevel";
public static final String CHANNEL_FAN_OUT_0 = "fanOut0";
public static final String CHANNEL_FAN_OUT_1 = "fanOut1";
public static final String CHANNEL_FAN_OUT_2 = "fanOut2";
public static final String CHANNEL_FAN_OUT_3 = "fanOut3";
public static final String CHANNEL_FAN_IN_0 = "fanIn0";
public static final String CHANNEL_FAN_IN_1 = "fanIn1";
public static final String CHANNEL_FAN_IN_2 = "fanIn2";
public static final String CHANNEL_FAN_IN_3 = "fanIn3";
public static final String CHANNEL_FAN_IN_PERCENT = "fanInPercent";
public static final String CHANNEL_FAN_OUT_PERCENT = "fanOutPercent";
public static final String CHANNEL_FAN_IN_RPM = "fanInRPM";
public static final String CHANNEL_FAN_OUT_RPM = "fanOutRPM";
// Temperature channels
public static final String CHANNEL_TEMP_TARGET = "targetTemperature";
public static final String CHANNEL_TEMP_OUTDOOR_IN = "outdoorTemperatureIn";
public static final String CHANNEL_TEMP_OUTDOOR_OUT = "outdoorTemperatureOut";
public static final String CHANNEL_TEMP_INDOOR_IN = "indoorTemperatureIn";
public static final String CHANNEL_TEMP_INDOOR_OUT = "indoorTemperatureOut";
public static final String CHANNEL_IS_SENSOR_T1 = "isT1Sensor";
public static final String CHANNEL_IS_SENSOR_T2 = "isT2Sensor";
public static final String CHANNEL_IS_SENSOR_T3 = "isT3Sensor";
public static final String CHANNEL_IS_SENSOR_T4 = "isT4Sensor";
public static final String CHANNEL_IS_SENSOR_EWT = "isEWTSensor";
public static final String CHANNEL_IS_SENSOR_HEATER = "isHeaterSensor";
public static final String CHANNEL_IS_SENSOR_COOKERHOOD = "isCookerhoodSensor";
public static final String CHANNEL_TEMP_EWT = "ewtTemperature";
public static final String CHANNEL_TEMP_HEATER = "heaterTemperature";
public static final String CHANNEL_TEMP_COOKERHOOD = "cookerhoodTemperature";
// Time channels
public static final String CHANNEL_TIME_LEVEL0 = "level0Time";
public static final String CHANNEL_TIME_LEVEL1 = "level1Time";
public static final String CHANNEL_TIME_LEVEL2 = "level2Time";
public static final String CHANNEL_TIME_LEVEL3 = "level3Time";
public static final String CHANNEL_TIME_FREEZE = "freezeTime";
public static final String CHANNEL_TIME_PREHEATER = "preheaterTime";
public static final String CHANNEL_TIME_BYPASS = "bypassTime";
public static final String CHANNEL_TIME_FILTER = "filterHours";
// Bypass channels
public static final String CHANNEL_BYPASS_FACTOR = "bypassFactor";
public static final String CHANNEL_BYPASS_LEVEL = "bypassLevel";
public static final String CHANNEL_BYPASS_CORRECTION = "bypassCorrection";
public static final String CHANNEL_BYPASS_SUMMER = "bypassSummer";
// Preheater channels
public static final String CHANNEL_PREHEATER_VALVE = "preheaterValve";
public static final String CHANNEL_PREHEATER_FROST_PROTECT = "preheaterFrostProtect";
public static final String CHANNEL_PREHEATER_HEATING = "preheaterHeating";
public static final String CHANNEL_PREHEATER_FROST_TIME = "preheaterFrostTime";
public static final String CHANNEL_PREHEATER_SAFETY = "preheaterSafety";
// EWT channels
public static final String CHANNEL_EWT_TEMP_LOW = "ewtTemperatureLow";
public static final String CHANNEL_EWT_TEMP_HIGH = "ewtTemperatureHigh";
public static final String CHANNEL_EWT_SPEED = "ewtSpeed";
// Heater channels
public static final String CHANNEL_HEATER_POWER = "heaterPower";
public static final String CHANNEL_HEATER_POWER_I = "heaterPowerI";
public static final String CHANNEL_HEATER_TEMP_TARGET = "heaterTargetTemperature";
// Cookerhood channels
public static final String CHANNEL_COOKERHOOD_SPEED = "cookerhoodSpeed";
// Enthalpy channels
public static final String CHANNEL_ENTHALPY_TEMP = "enthalpyTemperature";
public static final String CHANNEL_ENTHALPY_HUMIDITY = "enthalpyHumidity";
public static final String CHANNEL_ENTHALPY_LEVEL = "enthalpyLevel";
public static final String CHANNEL_ENTHALPY_TIME = "enthalpyTime";
// Menu P1 channels
public static final String CHANNEL_MENU20_MODE = "menu20Mode";
public static final String CHANNEL_MENU21_MODE = "menu21Mode";
public static final String CHANNEL_MENU22_MODE = "menu22Mode";
public static final String CHANNEL_MENU23_MODE = "menu23Mode";
public static final String CHANNEL_MENU24_MODE = "menu24Mode";
public static final String CHANNEL_MENU25_MODE = "menu25Mode";
public static final String CHANNEL_MENU26_MODE = "menu26Mode";
public static final String CHANNEL_MENU27_MODE = "menu27Mode";
public static final String CHANNEL_MENU28_MODE = "menu28Mode";
public static final String CHANNEL_MENU29_MODE = "menu29Mode";
// Menu P2 channels
public static final String CHANNEL_BR_START_DELAY = "bathroomStartDelay";
public static final String CHANNEL_BR_END_DELAY = "bathroomEndDelay";
public static final String CHANNEL_L1_END_DELAY = "L1EndDelay";
public static final String CHANNEL_PULSE_VENTILATION = "pulseVentilation";
public static final String CHANNEL_FILTER_WEEKS = "filterWeeks";
public static final String CHANNEL_RF_SHORT_DELAY = "RFShortDelay";
public static final String CHANNEL_RF_LONG_DELAY = "RFLongDelay";
public static final String CHANNEL_COOKERHOOD_DELAY = "cookerhoodDelay";
// Menu P9 channels
public static final String CHANNEL_CHIMNEY_STATE = "chimneyState";
public static final String CHANNEL_BYPASS_STATE = "bypassState";
public static final String CHANNEL_EWT_STATE = "ewtState";
public static final String CHANNEL_HEATER_STATE = "heaterState";
public static final String CHANNEL_VCONTROL_STATE = "vControlState";
public static final String CHANNEL_FROST_STATE = "frostState";
public static final String CHANNEL_COOKERHOOD_STATE = "cookerhoodState";
public static final String CHANNEL_ENTHALPY_STATE = "enthalpyState";
// Inputs channels
public static final String CHANNEL_IS_L1_SWITCH = "isL1Switch";
public static final String CHANNEL_IS_L2_SWITCH = "isL2Switch";
public static final String CHANNEL_IS_BATHROOM_SWITCH = "isBathroomSwitch";
public static final String CHANNEL_IS_COOKERHOOD_SWITCH = "isCookerhoodSwitch";
public static final String CHANNEL_IS_EXTERNAL_FILTER = "isExternalFilter";
public static final String CHANNEL_IS_WTW = "isWTW";
public static final String CHANNEL_IS_BATHROOM2_SWITCH = "isBathroom2Switch";
// Analog channels
public static final String CHANNEL_IS_ANALOG = "isAnalog";
public static final String CHANNEL_ANALOG_MODE = "analogMode";
public static final String CHANNEL_ANALOG_NEGATIVE = "analogNegative";
public static final String CHANNEL_ANALOG_VOLT = "analogVolt";
public static final String CHANNEL_ANALOG_MIN = "analogMin";
public static final String CHANNEL_ANALOG_MAX = "analogMax";
public static final String CHANNEL_ANALOG_VALUE = "analogValue";
public static final String CHANNEL_IS_RF = "isRF";
public static final String CHANNEL_RF_MODE = "RFMode";
public static final String CHANNEL_RF_NEGATIVE = "RFNegative";
public static final String CHANNEL_RF_MIN = "RFMin";
public static final String CHANNEL_RF_MAX = "RFMax";
public static final String CHANNEL_RF_VALUE = "RFValue";
public static final String CHANNEL_ANALOG_PRIORITY = "analogPriority";
// Error channels
public static final String CHANNEL_FILTER_ERROR = "filterError";
public static final String CHANNEL_ERRORS_CURRENT = "errorsCurrent";
public static final String CHANNEL_ERRORS_LAST = "errorsLast";
public static final String CHANNEL_ERRORS_PRELAST = "errorsPrelast";
public static final String CHANNEL_ERRORS_PREPRELAST = "errorsPrePrelast";
// Reset channels
public static final String CHANNEL_FILTER_RESET = "filterReset";
public static final String CHANNEL_ERROR_RESET = "errorReset";
}

View File

@@ -0,0 +1,149 @@
/**
* 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.comfoair.internal;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
/**
* Class to encapsulate all data which is needed to send a cmd to comfoair
*
* @author Holger Hees - Initial Contribution
* @author Hans Böhm - Refactoring
*/
@NonNullByDefault
public class ComfoAirCommand {
private final List<String> keys;
private @Nullable Integer requestCmd;
private @Nullable Integer replyCmd;
private int[] requestData;
private final @Nullable Integer requestValue;
private final @Nullable Integer dataPosition;
/**
* @param key
* command key
* @param requestCmd
* command as byte value
* @param replyCmd
* reply command as byte value
* @param data
* request byte values
* @param requestValue
* request byte value
* @param dataPosition
* request byte position
*/
public ComfoAirCommand(String key, @Nullable Integer requestCmd, @Nullable Integer replyCmd, int[] data,
@Nullable Integer dataPosition, @Nullable Integer requestValue) {
this.keys = new ArrayList<String>();
this.keys.add(key);
this.requestCmd = requestCmd;
this.replyCmd = replyCmd;
this.requestData = data;
this.dataPosition = dataPosition;
this.requestValue = requestValue;
}
/*
* Constructor for basic read command
*/
public ComfoAirCommand(String key) {
this.keys = new ArrayList<String>();
this.keys.add(key);
ComfoAirCommandType commandType = ComfoAirCommandType.getCommandTypeByKey(key);
if (commandType != null) {
this.requestCmd = commandType.getReadCommand() == 0 ? null : commandType.getReadCommand();
this.replyCmd = commandType.getReadReplyCommand();
}
this.requestData = ComfoAirCommandType.Constants.EMPTY_INT_ARRAY;
this.dataPosition = null;
this.requestValue = null;
}
/**
* @param key
* additional command key
*/
public void addKey(String key) {
keys.add(key);
}
/**
* @return command keys
*/
public List<String> getKeys() {
return keys;
}
/**
* @return command byte value
*/
public @Nullable Integer getRequestCmd() {
return requestCmd;
}
/**
* @return request data as byte values
*/
public int[] getRequestData() {
return requestData;
}
/**
* @return acknowledge cmd byte value
*/
public @Nullable Integer getReplyCmd() {
return replyCmd;
}
/**
* @return request value as byte value
*/
public @Nullable Integer getRequestValue() {
return requestValue;
}
/**
* @return position of request byte
*/
public @Nullable Integer getDataPosition() {
return dataPosition;
}
/**
* set request command byte value
*/
public void setRequestCmd(@Nullable Integer newRequestCmd) {
requestCmd = newRequestCmd;
}
/**
* set reply command byte value
*/
public void setReplyCmd(@Nullable Integer newReplyCmd) {
replyCmd = newReplyCmd;
}
/**
* set request data byte values
*/
public void setRequestData(int[] newRequestData) {
requestData = newRequestData;
}
}

View File

@@ -0,0 +1,908 @@
/**
* 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.comfoair.internal;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.binding.comfoair.internal.datatypes.ComfoAirDataType;
import org.openhab.binding.comfoair.internal.datatypes.DataTypeBoolean;
import org.openhab.binding.comfoair.internal.datatypes.DataTypeMessage;
import org.openhab.binding.comfoair.internal.datatypes.DataTypeNumber;
import org.openhab.binding.comfoair.internal.datatypes.DataTypeRPM;
import org.openhab.binding.comfoair.internal.datatypes.DataTypeTemperature;
import org.openhab.binding.comfoair.internal.datatypes.DataTypeTime;
import org.openhab.binding.comfoair.internal.datatypes.DataTypeVolt;
import org.openhab.core.library.types.DecimalType;
import org.openhab.core.library.types.QuantityType;
import org.openhab.core.types.Command;
import org.openhab.core.types.State;
import org.openhab.core.types.UnDefType;
/**
* Represents all valid commands which could be processed by this binding
*
* @author Holger Hees - Initial Contribution
* @author Hans Böhm - Refactoring
*/
@NonNullByDefault
public enum ComfoAirCommandType {
/**
* Below all valid commands to change or read parameters from ComfoAir
*
* @param key
* command name
* @param dataType
* data type (can be: DataTypeBoolean.getInstance(), DataTypeMessage.getInstance(),
* DataTypeNumber.getInstance(), DataTypeRPM.getInstance(), DataTypeTemperature.getInstance(),
* DataTypeTime.getInstance(), DataTypeVolt.getInstance())
* @param possibleValues
* possible values for write command, if it can only take certain values
* @param changeCommand
* byte number for ComfoAir write command
* @param changeDataSize
* size of bytes list for ComfoAir write command
* @param changeDataPos
* position in bytes list to change
* @param changeAffected
* list of affected commands (can be empty)
* is mandatory for read-write command
* @param readCommand
* request byte number for ComfoAir read command
* @param readReplyCommand
* reply byte list size for ComfoAir read command (list of values only)
* @param readReplyDataPos
* list of byte positions in reply bytes list from ComfoAir
* @param readReplyDataBits
* byte value on readReplyDataPos position to be considered by command (used with
* DataTypeBoolean.class dataType)
*/
ACTIVATE(ComfoAirBindingConstants.CG_CONTROL_PREFIX + ComfoAirBindingConstants.CHANNEL_ACTIVATE,
DataTypeBoolean.getInstance(), new int[] { 0x03 }, Constants.REQUEST_SET_RS232, 1, 0,
Constants.EMPTY_TYPE_ARRAY, Constants.REPLY_SET_RS232, Constants.REPLY_SET_RS232, new int[] { 0 }, 0x03),
MENU20_MODE(ComfoAirBindingConstants.CG_MENUP1_PREFIX + ComfoAirBindingConstants.CHANNEL_MENU20_MODE,
DataTypeBoolean.getInstance(), Constants.REQUEST_GET_STATES, Constants.REPLY_GET_STATES, new int[] { 6 },
0x01),
MENU21_MODE(ComfoAirBindingConstants.CG_MENUP1_PREFIX + ComfoAirBindingConstants.CHANNEL_MENU21_MODE,
DataTypeBoolean.getInstance(), Constants.REQUEST_GET_STATES, Constants.REPLY_GET_STATES, new int[] { 6 },
0x02),
MENU22_MODE(ComfoAirBindingConstants.CG_MENUP1_PREFIX + ComfoAirBindingConstants.CHANNEL_MENU22_MODE,
DataTypeBoolean.getInstance(), Constants.REQUEST_GET_STATES, Constants.REPLY_GET_STATES, new int[] { 6 },
0x04),
MENU23_MODE(ComfoAirBindingConstants.CG_MENUP1_PREFIX + ComfoAirBindingConstants.CHANNEL_MENU23_MODE,
DataTypeBoolean.getInstance(), Constants.REQUEST_GET_STATES, Constants.REPLY_GET_STATES, new int[] { 6 },
0x08),
MENU24_MODE(ComfoAirBindingConstants.CG_MENUP1_PREFIX + ComfoAirBindingConstants.CHANNEL_MENU24_MODE,
DataTypeBoolean.getInstance(), Constants.REQUEST_GET_STATES, Constants.REPLY_GET_STATES, new int[] { 6 },
0x10),
MENU25_MODE(ComfoAirBindingConstants.CG_MENUP1_PREFIX + ComfoAirBindingConstants.CHANNEL_MENU25_MODE,
DataTypeBoolean.getInstance(), Constants.REQUEST_GET_STATES, Constants.REPLY_GET_STATES, new int[] { 6 },
0x20),
MENU26_MODE(ComfoAirBindingConstants.CG_MENUP1_PREFIX + ComfoAirBindingConstants.CHANNEL_MENU26_MODE,
DataTypeBoolean.getInstance(), Constants.REQUEST_GET_STATES, Constants.REPLY_GET_STATES, new int[] { 6 },
0x40),
MENU27_MODE(ComfoAirBindingConstants.CG_MENUP1_PREFIX + ComfoAirBindingConstants.CHANNEL_MENU27_MODE,
DataTypeBoolean.getInstance(), Constants.REQUEST_GET_STATES, Constants.REPLY_GET_STATES, new int[] { 6 },
0x80),
MENU28_MODE(ComfoAirBindingConstants.CG_MENUP1_PREFIX + ComfoAirBindingConstants.CHANNEL_MENU28_MODE,
DataTypeBoolean.getInstance(), Constants.REQUEST_GET_STATES, Constants.REPLY_GET_STATES, new int[] { 7 },
0x01),
MENU29_MODE(ComfoAirBindingConstants.CG_MENUP1_PREFIX + ComfoAirBindingConstants.CHANNEL_MENU29_MODE,
DataTypeBoolean.getInstance(), Constants.REQUEST_GET_STATES, Constants.REPLY_GET_STATES, new int[] { 7 },
0x02),
BATHROOM_START_DELAY(ComfoAirBindingConstants.CG_MENUP2_PREFIX + ComfoAirBindingConstants.CHANNEL_BR_START_DELAY,
DataTypeNumber.getInstance(), Constants.REQUEST_SET_DELAYS, 8, 0, new ComfoAirCommandType[] { MENU21_MODE },
Constants.REQUEST_GET_DELAYS, Constants.REPLY_GET_DELAYS, new int[] { 0 }),
BATHROOM_END_DELAY(ComfoAirBindingConstants.CG_MENUP2_PREFIX + ComfoAirBindingConstants.CHANNEL_BR_END_DELAY,
DataTypeNumber.getInstance(), Constants.REQUEST_SET_DELAYS, 8, 1, new ComfoAirCommandType[] { MENU22_MODE },
Constants.REQUEST_GET_DELAYS, Constants.REPLY_GET_DELAYS, new int[] { 1 }),
L1_END_DELAY(ComfoAirBindingConstants.CG_MENUP2_PREFIX + ComfoAirBindingConstants.CHANNEL_L1_END_DELAY,
DataTypeNumber.getInstance(), Constants.REQUEST_SET_DELAYS, 8, 2, new ComfoAirCommandType[] { MENU27_MODE },
Constants.REQUEST_GET_DELAYS, Constants.REPLY_GET_DELAYS, new int[] { 2 }),
PULSE_VENTILATION(ComfoAirBindingConstants.CG_MENUP2_PREFIX + ComfoAirBindingConstants.CHANNEL_PULSE_VENTILATION,
DataTypeNumber.getInstance(), Constants.REQUEST_SET_DELAYS, 8, 3, new ComfoAirCommandType[] { MENU23_MODE },
Constants.REQUEST_GET_DELAYS, Constants.REPLY_GET_DELAYS, new int[] { 3 }),
FILTER_WEEKS(ComfoAirBindingConstants.CG_MENUP2_PREFIX + ComfoAirBindingConstants.CHANNEL_FILTER_WEEKS,
DataTypeNumber.getInstance(), Constants.REQUEST_SET_DELAYS, 8, 4, new ComfoAirCommandType[] { MENU24_MODE },
Constants.REQUEST_GET_DELAYS, Constants.REPLY_GET_DELAYS, new int[] { 4 }),
RF_SHORT_DELAY(ComfoAirBindingConstants.CG_MENUP2_PREFIX + ComfoAirBindingConstants.CHANNEL_RF_SHORT_DELAY,
DataTypeNumber.getInstance(), Constants.REQUEST_SET_DELAYS, 8, 5, new ComfoAirCommandType[] { MENU25_MODE },
Constants.REQUEST_GET_DELAYS, Constants.REPLY_GET_DELAYS, new int[] { 5 }),
RF_LONG_DELAY(ComfoAirBindingConstants.CG_MENUP2_PREFIX + ComfoAirBindingConstants.CHANNEL_RF_LONG_DELAY,
DataTypeNumber.getInstance(), Constants.REQUEST_SET_DELAYS, 8, 6, new ComfoAirCommandType[] { MENU26_MODE },
Constants.REQUEST_GET_DELAYS, Constants.REPLY_GET_DELAYS, new int[] { 6 }),
COOKERHOOD_DELAY(ComfoAirBindingConstants.CG_MENUP2_PREFIX + ComfoAirBindingConstants.CHANNEL_COOKERHOOD_DELAY,
DataTypeNumber.getInstance(), Constants.REQUEST_SET_DELAYS, 8, 7, new ComfoAirCommandType[] { MENU20_MODE },
Constants.REQUEST_GET_DELAYS, Constants.REPLY_GET_DELAYS, new int[] { 7 }),
CHIMNEY_STATE(ComfoAirBindingConstants.CG_MENUP9_PREFIX + ComfoAirBindingConstants.CHANNEL_CHIMNEY_STATE,
DataTypeBoolean.getInstance(), Constants.REQUEST_GET_STATES, Constants.REPLY_GET_STATES, new int[] { 8 },
0x01),
BYPASS_STATE(ComfoAirBindingConstants.CG_MENUP9_PREFIX + ComfoAirBindingConstants.CHANNEL_BYPASS_STATE,
DataTypeBoolean.getInstance(), Constants.REQUEST_GET_STATES, Constants.REPLY_GET_STATES, new int[] { 8 },
0x02),
EWT_STATE(ComfoAirBindingConstants.CG_MENUP9_PREFIX + ComfoAirBindingConstants.CHANNEL_EWT_STATE,
DataTypeBoolean.getInstance(), Constants.REQUEST_GET_STATES, Constants.REPLY_GET_STATES, new int[] { 8 },
0x04),
HEATER_STATE(ComfoAirBindingConstants.CG_MENUP9_PREFIX + ComfoAirBindingConstants.CHANNEL_HEATER_STATE,
DataTypeBoolean.getInstance(), Constants.REQUEST_GET_STATES, Constants.REPLY_GET_STATES, new int[] { 8 },
0x08),
V_CONTROL_STATE(ComfoAirBindingConstants.CG_MENUP9_PREFIX + ComfoAirBindingConstants.CHANNEL_VCONTROL_STATE,
DataTypeBoolean.getInstance(), Constants.REQUEST_GET_STATES, Constants.REPLY_GET_STATES, new int[] { 8 },
0x10),
FROST_STATE(ComfoAirBindingConstants.CG_MENUP9_PREFIX + ComfoAirBindingConstants.CHANNEL_FROST_STATE,
DataTypeBoolean.getInstance(), Constants.REQUEST_GET_STATES, Constants.REPLY_GET_STATES, new int[] { 8 },
0x20),
COOKERHOOD_STATE(ComfoAirBindingConstants.CG_MENUP9_PREFIX + ComfoAirBindingConstants.CHANNEL_COOKERHOOD_STATE,
DataTypeBoolean.getInstance(), Constants.REQUEST_GET_STATES, Constants.REPLY_GET_STATES, new int[] { 8 },
0x40),
ENTHALPY_STATE(ComfoAirBindingConstants.CG_MENUP9_PREFIX + ComfoAirBindingConstants.CHANNEL_ENTHALPY_STATE,
DataTypeBoolean.getInstance(), Constants.REQUEST_GET_STATES, Constants.REPLY_GET_STATES, new int[] { 8 },
0x80),
FAN_IN_PERCENT(ComfoAirBindingConstants.CG_VENTILATION_PREFIX + ComfoAirBindingConstants.CHANNEL_FAN_IN_PERCENT,
DataTypeNumber.getInstance(), Constants.REQUEST_GET_FAN, Constants.REPLY_GET_FAN, new int[] { 0 }),
FAN_OUT_PERCENT(ComfoAirBindingConstants.CG_VENTILATION_PREFIX + ComfoAirBindingConstants.CHANNEL_FAN_OUT_PERCENT,
DataTypeNumber.getInstance(), Constants.REQUEST_GET_FAN, Constants.REPLY_GET_FAN, new int[] { 1 }),
FAN_IN_RPM(ComfoAirBindingConstants.CG_VENTILATION_PREFIX + ComfoAirBindingConstants.CHANNEL_FAN_IN_RPM,
DataTypeRPM.getInstance(), Constants.REQUEST_GET_FAN, Constants.REPLY_GET_FAN, new int[] { 2, 3 }),
FAN_OUT_RPM(ComfoAirBindingConstants.CG_VENTILATION_PREFIX + ComfoAirBindingConstants.CHANNEL_FAN_OUT_RPM,
DataTypeRPM.getInstance(), Constants.REQUEST_GET_FAN, Constants.REPLY_GET_FAN, new int[] { 4, 5 }),
FAN_OUT_0(ComfoAirBindingConstants.CG_VENTILATION_PREFIX + ComfoAirBindingConstants.CHANNEL_FAN_OUT_0,
DataTypeNumber.getInstance(), Constants.REQUEST_SET_FAN_LEVEL, 9, 0,
new ComfoAirCommandType[] { FAN_OUT_PERCENT, FAN_OUT_RPM }, Constants.REQUEST_GET_FAN_LEVEL,
Constants.REPLY_GET_FAN_LEVEL, new int[] { 0 }),
FAN_OUT_1(ComfoAirBindingConstants.CG_VENTILATION_PREFIX + ComfoAirBindingConstants.CHANNEL_FAN_OUT_1,
DataTypeNumber.getInstance(), Constants.REQUEST_SET_FAN_LEVEL, 9, 1,
new ComfoAirCommandType[] { FAN_OUT_PERCENT, FAN_OUT_RPM }, Constants.REQUEST_GET_FAN_LEVEL,
Constants.REPLY_GET_FAN_LEVEL, new int[] { 1 }),
FAN_OUT_2(ComfoAirBindingConstants.CG_VENTILATION_PREFIX + ComfoAirBindingConstants.CHANNEL_FAN_OUT_2,
DataTypeNumber.getInstance(), Constants.REQUEST_SET_FAN_LEVEL, 9, 2,
new ComfoAirCommandType[] { FAN_OUT_PERCENT, FAN_OUT_RPM }, Constants.REQUEST_GET_FAN_LEVEL,
Constants.REPLY_GET_FAN_LEVEL, new int[] { 2 }),
FAN_OUT_3(ComfoAirBindingConstants.CG_VENTILATION_PREFIX + ComfoAirBindingConstants.CHANNEL_FAN_OUT_3,
DataTypeNumber.getInstance(), Constants.REQUEST_SET_FAN_LEVEL, 9, 6,
new ComfoAirCommandType[] { FAN_OUT_PERCENT, FAN_OUT_RPM }, Constants.REQUEST_GET_FAN_LEVEL,
Constants.REPLY_GET_FAN_LEVEL, new int[] { 10 }),
FAN_IN_0(ComfoAirBindingConstants.CG_VENTILATION_PREFIX + ComfoAirBindingConstants.CHANNEL_FAN_IN_0,
DataTypeNumber.getInstance(), Constants.REQUEST_SET_FAN_LEVEL, 9, 3,
new ComfoAirCommandType[] { FAN_IN_PERCENT, FAN_IN_RPM }, Constants.REQUEST_GET_FAN_LEVEL,
Constants.REPLY_GET_FAN_LEVEL, new int[] { 3 }),
FAN_IN_1(ComfoAirBindingConstants.CG_VENTILATION_PREFIX + ComfoAirBindingConstants.CHANNEL_FAN_IN_1,
DataTypeNumber.getInstance(), Constants.REQUEST_SET_FAN_LEVEL, 9, 4,
new ComfoAirCommandType[] { FAN_IN_PERCENT, FAN_IN_RPM }, Constants.REQUEST_GET_FAN_LEVEL,
Constants.REPLY_GET_FAN_LEVEL, new int[] { 4 }),
FAN_IN_2(ComfoAirBindingConstants.CG_VENTILATION_PREFIX + ComfoAirBindingConstants.CHANNEL_FAN_IN_2,
DataTypeNumber.getInstance(), Constants.REQUEST_SET_FAN_LEVEL, 9, 5,
new ComfoAirCommandType[] { FAN_IN_PERCENT, FAN_IN_RPM }, Constants.REQUEST_GET_FAN_LEVEL,
Constants.REPLY_GET_FAN_LEVEL, new int[] { 5 }),
FAN_IN_3(ComfoAirBindingConstants.CG_VENTILATION_PREFIX + ComfoAirBindingConstants.CHANNEL_FAN_IN_3,
DataTypeNumber.getInstance(), Constants.REQUEST_SET_FAN_LEVEL, 9, 7,
new ComfoAirCommandType[] { FAN_IN_PERCENT, FAN_IN_RPM }, Constants.REQUEST_GET_FAN_LEVEL,
Constants.REPLY_GET_FAN_LEVEL, new int[] { 11 }),
FAN_LEVEL(ComfoAirBindingConstants.CG_VENTILATION_PREFIX + ComfoAirBindingConstants.CHANNEL_FAN_LEVEL,
DataTypeNumber.getInstance(), new int[] { 0x01, 0x02, 0x03, 0x04 }, Constants.REQUEST_SET_LEVEL, 1, 0,
new ComfoAirCommandType[] { FAN_IN_PERCENT, FAN_IN_RPM, FAN_OUT_PERCENT, FAN_OUT_RPM },
Constants.REQUEST_GET_FAN_LEVEL, Constants.REPLY_GET_FAN_LEVEL, new int[] { 8 }),
LEVEL0_TIME(ComfoAirBindingConstants.CG_TIMES_PREFIX + ComfoAirBindingConstants.CHANNEL_TIME_LEVEL0,
DataTypeTime.getInstance(), Constants.REQUEST_GET_HOURS, Constants.REPLY_GET_HOURS, new int[] { 0, 1, 2 }),
LEVEL1_TIME(ComfoAirBindingConstants.CG_TIMES_PREFIX + ComfoAirBindingConstants.CHANNEL_TIME_LEVEL1,
DataTypeTime.getInstance(), Constants.REQUEST_GET_HOURS, Constants.REPLY_GET_HOURS, new int[] { 3, 4, 5 }),
LEVEL2_TIME(ComfoAirBindingConstants.CG_TIMES_PREFIX + ComfoAirBindingConstants.CHANNEL_TIME_LEVEL2,
DataTypeTime.getInstance(), Constants.REQUEST_GET_HOURS, Constants.REPLY_GET_HOURS, new int[] { 6, 7, 8 }),
LEVEL3_TIME(ComfoAirBindingConstants.CG_TIMES_PREFIX + ComfoAirBindingConstants.CHANNEL_TIME_LEVEL3,
DataTypeTime.getInstance(), Constants.REQUEST_GET_HOURS, Constants.REPLY_GET_HOURS,
new int[] { 17, 18, 19 }),
FREEZE_TIME(ComfoAirBindingConstants.CG_TIMES_PREFIX + ComfoAirBindingConstants.CHANNEL_TIME_FREEZE,
DataTypeTime.getInstance(), Constants.REQUEST_GET_HOURS, Constants.REPLY_GET_HOURS, new int[] { 9, 10 }),
PREHEATER_TIME(ComfoAirBindingConstants.CG_TIMES_PREFIX + ComfoAirBindingConstants.CHANNEL_TIME_PREHEATER,
DataTypeTime.getInstance(), Constants.REQUEST_GET_HOURS, Constants.REPLY_GET_HOURS, new int[] { 11, 12 }),
BYPASS_TIME(ComfoAirBindingConstants.CG_TIMES_PREFIX + ComfoAirBindingConstants.CHANNEL_TIME_BYPASS,
DataTypeTime.getInstance(), Constants.REQUEST_GET_HOURS, Constants.REPLY_GET_HOURS, new int[] { 13, 14 }),
BYPASS_FACTOR(ComfoAirBindingConstants.CG_BYPASS_PREFIX + ComfoAirBindingConstants.CHANNEL_BYPASS_FACTOR,
DataTypeNumber.getInstance(), Constants.REQUEST_GET_BYPASS, Constants.REPLY_GET_BYPASS, new int[] { 2 }),
BYPASS_LEVEL(ComfoAirBindingConstants.CG_BYPASS_PREFIX + ComfoAirBindingConstants.CHANNEL_BYPASS_LEVEL,
DataTypeNumber.getInstance(), Constants.REQUEST_GET_BYPASS, Constants.REPLY_GET_BYPASS, new int[] { 3 }),
BYPASS_CORRECTION(ComfoAirBindingConstants.CG_BYPASS_PREFIX + ComfoAirBindingConstants.CHANNEL_BYPASS_CORRECTION,
DataTypeNumber.getInstance(), Constants.REQUEST_GET_BYPASS, Constants.REPLY_GET_BYPASS, new int[] { 4 }),
BYPASS_SUMMER(ComfoAirBindingConstants.CG_BYPASS_PREFIX + ComfoAirBindingConstants.CHANNEL_BYPASS_SUMMER,
DataTypeBoolean.getInstance(), Constants.REQUEST_GET_BYPASS, Constants.REPLY_GET_BYPASS, new int[] { 6 }),
ENTHALPY_TEMPERATURE(ComfoAirBindingConstants.CG_ENTHALPY_PREFIX + ComfoAirBindingConstants.CHANNEL_ENTHALPY_TEMP,
DataTypeTemperature.getInstance(), Constants.REQUEST_GET_SENSORS, Constants.REPLY_GET_SENSORS,
new int[] { 0 }),
ENTHALPY_HUMIDITY(ComfoAirBindingConstants.CG_ENTHALPY_PREFIX + ComfoAirBindingConstants.CHANNEL_ENTHALPY_HUMIDITY,
DataTypeNumber.getInstance(), Constants.REQUEST_GET_SENSORS, Constants.REPLY_GET_SENSORS, new int[] { 1 }),
ENTHALPY_LEVEL(ComfoAirBindingConstants.CG_ENTHALPY_PREFIX + ComfoAirBindingConstants.CHANNEL_ENTHALPY_LEVEL,
DataTypeNumber.getInstance(), Constants.REQUEST_GET_SENSORS, Constants.REPLY_GET_SENSORS, new int[] { 4 }),
ENTHALPY_TIME(ComfoAirBindingConstants.CG_ENTHALPY_PREFIX + ComfoAirBindingConstants.CHANNEL_ENTHALPY_TIME,
DataTypeNumber.getInstance(), Constants.REQUEST_GET_SENSORS, Constants.REPLY_GET_SENSORS, new int[] { 5 }),
PREHEATER_VALVE(ComfoAirBindingConstants.CG_PREHEATER_PREFIX + ComfoAirBindingConstants.CHANNEL_PREHEATER_VALVE,
DataTypeNumber.getInstance(), Constants.REQUEST_GET_PREHEATER, Constants.REPLY_GET_PREHEATER,
new int[] { 0 }),
PREHEATER_FROST_PROTECT(
ComfoAirBindingConstants.CG_PREHEATER_PREFIX + ComfoAirBindingConstants.CHANNEL_PREHEATER_FROST_PROTECT,
DataTypeBoolean.getInstance(), Constants.REQUEST_GET_PREHEATER, Constants.REPLY_GET_PREHEATER,
new int[] { 1 }),
PREHEATER_HEATING(ComfoAirBindingConstants.CG_PREHEATER_PREFIX + ComfoAirBindingConstants.CHANNEL_PREHEATER_HEATING,
DataTypeBoolean.getInstance(), Constants.REQUEST_GET_PREHEATER, Constants.REPLY_GET_PREHEATER,
new int[] { 2 }),
PREHEATER_FROST_TIME(
ComfoAirBindingConstants.CG_PREHEATER_PREFIX + ComfoAirBindingConstants.CHANNEL_PREHEATER_FROST_TIME,
DataTypeNumber.getInstance(), Constants.REQUEST_GET_PREHEATER, Constants.REPLY_GET_PREHEATER,
new int[] { 3, 4 }),
PREHEATER_OPTION(ComfoAirBindingConstants.CG_PREHEATER_PREFIX + ComfoAirBindingConstants.CHANNEL_PREHEATER_SAFETY,
DataTypeNumber.getInstance(), Constants.REQUEST_GET_PREHEATER, Constants.REPLY_GET_PREHEATER,
new int[] { 5 }),
TARGET_TEMPERATURE(ComfoAirBindingConstants.CG_TEMPS_PREFIX + ComfoAirBindingConstants.CHANNEL_TEMP_TARGET,
DataTypeTemperature.getInstance(), Constants.REQUEST_SET_TEMPS, 1, 0,
new ComfoAirCommandType[] { BYPASS_FACTOR, BYPASS_LEVEL, BYPASS_SUMMER }, Constants.REQUEST_GET_TEMPS,
Constants.REPLY_GET_TEMPS, new int[] { 0 }),
OUTDOOR_TEMPERATURE_IN(ComfoAirBindingConstants.CG_TEMPS_PREFIX + ComfoAirBindingConstants.CHANNEL_TEMP_OUTDOOR_IN,
DataTypeTemperature.getInstance(), Constants.REQUEST_GET_TEMPS, Constants.REPLY_GET_TEMPS, new int[] { 1 }),
OUTDOOR_TEMPERATURE_OUT(
ComfoAirBindingConstants.CG_TEMPS_PREFIX + ComfoAirBindingConstants.CHANNEL_TEMP_OUTDOOR_OUT,
DataTypeTemperature.getInstance(), Constants.REQUEST_GET_TEMPS, Constants.REPLY_GET_TEMPS, new int[] { 4 }),
INDOOR_TEMPERATURE_IN(ComfoAirBindingConstants.CG_TEMPS_PREFIX + ComfoAirBindingConstants.CHANNEL_TEMP_INDOOR_IN,
DataTypeTemperature.getInstance(), Constants.REQUEST_GET_TEMPS, Constants.REPLY_GET_TEMPS, new int[] { 2 }),
INDOOR_TEMPERATURE_OUT(ComfoAirBindingConstants.CG_TEMPS_PREFIX + ComfoAirBindingConstants.CHANNEL_TEMP_INDOOR_OUT,
DataTypeTemperature.getInstance(), Constants.REQUEST_GET_TEMPS, Constants.REPLY_GET_TEMPS, new int[] { 3 }),
IS_T1_SENSOR(ComfoAirBindingConstants.CG_TEMPS_PREFIX + ComfoAirBindingConstants.CHANNEL_IS_SENSOR_T1,
DataTypeBoolean.getInstance(), Constants.REQUEST_GET_TEMPS, Constants.REPLY_GET_TEMPS, new int[] { 5 },
0x01),
IS_T2_SENSOR(ComfoAirBindingConstants.CG_TEMPS_PREFIX + ComfoAirBindingConstants.CHANNEL_IS_SENSOR_T2,
DataTypeBoolean.getInstance(), Constants.REQUEST_GET_TEMPS, Constants.REPLY_GET_TEMPS, new int[] { 5 },
0x02),
IS_T3_SENSOR(ComfoAirBindingConstants.CG_TEMPS_PREFIX + ComfoAirBindingConstants.CHANNEL_IS_SENSOR_T3,
DataTypeBoolean.getInstance(), Constants.REQUEST_GET_TEMPS, Constants.REPLY_GET_TEMPS, new int[] { 5 },
0x04),
IS_T4_SENSOR(ComfoAirBindingConstants.CG_TEMPS_PREFIX + ComfoAirBindingConstants.CHANNEL_IS_SENSOR_T4,
DataTypeBoolean.getInstance(), Constants.REQUEST_GET_TEMPS, Constants.REPLY_GET_TEMPS, new int[] { 5 },
0x08),
IS_EWT_SENSOR(ComfoAirBindingConstants.CG_TEMPS_PREFIX + ComfoAirBindingConstants.CHANNEL_IS_SENSOR_EWT,
DataTypeBoolean.getInstance(), Constants.REQUEST_GET_TEMPS, Constants.REPLY_GET_TEMPS, new int[] { 5 },
0x10),
IS_HEATER_SENSOR(ComfoAirBindingConstants.CG_TEMPS_PREFIX + ComfoAirBindingConstants.CHANNEL_IS_SENSOR_HEATER,
DataTypeBoolean.getInstance(), Constants.REQUEST_GET_TEMPS, Constants.REPLY_GET_TEMPS, new int[] { 5 },
0x20),
IS_COOKERHOOD_SENSOR(
ComfoAirBindingConstants.CG_TEMPS_PREFIX + ComfoAirBindingConstants.CHANNEL_IS_SENSOR_COOKERHOOD,
DataTypeBoolean.getInstance(), Constants.REQUEST_GET_TEMPS, Constants.REPLY_GET_TEMPS, new int[] { 5 },
0x40),
EWT_TEMPERATURE(ComfoAirBindingConstants.CG_TEMPS_PREFIX + ComfoAirBindingConstants.CHANNEL_TEMP_EWT,
DataTypeTemperature.getInstance(), Constants.REQUEST_GET_TEMPS, Constants.REPLY_GET_TEMPS, new int[] { 6 }),
HEATER_TEMPERATURE(ComfoAirBindingConstants.CG_TEMPS_PREFIX + ComfoAirBindingConstants.CHANNEL_TEMP_HEATER,
DataTypeTemperature.getInstance(), Constants.REQUEST_GET_TEMPS, Constants.REPLY_GET_TEMPS, new int[] { 7 }),
COOKERHOOD_TEMPERATURE(ComfoAirBindingConstants.CG_TEMPS_PREFIX + ComfoAirBindingConstants.CHANNEL_TEMP_COOKERHOOD,
DataTypeTemperature.getInstance(), Constants.REQUEST_GET_TEMPS, Constants.REPLY_GET_TEMPS, new int[] { 8 }),
EWT_SPEED(ComfoAirBindingConstants.CG_EWT_PREFIX + ComfoAirBindingConstants.CHANNEL_EWT_SPEED,
DataTypeNumber.getInstance(), Constants.REQUEST_SET_EWT, 5, 2,
new ComfoAirCommandType[] { EWT_STATE, EWT_TEMPERATURE }, Constants.REQUEST_GET_EWT,
Constants.REPLY_GET_EWT, new int[] { 2 }),
EWT_TEMPERATURE_LOW(ComfoAirBindingConstants.CG_EWT_PREFIX + ComfoAirBindingConstants.CHANNEL_EWT_TEMP_LOW,
DataTypeTemperature.getInstance(), Constants.REQUEST_SET_EWT, 5, 0, new ComfoAirCommandType[] { EWT_STATE },
Constants.REQUEST_GET_EWT, Constants.REPLY_GET_EWT, new int[] { 0 }),
EWT_TEMPERATURE_HIGH(ComfoAirBindingConstants.CG_EWT_PREFIX + ComfoAirBindingConstants.CHANNEL_EWT_TEMP_HIGH,
DataTypeTemperature.getInstance(), Constants.REQUEST_SET_EWT, 5, 1, new ComfoAirCommandType[] { EWT_STATE },
Constants.REQUEST_GET_EWT, Constants.REPLY_GET_EWT, new int[] { 1 }),
COOKERHOOD_SPEED(ComfoAirBindingConstants.CG_COOKERHOOD_PREFIX + ComfoAirBindingConstants.CHANNEL_COOKERHOOD_SPEED,
DataTypeNumber.getInstance(), Constants.REQUEST_SET_EWT, 5, 3,
new ComfoAirCommandType[] { COOKERHOOD_STATE, COOKERHOOD_TEMPERATURE }, Constants.REQUEST_GET_EWT,
Constants.REPLY_GET_EWT, new int[] { 3 }),
HEATER_POWER(ComfoAirBindingConstants.CG_HEATER_PREFIX + ComfoAirBindingConstants.CHANNEL_HEATER_POWER,
DataTypeNumber.getInstance(), Constants.REQUEST_GET_EWT, Constants.REPLY_GET_EWT, new int[] { 4 }),
HEATER_POWER_I(ComfoAirBindingConstants.CG_HEATER_PREFIX + ComfoAirBindingConstants.CHANNEL_HEATER_POWER_I,
DataTypeNumber.getInstance(), Constants.REQUEST_GET_EWT, Constants.REPLY_GET_EWT, new int[] { 5 }),
HEATER_TARGET_TEMPERATURE(
ComfoAirBindingConstants.CG_HEATER_PREFIX + ComfoAirBindingConstants.CHANNEL_HEATER_TEMP_TARGET,
DataTypeTemperature.getInstance(), Constants.REQUEST_SET_EWT, 5, 4,
new ComfoAirCommandType[] { HEATER_STATE, HEATER_POWER, HEATER_TEMPERATURE }, Constants.REQUEST_GET_EWT,
Constants.REPLY_GET_EWT, new int[] { 6 }),
IS_PREHEATER(ComfoAirBindingConstants.PROPERTY_OPTION_PREHEATER, DataTypeBoolean.getInstance(),
Constants.REQUEST_SET_STATES, 8, 0,
new ComfoAirCommandType[] { OUTDOOR_TEMPERATURE_IN, INDOOR_TEMPERATURE_IN, PREHEATER_FROST_PROTECT,
PREHEATER_FROST_TIME, PREHEATER_HEATING, FROST_STATE, PREHEATER_OPTION, PREHEATER_TIME,
PREHEATER_VALVE },
Constants.REQUEST_GET_STATES, Constants.REPLY_GET_STATES, new int[] { 0 }),
IS_BYPASS(ComfoAirBindingConstants.PROPERTY_OPTION_BYPASS, DataTypeBoolean.getInstance(),
Constants.REQUEST_SET_STATES, 8, 1,
new ComfoAirCommandType[] { INDOOR_TEMPERATURE_IN, OUTDOOR_TEMPERATURE_OUT }, Constants.REQUEST_GET_STATES,
Constants.REPLY_GET_STATES, new int[] { 1 }),
RECU_TYPE(ComfoAirBindingConstants.PROPERTY_OPTION_RECU_TYPE, DataTypeNumber.getInstance(),
new int[] { 0x01, 0x02 }, Constants.REQUEST_SET_STATES, 8, 2,
new ComfoAirCommandType[] { FAN_IN_PERCENT, FAN_OUT_PERCENT, INDOOR_TEMPERATURE_IN, INDOOR_TEMPERATURE_OUT,
OUTDOOR_TEMPERATURE_IN, OUTDOOR_TEMPERATURE_OUT },
Constants.REQUEST_GET_STATES, Constants.REPLY_GET_STATES, new int[] { 2 }),
RECU_SIZE(ComfoAirBindingConstants.PROPERTY_OPTION_RECU_SIZE, DataTypeNumber.getInstance(),
new int[] { 0x01, 0x02 }, Constants.REQUEST_SET_STATES, 8, 3,
new ComfoAirCommandType[] { FAN_IN_PERCENT, FAN_OUT_PERCENT, FAN_IN_0, FAN_IN_1, FAN_IN_2, FAN_IN_3,
FAN_OUT_0, FAN_OUT_1, FAN_OUT_2, FAN_OUT_3 },
Constants.REQUEST_GET_STATES, Constants.REPLY_GET_STATES, new int[] { 3 }),
IS_CHIMNEY(ComfoAirBindingConstants.PROPERTY_OPTION_CHIMNEY, DataTypeBoolean.getInstance(), new int[] { 0x01 },
Constants.REQUEST_SET_STATES, 8, 4, Constants.EMPTY_TYPE_ARRAY, Constants.REQUEST_GET_STATES,
Constants.REPLY_GET_STATES, new int[] { 4 }, 0x01),
IS_COOKERHOOD(ComfoAirBindingConstants.PROPERTY_OPTION_COOKERHOOD, DataTypeBoolean.getInstance(),
new int[] { 0x02 }, Constants.REQUEST_SET_STATES, 8, 4,
new ComfoAirCommandType[] { COOKERHOOD_DELAY, COOKERHOOD_STATE, COOKERHOOD_SPEED, COOKERHOOD_TEMPERATURE },
Constants.REQUEST_GET_STATES, Constants.REPLY_GET_STATES, new int[] { 4 }, 0x02),
IS_HEATER(ComfoAirBindingConstants.PROPERTY_OPTION_HEATER, DataTypeBoolean.getInstance(), new int[] { 0x04 },
Constants.REQUEST_SET_STATES, 8, 4,
new ComfoAirCommandType[] { HEATER_TARGET_TEMPERATURE, HEATER_POWER, HEATER_STATE, HEATER_POWER_I,
HEATER_TEMPERATURE },
Constants.REQUEST_GET_STATES, Constants.REPLY_GET_STATES, new int[] { 4 }, 0x04),
IS_ENTHALPY(ComfoAirBindingConstants.PROPERTY_OPTION_ENTHALPY, DataTypeNumber.getInstance(),
new int[] { 0x00, 0x01, 0x02 }, Constants.REQUEST_SET_STATES, 8, 6,
new ComfoAirCommandType[] { ENTHALPY_TEMPERATURE, ENTHALPY_HUMIDITY, ENTHALPY_LEVEL, ENTHALPY_STATE,
ENTHALPY_TIME },
Constants.REQUEST_GET_STATES, Constants.REPLY_GET_STATES, new int[] { 9 }),
IS_EWT(ComfoAirBindingConstants.PROPERTY_OPTION_EWT, DataTypeNumber.getInstance(), new int[] { 0x00, 0x01, 0x02 },
Constants.REQUEST_SET_STATES, 8, 7,
new ComfoAirCommandType[] { EWT_SPEED, EWT_TEMPERATURE_LOW, EWT_TEMPERATURE_HIGH, EWT_STATE,
EWT_TEMPERATURE },
Constants.REQUEST_GET_STATES, Constants.REPLY_GET_STATES, new int[] { 10 }),
SOFTWARE_MAIN_VERSION(ComfoAirBindingConstants.PROPERTY_SOFTWARE_MAIN_VERSION, DataTypeNumber.getInstance(),
Constants.REQUEST_GET_FIRMWARE, Constants.REPLY_GET_FIRMWARE, new int[] { 0 }),
SOFTWARE_MINOR_VERSION(ComfoAirBindingConstants.PROPERTY_SOFTWARE_MINOR_VERSION, DataTypeNumber.getInstance(),
Constants.REQUEST_GET_FIRMWARE, Constants.REPLY_GET_FIRMWARE, new int[] { 1 }),
DEVICE_NAME(ComfoAirBindingConstants.PROPERTY_DEVICE_NAME, DataTypeNumber.getInstance(),
Constants.REQUEST_GET_FIRMWARE, Constants.REPLY_GET_FIRMWARE,
new int[] { 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 }),
ERRORS_CURRENT(ComfoAirBindingConstants.CG_ERRORS_PREFIX + ComfoAirBindingConstants.CHANNEL_ERRORS_CURRENT,
DataTypeMessage.getInstance(), Constants.REQUEST_GET_ERRORS, Constants.REPLY_GET_ERRORS,
new int[] { 0, 1, 9, 13 }),
ERRORS_LAST(ComfoAirBindingConstants.CG_ERRORS_PREFIX + ComfoAirBindingConstants.CHANNEL_ERRORS_LAST,
DataTypeMessage.getInstance(), Constants.REQUEST_GET_ERRORS, Constants.REPLY_GET_ERRORS,
new int[] { 2, 3, 10, 14 }),
ERRORS_PRELAST(ComfoAirBindingConstants.CG_ERRORS_PREFIX + ComfoAirBindingConstants.CHANNEL_ERRORS_PRELAST,
DataTypeMessage.getInstance(), Constants.REQUEST_GET_ERRORS, Constants.REPLY_GET_ERRORS,
new int[] { 4, 5, 11, 15 }),
ERRORS_PREPRELAST(ComfoAirBindingConstants.CG_ERRORS_PREFIX + ComfoAirBindingConstants.CHANNEL_ERRORS_PREPRELAST,
DataTypeMessage.getInstance(), Constants.REQUEST_GET_ERRORS, Constants.REPLY_GET_ERRORS,
new int[] { 6, 7, 12, 16 }),
ERROR_RESET(ComfoAirBindingConstants.CG_RESETS_PREFIX + ComfoAirBindingConstants.CHANNEL_ERROR_RESET,
DataTypeNumber.getInstance(), new int[] { 0x01 }, Constants.REQUEST_SET_RESETS, 4, 0,
new ComfoAirCommandType[] { ERRORS_CURRENT, ERRORS_LAST, ERRORS_PRELAST, ERRORS_PREPRELAST }),
FILTER_ERROR(ComfoAirBindingConstants.CG_ERRORS_PREFIX + ComfoAirBindingConstants.CHANNEL_FILTER_ERROR,
DataTypeBoolean.getInstance(), Constants.REQUEST_GET_ERRORS, Constants.REPLY_GET_ERRORS, new int[] { 8 },
0x01),
FILTER_HOURS(ComfoAirBindingConstants.CG_TIMES_PREFIX + ComfoAirBindingConstants.CHANNEL_TIME_FILTER,
DataTypeTime.getInstance(), Constants.REQUEST_GET_HOURS, Constants.REPLY_GET_HOURS, new int[] { 15, 16 }),
FILTER_RESET(ComfoAirBindingConstants.CG_RESETS_PREFIX + ComfoAirBindingConstants.CHANNEL_FILTER_RESET,
DataTypeNumber.getInstance(), new int[] { 0x01 }, Constants.REQUEST_SET_RESETS, 4, 3,
new ComfoAirCommandType[] { FILTER_HOURS, FILTER_ERROR }),
ANALOG1_NEGATIVE(ComfoAirBindingConstants.CG_ANALOG1_PREFIX + ComfoAirBindingConstants.CHANNEL_ANALOG_NEGATIVE,
DataTypeBoolean.getInstance(), new int[] { 0x01 }, Constants.REQUEST_SET_ANALOGS, 19, 2,
Constants.EMPTY_TYPE_ARRAY, Constants.REQUEST_GET_ANALOGS, Constants.REPLY_GET_ANALOGS, new int[] { 2 },
0x01),
ANALOG2_NEGATIVE(ComfoAirBindingConstants.CG_ANALOG2_PREFIX + ComfoAirBindingConstants.CHANNEL_ANALOG_NEGATIVE,
DataTypeBoolean.getInstance(), new int[] { 0x02 }, Constants.REQUEST_SET_ANALOGS, 19, 2,
Constants.EMPTY_TYPE_ARRAY, Constants.REQUEST_GET_ANALOGS, Constants.REPLY_GET_ANALOGS, new int[] { 2 },
0x02),
ANALOG3_NEGATIVE(ComfoAirBindingConstants.CG_ANALOG3_PREFIX + ComfoAirBindingConstants.CHANNEL_ANALOG_NEGATIVE,
DataTypeBoolean.getInstance(), new int[] { 0x04 }, Constants.REQUEST_SET_ANALOGS, 19, 2,
Constants.EMPTY_TYPE_ARRAY, Constants.REQUEST_GET_ANALOGS, Constants.REPLY_GET_ANALOGS, new int[] { 2 },
0x04),
ANALOG4_NEGATIVE(ComfoAirBindingConstants.CG_ANALOG4_PREFIX + ComfoAirBindingConstants.CHANNEL_ANALOG_NEGATIVE,
DataTypeBoolean.getInstance(), new int[] { 0x08 }, Constants.REQUEST_SET_ANALOGS, 19, 2,
Constants.EMPTY_TYPE_ARRAY, Constants.REQUEST_GET_ANALOGS, Constants.REPLY_GET_ANALOGS, new int[] { 2 },
0x08),
RF_NEGATIVE(ComfoAirBindingConstants.CG_ANALOGRF_PREFIX + ComfoAirBindingConstants.CHANNEL_RF_NEGATIVE,
DataTypeBoolean.getInstance(), new int[] { 0x10 }, Constants.REQUEST_SET_ANALOGS, 19, 2,
Constants.EMPTY_TYPE_ARRAY, Constants.REQUEST_GET_ANALOGS, Constants.REPLY_GET_ANALOGS, new int[] { 2 },
0x10),
ANALOG1_MIN(ComfoAirBindingConstants.CG_ANALOG1_PREFIX + ComfoAirBindingConstants.CHANNEL_ANALOG_MIN,
DataTypeNumber.getInstance(), Constants.REQUEST_SET_ANALOGS, 19, 3, Constants.EMPTY_TYPE_ARRAY,
Constants.REQUEST_GET_ANALOGS, Constants.REPLY_GET_ANALOGS, new int[] { 3 }),
ANALOG1_MAX(ComfoAirBindingConstants.CG_ANALOG1_PREFIX + ComfoAirBindingConstants.CHANNEL_ANALOG_MAX,
DataTypeNumber.getInstance(), Constants.REQUEST_SET_ANALOGS, 19, 4, Constants.EMPTY_TYPE_ARRAY,
Constants.REQUEST_GET_ANALOGS, Constants.REPLY_GET_ANALOGS, new int[] { 4 }),
ANALOG1_VALUE(ComfoAirBindingConstants.CG_ANALOG1_PREFIX + ComfoAirBindingConstants.CHANNEL_ANALOG_VALUE,
DataTypeNumber.getInstance(), Constants.REQUEST_SET_ANALOGS, 19, 5, Constants.EMPTY_TYPE_ARRAY,
Constants.REQUEST_GET_ANALOGS, Constants.REPLY_GET_ANALOGS, new int[] { 5 }),
ANALOG2_MIN(ComfoAirBindingConstants.CG_ANALOG2_PREFIX + ComfoAirBindingConstants.CHANNEL_ANALOG_MIN,
DataTypeNumber.getInstance(), Constants.REQUEST_SET_ANALOGS, 19, 6, Constants.EMPTY_TYPE_ARRAY,
Constants.REQUEST_GET_ANALOGS, Constants.REPLY_GET_ANALOGS, new int[] { 6 }),
ANALOG2_MAX(ComfoAirBindingConstants.CG_ANALOG2_PREFIX + ComfoAirBindingConstants.CHANNEL_ANALOG_MAX,
DataTypeNumber.getInstance(), Constants.REQUEST_SET_ANALOGS, 19, 7, Constants.EMPTY_TYPE_ARRAY,
Constants.REQUEST_GET_ANALOGS, Constants.REPLY_GET_ANALOGS, new int[] { 7 }),
ANALOG2_VALUE(ComfoAirBindingConstants.CG_ANALOG2_PREFIX + ComfoAirBindingConstants.CHANNEL_ANALOG_VALUE,
DataTypeNumber.getInstance(), Constants.REQUEST_SET_ANALOGS, 19, 8, Constants.EMPTY_TYPE_ARRAY,
Constants.REQUEST_GET_ANALOGS, Constants.REPLY_GET_ANALOGS, new int[] { 8 }),
ANALOG3_MIN(ComfoAirBindingConstants.CG_ANALOG3_PREFIX + ComfoAirBindingConstants.CHANNEL_ANALOG_MIN,
DataTypeNumber.getInstance(), Constants.REQUEST_SET_ANALOGS, 19, 9, Constants.EMPTY_TYPE_ARRAY,
Constants.REQUEST_GET_ANALOGS, Constants.REPLY_GET_ANALOGS, new int[] { 9 }),
ANALOG3_MAX(ComfoAirBindingConstants.CG_ANALOG3_PREFIX + ComfoAirBindingConstants.CHANNEL_ANALOG_MAX,
DataTypeNumber.getInstance(), Constants.REQUEST_SET_ANALOGS, 19, 10, Constants.EMPTY_TYPE_ARRAY,
Constants.REQUEST_GET_ANALOGS, Constants.REPLY_GET_ANALOGS, new int[] { 10 }),
ANALOG3_VALUE(ComfoAirBindingConstants.CG_ANALOG3_PREFIX + ComfoAirBindingConstants.CHANNEL_ANALOG_VALUE,
DataTypeNumber.getInstance(), Constants.REQUEST_SET_ANALOGS, 19, 11, Constants.EMPTY_TYPE_ARRAY,
Constants.REQUEST_GET_ANALOGS, Constants.REPLY_GET_ANALOGS, new int[] { 11 }),
ANALOG4_MIN(ComfoAirBindingConstants.CG_ANALOG4_PREFIX + ComfoAirBindingConstants.CHANNEL_ANALOG_MIN,
DataTypeNumber.getInstance(), Constants.REQUEST_SET_ANALOGS, 19, 12, Constants.EMPTY_TYPE_ARRAY,
Constants.REQUEST_GET_ANALOGS, Constants.REPLY_GET_ANALOGS, new int[] { 12 }),
ANALOG4_MAX(ComfoAirBindingConstants.CG_ANALOG4_PREFIX + ComfoAirBindingConstants.CHANNEL_ANALOG_MAX,
DataTypeNumber.getInstance(), Constants.REQUEST_SET_ANALOGS, 19, 13, Constants.EMPTY_TYPE_ARRAY,
Constants.REQUEST_GET_ANALOGS, Constants.REPLY_GET_ANALOGS, new int[] { 13 }),
ANALOG4_VALUE(ComfoAirBindingConstants.CG_ANALOG4_PREFIX + ComfoAirBindingConstants.CHANNEL_ANALOG_VALUE,
DataTypeNumber.getInstance(), Constants.REQUEST_SET_ANALOGS, 19, 14, Constants.EMPTY_TYPE_ARRAY,
Constants.REQUEST_GET_ANALOGS, Constants.REPLY_GET_ANALOGS, new int[] { 14 }),
RF_MIN(ComfoAirBindingConstants.CG_ANALOGRF_PREFIX + ComfoAirBindingConstants.CHANNEL_RF_MIN,
DataTypeNumber.getInstance(), Constants.REQUEST_SET_ANALOGS, 19, 15, Constants.EMPTY_TYPE_ARRAY,
Constants.REQUEST_GET_ANALOGS, Constants.REPLY_GET_ANALOGS, new int[] { 15 }),
RF_MAX(ComfoAirBindingConstants.CG_ANALOGRF_PREFIX + ComfoAirBindingConstants.CHANNEL_RF_MAX,
DataTypeNumber.getInstance(), Constants.REQUEST_SET_ANALOGS, 19, 16, Constants.EMPTY_TYPE_ARRAY,
Constants.REQUEST_GET_ANALOGS, Constants.REPLY_GET_ANALOGS, new int[] { 16 }),
RF_VALUE(ComfoAirBindingConstants.CG_ANALOGRF_PREFIX + ComfoAirBindingConstants.CHANNEL_RF_VALUE,
DataTypeNumber.getInstance(), Constants.REQUEST_SET_ANALOGS, 19, 17, Constants.EMPTY_TYPE_ARRAY,
Constants.REQUEST_GET_ANALOGS, Constants.REPLY_GET_ANALOGS, new int[] { 17 }),
ANALOG_MODE(ComfoAirBindingConstants.CG_ANALOGRF_PREFIX + ComfoAirBindingConstants.CHANNEL_ANALOG_PRIORITY,
DataTypeNumber.getInstance(), new int[] { 0x00, 0x01 }, Constants.REQUEST_SET_ANALOGS, 19, 18,
Constants.EMPTY_TYPE_ARRAY, Constants.REQUEST_GET_ANALOGS, Constants.REPLY_GET_ANALOGS, new int[] { 18 }),
ANALOG1_VOLT(ComfoAirBindingConstants.CG_ANALOG1_PREFIX + ComfoAirBindingConstants.CHANNEL_ANALOG_VOLT,
DataTypeVolt.getInstance(), Constants.REQUEST_GET_ANALOG_VOLTS, Constants.REPLY_GET_ANALOG_VOLTS,
new int[] { 0 }),
ANALOG2_VOLT(ComfoAirBindingConstants.CG_ANALOG2_PREFIX + ComfoAirBindingConstants.CHANNEL_ANALOG_VOLT,
DataTypeVolt.getInstance(), Constants.REQUEST_GET_ANALOG_VOLTS, Constants.REPLY_GET_ANALOG_VOLTS,
new int[] { 1 }),
ANALOG3_VOLT(ComfoAirBindingConstants.CG_ANALOG3_PREFIX + ComfoAirBindingConstants.CHANNEL_ANALOG_VOLT,
DataTypeVolt.getInstance(), Constants.REQUEST_GET_ANALOG_VOLTS, Constants.REPLY_GET_ANALOG_VOLTS,
new int[] { 2 }),
ANALOG4_VOLT(ComfoAirBindingConstants.CG_ANALOG4_PREFIX + ComfoAirBindingConstants.CHANNEL_ANALOG_VOLT,
DataTypeVolt.getInstance(), Constants.REQUEST_GET_ANALOG_VOLTS, Constants.REPLY_GET_ANALOG_VOLTS,
new int[] { 3 }),
ANALOG1_MODE(ComfoAirBindingConstants.CG_ANALOG1_PREFIX + ComfoAirBindingConstants.CHANNEL_ANALOG_MODE,
DataTypeBoolean.getInstance(), new int[] { 0x01 }, Constants.REQUEST_SET_ANALOGS, 19, 1,
new ComfoAirCommandType[] { ANALOG1_NEGATIVE, ANALOG1_MIN, ANALOG1_MAX, ANALOG1_VALUE, ANALOG1_VOLT },
Constants.REQUEST_GET_ANALOGS, Constants.REPLY_GET_ANALOGS, new int[] { 1 }, 0x01),
ANALOG2_MODE(ComfoAirBindingConstants.CG_ANALOG2_PREFIX + ComfoAirBindingConstants.CHANNEL_ANALOG_MODE,
DataTypeBoolean.getInstance(), new int[] { 0x02 }, Constants.REQUEST_SET_ANALOGS, 19, 1,
new ComfoAirCommandType[] { ANALOG2_NEGATIVE, ANALOG2_MIN, ANALOG2_MAX, ANALOG2_VALUE, ANALOG2_VOLT },
Constants.REQUEST_GET_ANALOGS, Constants.REPLY_GET_ANALOGS, new int[] { 1 }, 0x02),
ANALOG3_MODE(ComfoAirBindingConstants.CG_ANALOG3_PREFIX + ComfoAirBindingConstants.CHANNEL_ANALOG_MODE,
DataTypeBoolean.getInstance(), new int[] { 0x04 }, Constants.REQUEST_SET_ANALOGS, 19, 1,
new ComfoAirCommandType[] { ANALOG3_NEGATIVE, ANALOG3_MIN, ANALOG3_MAX, ANALOG3_VALUE, ANALOG3_VOLT },
Constants.REQUEST_GET_ANALOGS, Constants.REPLY_GET_ANALOGS, new int[] { 1 }, 0x04),
ANALOG4_MODE(ComfoAirBindingConstants.CG_ANALOG4_PREFIX + ComfoAirBindingConstants.CHANNEL_ANALOG_MODE,
DataTypeBoolean.getInstance(), new int[] { 0x08 }, Constants.REQUEST_SET_ANALOGS, 19, 1,
new ComfoAirCommandType[] { ANALOG4_NEGATIVE, ANALOG4_MIN, ANALOG4_MAX, ANALOG4_VALUE, ANALOG4_VOLT },
Constants.REQUEST_GET_ANALOGS, Constants.REPLY_GET_ANALOGS, new int[] { 1 }, 0x08),
RF_MODE(ComfoAirBindingConstants.CG_ANALOGRF_PREFIX + ComfoAirBindingConstants.CHANNEL_RF_MODE,
DataTypeBoolean.getInstance(), new int[] { 0x10 }, Constants.REQUEST_SET_ANALOGS, 19, 1,
new ComfoAirCommandType[] { RF_NEGATIVE, RF_MIN, RF_MAX, RF_VALUE }, Constants.REQUEST_GET_ANALOGS,
Constants.REPLY_GET_ANALOGS, new int[] { 1 }, 0x10),
IS_L1_SWITCH(ComfoAirBindingConstants.CG_INPUTS_PREFIX + ComfoAirBindingConstants.CHANNEL_IS_L1_SWITCH,
DataTypeBoolean.getInstance(), Constants.REQUEST_GET_INPUTS, Constants.REPLY_GET_INPUTS, new int[] { 0 },
0x01),
IS_L2_SWITCH(ComfoAirBindingConstants.CG_INPUTS_PREFIX + ComfoAirBindingConstants.CHANNEL_IS_L2_SWITCH,
DataTypeBoolean.getInstance(), Constants.REQUEST_GET_INPUTS, Constants.REPLY_GET_INPUTS, new int[] { 0 },
0x02),
IS_BATHROOM_SWITCH(ComfoAirBindingConstants.CG_INPUTS_PREFIX + ComfoAirBindingConstants.CHANNEL_IS_BATHROOM_SWITCH,
DataTypeBoolean.getInstance(), Constants.REQUEST_GET_INPUTS, Constants.REPLY_GET_INPUTS, new int[] { 1 },
0x01),
IS_COOKERHOOD_SWITCH(
ComfoAirBindingConstants.CG_INPUTS_PREFIX + ComfoAirBindingConstants.CHANNEL_IS_COOKERHOOD_SWITCH,
DataTypeBoolean.getInstance(), Constants.REQUEST_GET_INPUTS, Constants.REPLY_GET_INPUTS, new int[] { 1 },
0x02),
IS_EXTERNAL_FILTER(ComfoAirBindingConstants.CG_INPUTS_PREFIX + ComfoAirBindingConstants.CHANNEL_IS_EXTERNAL_FILTER,
DataTypeBoolean.getInstance(), Constants.REQUEST_GET_INPUTS, Constants.REPLY_GET_INPUTS, new int[] { 1 },
0x04),
IS_WTW(ComfoAirBindingConstants.CG_INPUTS_PREFIX + ComfoAirBindingConstants.CHANNEL_IS_WTW,
DataTypeBoolean.getInstance(), Constants.REQUEST_GET_INPUTS, Constants.REPLY_GET_INPUTS, new int[] { 1 },
0x08),
IS_BATHROOM2_SWITCH(
ComfoAirBindingConstants.CG_INPUTS_PREFIX + ComfoAirBindingConstants.CHANNEL_IS_BATHROOM2_SWITCH,
DataTypeBoolean.getInstance(), Constants.REQUEST_GET_INPUTS, Constants.REPLY_GET_INPUTS, new int[] { 1 },
0x10),
IS_ANALOG1(ComfoAirBindingConstants.CG_ANALOG1_PREFIX + ComfoAirBindingConstants.CHANNEL_IS_ANALOG,
DataTypeBoolean.getInstance(), new int[] { 0x01 }, Constants.REQUEST_SET_ANALOGS, 19, 0,
new ComfoAirCommandType[] { ANALOG1_MODE, ANALOG1_NEGATIVE, ANALOG1_MIN, ANALOG1_MAX, ANALOG1_VALUE,
ANALOG1_VOLT },
Constants.REQUEST_GET_ANALOGS, Constants.REPLY_GET_ANALOGS, new int[] { 0 }, 0x01),
IS_ANALOG2(ComfoAirBindingConstants.CG_ANALOG1_PREFIX + ComfoAirBindingConstants.CHANNEL_IS_ANALOG,
DataTypeBoolean.getInstance(), new int[] { 0x02 }, Constants.REQUEST_SET_ANALOGS, 19, 0,
new ComfoAirCommandType[] { ANALOG2_MODE, ANALOG2_NEGATIVE, ANALOG2_MIN, ANALOG2_MAX, ANALOG2_VALUE,
ANALOG2_VOLT },
Constants.REQUEST_GET_ANALOGS, Constants.REPLY_GET_ANALOGS, new int[] { 0 }, 0x02),
IS_ANALOG3(ComfoAirBindingConstants.CG_ANALOG1_PREFIX + ComfoAirBindingConstants.CHANNEL_IS_ANALOG,
DataTypeBoolean.getInstance(), new int[] { 0x04 }, Constants.REQUEST_SET_ANALOGS, 19, 0,
new ComfoAirCommandType[] { ANALOG3_MODE, ANALOG3_NEGATIVE, ANALOG3_MIN, ANALOG3_MAX, ANALOG3_VALUE,
ANALOG3_VOLT },
Constants.REQUEST_GET_ANALOGS, Constants.REPLY_GET_ANALOGS, new int[] { 0 }, 0x04),
IS_ANALOG4(ComfoAirBindingConstants.CG_ANALOG1_PREFIX + ComfoAirBindingConstants.CHANNEL_IS_ANALOG,
DataTypeBoolean.getInstance(), new int[] { 0x08 }, Constants.REQUEST_SET_ANALOGS, 19, 0,
new ComfoAirCommandType[] { ANALOG4_MODE, ANALOG4_NEGATIVE, ANALOG4_MIN, ANALOG4_MAX, ANALOG4_VALUE,
ANALOG4_VOLT },
Constants.REQUEST_GET_ANALOGS, Constants.REPLY_GET_ANALOGS, new int[] { 0 }, 0x08),
IS_RF(ComfoAirBindingConstants.CG_ANALOGRF_PREFIX + ComfoAirBindingConstants.CHANNEL_IS_RF,
DataTypeBoolean.getInstance(), new int[] { 0x10 }, Constants.REQUEST_SET_ANALOGS, 19, 0,
new ComfoAirCommandType[] { RF_MODE, RF_NEGATIVE, RF_MIN, RF_MAX, RF_VALUE }, Constants.REQUEST_GET_ANALOGS,
Constants.REPLY_GET_ANALOGS, new int[] { 0 }, 0x10);
private final String key;
private final ComfoAirDataType dataType;
/*
* Possible values
*/
private final int @Nullable [] possibleValues;
/*
* Cmd code to change properties on the comfoair.
*/
private final int changeCommand;
/*
* The size of the data block.
*/
private final int changeDataSize;
/*
* The byte inside the data block which holds the crucial value.
*/
private final int changeDataPos;
/*
* Affected commands which should be refreshed after a successful change
* command call.
*/
private final ComfoAirCommandType @Nullable [] changeAffected;
/*
* Command for reading properties.
*/
private final int readCommand;
/*
* ACK Command which identifies the matching response.
*/
private final int readReplyCommand;
/*
* The byte position inside the response data.
*/
private final int @Nullable [] readReplyDataPos;
/*
* Bit mask for boolean response properties to identify a true value.
*/
private final int readReplyDataBits;
/*
* Constructor for full read/write command
*/
private ComfoAirCommandType(String key, ComfoAirDataType dataType, int @Nullable [] possibleValues,
int changeCommand, int changeDataSize, int changeDataPos, ComfoAirCommandType @Nullable [] changeAffected,
int readCommand, int readReplyCommand, int @Nullable [] readReplyDataPos, int readReplyDataBits) {
this.key = key;
this.dataType = dataType;
this.possibleValues = possibleValues;
this.changeCommand = changeCommand;
this.changeDataSize = changeDataSize;
this.changeDataPos = changeDataPos;
this.changeAffected = changeAffected;
this.readCommand = readCommand;
this.readReplyCommand = readReplyCommand;
this.readReplyDataPos = readReplyDataPos;
this.readReplyDataBits = readReplyDataBits;
}
/*
* Constructor for read/write command w/o predefined readReplyDataBits
*/
private ComfoAirCommandType(String key, ComfoAirDataType dataType, int[] possibleValues, int changeCommand,
int changeDataSize, int changeDataPos, ComfoAirCommandType[] changeAffected, int readCommand,
int readReplyCommand, int[] readReplyDataPos) {
this(key, dataType, possibleValues, changeCommand, changeDataSize, changeDataPos, changeAffected, readCommand,
readReplyCommand, readReplyDataPos, 0);
}
/*
* Constructor for read/write command w/o predefined readReplyDataBits & possibleValues
*/
private ComfoAirCommandType(String key, ComfoAirDataType dataType, int changeCommand, int changeDataSize,
int changeDataPos, ComfoAirCommandType[] changeAffected, int readCommand, int readReplyCommand,
int[] readReplyDataPos) {
this(key, dataType, null, changeCommand, changeDataSize, changeDataPos, changeAffected, readCommand,
readReplyCommand, readReplyDataPos, 0);
}
/*
* Constructor for write-only command (reset)
*/
private ComfoAirCommandType(String key, ComfoAirDataType dataType, int[] possibleValues, int changeCommand,
int changeDataSize, int changeDataPos, ComfoAirCommandType[] changeAffected) {
this(key, dataType, possibleValues, changeCommand, changeDataSize, changeDataPos, changeAffected, 0, 0, null,
0);
}
/*
* Constructor for read-only command
*/
private ComfoAirCommandType(String key, ComfoAirDataType dataType, int readCommand, int readReplyCommand,
int[] readReplyDataPos, int readReplyDataBits) {
this(key, dataType, null, 0, 0, 0, null, readCommand, readReplyCommand, readReplyDataPos, readReplyDataBits);
}
/*
* Constructor for read-only command w/o readReplyDataBits
*/
private ComfoAirCommandType(String key, ComfoAirDataType dataType, int readCommand, int readReplyCommand,
int[] readReplyDataPos) {
this(key, dataType, null, 0, 0, 0, null, readCommand, readReplyCommand, readReplyDataPos, 0);
}
public static class Constants {
public static final int REQUEST_GET_INPUTS = 0x03;
public static final int REPLY_GET_INPUTS = 0x04;
public static final int REQUEST_GET_FAN = 0x0b;
public static final int REPLY_GET_FAN = 0x0c;
public static final int REQUEST_GET_ANALOG_VOLTS = 0x13;
public static final int REPLY_GET_ANALOG_VOLTS = 0x14;
public static final int REQUEST_GET_FIRMWARE = 0x69;
public static final int REPLY_GET_FIRMWARE = 0x6a;
public static final int REQUEST_GET_SENSORS = 0x97;
public static final int REPLY_GET_SENSORS = 0x98;
public static final int REQUEST_SET_LEVEL = 0x99;
public static final int REQUEST_SET_RS232 = 0x9b;
public static final int REPLY_SET_RS232 = 0x9c;
public static final int REQUEST_GET_ANALOGS = 0x9d;
public static final int REPLY_GET_ANALOGS = 0x9e;
public static final int REQUEST_SET_ANALOGS = 0x9f;
public static final int REQUEST_GET_DELAYS = 0xc9;
public static final int REPLY_GET_DELAYS = 0xca;
public static final int REQUEST_SET_DELAYS = 0xcb;
public static final int REQUEST_GET_FAN_LEVEL = 0xcd;
public static final int REPLY_GET_FAN_LEVEL = 0xce;
public static final int REQUEST_SET_FAN_LEVEL = 0xcf;
public static final int REQUEST_GET_TEMPS = 0xd1;
public static final int REPLY_GET_TEMPS = 0xd2;
public static final int REQUEST_SET_TEMPS = 0xd3;
public static final int REQUEST_GET_STATES = 0xd5;
public static final int REPLY_GET_STATES = 0xd6;
public static final int REQUEST_SET_STATES = 0xd7;
public static final int REQUEST_GET_ERRORS = 0xd9;
public static final int REPLY_GET_ERRORS = 0xda;
public static final int REQUEST_SET_RESETS = 0xdb;
public static final int REQUEST_GET_HOURS = 0xdd;
public static final int REPLY_GET_HOURS = 0xde;
public static final int REQUEST_GET_BYPASS = 0xdf;
public static final int REPLY_GET_BYPASS = 0xe0;
public static final int REQUEST_GET_PREHEATER = 0xe1;
public static final int REPLY_GET_PREHEATER = 0xe2;
public static final int REQUEST_GET_RF = 0xe5;
public static final int REPLY_GET_RF = 0xe6;
public static final int REQUEST_GET_EWT = 0xeb;
public static final int REPLY_GET_EWT = 0xec;
public static final int REQUEST_SET_EWT = 0xed;
public static final String[] EMPTY_STRING_ARRAY = new String[0];
public static final int[] EMPTY_INT_ARRAY = new int[0];
public static final ComfoAirCommandType[] EMPTY_TYPE_ARRAY = new ComfoAirCommandType[0];
}
/**
* @return command key
*/
public String getKey() {
return key;
}
/**
* @return data type for this command key
*/
public ComfoAirDataType getDataType() {
return dataType;
}
/**
* @return readCommand for this command key
*/
public int getReadCommand() {
return readCommand;
}
/**
* @return readCommand for this command key
*/
public int getReadReplyCommand() {
return readReplyCommand;
}
/**
* @return possible byte values
*/
public int @Nullable [] getPossibleValues() {
return possibleValues;
}
/**
* @return relevant byte position inside the response byte value array
*/
public int getChangeDataPos() {
return changeDataPos;
}
/**
* @return generate a byte value sequence for the response stream
*/
public int[] getChangeDataTemplate() {
int[] template = new int[changeDataSize];
for (int i = 0; i < template.length; i++) {
template[i] = 0x00;
}
return template;
}
/**
* @return byte position inside the request byte value array
*/
public int @Nullable [] getReadReplyDataPos() {
return readReplyDataPos;
}
/**
* @return bit mask for the response byte value
*/
public int getReadReplyDataBits() {
return readReplyDataBits;
}
/**
* Get single read command to update item.
*
* @param key
*
* @return ComfoAirCommand identified by key
*/
public static @Nullable ComfoAirCommand getReadCommand(String key) {
ComfoAirCommandType commandType = getCommandTypeByKey(key);
if (commandType != null) {
return new ComfoAirCommand(key);
}
return null;
}
/**
* Get a command to change properties on the comfoair.
*
* @param key
* command key
* @param value
* new state
* @return initialized ComfoAirCommand
*/
public static @Nullable ComfoAirCommand getChangeCommand(String key, Command command) {
ComfoAirCommandType commandType = getCommandTypeByKey(key);
State value = UnDefType.NULL;
if (commandType != null) {
ComfoAirDataType dataType = commandType.getDataType();
if (dataType == DataTypeBoolean.getInstance() || dataType == DataTypeNumber.getInstance()
|| dataType == DataTypeRPM.getInstance() || command instanceof QuantityType<?>) {
value = (State) command;
}
if (value instanceof UnDefType) {
return null;
} else {
int[] data = dataType.convertFromState(value, commandType);
DecimalType decimalValue = value.as(DecimalType.class);
if (decimalValue != null) {
int intValue = decimalValue.intValue();
if (data != null) {
int dataPosition = commandType.getChangeDataPos();
return new ComfoAirCommand(key, commandType.changeCommand, null, data, dataPosition, intValue);
}
}
}
}
return null;
}
/**
* Get all commands which should be refreshed after a successful change
* command.
*
* @param key
* command key
* @param usedKeys
* @return ComfoAirCommand's which should be updated after a modifying
* ComfoAirCommand named by key
*/
public static Collection<ComfoAirCommand> getAffectedReadCommands(String key, Set<String> usedKeys) {
Map<Integer, ComfoAirCommand> commands = new HashMap<>();
ComfoAirCommandType commandType = getCommandTypeByKey(key);
if (commandType != null) {
uniteCommandsMap(commands, commandType);
if (commandType.changeAffected != null) {
for (ComfoAirCommandType affectedCommandType : commandType.changeAffected) {
// refresh affected event keys only when they are used
if (usedKeys.contains(affectedCommandType.getKey())) {
uniteCommandsMap(commands, affectedCommandType);
}
}
}
}
return commands.values();
}
/**
* Get all commands which receive informations to update items.
*
* @return all ComfoAirCommand's identified by keys
*/
public static Collection<ComfoAirCommand> getReadCommandsByEventTypes(List<String> keys) {
Map<Integer, ComfoAirCommand> commands = new HashMap<>();
for (ComfoAirCommandType entry : values()) {
if (keys.contains(entry.key)) {
uniteCommandsMap(commands, entry);
}
}
return commands.values();
}
/**
* Get commandtypes which matches the replyCmd.
*
* @param replyCmd
* reply command byte value
* @return ComfoAirCommandType identified by replyCmd
*/
public static List<ComfoAirCommandType> getCommandTypesByReplyCmd(int replyCmd) {
List<ComfoAirCommandType> commands = new ArrayList<>();
for (ComfoAirCommandType entry : values()) {
if (entry.readReplyCommand == replyCmd) {
commands.add(entry);
}
}
return commands;
}
/**
* Get a specific command.
*
* @param key
* command key
* @return ComfoAirCommandType identified by key
*/
public static @Nullable ComfoAirCommandType getCommandTypeByKey(String key) {
for (ComfoAirCommandType entry : values()) {
if (entry.key.equals(key)) {
return entry;
}
}
return null;
}
@SuppressWarnings("null")
private static void uniteCommandsMap(Map<Integer, ComfoAirCommand> commands, ComfoAirCommandType commandType) {
if (commandType.readReplyCommand != 0) {
int replyCmd = commandType.readReplyCommand;
ComfoAirCommand command = commands.get(replyCmd);
if (command == null) {
command = new ComfoAirCommand(commandType.key);
commands.put(replyCmd, command);
} else {
command.addKey(commandType.key);
}
}
}
}

View File

@@ -0,0 +1,34 @@
/**
* 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.comfoair.internal;
import org.eclipse.jdt.annotation.NonNullByDefault;
/**
* The {@link ComfoAirConfiguration} class contains fields mapping thing configuration parameters.
*
* @author Hans Böhm - Initial contribution
*/
@NonNullByDefault
public class ComfoAirConfiguration {
/**
* Serial port used for communication.
*/
public String serialPort = "";
/**
* Polling interval for state refresh.
*/
public int refreshInterval;
}

View File

@@ -0,0 +1,438 @@
/**
* 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.comfoair.internal;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.binding.comfoair.internal.datatypes.ComfoAirDataType;
import org.openhab.core.io.transport.serial.SerialPortManager;
import org.openhab.core.thing.Channel;
import org.openhab.core.thing.ChannelUID;
import org.openhab.core.thing.Thing;
import org.openhab.core.thing.ThingStatus;
import org.openhab.core.thing.ThingStatusDetail;
import org.openhab.core.thing.binding.BaseThingHandler;
import org.openhab.core.thing.binding.builder.ThingBuilder;
import org.openhab.core.types.Command;
import org.openhab.core.types.RefreshType;
import org.openhab.core.types.State;
import org.openhab.core.types.UnDefType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* The {@link ComfoAirHandler} is responsible for handling commands, which are
* sent to one of the channels.
*
* @author Hans Böhm - Initial contribution
*/
@NonNullByDefault
public class ComfoAirHandler extends BaseThingHandler {
private static final int DEFAULT_REFRESH_INTERVAL_SEC = 60;
private final Logger logger = LoggerFactory.getLogger(ComfoAirHandler.class);
private final ComfoAirConfiguration config = getConfigAs(ComfoAirConfiguration.class);
private final SerialPortManager serialPortManager;
private @Nullable ScheduledFuture<?> poller;
private @Nullable ScheduledFuture<?> affectedItemsPoller;
private @Nullable ComfoAirSerialConnector comfoAirConnector;
public static final int BAUDRATE = 9600;
public ComfoAirHandler(Thing thing, final SerialPortManager serialPortManager) {
super(thing);
this.serialPortManager = serialPortManager;
}
@Override
public void handleCommand(ChannelUID channelUID, Command command) {
String channelId = channelUID.getId();
if (command instanceof RefreshType) {
Channel channel = this.thing.getChannel(channelUID);
if (channel != null) {
updateChannelState(channel);
}
} else {
ComfoAirCommand changeCommand = ComfoAirCommandType.getChangeCommand(channelId, command);
if (changeCommand != null) {
Set<String> keysToUpdate = getThing().getChannels().stream().map(Channel::getUID).filter(this::isLinked)
.map(ChannelUID::getId).collect(Collectors.toSet());
sendCommand(changeCommand, channelId);
Collection<ComfoAirCommand> affectedReadCommands = ComfoAirCommandType
.getAffectedReadCommands(channelId, keysToUpdate);
if (affectedReadCommands.size() > 0) {
Runnable updateThread = new AffectedItemsUpdateThread(affectedReadCommands);
affectedItemsPoller = scheduler.schedule(updateThread, 3, TimeUnit.SECONDS);
}
} else {
logger.warn("Unhandled command type: {}, channelId: {}", command.toString(), channelId);
}
}
}
@Override
public void initialize() {
String serialPort = this.config.serialPort;
if (serialPort.isEmpty()) {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, "Serial port is not configured.");
return;
} else {
ComfoAirSerialConnector comfoAirConnector = new ComfoAirSerialConnector(serialPortManager, serialPort,
BAUDRATE);
this.comfoAirConnector = comfoAirConnector;
}
updateStatus(ThingStatus.UNKNOWN);
scheduler.submit(this::connect);
}
private void connect() {
if (comfoAirConnector != null) {
try {
comfoAirConnector.open();
if (comfoAirConnector != null) {
updateStatus(ThingStatus.ONLINE);
pullDeviceProperties();
Map<String, String> properties = thing.getProperties();
List<Channel> toBeRemovedChannels = new ArrayList<>();
if (properties.get(ComfoAirBindingConstants.PROPERTY_OPTION_PREHEATER)
.equals(ComfoAirBindingConstants.COMMON_OPTION_STATES[0])) {
toBeRemovedChannels.addAll(getThing()
.getChannelsOfGroup(ComfoAirBindingConstants.CG_PREHEATER_PREFIX.replaceAll("#$", "")));
Channel stateChannel = getThing().getChannel(ComfoAirBindingConstants.CG_MENUP9_PREFIX
+ ComfoAirBindingConstants.CHANNEL_FROST_STATE);
if (stateChannel != null) {
toBeRemovedChannels.add(stateChannel);
}
}
if (properties.get(ComfoAirBindingConstants.PROPERTY_OPTION_BYPASS)
.equals(ComfoAirBindingConstants.COMMON_OPTION_STATES[0])) {
toBeRemovedChannels.addAll(getThing()
.getChannelsOfGroup(ComfoAirBindingConstants.CG_BYPASS_PREFIX.replaceAll("#$", "")));
Channel stateChannel = getThing().getChannel(ComfoAirBindingConstants.CG_MENUP9_PREFIX
+ ComfoAirBindingConstants.CHANNEL_BYPASS_STATE);
if (stateChannel != null) {
toBeRemovedChannels.add(stateChannel);
}
}
if (properties.get(ComfoAirBindingConstants.PROPERTY_OPTION_CHIMNEY)
.equals(ComfoAirBindingConstants.COMMON_OPTION_STATES[0])) {
Channel stateChannel = getThing().getChannel(ComfoAirBindingConstants.CG_MENUP9_PREFIX
+ ComfoAirBindingConstants.CHANNEL_CHIMNEY_STATE);
if (stateChannel != null) {
toBeRemovedChannels.add(stateChannel);
}
}
if (properties.get(ComfoAirBindingConstants.PROPERTY_OPTION_COOKERHOOD)
.equals(ComfoAirBindingConstants.COMMON_OPTION_STATES[0])) {
toBeRemovedChannels.addAll(getThing().getChannelsOfGroup(
ComfoAirBindingConstants.CG_COOKERHOOD_PREFIX.replaceAll("#$", "")));
Channel stateChannel = getThing().getChannel(ComfoAirBindingConstants.CG_MENUP9_PREFIX
+ ComfoAirBindingConstants.CHANNEL_COOKERHOOD_STATE);
if (stateChannel != null) {
toBeRemovedChannels.add(stateChannel);
}
}
if (properties.get(ComfoAirBindingConstants.PROPERTY_OPTION_HEATER)
.equals(ComfoAirBindingConstants.COMMON_OPTION_STATES[0])) {
toBeRemovedChannels.addAll(getThing()
.getChannelsOfGroup(ComfoAirBindingConstants.CG_HEATER_PREFIX.replaceAll("#$", "")));
Channel stateChannel = getThing().getChannel(ComfoAirBindingConstants.CG_MENUP9_PREFIX
+ ComfoAirBindingConstants.CHANNEL_HEATER_STATE);
if (stateChannel != null) {
toBeRemovedChannels.add(stateChannel);
}
}
if (properties.get(ComfoAirBindingConstants.PROPERTY_OPTION_ENTHALPY)
.equals(ComfoAirBindingConstants.COMMON_OPTION_STATES[0])) {
toBeRemovedChannels.addAll(getThing()
.getChannelsOfGroup(ComfoAirBindingConstants.CG_ENTHALPY_PREFIX.replaceAll("#$", "")));
Channel stateChannel = getThing().getChannel(ComfoAirBindingConstants.CG_MENUP9_PREFIX
+ ComfoAirBindingConstants.CHANNEL_ENTHALPY_STATE);
if (stateChannel != null) {
toBeRemovedChannels.add(stateChannel);
}
}
if (properties.get(ComfoAirBindingConstants.PROPERTY_OPTION_EWT)
.equals(ComfoAirBindingConstants.COMMON_OPTION_STATES[0])) {
toBeRemovedChannels.addAll(getThing()
.getChannelsOfGroup(ComfoAirBindingConstants.CG_EWT_PREFIX.replaceAll("#$", "")));
Channel stateChannel = getThing().getChannel(
ComfoAirBindingConstants.CG_MENUP9_PREFIX + ComfoAirBindingConstants.CHANNEL_EWT_STATE);
if (stateChannel != null) {
toBeRemovedChannels.add(stateChannel);
}
}
ThingBuilder builder = editThing().withoutChannels(toBeRemovedChannels);
updateThing(builder.build());
List<Channel> channels = this.thing.getChannels();
poller = scheduler.scheduleWithFixedDelay(() -> {
for (Channel channel : channels) {
updateChannelState(channel);
}
}, 0, (this.config.refreshInterval > 0) ? this.config.refreshInterval
: DEFAULT_REFRESH_INTERVAL_SEC, TimeUnit.SECONDS);
} else {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR);
}
} catch (ComfoAirSerialException e) {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, e.getMessage());
}
} else {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR);
}
}
@Override
public void dispose() {
if (comfoAirConnector != null) {
comfoAirConnector.close();
}
final ScheduledFuture<?> localPoller = poller;
if (localPoller != null) {
localPoller.cancel(true);
poller = null;
}
final ScheduledFuture<?> localAffectedItemsPoller = affectedItemsPoller;
if (localAffectedItemsPoller != null) {
localAffectedItemsPoller.cancel(true);
affectedItemsPoller = null;
}
}
private void updateChannelState(Channel channel) {
if (!isLinked(channel.getUID())) {
return;
}
String commandKey = channel.getUID().getId();
ComfoAirCommand readCommand = ComfoAirCommandType.getReadCommand(commandKey);
if (readCommand != null) {
scheduler.submit(() -> {
State state = sendCommand(readCommand, commandKey);
updateState(channel.getUID(), state);
});
}
}
private State sendCommand(ComfoAirCommand command, String commandKey) {
ComfoAirSerialConnector comfoAirConnector = this.comfoAirConnector;
if (comfoAirConnector != null) {
Integer requestCmd = command.getRequestCmd();
Integer replyCmd = command.getReplyCmd();
int[] requestData = command.getRequestData();
Integer preRequestCmd;
Integer preReplyCmd;
int[] preResponse = ComfoAirCommandType.Constants.EMPTY_INT_ARRAY;
if (requestCmd != null) {
switch (requestCmd) {
case ComfoAirCommandType.Constants.REQUEST_SET_ANALOGS:
preRequestCmd = ComfoAirCommandType.Constants.REQUEST_GET_ANALOGS;
preReplyCmd = ComfoAirCommandType.Constants.REPLY_GET_ANALOGS;
break;
case ComfoAirCommandType.Constants.REQUEST_SET_DELAYS:
preRequestCmd = ComfoAirCommandType.Constants.REQUEST_GET_DELAYS;
preReplyCmd = ComfoAirCommandType.Constants.REPLY_GET_DELAYS;
break;
case ComfoAirCommandType.Constants.REQUEST_SET_FAN_LEVEL:
preRequestCmd = ComfoAirCommandType.Constants.REQUEST_GET_FAN_LEVEL;
preReplyCmd = ComfoAirCommandType.Constants.REPLY_GET_FAN_LEVEL;
break;
case ComfoAirCommandType.Constants.REQUEST_SET_STATES:
preRequestCmd = ComfoAirCommandType.Constants.REQUEST_GET_STATES;
preReplyCmd = ComfoAirCommandType.Constants.REPLY_GET_STATES;
break;
case ComfoAirCommandType.Constants.REQUEST_SET_EWT:
preRequestCmd = ComfoAirCommandType.Constants.REQUEST_GET_EWT;
preReplyCmd = ComfoAirCommandType.Constants.REPLY_GET_EWT;
break;
default:
preRequestCmd = requestCmd;
preReplyCmd = replyCmd;
}
if (!preRequestCmd.equals(requestCmd)) {
command.setRequestCmd(preRequestCmd);
command.setReplyCmd(preReplyCmd);
command.setRequestData(ComfoAirCommandType.Constants.EMPTY_INT_ARRAY);
preResponse = comfoAirConnector.sendCommand(command, ComfoAirCommandType.Constants.EMPTY_INT_ARRAY);
if (preResponse.length <= 0) {
return UnDefType.NULL;
} else {
command.setRequestCmd(requestCmd);
command.setReplyCmd(replyCmd);
command.setRequestData(requestData);
}
}
int[] response = comfoAirConnector.sendCommand(command, preResponse);
if (response.length > 0) {
ComfoAirCommandType comfoAirCommandType = ComfoAirCommandType.getCommandTypeByKey(commandKey);
State value = UnDefType.UNDEF;
if (comfoAirCommandType != null) {
ComfoAirDataType dataType = comfoAirCommandType.getDataType();
value = dataType.convertToState(response, comfoAirCommandType);
}
if (value instanceof UnDefType) {
if (logger.isWarnEnabled()) {
logger.warn("unexpected value for DATA: {}", ComfoAirSerialConnector.dumpData(response));
}
}
return value;
}
}
}
return UnDefType.UNDEF;
}
public void pullDeviceProperties() {
Map<String, String> properties = editProperties();
ComfoAirSerialConnector comfoAirConnector = this.comfoAirConnector;
if (comfoAirConnector != null) {
String[] namedProperties = new String[] { ComfoAirBindingConstants.PROPERTY_SOFTWARE_MAIN_VERSION,
ComfoAirBindingConstants.PROPERTY_SOFTWARE_MINOR_VERSION,
ComfoAirBindingConstants.PROPERTY_DEVICE_NAME };
String[] optionProperties = new String[] { ComfoAirBindingConstants.PROPERTY_OPTION_PREHEATER,
ComfoAirBindingConstants.PROPERTY_OPTION_BYPASS, ComfoAirBindingConstants.PROPERTY_OPTION_RECU_TYPE,
ComfoAirBindingConstants.PROPERTY_OPTION_RECU_SIZE,
ComfoAirBindingConstants.PROPERTY_OPTION_CHIMNEY,
ComfoAirBindingConstants.PROPERTY_OPTION_COOKERHOOD,
ComfoAirBindingConstants.PROPERTY_OPTION_HEATER, ComfoAirBindingConstants.PROPERTY_OPTION_ENTHALPY,
ComfoAirBindingConstants.PROPERTY_OPTION_EWT };
for (String prop : namedProperties) {
ComfoAirCommand readCommand = ComfoAirCommandType.getReadCommand(prop);
if (readCommand != null) {
int[] response = comfoAirConnector.sendCommand(readCommand,
ComfoAirCommandType.Constants.EMPTY_INT_ARRAY);
if (response.length > 0) {
ComfoAirCommandType comfoAirCommandType = ComfoAirCommandType.getCommandTypeByKey(prop);
String value = "";
if (comfoAirCommandType != null) {
ComfoAirDataType dataType = comfoAirCommandType.getDataType();
if (prop.equals(ComfoAirBindingConstants.PROPERTY_DEVICE_NAME)) {
value = dataType.calculateStringValue(response, comfoAirCommandType);
} else {
value = String.valueOf(dataType.calculateNumberValue(response, comfoAirCommandType));
}
}
properties.put(prop, value);
}
}
}
ComfoAirCommand optionsReadCommand = new ComfoAirCommand(ComfoAirBindingConstants.PROPERTY_OPTION_PREHEATER,
ComfoAirCommandType.Constants.REQUEST_GET_STATES, ComfoAirCommandType.Constants.REPLY_GET_STATES,
ComfoAirCommandType.Constants.EMPTY_INT_ARRAY, null, null);
int[] response = comfoAirConnector.sendCommand(optionsReadCommand,
ComfoAirCommandType.Constants.EMPTY_INT_ARRAY);
if (response.length > 0) {
for (String prop : optionProperties) {
ComfoAirCommandType comfoAirCommandType = ComfoAirCommandType.getCommandTypeByKey(prop);
String value = "";
if (comfoAirCommandType != null) {
ComfoAirDataType dataType = comfoAirCommandType.getDataType();
int intValue = dataType.calculateNumberValue(response, comfoAirCommandType);
switch (prop) {
case ComfoAirBindingConstants.PROPERTY_OPTION_RECU_TYPE:
value = intValue == 1 ? "LEFT" : "RIGHT";
break;
case ComfoAirBindingConstants.PROPERTY_OPTION_RECU_SIZE:
value = intValue == 1 ? "BIG" : "SMALL";
break;
case ComfoAirBindingConstants.PROPERTY_OPTION_ENTHALPY:
if (intValue == 1) {
value = ComfoAirBindingConstants.COMMON_OPTION_STATES[1];
} else if (intValue == 2) {
value = "Installed w\\o sensor";
} else {
value = ComfoAirBindingConstants.COMMON_OPTION_STATES[0];
}
break;
case ComfoAirBindingConstants.PROPERTY_OPTION_EWT:
if (intValue == 1) {
value = "Regulated";
} else if (intValue == 2) {
value = "Unregulated";
} else {
value = ComfoAirBindingConstants.COMMON_OPTION_STATES[0];
}
break;
default:
value = intValue > 0 ? ComfoAirBindingConstants.COMMON_OPTION_STATES[1]
: ComfoAirBindingConstants.COMMON_OPTION_STATES[0];
break;
}
}
properties.put(prop, value);
}
}
thing.setProperties(properties);
}
}
private class AffectedItemsUpdateThread implements Runnable {
private Collection<ComfoAirCommand> affectedReadCommands;
public AffectedItemsUpdateThread(Collection<ComfoAirCommand> affectedReadCommands) {
this.affectedReadCommands = affectedReadCommands;
}
@Override
public void run() {
for (ComfoAirCommand readCommand : this.affectedReadCommands) {
Integer replyCmd = readCommand.getReplyCmd();
if (replyCmd != null) {
List<ComfoAirCommandType> commandTypes = ComfoAirCommandType.getCommandTypesByReplyCmd(replyCmd);
for (ComfoAirCommandType commandType : commandTypes) {
String commandKey = commandType.getKey();
sendCommand(readCommand, commandKey);
}
}
}
}
}
}

View File

@@ -0,0 +1,68 @@
/**
* 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.comfoair.internal;
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.Component;
import org.osgi.service.component.annotations.Reference;
/**
* The {@link ComfoAirHandlerFactory} is responsible for creating things and thing
* handlers.
*
* @author Hans Böhm - Initial contribution
*/
@NonNullByDefault
@Component(configurationPid = "binding.comfoair", service = ThingHandlerFactory.class)
public class ComfoAirHandlerFactory extends BaseThingHandlerFactory {
private static final Set<ThingTypeUID> SUPPORTED_THING_TYPES_UIDS = Collections
.singleton(ComfoAirBindingConstants.THING_TYPE_COMFOAIR_GENERIC);
private @NonNullByDefault({}) SerialPortManager serialPortManager;
@Reference
protected void setSerialPortManager(final SerialPortManager serialPortManager) {
this.serialPortManager = serialPortManager;
}
protected void unsetSerialPortManager(final SerialPortManager serialPortManager) {
this.serialPortManager = null;
}
@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 (ComfoAirBindingConstants.THING_TYPE_COMFOAIR_GENERIC.equals(thingTypeUID)) {
return new ComfoAirHandler(thing, serialPortManager);
}
return null;
}
}

View File

@@ -0,0 +1,563 @@
/**
* 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.comfoair.internal;
import java.io.BufferedInputStream;
import java.io.DataInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InterruptedIOException;
import java.io.OutputStream;
import java.util.Arrays;
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.SerialPortIdentifier;
import org.openhab.core.io.transport.serial.SerialPortManager;
import org.openhab.core.io.transport.serial.UnsupportedCommOperationException;
import org.openhab.core.library.types.OnOffType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Connector class for serial communication with ComfoAir device
*
* @author Hans Böhm - Initial contribution
*
*/
@NonNullByDefault
public class ComfoAirSerialConnector {
private final Logger logger = LoggerFactory.getLogger(ComfoAirSerialConnector.class);
private static final byte CTRL = (byte) 0x07;
private static final byte[] START = { CTRL, (byte) 0xf0 };
private static final byte[] END = { CTRL, (byte) 0x0f };
private static final byte[] ACK = { CTRL, (byte) 0xf3 };
private static final int RS232_ENABLED_VALUE = 0x03;
private static final int RS232_DISABLED_VALUE = 0x00;
private boolean isSuspended = true;
private final String serialPortName;
private final int baudRate;
private final SerialPortManager serialPortManager;
private @Nullable SerialPort serialPort;
private @Nullable InputStream inputStream;
private @Nullable OutputStream outputStream;
public ComfoAirSerialConnector(final SerialPortManager serialPortManager, final String serialPortName,
final int baudRate) {
this.serialPortManager = serialPortManager;
this.serialPortName = serialPortName;
this.baudRate = baudRate;
}
/**
* Open serial port.
*
* @throws PortInUseException, UnsupportedCommOperationException, IOException
*/
public void open() throws ComfoAirSerialException {
logger.debug("open(): Opening ComfoAir connection");
try {
SerialPortIdentifier portIdentifier = serialPortManager.getIdentifier(serialPortName);
if (portIdentifier != null) {
SerialPort serialPort = portIdentifier.open(this.getClass().getName(), 3000);
serialPort.setSerialPortParams(baudRate, SerialPort.DATABITS_8, SerialPort.STOPBITS_1,
SerialPort.PARITY_NONE);
serialPort.enableReceiveThreshold(1);
serialPort.enableReceiveTimeout(1000);
serialPort.notifyOnDataAvailable(true);
this.serialPort = serialPort;
inputStream = new DataInputStream(new BufferedInputStream(serialPort.getInputStream()));
outputStream = serialPort.getOutputStream();
ComfoAirCommand command = ComfoAirCommandType.getChangeCommand(ComfoAirCommandType.ACTIVATE.getKey(),
OnOffType.ON);
if (command != null) {
sendCommand(command, ComfoAirCommandType.Constants.EMPTY_INT_ARRAY);
} else {
logger.debug("Failure while creating COMMAND: {}", command);
}
} else {
throw new ComfoAirSerialException("No such Port: " + serialPortName);
}
} catch (PortInUseException | UnsupportedCommOperationException | IOException e) {
throw new ComfoAirSerialException(e);
}
}
/**
* Close serial port.
*/
public void close() {
logger.debug("close(): Close ComfoAir connection");
SerialPort serialPort = this.serialPort;
if (serialPort != null) {
ComfoAirCommand command = ComfoAirCommandType.getChangeCommand(ComfoAirCommandType.ACTIVATE.getKey(),
OnOffType.OFF);
if (command != null) {
sendCommand(command, ComfoAirCommandType.Constants.EMPTY_INT_ARRAY);
} else {
logger.debug("Failure while creating COMMAND: {}", command);
}
if (inputStream != null) {
try {
inputStream.close();
} catch (IOException e) {
logger.debug("Error while closing input stream: {}", e.getMessage());
}
}
if (outputStream != null) {
try {
outputStream.close();
} catch (IOException e) {
logger.debug("Error while closing output stream: {}", e.getMessage());
}
}
serialPort.close();
}
}
/**
* Prepare a command for sending using the serial port.
*
* @param command
* @param preRequestData
* @return reply byte values
*/
public synchronized int[] sendCommand(ComfoAirCommand command, int[] preRequestData) {
Integer requestCmd = command.getRequestCmd();
int retry = 0;
if (requestCmd != null) {
// Switch support for app or ccease control
if (requestCmd == ComfoAirCommandType.Constants.REQUEST_SET_RS232) {
isSuspended = !isSuspended;
} else if (requestCmd == ComfoAirCommandType.Constants.REPLY_SET_RS232) {
return new int[] { isSuspended ? RS232_DISABLED_VALUE : RS232_ENABLED_VALUE };
} else if (isSuspended) {
logger.trace("Ignore cmd. Service is currently suspended");
return ComfoAirCommandType.Constants.EMPTY_INT_ARRAY;
}
do {
// If preRequestData param was send (preRequestData is sending for write command)
int[] requestData;
if (preRequestData.length <= 0) {
requestData = command.getRequestData();
} else {
requestData = buildRequestData(command, preRequestData);
if (requestData.length <= 0) {
logger.debug("Unable to build data for write command: {}",
String.format("%02x", command.getReplyCmd()));
return ComfoAirCommandType.Constants.EMPTY_INT_ARRAY;
}
}
byte[] requestBlock = calculateRequest(requestCmd, requestData);
if (logger.isTraceEnabled()) {
logger.trace("send DATA: {}", dumpData(requestBlock));
}
if (!send(requestBlock)) {
return ComfoAirCommandType.Constants.EMPTY_INT_ARRAY;
}
byte[] responseBlock = new byte[0];
try {
InputStream inputStream = this.inputStream;
// 31 is max. response length
byte[] readBuffer = new byte[31];
do {
while (inputStream != null && inputStream.available() > 0) {
int bytes = inputStream.read(readBuffer);
// merge bytes
byte[] mergedBytes = new byte[responseBlock.length + bytes];
System.arraycopy(responseBlock, 0, mergedBytes, 0, responseBlock.length);
System.arraycopy(readBuffer, 0, mergedBytes, responseBlock.length, bytes);
responseBlock = mergedBytes;
}
try {
// add wait states around reading the stream, so that
// interrupted transmissions are merged
Thread.sleep(100);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
logger.warn("Transmission was interrupted: {}", e.getMessage());
throw new RuntimeException(e);
}
} while (inputStream != null && inputStream.available() > 0);
// check for ACK
if (responseBlock.length >= 2 && responseBlock[0] == ACK[0] && responseBlock[1] == ACK[1]) {
if (command.getReplyCmd() == null) {
// confirm additional data with an ACK
if (responseBlock.length > 2) {
send(ACK);
}
return ComfoAirCommandType.Constants.EMPTY_INT_ARRAY;
}
// check for start and end sequence and if the response cmd
// matches
// 11 is the minimum response length with one data byte
if (responseBlock.length >= 11 && responseBlock[2] == START[0] && responseBlock[3] == START[1]
&& responseBlock[responseBlock.length - 2] == END[0]
&& responseBlock[responseBlock.length - 1] == END[1]
&& (responseBlock[5] & 0xff) == command.getReplyCmd()) {
if (logger.isTraceEnabled()) {
logger.trace("receive RAW DATA: {}", dumpData(responseBlock));
}
byte[] cleanedBlock = cleanupBlock(responseBlock);
int dataSize = cleanedBlock[2];
// the cleanedBlock size should equal dataSize + 2 cmd
// bytes and + 1 checksum byte
if (dataSize + 3 == cleanedBlock.length - 1) {
byte checksum = cleanedBlock[dataSize + 3];
int[] replyData = new int[dataSize];
for (int i = 0; i < dataSize; i++) {
replyData[i] = cleanedBlock[i + 3] & 0xff;
}
byte[] block = Arrays.copyOf(cleanedBlock, 3 + dataSize);
// validate calculated checksum against submitted
// checksum
if (calculateChecksum(block) == checksum) {
if (logger.isTraceEnabled()) {
logger.trace("receive CMD: {} DATA: {}",
String.format("%02x", command.getReplyCmd()), dumpData(replyData));
}
send(ACK);
return replyData;
}
logger.debug("Unable to handle data. Checksum verification failed");
} else {
logger.debug("Unable to handle data. Data size not valid");
}
if (logger.isTraceEnabled()) {
logger.trace("skip CMD: {} DATA: {}", String.format("%02x", command.getReplyCmd()),
dumpData(cleanedBlock));
}
}
}
} catch (InterruptedIOException e) {
Thread.currentThread().interrupt();
logger.warn("Transmission was interrupted: {}", e.getMessage());
throw new RuntimeException(e);
} catch (IOException e) {
logger.debug("IO error: {}", e.getMessage());
}
try {
Thread.sleep(1000);
if (logger.isDebugEnabled()) {
logger.debug("Retry cmd. Last call was not successful. Request: {} Response: {}",
dumpData(requestBlock), (responseBlock.length > 0 ? dumpData(responseBlock) : "null"));
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
logger.warn("Transmission was interrupted: {}", e.getMessage());
throw new RuntimeException(e);
}
} while (retry++ < 5);
if (retry == 5) {
logger.debug("Unable to send command. {} retries failed.", retry);
}
}
return ComfoAirCommandType.Constants.EMPTY_INT_ARRAY;
}
/**
* Generate the byte sequence for sending to ComfoAir (incl. START & END
* sequence and checksum).
*
* @param command
* @param requestData
* @return response byte value block with cmd, data and checksum
*/
private byte[] calculateRequest(int command, int[] requestData) {
// generate the command block (cmd and request data)
int length = requestData.length;
byte[] block = new byte[4 + length];
block[0] = 0x00;
block[1] = (byte) command;
block[2] = (byte) length;
if (requestData.length > 0) {
for (int i = 0; i < requestData.length; i++) {
block[i + 3] = (byte) requestData[i];
}
}
// calculate checksum for command block
byte checksum = calculateChecksum(block);
block[block.length - 1] = checksum;
// escape the command block with checksum included
block = escapeBlock(block);
byte[] request = new byte[4 + block.length];
request[0] = START[0];
request[1] = START[1];
System.arraycopy(block, 0, request, 2, block.length);
request[request.length - 2] = END[0];
request[request.length - 1] = END[1];
return request;
}
/**
* Calculates a checksum for a command block (cmd, data and checksum).
*
* @param block
* @return checksum byte value
*/
private byte calculateChecksum(byte[] block) {
int datasum = 0;
for (int i = 0; i < block.length; i++) {
datasum += block[i];
}
datasum += 173;
return (byte) (datasum & 0xFF);
}
/**
* Cleanup a commandblock from quoted 0x07 characters.
*
* @param processBuffer
* @return the 0x07 cleaned byte values
*/
private byte[] cleanupBlock(byte[] processBuffer) {
int pos = 0;
byte[] cleanedBuffer = new byte[processBuffer.length];
for (int i = 4; i < processBuffer.length - 2; i++) {
if (CTRL == processBuffer[i] && CTRL == processBuffer[i + 1]) {
i++;
}
cleanedBuffer[pos] = processBuffer[i];
pos++;
}
return Arrays.copyOf(cleanedBuffer, pos);
}
/**
* Escape special 0x07 character.
*
* @param cleanedBuffer
* @return escaped byte value array
*/
private byte[] escapeBlock(byte[] cleanedBuffer) {
int pos = 0;
byte[] processBuffer = new byte[50];
for (int i = 0; i < cleanedBuffer.length; i++) {
if (CTRL == cleanedBuffer[i]) {
processBuffer[pos] = CTRL;
pos++;
}
processBuffer[pos] = cleanedBuffer[i];
pos++;
}
return Arrays.copyOf(processBuffer, pos);
}
/**
* Send the byte values.
*
* @param request
* @return successful flag
*/
private boolean send(byte[] request) {
if (logger.isTraceEnabled()) {
logger.trace("send DATA: {}", dumpData(request));
}
try {
if (outputStream != null) {
outputStream.write(request);
}
return true;
} catch (IOException e) {
logger.debug("Error writing to serial port {}: {}", serialPortName, e.getLocalizedMessage());
return false;
}
}
/**
* Is used to debug byte values.
*
* @param replyData
* @return
*/
public static String dumpData(int[] replyData) {
StringBuilder sb = new StringBuilder();
for (int ch : replyData) {
sb.append(String.format(" %02x", ch));
}
return sb.toString();
}
private String dumpData(byte[] data) {
StringBuilder sb = new StringBuilder();
for (byte ch : data) {
sb.append(String.format(" %02x", ch));
}
return sb.toString();
}
/**
* Build request data based on reply data
*
* @param command
* @param preRequestData
* @return new build int values array
*/
private int[] buildRequestData(ComfoAirCommand command, int[] preRequestData) {
int[] newRequestData;
Integer requestCmd = command.getRequestCmd();
Integer dataPosition = command.getDataPosition();
Integer requestValue = command.getRequestValue();
if (requestCmd != null && dataPosition != null && requestValue != null) {
switch (requestCmd) {
case ComfoAirCommandType.Constants.REQUEST_SET_DELAYS:
newRequestData = new int[8];
if (preRequestData.length > 0 && newRequestData.length <= preRequestData.length) {
System.arraycopy(preRequestData, 0, newRequestData, 0, newRequestData.length);
newRequestData[dataPosition] = requestValue;
} else {
return ComfoAirCommandType.Constants.EMPTY_INT_ARRAY;
}
break;
case ComfoAirCommandType.Constants.REQUEST_SET_FAN_LEVEL:
newRequestData = new int[9];
if (preRequestData.length > 0 && newRequestData.length <= preRequestData.length) {
System.arraycopy(preRequestData, 0, newRequestData, 0, 6);
System.arraycopy(preRequestData, 10, newRequestData, 6, newRequestData.length - 6);
newRequestData[dataPosition] = requestValue;
} else {
return ComfoAirCommandType.Constants.EMPTY_INT_ARRAY;
}
break;
case ComfoAirCommandType.Constants.REQUEST_SET_STATES:
newRequestData = new int[8];
if (preRequestData.length > 0 && newRequestData.length <= preRequestData.length) {
if (dataPosition == 4) {
requestValue = preRequestData[dataPosition]
+ checkByteAndCalculateValue(command, requestValue, preRequestData[dataPosition]);
}
System.arraycopy(preRequestData, 0, newRequestData, 0, 6);
System.arraycopy(preRequestData, 9, newRequestData, 6, newRequestData.length - 6);
newRequestData[dataPosition] = requestValue;
} else {
return ComfoAirCommandType.Constants.EMPTY_INT_ARRAY;
}
break;
case ComfoAirCommandType.Constants.REQUEST_SET_EWT:
newRequestData = new int[5];
if (preRequestData.length > 0 && newRequestData.length <= preRequestData.length) {
System.arraycopy(preRequestData, 0, newRequestData, 0, 4);
System.arraycopy(preRequestData, 6, newRequestData, 4, newRequestData.length - 4);
newRequestData[dataPosition] = requestValue;
} else {
return ComfoAirCommandType.Constants.EMPTY_INT_ARRAY;
}
break;
case ComfoAirCommandType.Constants.REQUEST_SET_ANALOGS:
newRequestData = new int[19];
if (preRequestData.length > 0 && newRequestData.length <= preRequestData.length) {
switch (dataPosition) {
case 0:
case 1:
case 2:
requestValue = preRequestData[dataPosition] + checkByteAndCalculateValue(command,
requestValue, preRequestData[dataPosition]);
}
System.arraycopy(preRequestData, 0, newRequestData, 0, newRequestData.length);
newRequestData[dataPosition] = requestValue;
} else {
return ComfoAirCommandType.Constants.EMPTY_INT_ARRAY;
}
break;
default:
return ComfoAirCommandType.Constants.EMPTY_INT_ARRAY;
}
return newRequestData;
} else {
return ComfoAirCommandType.Constants.EMPTY_INT_ARRAY;
}
}
/**
* Check if preValue contains possible byte and calculate new value
*
* @param command
* @param requestValue
* @param preValue
* @return new int value
*/
private int checkByteAndCalculateValue(ComfoAirCommand command, int requestValue, int preValue) {
String key = command.getKeys().get(0);
ComfoAirCommandType commandType = ComfoAirCommandType.getCommandTypeByKey(key);
if (commandType != null) {
int[] possibleValues = commandType.getPossibleValues();
if (possibleValues != null) {
int possibleValue = possibleValues[0];
boolean isActive = (preValue & possibleValue) == possibleValue;
int newValue;
if (isActive) {
newValue = requestValue == 1 ? 0 : -possibleValue;
} else {
newValue = requestValue == 1 ? possibleValue : 0;
}
return newValue;
}
}
return 0;
}
}

View File

@@ -0,0 +1,37 @@
/**
* 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.comfoair.internal;
import org.eclipse.jdt.annotation.NonNullByDefault;
/**
* The {@link ConnectException} is thrown on errors relating the serial connection.
*
* @author Hans Böhm - Initial contribution
*/
@NonNullByDefault
public class ComfoAirSerialException extends Exception {
private static final long serialVersionUID = 5439939653331189828L;
public ComfoAirSerialException(Throwable cause) {
super(cause);
}
public ComfoAirSerialException(String message) {
super(message);
}
public ComfoAirSerialException(String message, Exception e) {
super(message, e);
}
}

View File

@@ -0,0 +1,79 @@
/**
* 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.comfoair.internal.datatypes;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.binding.comfoair.internal.ComfoAirCommandType;
import org.openhab.core.types.State;
/**
* Abstract class to convert binary hex values into openHAB states and vice
* versa
*
* @author Holger Hees - Initial Contribution
* @author Hans Böhm - Refactoring
*/
@NonNullByDefault
public interface ComfoAirDataType {
/**
* Generate a openHAB State object based on response data.
*
* @param response
* @param commandType
* @return converted State object
*/
State convertToState(int[] response, ComfoAirCommandType commandType);
/**
* Generate byte array based on a openHAB State.
*
* @param value
* @param commandType
* @return converted byte array
*/
int @Nullable [] convertFromState(State value, ComfoAirCommandType commandType);
default int calculateNumberValue(int[] data, ComfoAirCommandType commandType) {
int[] readReplyDataPos = commandType.getReadReplyDataPos();
int value = 0;
if (readReplyDataPos != null) {
int base = 0;
for (int i = readReplyDataPos.length - 1; i >= 0; i--) {
if (readReplyDataPos[i] < data.length) {
value += data[readReplyDataPos[i]] << base;
base += 8;
} else {
return -1;
}
}
} else {
value = -1;
}
return value;
}
default String calculateStringValue(int[] data, ComfoAirCommandType commandType) {
int[] readReplyDataPos = commandType.getReadReplyDataPos();
StringBuilder value = new StringBuilder();
if (readReplyDataPos != null) {
for (int pos : readReplyDataPos) {
if (pos < data.length) {
value.append((char) data[pos]);
}
}
}
return value.toString();
}
}

View File

@@ -0,0 +1,97 @@
/**
* 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.comfoair.internal.datatypes;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.binding.comfoair.internal.ComfoAirCommandType;
import org.openhab.core.library.types.DecimalType;
import org.openhab.core.library.types.OnOffType;
import org.openhab.core.types.State;
import org.openhab.core.types.UnDefType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Class to handle boolean values which are handled as decimal 0/1 states
*
* @author Holger Hees - Initial Contribution
* @author Hans Böhm - Refactoring
*/
@NonNullByDefault
public class DataTypeBoolean implements ComfoAirDataType {
private static final DataTypeBoolean SINGLETON_INSTANCE = new DataTypeBoolean();
private DataTypeBoolean() {
}
private final Logger logger = LoggerFactory.getLogger(DataTypeBoolean.class);
public static DataTypeBoolean getInstance() {
return SINGLETON_INSTANCE;
}
@Override
public State convertToState(int @Nullable [] data, ComfoAirCommandType commandType) {
if (data == null) {
logger.trace("\"DataTypeBoolean\" class \"convertToState\" method parameter: null");
return UnDefType.NULL;
} else {
int[] readReplyDataPos = commandType.getReadReplyDataPos();
int readReplyDataBits = commandType.getReadReplyDataBits();
int readCommand = commandType.getReadCommand();
boolean result;
if (readReplyDataPos != null && readReplyDataPos[0] < data.length) {
if (readReplyDataBits == 0) {
result = data[readReplyDataPos[0]] == 1;
} else {
result = (data[readReplyDataPos[0]] & readReplyDataBits) == readReplyDataBits;
}
return OnOffType.from(result);
} else if (readCommand == 0) {
return OnOffType.OFF; // handle write-only commands (resets)
} else {
return UnDefType.NULL;
}
}
}
@Override
public int @Nullable [] convertFromState(State value, ComfoAirCommandType commandType) {
if (value instanceof UnDefType) {
logger.trace("\"DataTypeBoolean\" class \"convertFromState\" undefined state");
return null;
} else {
DecimalType decimalValue = value.as(DecimalType.class);
int[] possibleValues = commandType.getPossibleValues();
int returnValue = 0x01;
if (possibleValues != null) {
returnValue = possibleValues[0];
}
if (decimalValue != null) {
int[] template = commandType.getChangeDataTemplate();
template[commandType.getChangeDataPos()] = decimalValue.intValue() == 1 ? returnValue : 0x00;
return template;
} else {
logger.trace(
"\"DataTypeBoolean\" class \"convertFromState\" method: State value conversion returned null");
return null;
}
}
}
}

View File

@@ -0,0 +1,117 @@
/**
* 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.comfoair.internal.datatypes;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.binding.comfoair.internal.ComfoAirCommandType;
import org.openhab.core.library.types.StringType;
import org.openhab.core.types.State;
import org.openhab.core.types.UnDefType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Class to handle error messages
*
* @author Holger Hees - Initial Contribution
* @author Hans Böhm - Refactoring
*/
@NonNullByDefault
public class DataTypeMessage implements ComfoAirDataType {
private static final DataTypeMessage SINGLETON_INSTANCE = new DataTypeMessage();
private DataTypeMessage() {
}
private final Logger logger = LoggerFactory.getLogger(DataTypeMessage.class);
public static DataTypeMessage getInstance() {
return SINGLETON_INSTANCE;
}
@Override
public State convertToState(int @Nullable [] data, ComfoAirCommandType commandType) {
if (data == null) {
logger.trace("\"DataTypeMessage\" class \"convertToState\" method parameter: null");
return UnDefType.NULL;
} else {
int[] readReplyDataPos = commandType.getReadReplyDataPos();
if (readReplyDataPos != null) {
int errorAlo = data[readReplyDataPos[0]];
int errorE = data[readReplyDataPos[1]];
int errorEA = data[readReplyDataPos[2]];
int errorAhi = data[readReplyDataPos[3]];
StringBuilder errorCode = new StringBuilder();
if (errorAlo > 0) {
errorCode.append("A");
errorCode.append(convertToCode(errorAlo));
} else if (errorAhi > 0) {
if (errorAhi == 0x80) {
errorCode.append("A0");
} else {
errorCode.append("A");
errorCode.append(convertToCode(errorAhi) + 8);
}
}
if (errorE > 0) {
if (errorCode.length() > 0) {
errorCode.append(" ");
}
errorCode.append("E");
errorCode.append(convertToCode(errorE));
} else if (errorEA > 0) {
if (errorCode.length() > 0) {
errorCode.append(" ");
}
errorCode.append("EA");
errorCode.append(convertToCode(errorEA));
}
return new StringType(errorCode.length() > 0 ? errorCode.toString() : "No Errors");
} else {
return UnDefType.UNDEF;
}
}
}
@Override
public int @Nullable [] convertFromState(State value, ComfoAirCommandType commandType) {
return null;
}
private int convertToCode(int code) {
switch (code) {
case 0x01:
return 1;
case 0x02:
return 2;
case 0x04:
return 3;
case 0x08:
return 4;
case 0x10:
return 5;
case 0x20:
return 6;
case 0x40:
return 7;
case 0x80:
return 8;
default:
return -1;
}
}
}

View File

@@ -0,0 +1,97 @@
/**
* 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.comfoair.internal.datatypes;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.binding.comfoair.internal.ComfoAirCommandType;
import org.openhab.core.library.types.DecimalType;
import org.openhab.core.types.State;
import org.openhab.core.types.UnDefType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Class to handle numeric values
*
* @author Holger Hees - Initial Contribution
* @author Hans Böhm - Refactoring
*/
@NonNullByDefault
public class DataTypeNumber implements ComfoAirDataType {
private static final DataTypeNumber SINGLETON_INSTANCE = new DataTypeNumber();
private DataTypeNumber() {
}
private final Logger logger = LoggerFactory.getLogger(DataTypeNumber.class);
public static DataTypeNumber getInstance() {
return SINGLETON_INSTANCE;
}
@Override
public State convertToState(int @Nullable [] data, ComfoAirCommandType commandType) {
if (data == null) {
logger.trace("\"DataTypeNumber\" class \"convertToState\" method parameter: null");
return UnDefType.NULL;
} else {
int value = calculateNumberValue(data, commandType);
if (value < 0) {
return UnDefType.NULL;
}
int[] possibleValues = commandType.getPossibleValues();
if (possibleValues != null) {
// fix for unexpected value for "level" value. got a 0x33. valid was
// the 0x03. 0x30 was to much.
// send DATA: 07 f0 00 cd 00 7a 07 0f
// receive CMD: ce DATA: 0f 20 32 00 0f 21 33 2d 33 03 01 5a 5b 00
for (int possibleValue : possibleValues) {
if ((value & possibleValue) == possibleValue) {
return new DecimalType(value);
}
}
return UnDefType.NULL;
}
return new DecimalType(value);
}
}
@Override
public int @Nullable [] convertFromState(State value, ComfoAirCommandType commandType) {
if (value instanceof UnDefType) {
logger.trace("\"DataTypeNumber\" class \"convertFromState\" undefined state");
return null;
} else {
int[] template = commandType.getChangeDataTemplate();
int[] possibleValues = commandType.getPossibleValues();
int position = commandType.getChangeDataPos();
int intValue = ((DecimalType) value).intValue();
if (possibleValues == null) {
template[position] = intValue;
} else {
for (int i = 0; i < possibleValues.length; i++) {
if (possibleValues[i] == intValue) {
template[position] = intValue;
break;
}
}
}
return template;
}
}
}

View File

@@ -0,0 +1,71 @@
/**
* 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.comfoair.internal.datatypes;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.binding.comfoair.internal.ComfoAirCommandType;
import org.openhab.core.library.types.DecimalType;
import org.openhab.core.types.State;
import org.openhab.core.types.UnDefType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Class to handle revolutions per minute values
*
* @author Grzegorz Miasko - Initial Contribution
* @author Hans Böhm - Refactoring
*/
@NonNullByDefault
public class DataTypeRPM implements ComfoAirDataType {
private static final DataTypeRPM SINGLETON_INSTANCE = new DataTypeRPM();
private DataTypeRPM() {
}
private final Logger logger = LoggerFactory.getLogger(DataTypeRPM.class);
public static DataTypeRPM getInstance() {
return SINGLETON_INSTANCE;
}
@Override
public State convertToState(int @Nullable [] data, ComfoAirCommandType commandType) {
if (data == null) {
logger.trace("\"DataTypeRPM\" class \"convertToState\" method parameter: null");
return UnDefType.NULL;
} else {
int value = calculateNumberValue(data, commandType);
if (value < 0) {
return UnDefType.NULL;
}
// transferred value is (1875000 / rpm) per protocol
return new DecimalType((int) (1875000.0 / value));
}
}
@Override
public int @Nullable [] convertFromState(State value, ComfoAirCommandType commandType) {
if (value instanceof UnDefType) {
logger.trace("\"DataTypeRPM\" class \"convertFromState\" undefined state");
return null;
} else {
int[] template = commandType.getChangeDataTemplate();
// transferred value is (1875000 / rpm) per protocol
template[commandType.getChangeDataPos()] = (int) (1875000 / ((DecimalType) value).doubleValue());
return template;
}
}
}

View File

@@ -0,0 +1,72 @@
/**
* 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.comfoair.internal.datatypes;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.binding.comfoair.internal.ComfoAirCommandType;
import org.openhab.core.library.types.QuantityType;
import org.openhab.core.library.unit.SIUnits;
import org.openhab.core.types.State;
import org.openhab.core.types.UnDefType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Class to handle temperature values
*
* @author Holger Hees - Initial Contribution
* @author Hans Böhm - QuantityTypes
*/
@NonNullByDefault
public class DataTypeTemperature implements ComfoAirDataType {
private static final DataTypeTemperature SINGLETON_INSTANCE = new DataTypeTemperature();
private DataTypeTemperature() {
}
private final Logger logger = LoggerFactory.getLogger(DataTypeTemperature.class);
public static DataTypeTemperature getInstance() {
return SINGLETON_INSTANCE;
}
@Override
public State convertToState(int @Nullable [] data, ComfoAirCommandType commandType) {
if (data == null) {
logger.trace("\"DataTypeTemperature\" class \"convertToState\" method parameter: null");
return UnDefType.NULL;
} else {
int[] readReplyDataPos = commandType.getReadReplyDataPos();
if (readReplyDataPos != null && readReplyDataPos[0] < data.length) {
return new QuantityType<>((((double) data[readReplyDataPos[0]]) / 2) - 20, SIUnits.CELSIUS);
} else {
return UnDefType.NULL;
}
}
}
@Override
public int @Nullable [] convertFromState(State value, ComfoAirCommandType commandType) {
int[] template = commandType.getChangeDataTemplate();
QuantityType<?> celsius = ((QuantityType<?>) value).toUnit(SIUnits.CELSIUS);
if (celsius != null) {
template[commandType.getChangeDataPos()] = (int) (celsius.doubleValue() + 20) * 2;
return template;
} else {
logger.trace("\"DataTypeTemperature\" class \"convertFromState\" undefined state");
return null;
}
}
}

View File

@@ -0,0 +1,85 @@
/**
* 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.comfoair.internal.datatypes;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.binding.comfoair.internal.ComfoAirCommandType;
import org.openhab.core.library.types.QuantityType;
import org.openhab.core.library.unit.SmartHomeUnits;
import org.openhab.core.types.State;
import org.openhab.core.types.UnDefType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Class to handle time values
*
* @author Hans Böhm - Initial Contribution
*/
@NonNullByDefault
public class DataTypeTime implements ComfoAirDataType {
private static final DataTypeTime SINGLETON_INSTANCE = new DataTypeTime();
private DataTypeTime() {
}
private final Logger logger = LoggerFactory.getLogger(DataTypeTime.class);
public static DataTypeTime getInstance() {
return SINGLETON_INSTANCE;
}
@Override
public State convertToState(int @Nullable [] data, ComfoAirCommandType commandType) {
if (data == null) {
logger.trace("\"DataTypeTime\" class \"convertToState\" method parameter: null");
return UnDefType.NULL;
} else {
int value = calculateNumberValue(data, commandType);
if (value < 0) {
return UnDefType.NULL;
}
return new QuantityType<>(value, SmartHomeUnits.HOUR);
}
}
@Override
public int @Nullable [] convertFromState(State value, ComfoAirCommandType commandType) {
int[] template = commandType.getChangeDataTemplate();
int[] possibleValues = commandType.getPossibleValues();
int position = commandType.getChangeDataPos();
QuantityType<?> hours = ((QuantityType<?>) value).toUnit(SmartHomeUnits.HOUR);
if (hours != null) {
int intValue = hours.intValue();
if (possibleValues == null) {
template[position] = intValue;
} else {
for (int i = 0; i < possibleValues.length; i++) {
if (possibleValues[i] == intValue) {
template[position] = intValue;
break;
}
}
}
return template;
} else {
logger.trace("\"DataTypeTime\" class \"convertFromState\" undefined state");
return null;
}
}
}

View File

@@ -0,0 +1,72 @@
/**
* 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.comfoair.internal.datatypes;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.binding.comfoair.internal.ComfoAirCommandType;
import org.openhab.core.library.types.QuantityType;
import org.openhab.core.library.unit.SmartHomeUnits;
import org.openhab.core.types.State;
import org.openhab.core.types.UnDefType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Class to handle volt values
*
* @author Grzegorz Miasko - Initial Contribution
* @author Hans Böhm - QuantityTypes
*/
@NonNullByDefault
public class DataTypeVolt implements ComfoAirDataType {
private static final DataTypeVolt SINGLETON_INSTANCE = new DataTypeVolt();
private DataTypeVolt() {
}
private final Logger logger = LoggerFactory.getLogger(DataTypeVolt.class);
public static DataTypeVolt getInstance() {
return SINGLETON_INSTANCE;
}
@Override
public State convertToState(int @Nullable [] data, ComfoAirCommandType commandType) {
if (data == null) {
logger.trace("\"DataTypeVolt\" class \"convertToState\" method parameter: null");
return UnDefType.NULL;
} else {
int[] readReplyDataPos = commandType.getReadReplyDataPos();
if (readReplyDataPos != null && readReplyDataPos[0] < data.length) {
return new QuantityType<>((double) data[readReplyDataPos[0]] * 10 / 255, SmartHomeUnits.VOLT);
} else {
return UnDefType.NULL;
}
}
}
@Override
public int @Nullable [] convertFromState(State value, ComfoAirCommandType commandType) {
int[] template = commandType.getChangeDataTemplate();
QuantityType<?> volts = ((QuantityType<?>) value).toUnit(SmartHomeUnits.VOLT);
if (volts != null) {
template[commandType.getChangeDataPos()] = (int) (volts.doubleValue() * 255 / 10);
return template;
} else {
logger.trace("\"DataTypeVolt\" class \"convertFromState\" undefined state");
return null;
}
}
}

View File

@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<binding:binding id="comfoair" 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>ComfoAir Binding</name>
<description>This is the binding for ComfoAir.</description>
<author>Hans Böhm</author>
</binding:binding>

View File

@@ -0,0 +1,237 @@
# binding
binding.comfoair.comfoair.name = ComfoAir Binding
binding.comfoair.comfoair.description = ComfoAir Wohnraumlüftung
# thing types
thing-type.comfoair.comfoair.label = ComfoAir Wohnraumlüftung
thing-type.comfoair.comfoair.description = Serielle Verbindung zu einer ComfoAir-kompatiblen Lüftungsanlage
# thing type configuration
thing-type.config.comfoair.comfoair.serialPort.label = Serieller Port
thing-type.config.comfoair.comfoair.serialPort.description = Serieller Port über den die Lüftungsanlage verbunden ist
thing-type.config.comfoair.comfoair.refreshInterval.label = Aktualisierungsinterval
thing-type.config.comfoair.comfoair.refreshInterval.description = Aktualisierungsinterval in Sekunden
# channel type
channel-type.comfoair.activate.label = Steuerung aktivieren
channel-type.comfoair.activate.description = Kontrolle aktivieren (über openHAB) oder deaktivieren (zurück auf CCEase)
channel-type.comfoair.fan_evel.label = Lüftungsstufe
channel-type.comfoair.fan_evel.description = Lüftungsstufe
channel-type.comfoair.target_temperature.label = Zieltemperatur
channel-type.comfoair.target_temperature.description = Ziel- bzw. Komforttemperatur
channel-type.comfoair.filter_error.label = Filterfehler
channel-type.comfoair.filter_error.description = Filter voll
channel-type.comfoair.filter_reset.label = Filterzähler Zurücksetzen
channel-type.comfoair.filter_reset.description = Zurücksetzen der Filterlaufzeit
channel-type.comfoair.error_reset.label = Fehler Zurücksetzen
channel-type.comfoair.error_reset.description = Zurücksetzen der Fehlermeldungen
channel-type.comfoair.fan_out_0.label = Abluftstufe 0 (abwesend)
channel-type.comfoair.fan_out_0.description = Lüftungsleistung (%) des Abluftventilators auf Stufe 0
channel-type.comfoair.fan_out_1.label = Abluftstufe 1
channel-type.comfoair.fan_out_1.description = Lüftungsleistung (%) des Abluftventilators auf Stufe 1
channel-type.comfoair.fan_out_2.label = Abluftstufe 2
channel-type.comfoair.fan_out_2.description = Lüftungsleistung (%) des Abluftventilators auf Stufe 2
channel-type.comfoair.fan_out_3.label = Abluftstufe 3
channel-type.comfoair.fan_out_3.description = Lüftungsleistung (%) des Abluftventilators auf Stufe 3
channel-type.comfoair.fan_in_0.label = Zuluftstufe 0 (abwesend)
channel-type.comfoair.fan_in_0.description = Lüftungsleistung (%) des Zuluftventilators auf Stufe 0
channel-type.comfoair.fan_in_1.label = Zuluftstufe 1
channel-type.comfoair.fan_in_1.description = Lüftungsleistung (%) des Zuluftventilators auf Stufe 1
channel-type.comfoair.fan_in_2.label = Zuluftstufe 2
channel-type.comfoair.fan_in_2.description = Lüftungsleistung (%) des Zuluftventilators auf Stufe 2
channel-type.comfoair.fan_in_3.label = Zuluftstufe 3
channel-type.comfoair.fan_in_3.description = Lüftungsleistung (%) des Zuluftventilators auf Stufe 3
channel-type.comfoair.fan_in_percent.label = Zuluftventilator (%)
channel-type.comfoair.fan_in_percent.description = Aktuelle Geschwindigkeit (%) des Zuluftventilators
channel-type.comfoair.fan_out_percent.label = Abluftventilator (%)
channel-type.comfoair.fan_out_percent.description = Aktuelle Geschwindigkeit (%) des Abluftventilators
channel-type.comfoair.fan_in_RPM.label = Zuluftventilator (U/min)
channel-type.comfoair.fan_in_RPM.description = Aktuelle Drehzahl des Zuluftventilators
channel-type.comfoair.fan_out_RPM.label = Abluftventilator (U/min)
channel-type.comfoair.fan_out_RPM.description = Aktuelle Drehzahl des Abluftventilators
channel-type.comfoair.outdoor_temperature_in.label = Außenlufttemperatur
channel-type.comfoair.outdoor_temperature_in.description = Temperatur der Außenzuluft
channel-type.comfoair.outdoor_temperature_out.label = Fortlufttemperatur
channel-type.comfoair.outdoor_temperature_out.description = Temperatur der Außenabluft
channel-type.comfoair.indoor_temperature_in.label = Zulufttemperatur
channel-type.comfoair.indoor_temperature_in.description = Temperatur der Raumzuluft
channel-type.comfoair.indoor_temperature_out.label = Ablufttemperatur
channel-type.comfoair.indoor_temperature_out.description = Temperatur der Raumabluft
channel-type.comfoair.is_T1_sensor.label = Sensor T1 Verfügbarkeit
channel-type.comfoair.is_T1_sensor.description = Verfügbarkeit des Temperatursensors T1 (Außenluft)
channel-type.comfoair.is_T2_sensor.label = Sensor T2 Verfügbarkeit
channel-type.comfoair.is_T2_sensor.description = Verfügbarkeit des Temperatursensors T2 (Zuluft)
channel-type.comfoair.is_T3_sensor.label = Sensor T3 Verfügbarkeit
channel-type.comfoair.is_T3_sensor.description = Verfügbarkeit des Temperatursensors T3 (Abluft)
channel-type.comfoair.is_T4_sensor.label = Sensor T4 Verfügbarkeit
channel-type.comfoair.is_T4_sensor.description = Verfügbarkeit des Temperatursensors T4 (Fortluft)
channel-type.comfoair.is_EWT_sensor.label = Sensor EWT Verfügbarkeit
channel-type.comfoair.is_EWT_sensor.description = Verfügbarkeit des EWT-Temperatursensors
channel-type.comfoair.is_heater_sensor.label = Sensor Nachheizung Verfügbarkeit
channel-type.comfoair.is_heater_sensor.description = Verfügbarkeit des Nachheizung-Temperatursensors
channel-type.comfoair.is_cookerhood_sensor.label = Sensor Dunstabzugshaube Verfügbarkeit
channel-type.comfoair.is_cookerhood_sensor.description = Verfügbarkeit des Dunstabzugshauben-Temperatursensors
channel-type.comfoair.chimney_state.label = Schornsteinfegerregelung Status
channel-type.comfoair.chimney_state.description = Status der Schornsteinfegerregelung
channel-type.comfoair.bypass_state.label = Bypass Status
channel-type.comfoair.bypass_state.description = Status der Bypassklappe (ON = offen / OFF = geschlossen)
channel-type.comfoair.ewt_state.label = EWT Status
channel-type.comfoair.ewt_state.description = Status des EWT-Ventils (ON = offen / OFF = geschlossen)
channel-type.comfoair.heater_state.label = Nacherhitzer Status
channel-type.comfoair.heater_state.description = Status des Nacherhitzers
channel-type.comfoair.v_control_state.label = 0-10V-Regelung Status
channel-type.comfoair.v_control_state.description = Status der 0-10V-Regelung
channel-type.comfoair.frost_state.label = Frostschutz Status
channel-type.comfoair.frost_state.description = Status der Frostschutzregelung
channel-type.comfoair.cookerhood_state.label = Dunstabzugshaube Status
channel-type.comfoair.cookerhood_state.description = Status der Dunstabzugshaubenregelung
channel-type.comfoair.enthalpy_state.label = Enthalpietauscher Status
channel-type.comfoair.enthalpy_state.description = Status des Enthalpietauschers
channel-type.comfoair.ewt_temperature.label = EWT Temperatur
channel-type.comfoair.ewt_temperature.description = Temperatur des Erdwärmetauschers
channel-type.comfoair.heater_temperature.label = Nacherhitzer Temperatur
channel-type.comfoair.heater_temperature.description = Temperatur des Nacherhitzers
channel-type.comfoair.cookerhood_temperature.label = Dunstabzugshaube Temperatur
channel-type.comfoair.cookerhood_temperature.description = Temperatur der Dunstabzugshaube
channel-type.comfoair.level0_time.label = Stufe 0 Laufzeit
channel-type.comfoair.level0_time.description = Betriebsstunden auf Stufe 0 (abwesend)
channel-type.comfoair.level1_time.label = Stufe 1 Laufzeit
channel-type.comfoair.level1_time.description = Betriebsstunden auf Stufe 1
channel-type.comfoair.level2_time.label = Stufe 2 Laufzeit
channel-type.comfoair.level2_time.description = Betriebsstunden auf Stufe 2
channel-type.comfoair.level3_time.label = Stufe 3 Laufzeit
channel-type.comfoair.level3_time.description = Betriebsstunden auf Stufe 3
channel-type.comfoair.freeze_time.label = Frostschutz Laufzeit
channel-type.comfoair.freeze_time.description = Betriebsstunden der Frostschutzregelung
channel-type.comfoair.preheater_time.label = Vorheizung Laufzeit
channel-type.comfoair.preheater_time.description = Betriebsstunden der Vorheizung
channel-type.comfoair.bypass_time.label = Bypass Laufzeit
channel-type.comfoair.bypass_time.description = Öffnungsstunden der Bypassklappe
channel-type.comfoair.filter_hours.label = Filter Laufzeit
channel-type.comfoair.filter_hours.description = Betriebsstunden seit Filterwechsel
channel-type.comfoair.bypass_factor.label = Bypass Faktor
channel-type.comfoair.bypass_factor.description = Aktueller Bypassfaktor
channel-type.comfoair.bypass_level.label = Bypass Stufe
channel-type.comfoair.bypass_level.description = Aktuelle Bypassstufe
channel-type.comfoair.bypass_correction.label = Bypass Korrektur
channel-type.comfoair.bypass_correction.description = Status der Bypasskorrektur
channel-type.comfoair.bypass_summer.label = Bypass Sommermodus
channel-type.comfoair.bypass_summer.description = Aktivität des Sommermodus
channel-type.comfoair.preheater_valve.label = Vorheizer Klappe
channel-type.comfoair.preheater_valve.description = Status der Vorheizerklappe
channel-type.comfoair.preheater_frost_protect.label = Frostschutz Status
channel-type.comfoair.preheater_frost_protect.description = Status der Frostschutzregelung
channel-type.comfoair.preheater_heating.label = Vorheizer Status
channel-type.comfoair.preheater_heating.description = Status der Vorheizung
channel-type.comfoair.preheater_frost_time.label = Frostminuten
channel-type.comfoair.preheater_frost_time.description = Gesamtfrostdauer in Minuten
channel-type.comfoair.preheater_safety.label = Frostsicherheit
channel-type.comfoair.preheater_safety.description = Einstellung der Frostsicherheit
channel-type.comfoair.ewt_temperature_low.label = EWT Temperatur (niedrig)
channel-type.comfoair.ewt_temperature_low.description = Untere Temperatur des Erdwärmetauschers
channel-type.comfoair.ewt_temperature_high.label = EWT Temperatur (hoch)
channel-type.comfoair.ewt_temperature_high.description = Obere Temperatur des Erdwärmetauschers
channel-type.comfoair.ewt_speed.label = EWT Hochlauf (%)
channel-type.comfoair.ewt_speed.description = Hochlauf des Erdwärmetauschers
channel-type.comfoair.heater_power.label = Nachheizung Leistung
channel-type.comfoair.heater_power.description = Leistung der Nachheizung
channel-type.comfoair.heater_power_I.label = Nachheizung Leistung I-Parameter
channel-type.comfoair.heater_power_I.description = Leistung I-Parameter der Nachheizung
channel-type.comfoair.heater_target_temperature.label = Nachheizung Zieltemperatur
channel-type.comfoair.heater_target_temperature.description = Zieltemperatur der Nachheizung
channel-type.comfoair.cookerhood_speed.label = Dunstabzugshaube Hochlauf (%)
channel-type.comfoair.cookerhood_speed.description = Hochlauf der Dunstabzugshaube
channel-type.comfoair.enthalpy_temperature.label = Enthalpiesensor Temperatur
channel-type.comfoair.enthalpy_temperature.description = Temperatur des Enthalpiesensors
channel-type.comfoair.enthalpy_humidity.label = Enthalpiesensor Feuchtigkeit
channel-type.comfoair.enthalpy_humidity.description = Feuchtigkeit des Enthalpiesensors
channel-type.comfoair.enthalpy_level.label = Enthalpietauscher Koeffizient
channel-type.comfoair.enthalpy_level.description = Koeffizient des Enthalpietauscher
channel-type.comfoair.enthalpy_time.label = Enthalpietauscher Timer
channel-type.comfoair.enthalpy_time.description = Timerstatus des Enthalpietauschers
channel-type.comfoair.is_L1_switch.label = L1-Schalter
channel-type.comfoair.is_L1_switch.description = Verfügbarkeit des L1-Schalters
channel-type.comfoair.is_L2_switch.label = L2-Schalter
channel-type.comfoair.is_L2_switch.description = Verfügbarkeit des L2-Schalters
channel-type.comfoair.is_bathroom_switch.label = Badezimmerschalter
channel-type.comfoair.is_bathroom_switch.description = Verfügbarkeit eines Badezimmerchalters
channel-type.comfoair.is_cookerhood_switch.label = Dunstabzugshaubenschalter
channel-type.comfoair.is_cookerhood_switch.description = Verfügbarkeit eines Dunstabzugshaubenschalters
channel-type.comfoair.is_external_filter.label = Externer Filter
channel-type.comfoair.is_external_filter.description = Verfügbarkeit eines externen Filters
channel-type.comfoair.is_wtw.label = Wärmerückgewinnung
channel-type.comfoair.is_wtw.description = Verfügbarkeit der Wärmerückgewinnung
channel-type.comfoair.is_bathroom2_switch.label = Badezimmerschalter 2
channel-type.comfoair.is_bathroom2_switch.description = Verfügbarkeit eines zweiten Badezimmerchalters (luxe)
channel-type.comfoair.menu20_mode.label = Menü 20 Status (P10)
channel-type.comfoair.menu20_mode.description = Menü 20 zurzeit aktiv? (P10)
channel-type.comfoair.menu21_mode.label = Menü 21 Status (P11)
channel-type.comfoair.menu21_mode.description = Menü 21 zurzeit aktiv? (P11)
channel-type.comfoair.menu22_mode.label = Menü 22 Status (P12)
channel-type.comfoair.menu22_mode.description = Menü 22 zurzeit aktiv? (P12)
channel-type.comfoair.menu23_mode.label = Menü 23 Status (P13)
channel-type.comfoair.menu23_mode.description = Menü 23 zurzeit aktiv? (P13)
channel-type.comfoair.menu24_mode.label = Menü 24 Status (P14)
channel-type.comfoair.menu24_mode.description = Menü 24 zurzeit aktiv? (P14)
channel-type.comfoair.menu25_mode.label = Menü 25 Status (P15)
channel-type.comfoair.menu25_mode.description = Menü 25 zurzeit aktiv? (P15)
channel-type.comfoair.menu26_mode.label = Menü 26 Status (P16)
channel-type.comfoair.menu26_mode.description = Menü 26 zurzeit aktiv? (P16)
channel-type.comfoair.menu27_mode.label = Menü 27 Status (P17)
channel-type.comfoair.menu27_mode.description = Menü 27 zurzeit aktiv? (P17)
channel-type.comfoair.menu28_mode.label = MMenü 28 Status (P18)
channel-type.comfoair.menu28_mode.description = Menü 28 zurzeit aktiv? (P18)
channel-type.comfoair.menu29_mode.label = Menü 29 Status (P19)
channel-type.comfoair.menu29_mode.description = Menü 29 zurzeit aktiv? (P19)
channel-type.comfoair.cookerhood_delay.label = Ausschaltverzögerung Dunstabzugshaube (P20)
channel-type.comfoair.cookerhood_delay.description = Ausschaltverzögerung für die Dunstabzugshaubenregelung (min)
channel-type.comfoair.bathroom_start_delay.label = Einschaltverzögerung Badezimmerschalter (P21)
channel-type.comfoair.bathroom_start_delay.description = Einschaltverzögerung für den Badezimmerschalter (min)
channel-type.comfoair.bathroom_end_delay.label = Ausschaltverzögerung Badezimmerschalter (P22)
channel-type.comfoair.bathroom_end_delay.description = Ausschaltverzögerung für den Badezimmerschalter (min)
channel-type.comfoair.L1_end_delay.label = Ausschaltverzögerung L1-Schalter (P23)
channel-type.comfoair.L1_end_delay.description = Ausschaltverzögerung für den L1-Schalter (min)
channel-type.comfoair.filter_weeks.label = Filterlaufzeit (P24)
channel-type.comfoair.filter_weeks.description = Laufzeit bis "Filter verschmutzt"-Meldung (weeks)
channel-type.comfoair.RF_short_delay.label = Ausschaltverzögerung RF Kurz (P25)
channel-type.comfoair.RF_short_delay.description = Ausschaltverzögerung für Lüftungsstufe 3 bei kurzer Betätigung des RF-Schalters (min)
channel-type.comfoair.RF_long_delay.label = Ausschaltverzögerung RF Lang (P26)
channel-type.comfoair.RF_long_delay.description = Ausschaltverzögerung für Lüftungsstufe 3 bei langer Betätigung des RF-Schalters (min)
channel-type.comfoair.pulse_ventilation.label = Zeit Stoßlüftung (P27)
channel-type.comfoair.pulse_ventilation.description = Dauer für die Stoßlüftung (min)
channel-type.comfoair.is_analog.label = Verfügbarkeit Analoger Eingang
channel-type.comfoair.is_analog.description = Verfügbarkeit eines analogen Eingangs
channel-type.comfoair.is_RF.label = Verfügbarkeit RF Eingang
channel-type.comfoair.is_RF.description = Verfügbarkeit eines RF-Eingangs
channel-type.comfoair.analog_mode.label = Status Analoger Eingang
channel-type.comfoair.analog_mode.description = Status des analogen Eingangs
channel-type.comfoair.RF_mode.label = Status RF Eingang
channel-type.comfoair.RF_mode.description = Status des RF-Eingangs
channel-type.comfoair.analog_negative.label = Analoger Eingang Postiv/Negativ
channel-type.comfoair.analog_negative.description = Postiv/Negativ-Einstellung des analogen Eingangs
channel-type.comfoair.RF_negative.label = RF Eingang Postiv/Negativ
channel-type.comfoair.RF_negative.description = Postiv/Negativ-Einstellung des RF-Eingangs
channel-type.comfoair.analog_volt.label = Analoger Eingang Spannungslevel
channel-type.comfoair.analog_volt.description = Spannungslevel des analogen Eingangs
channel-type.comfoair.analog_min.label = Analoger Eingang Minimum
channel-type.comfoair.analog_min.description = Minimaleinstellung des analogen Eingangs
channel-type.comfoair.analog_max.label = Analoger Eingang Maximum
channel-type.comfoair.analog_max.description = Maximaleinstellung des analogen Eingangs
channel-type.comfoair.analog_value.label = Analoger Eingang Zielwert
channel-type.comfoair.analog_value.description = Zielwert des analogen Eingangs
channel-type.comfoair.RF_min.label = RF Eingang Minimum
channel-type.comfoair.RF_min.description = Minimaleinstellung des RF-Eingangs
channel-type.comfoair.RF_max.label = RF Eingang Maximum
channel-type.comfoair.RF_max.description = Maximaleinstellung des RF-Eingangs
channel-type.comfoair.RF_value.label = RF Eingang Zielwert
channel-type.comfoair.RF_value.description = Zielwert des RF-Eingangs
channel-type.comfoair.analog_priority.label = Controller Priorität
channel-type.comfoair.analog_priority.description = Priorität der analogen Eingänge für die höchste Lufteinstellung
channel-type.comfoair.errors_current.label = Fehler Aktuell
channel-type.comfoair.errors_current.description = Aktuelle Fehler
channel-type.comfoair.errors_last.label = Fehler Letzte
channel-type.comfoair.errors_last.description = Letzte Fehler
channel-type.comfoair.errors_prelast.label = Fehler Vorletzte
channel-type.comfoair.errors_prelast.description = Vorletzte Fehler
channel-type.comfoair.errors_pre_prelast.label = Fehler Vorvorletzte
channel-type.comfoair.errors_pre_prelast.description = Vorvorletzte Fehler