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,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<features name="org.openhab.binding.modbus.helioseasycontrols-${project.version}" xmlns="http://karaf.apache.org/xmlns/features/v1.4.0">
<repository>file:${basedirRoot}/bundles/org.openhab.io.transport.modbus/target/feature/feature.xml</repository>
<feature name="openhab-binding-modbus.helioseasycontrols" description="Modbus.HeliosEasyControls Binding" version="${project.version}">
<feature>openhab-runtime-base</feature>
<feature>openhab-transport-modbus</feature>
<bundle start-level="80">mvn:org.openhab.addons.bundles/org.openhab.binding.modbus/${project.version}</bundle>
<bundle start-level="80">mvn:org.openhab.addons.bundles/org.openhab.binding.modbus.helioseasycontrols/${project.version}</bundle>
</feature>
</features>

View File

@@ -0,0 +1,162 @@
/**
* 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.modbus.helioseasycontrols.internal;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.core.automation.annotation.ActionInput;
import org.openhab.core.automation.annotation.RuleAction;
import org.openhab.core.thing.binding.ThingActions;
import org.openhab.core.thing.binding.ThingActionsScope;
import org.openhab.core.thing.binding.ThingHandler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* This class provides the actions available for the Helios device
*
* @author Bernhard Bauer - Initial contribution
*/
@ThingActionsScope(name = "modbus.helioseasycontrols")
@NonNullByDefault
public class HeliosEasyControlsActions implements ThingActions {
private @Nullable HeliosEasyControlsHandler handler;
private final Logger logger = LoggerFactory.getLogger(HeliosEasyControlsActions.class);
@Override
public void setThingHandler(@Nullable ThingHandler handler) {
this.handler = (HeliosEasyControlsHandler) handler;
}
@Override
public @Nullable ThingHandler getThingHandler() {
return handler;
}
private void triggerSwitch(String variableName) {
try {
if (this.handler != null) {
this.handler.writeValue(variableName, "1");
}
} catch (HeliosException e) {
logger.warn("Error executing action 'resetFilterChangeTimer': {}", e.getMessage());
}
}
@RuleAction(label = "Reset filter change timer", description = "Sets the filter change timer back to the configured interval")
public void resetFilterChangeTimer() {
this.triggerSwitch(HeliosEasyControlsBindingConstants.FILTER_CHANGE_RESET);
}
public static void resetFilterChangeTimer(@Nullable ThingActions actions) {
if (actions instanceof HeliosEasyControlsActions) {
((HeliosEasyControlsActions) actions).resetFilterChangeTimer();
} else {
throw new IllegalArgumentException("Instance is not an HeliosEasyControlsActions class.");
}
}
@RuleAction(label = "Reset error messages", description = "Reset error/warning/info messages")
public void resetErrors() {
this.triggerSwitch(HeliosEasyControlsBindingConstants.RESET_FLAG);
}
public static void resetErrors(@Nullable ThingActions actions) {
if (actions instanceof HeliosEasyControlsActions) {
((HeliosEasyControlsActions) actions).resetErrors();
} else {
throw new IllegalArgumentException("Instance is not an HeliosEasyControlsActions class.");
}
}
@RuleAction(label = "Reset to factory defaults", description = "Reset device to factory defaults")
public void resetToFactoryDefaults() {
this.triggerSwitch(HeliosEasyControlsBindingConstants.FACTORY_RESET);
}
public static void resetToFactoryDefaults(@Nullable ThingActions actions) {
if (actions instanceof HeliosEasyControlsActions) {
((HeliosEasyControlsActions) actions).resetToFactoryDefaults();
} else {
throw new IllegalArgumentException("Instance is not an HeliosEasyControlsActions class.");
}
}
@RuleAction(label = "Reset individual switching times", description = "Reset individual switching times")
public void resetSwitchingTimes() {
this.triggerSwitch(HeliosEasyControlsBindingConstants.FACTORY_SETTING_WZU);
}
public static void resetSwitchingTimes(@Nullable ThingActions actions) {
if (actions instanceof HeliosEasyControlsActions) {
((HeliosEasyControlsActions) actions).resetSwitchingTimes();
} else {
throw new IllegalArgumentException("Instance is not an HeliosEasyControlsActions class.");
}
}
@RuleAction(label = "Set system date and time", description = "Sets the device's system date and time based on OH's system date and time")
public void setSysDateTime() {
HeliosEasyControlsHandler handler = this.handler;
if (handler != null) {
handler.setSysDateTime();
}
}
public static void setSysDateTime(@Nullable ThingActions actions) {
if (actions instanceof HeliosEasyControlsActions) {
((HeliosEasyControlsActions) actions).setSysDateTime();
} else {
throw new IllegalArgumentException("Instance is not an HeliosEasyControlsActions class.");
}
}
private void setBypass(boolean from, int day, int month) {
HeliosEasyControlsHandler handler = this.handler;
if (handler != null) {
handler.setBypass(from, day, month);
}
}
@RuleAction(label = "Set the bypass from day and month", description = "Sets the day and month from when the bypass should be active")
public void setBypassFrom(
@ActionInput(name = "day", label = "bypass from day", description = "The day from when the bypass should be active") int day,
@ActionInput(name = "month", label = "bypass from month", description = "The month from when the bypass should be active") int month) {
this.setBypass(true, day, month);
}
public static void setBypassFrom(@Nullable ThingActions actions, int day, int month) {
if (actions instanceof HeliosEasyControlsActions) {
((HeliosEasyControlsActions) actions).setBypassFrom(day, month);
} else {
throw new IllegalArgumentException("Instance is not an HeliosEasyControlsActions class.");
}
}
@RuleAction(label = "Set the bypass to day and month", description = "Sets the day and month until when the bypass should be active")
public void setBypassTo(
@ActionInput(name = "day", label = "bypass to day", description = "The day until when the bypass should be active") int day,
@ActionInput(name = "month", label = "bypass to month", description = "The month until when the bypass should be active") int month) {
this.setBypass(false, day, month);
}
public static void setBypassTo(@Nullable ThingActions actions, int day, int month) {
if (actions instanceof HeliosEasyControlsActions) {
((HeliosEasyControlsActions) actions).setBypassTo(day, month);
} else {
throw new IllegalArgumentException("Instance is not an HeliosEasyControlsActions class.");
}
}
}

View File

@@ -0,0 +1,319 @@
/**
* 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.modbus.helioseasycontrols.internal;
import java.util.Arrays;
import java.util.List;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.binding.modbus.ModbusBindingConstants;
import org.openhab.core.thing.ThingTypeUID;
/**
* The {@link HeliosEasyControlsBindingConstants} class defines common constants, which are
* used across the whole binding.
*
* @author Bernhard Bauer - Initial contribution
*/
@NonNullByDefault
public class HeliosEasyControlsBindingConstants {
private static final String BINDING_ID = ModbusBindingConstants.BINDING_ID;
// List of all Thing Type UIDs
public static final ThingTypeUID THING_TYPE_HELIOS_VENTILATION_EASY_CONTROLS = new ThingTypeUID(BINDING_ID,
"helios-easycontrols");
// List of all Channel IDs
// -----------------------
// Device Config
public final static String SYS_DATE = "sysdate"; // for the combined item (based on DATE, TIME and
// TIME_ZONE_DIFFERENCE_TO_GMT)
public final static String DATE = "date";
public final static String TIME = "time";
public final static String TIME_ZONE_DIFFERENCE_TO_GMT = "timeZoneDifferenceToGmt";
public final static String SUMMER_WINTER = "summerWinter";
public final static String ACCESS_HELIOS_PORTAL = "accessHeliosPortal";
public final static String AUTO_SW_UPDATE = "autoSwUpdate";
public final static String MIN_FAN_STAGE = "minFanStage";
public final static String COMFORT_TEMP = "comfortTemp";
public final static String SUPPLY_AIR_FAN_STAGE = "supplyAirFanStage";
public final static String EXTRACT_AIR_FAN_STAGE = "extractAirFanStage";
// Operation
public final static String PARTY_MODE_DURATION = "partyModeDuration";
public final static String PARTY_MODE_FAN_STAGE = "partyModeFanStage";
public final static String PARTY_MODE_REMAINING_TIME = "partyModeRemainingTime";
public final static String PARTY_MODE_STATUS = "partyModeStatus";
public final static String STANDBY_MODE_DURATION = "standbyModeDuration";
public final static String STANDBY_MODE_FAN_STAGE = "standbyModeFanStage";
public final static String STANDBY_MODE_REMAINING_TIME = "standbyModeRemainingTime";
public final static String STANDBY_MODE_STATUS = "standbyModeStatus";
public final static String HOLIDAY_PROGRAMME = "holidayProgramme";
public final static String HOLIDAY_PROGRAMME_FAN_STAGE = "holidayProgrammeFanStage";
public final static String HOLIDAY_PROGRAMME_START = "holidayProgrammeStart";
public final static String HOLIDAY_PROGRAMME_END = "holidayProgrammeEnd";
public final static String HOLIDAY_PROGRAMME_INTERVAL = "holidayProgrammeInterval";
public final static String HOLIDAY_PROGRAMME_ACTIVATION_TIME = "holidayProgrammeActivationTime";
public final static String OPERATING_MODE = "operatingMode";
public final static String FAN_STAGE = "fanStage";
public final static String PERCENTAGE_FAN_STAGE = "percentageFanStage";
public final static String TEMPERATURE_OUTSIDE_AIR = "temperatureOutsideAir";
public final static String TEMPERATURE_SUPPLY_AIR = "temperatureSupplyAir";
public final static String TEMPERATURE_OUTGOING_AIR = "temperatureOutgoingAir";
public final static String TEMPERATURE_EXTRACT_AIR = "temperatureExtractAir";
public final static String VHZ_DUCT_SENSOR = "vhzDuctSensor";
public final static String NHZ_DUCT_SENSOR = "nhzDuctSensor";
public final static String NHZ_RETURN_SENSOR = "nhzReturnSensor";
public final static String SUPPLY_AIR_RPM = "supplyAirRpm";
public final static String EXTRACT_AIR_RPM = "extractAirRpm";
public final static String OPERATING_HOURS_SUPPLY_AIR_VENT = "operatingHoursSupplyAirVent";
public final static String OPERATING_HOURS_EXTRACT_AIR_VENT = "operatingHoursExtractAirVent";
// Heater
public final static String PRE_HEATER_STATUS = "preHeaterStatus";
public final static String WEEK_PROFILE_NHZ = "weekProfileNhz";
public final static String RUN_ON_TIME_VHZ_NHZ = "runOnTimeVhzNhz";
public final static String OPERATING_HOURS_VHZ = "operatingHoursVhz";
public final static String OPERATING_HOURS_NHZ = "operatingHoursNhz";
public final static String OUTPUT_POWER_VHZ = "outputPowerVhz";
public final static String OUTPUT_POWER_NHZ = "outputPowerNhz";
// Humidity control
public final static String HUMIDITY_CONTROL_SET_VALUE = "humidityControlSetValue";
public final static String HUMIDITY_CONTROL_STEPS = "humidityControlSteps";
public final static String HUMIDITY_STOP_TIME = "humidityStopTime";
public final static String EXTERNAL_SENSOR_KWL_FTF_HUMIDITY_1 = "externalSensorKwlFtfHumidity1";
public final static String EXTERNAL_SENSOR_KWL_FTF_HUMIDITY_2 = "externalSensorKwlFtfHumidity2";
public final static String EXTERNAL_SENSOR_KWL_FTF_HUMIDITY_3 = "externalSensorKwlFtfHumidity3";
public final static String EXTERNAL_SENSOR_KWL_FTF_HUMIDITY_4 = "externalSensorKwlFtfHumidity4";
public final static String EXTERNAL_SENSOR_KWL_FTF_HUMIDITY_5 = "externalSensorKwlFtfHumidity5";
public final static String EXTERNAL_SENSOR_KWL_FTF_HUMIDITY_6 = "externalSensorKwlFtfHumidity6";
public final static String EXTERNAL_SENSOR_KWL_FTF_HUMIDITY_7 = "externalSensorKwlFtfHumidity7";
public final static String EXTERNAL_SENSOR_KWL_FTF_HUMIDITY_8 = "externalSensorKwlFtfHumidity8";
public final static String EXTERNAL_SENSOR_KWL_FTF_TEMPERATURE_1 = "externalSensorKwlFtfTemperature1";
public final static String EXTERNAL_SENSOR_KWL_FTF_TEMPERATURE_2 = "externalSensorKwlFtfTemperature2";
public final static String EXTERNAL_SENSOR_KWL_FTF_TEMPERATURE_3 = "externalSensorKwlFtfTemperature3";
public final static String EXTERNAL_SENSOR_KWL_FTF_TEMPERATURE_4 = "externalSensorKwlFtfTemperature4";
public final static String EXTERNAL_SENSOR_KWL_FTF_TEMPERATURE_5 = "externalSensorKwlFtfTemperature5";
public final static String EXTERNAL_SENSOR_KWL_FTF_TEMPERATURE_6 = "externalSensorKwlFtfTemperature6";
public final static String EXTERNAL_SENSOR_KWL_FTF_TEMPERATURE_7 = "externalSensorKwlFtfTemperature7";
public final static String EXTERNAL_SENSOR_KWL_FTF_TEMPERATURE_8 = "externalSensorKwlFtfTemperature8";
// CO2 control
public final static String CO2_CONTROL_SET_VALUE = "co2ControlSetValue";
public final static String CO2_CONTROL_STEPS = "co2ControlSteps";
public final static String EXTERNAL_SENSOR_KWL_CO2_1 = "externalSensorKwlCo21";
public final static String EXTERNAL_SENSOR_KWL_CO2_2 = "externalSensorKwlCo22";
public final static String EXTERNAL_SENSOR_KWL_CO2_3 = "externalSensorKwlCo23";
public final static String EXTERNAL_SENSOR_KWL_CO2_4 = "externalSensorKwlCo24";
public final static String EXTERNAL_SENSOR_KWL_CO2_5 = "externalSensorKwlCo25";
public final static String EXTERNAL_SENSOR_KWL_CO2_6 = "externalSensorKwlCo26";
public final static String EXTERNAL_SENSOR_KWL_CO2_7 = "externalSensorKwlCo27";
public final static String EXTERNAL_SENSOR_KWL_CO2_8 = "externalSensorKwlCo28";
public final static String SENSOR_NAME_CO2_1 = "sensorNameCo21";
public final static String SENSOR_NAME_CO2_2 = "sensorNameCo22";
public final static String SENSOR_NAME_CO2_3 = "sensorNameCo23";
public final static String SENSOR_NAME_CO2_4 = "sensorNameCo24";
public final static String SENSOR_NAME_CO2_5 = "sensorNameCo25";
public final static String SENSOR_NAME_CO2_6 = "sensorNameCo26";
public final static String SENSOR_NAME_CO2_7 = "sensorNameCo27";
public final static String SENSOR_NAME_CO2_8 = "sensorNameCo28";
// VOC control
public final static String VOC_CONTROL_SET_VALUE = "vocControlSetValue";
public final static String VOC_CONTROL_STEPS = "vocControlSteps";
public final static String EXTERNAL_SENSOR_KWL_VOC_1 = "externalSensorKwlVoc1";
public final static String EXTERNAL_SENSOR_KWL_VOC_2 = "externalSensorKwlVoc2";
public final static String EXTERNAL_SENSOR_KWL_VOC_3 = "externalSensorKwlVoc3";
public final static String EXTERNAL_SENSOR_KWL_VOC_4 = "externalSensorKwlVoc4";
public final static String EXTERNAL_SENSOR_KWL_VOC_5 = "externalSensorKwlVoc5";
public final static String EXTERNAL_SENSOR_KWL_VOC_6 = "externalSensorKwlVoc6";
public final static String EXTERNAL_SENSOR_KWL_VOC_7 = "externalSensorKwlVoc7";
public final static String EXTERNAL_SENSOR_KWL_VOC_8 = "externalSensorKwlVoc8";
public final static String SENSOR_NAME_VOC_1 = "sensorNameVoc1";
public final static String SENSOR_NAME_VOC_2 = "sensorNameVoc2";
public final static String SENSOR_NAME_VOC_3 = "sensorNameVoc3";
public final static String SENSOR_NAME_VOC_4 = "sensorNameVoc4";
public final static String SENSOR_NAME_VOC_5 = "sensorNameVoc5";
public final static String SENSOR_NAME_VOC_6 = "sensorNameVoc6";
public final static String SENSOR_NAME_VOC_7 = "sensorNameVoc7";
public final static String SENSOR_NAME_VOC_8 = "sensorNameVoc8";
// Errors
public final static String ERROR_OUTPUT_FUNCTION = "errorOutputFunction";
public final static String ERRORS = "errors";
public final static String WARNINGS = "warnings";
public final static String INFOS = "infos";
public final static String NO_OF_ERRORS = "noOfErrors";
public final static String NO_OF_WARNINGS = "noOfWarnings";
public final static String NO_OF_INFOS = "noOfInfos";
public final static String ERRORS_MSG = "errorsMsg";
public final static String WARNINGS_MSG = "warningsMsg";
public final static String INFOS_MSG = "infosMsg";
public final static String STATUS_FLAGS = "statusFlags";
// Filter
public final static String FILTER_CHANGE = "filterChange";
public final static String FILTER_CHANGE_INTERVAL = "filterChangeInterval";
public final static String FILTER_CHANGE_REMAINING_TIME = "filterChangeRemainingTime";
// Bypass
public final static String BYPASS_ROOM_TEMPERATURE = "bypassRoomTemperature";
public final static String BYPASS_MIN_OUTSIDE_TEMPERATURE = "bypassMinOutsideTemperature";
public final static String BYPASS_STATUS = "bypassStatus";
public final static String BYPASS_FROM = "bypassFrom"; // for the combined item (based on BYPASS_FROM_DAY and
// BYPASS_FROM_MONTH)
public final static String BYPASS_FROM_DAY = "bypassFromDay";
public final static String BYPASS_FROM_MONTH = "bypassFromMonth";
public final static String BYPASS_TO = "bypassTo"; // for the combined item (based on BYPASS_TO_DAY and
// BYPASS_TO_MONTH)
public final static String BYPASS_TO_DAY = "bypassToDay";
public final static String BYPASS_TO_MONTH = "bypassToMonth";
// List of all Properties
// ----------------------
// Device Config
public final static String ARTICLE_DESCRIPTION = "articleDescription";
public final static String REF_NO = "refNo";
public final static String SER_NO = "serNo";
public final static String PROD_CODE = "prodCode";
public final static String MAC_ADDRESS = "macAddress";
public final static String SOFTWARE_VERSION_BASIS = "softwareVersionBasis";
public final static String DATE_FORMAT = "dateFormat";
public final static String LANGUAGE = "language";
public final static String UNIT_CONFIG = "unitConfig";
public final static String KWL_BE = "kwlBe";
public final static String KWL_BEC = "kwlBec";
public final static String EXTERNAL_CONTACT = "externalContact";
public final static String FUNCTION_TYPE_KWL_EM = "functionTypeKwlEm";
public final static String HEAT_EXCHANGER_TYPE = "heatExchangerType";
public final static String OFFSET_EXTRACT_AIR = "offsetExtractAir";
public final static String ASSIGNMENT_FAN_STAGES = "assignmentFanStages";
public final static String VOLTAGE_FAN_STAGE_1_EXTRACT_AIR = "voltageFanStage1ExtractAir";
public final static String VOLTAGE_FAN_STAGE_2_EXTRACT_AIR = "voltageFanStage2ExtractAir";
public final static String VOLTAGE_FAN_STAGE_3_EXTRACT_AIR = "voltageFanStage3ExtractAir";
public final static String VOLTAGE_FAN_STAGE_4_EXTRACT_AIR = "voltageFanStage4ExtractAir";
public final static String VOLTAGE_FAN_STAGE_1_SUPPLY_AIR = "voltageFanStage1SupplyAir";
public final static String VOLTAGE_FAN_STAGE_2_SUPPLY_AIR = "voltageFanStage2SupplyAir";
public final static String VOLTAGE_FAN_STAGE_3_SUPPLY_AIR = "voltageFanStage3SupplyAir";
public final static String VOLTAGE_FAN_STAGE_4_SUPPLY_AIR = "voltageFanStage4SupplyAir";
public final static String FAN_STAGE_STEPPED_0TO2V = "fanStageStepped0to2v";
public final static String FAN_STAGE_STEPPED_2TO4V = "fanStageStepped2to4v";
public final static String FAN_STAGE_STEPPED_4TO6V = "fanStageStepped4to6v";
public final static String FAN_STAGE_STEPPED_6TO8V = "fanStageStepped6to8v";
public final static String FAN_STAGE_STEPPED_8TO10V = "fanStageStepped8to10v";
// Heater
public final static String VHZ_TYPE = "vhzType";
// Humidty control
public final static String HUMIDITY_CONTROL_STATUS = "humidityControlStatus";
public final static String KWL_FTF_CONFIG_0 = "kwlFtfConfig0";
public final static String KWL_FTF_CONFIG_1 = "kwlFtfConfig1";
public final static String KWL_FTF_CONFIG_2 = "kwlFtfConfig2";
public final static String KWL_FTF_CONFIG_3 = "kwlFtfConfig3";
public final static String KWL_FTF_CONFIG_4 = "kwlFtfConfig4";
public final static String KWL_FTF_CONFIG_5 = "kwlFtfConfig5";
public final static String KWL_FTF_CONFIG_6 = "kwlFtfConfig6";
public final static String KWL_FTF_CONFIG_7 = "kwlFtfConfig7";
public final static String SENSOR_CONFIG_KWL_FTF_1 = "sensorConfigKwlFtf1";
public final static String SENSOR_CONFIG_KWL_FTF_2 = "sensorConfigKwlFtf2";
public final static String SENSOR_CONFIG_KWL_FTF_3 = "sensorConfigKwlFtf3";
public final static String SENSOR_CONFIG_KWL_FTF_4 = "sensorConfigKwlFtf4";
public final static String SENSOR_CONFIG_KWL_FTF_5 = "sensorConfigKwlFtf5";
public final static String SENSOR_CONFIG_KWL_FTF_6 = "sensorConfigKwlFtf6";
public final static String SENSOR_CONFIG_KWL_FTF_7 = "sensorConfigKwlFtf7";
public final static String SENSOR_CONFIG_KWL_FTF_8 = "sensorConfigKwlFtf8";
public final static String SENSOR_NAME_HUMIDITY_AND_TEMP_1 = "sensorNameHumidityAndTemp1";
public final static String SENSOR_NAME_HUMIDITY_AND_TEMP_2 = "sensorNameHumidityAndTemp2";
public final static String SENSOR_NAME_HUMIDITY_AND_TEMP_3 = "sensorNameHumidityAndTemp3";
public final static String SENSOR_NAME_HUMIDITY_AND_TEMP_4 = "sensorNameHumidityAndTemp4";
public final static String SENSOR_NAME_HUMIDITY_AND_TEMP_5 = "sensorNameHumidityAndTemp5";
public final static String SENSOR_NAME_HUMIDITY_AND_TEMP_6 = "sensorNameHumidityAndTemp6";
public final static String SENSOR_NAME_HUMIDITY_AND_TEMP_7 = "sensorNameHumidityAndTemp7";
public final static String SENSOR_NAME_HUMIDITY_AND_TEMP_8 = "sensorNameHumidityAndTemp8";
// CO2 control
public final static String CO2_CONTROL_STATUS = "co2ControlStatus";
// VOC control
public final static String VOC_CONTROL_STATUS = "vocControlStatus";
// List of all variables used in actions
public final static String FILTER_CHANGE_RESET = "filterChangeReset";
public final static String FACTORY_SETTING_WZU = "factorySettingWzu";
public final static String FACTORY_RESET = "factoryReset";
public final static String RESET_FLAG = "resetFlag";
// List of all unused variables (defined in the specification but not implemented as channels, properties or
// actions)
public final static String GLOBAL_MANUAL_WEB_UPDATE = "globalManualWebUpdate";
public final static String PORTAL_GLOBALS_ERROR_FOR_WEB = "portalGlobalsErrorForWeb";
public final static String CLEAR_ERROR = "clearError";
public final static String TBD = "tbd";
public final static String LOGOUT = "logout";
// List of all Configuration Parameters
public final static String CONFIG_REFRESH_INTERVAL = "refreshInterval";
// Other constants
public final static int UNIT_ID = 180;
public final static int START_ADDRESS = 1;
public final static String VARIABLES_DEFINITION_FILE = "variables.json";
public final static int MAX_TRIES = 5;
// List of all variables that have to be updated regardless if they are linked to an item
public final static List<String> ALWAYS_UPDATE_VARIABLES = Arrays.asList(
HeliosEasyControlsBindingConstants.DATE_FORMAT, HeliosEasyControlsBindingConstants.DATE,
HeliosEasyControlsBindingConstants.TIME, HeliosEasyControlsBindingConstants.TIME_ZONE_DIFFERENCE_TO_GMT,
HeliosEasyControlsBindingConstants.BYPASS_FROM_DAY, HeliosEasyControlsBindingConstants.BYPASS_FROM_MONTH,
HeliosEasyControlsBindingConstants.BYPASS_TO_DAY, HeliosEasyControlsBindingConstants.BYPASS_TO_MONTH);
// List of all properties
public final static List<String> PROPERTY_NAMES = Arrays.asList(
HeliosEasyControlsBindingConstants.ARTICLE_DESCRIPTION, HeliosEasyControlsBindingConstants.REF_NO,
HeliosEasyControlsBindingConstants.SER_NO, HeliosEasyControlsBindingConstants.PROD_CODE,
HeliosEasyControlsBindingConstants.MAC_ADDRESS, HeliosEasyControlsBindingConstants.SOFTWARE_VERSION_BASIS,
HeliosEasyControlsBindingConstants.DATE_FORMAT, HeliosEasyControlsBindingConstants.LANGUAGE,
HeliosEasyControlsBindingConstants.UNIT_CONFIG, HeliosEasyControlsBindingConstants.KWL_BE,
HeliosEasyControlsBindingConstants.KWL_BEC, HeliosEasyControlsBindingConstants.EXTERNAL_CONTACT,
HeliosEasyControlsBindingConstants.FUNCTION_TYPE_KWL_EM,
HeliosEasyControlsBindingConstants.HEAT_EXCHANGER_TYPE,
HeliosEasyControlsBindingConstants.OFFSET_EXTRACT_AIR,
HeliosEasyControlsBindingConstants.ASSIGNMENT_FAN_STAGES,
HeliosEasyControlsBindingConstants.VOLTAGE_FAN_STAGE_1_EXTRACT_AIR,
HeliosEasyControlsBindingConstants.VOLTAGE_FAN_STAGE_2_EXTRACT_AIR,
HeliosEasyControlsBindingConstants.VOLTAGE_FAN_STAGE_3_EXTRACT_AIR,
HeliosEasyControlsBindingConstants.VOLTAGE_FAN_STAGE_4_EXTRACT_AIR,
HeliosEasyControlsBindingConstants.VOLTAGE_FAN_STAGE_1_SUPPLY_AIR,
HeliosEasyControlsBindingConstants.VOLTAGE_FAN_STAGE_2_SUPPLY_AIR,
HeliosEasyControlsBindingConstants.VOLTAGE_FAN_STAGE_3_SUPPLY_AIR,
HeliosEasyControlsBindingConstants.VOLTAGE_FAN_STAGE_4_SUPPLY_AIR,
HeliosEasyControlsBindingConstants.FAN_STAGE_STEPPED_0TO2V,
HeliosEasyControlsBindingConstants.FAN_STAGE_STEPPED_2TO4V,
HeliosEasyControlsBindingConstants.FAN_STAGE_STEPPED_4TO6V,
HeliosEasyControlsBindingConstants.FAN_STAGE_STEPPED_6TO8V,
HeliosEasyControlsBindingConstants.FAN_STAGE_STEPPED_8TO10V, HeliosEasyControlsBindingConstants.VHZ_TYPE,
HeliosEasyControlsBindingConstants.HUMIDITY_CONTROL_STATUS,
HeliosEasyControlsBindingConstants.KWL_FTF_CONFIG_0, HeliosEasyControlsBindingConstants.KWL_FTF_CONFIG_1,
HeliosEasyControlsBindingConstants.KWL_FTF_CONFIG_2, HeliosEasyControlsBindingConstants.KWL_FTF_CONFIG_3,
HeliosEasyControlsBindingConstants.KWL_FTF_CONFIG_4, HeliosEasyControlsBindingConstants.KWL_FTF_CONFIG_5,
HeliosEasyControlsBindingConstants.KWL_FTF_CONFIG_6, HeliosEasyControlsBindingConstants.KWL_FTF_CONFIG_7,
HeliosEasyControlsBindingConstants.SENSOR_CONFIG_KWL_FTF_1,
HeliosEasyControlsBindingConstants.SENSOR_CONFIG_KWL_FTF_2,
HeliosEasyControlsBindingConstants.SENSOR_CONFIG_KWL_FTF_3,
HeliosEasyControlsBindingConstants.SENSOR_CONFIG_KWL_FTF_4,
HeliosEasyControlsBindingConstants.SENSOR_CONFIG_KWL_FTF_5,
HeliosEasyControlsBindingConstants.SENSOR_CONFIG_KWL_FTF_6,
HeliosEasyControlsBindingConstants.SENSOR_CONFIG_KWL_FTF_7,
HeliosEasyControlsBindingConstants.SENSOR_CONFIG_KWL_FTF_8,
HeliosEasyControlsBindingConstants.SENSOR_NAME_HUMIDITY_AND_TEMP_1,
HeliosEasyControlsBindingConstants.SENSOR_NAME_HUMIDITY_AND_TEMP_2,
HeliosEasyControlsBindingConstants.SENSOR_NAME_HUMIDITY_AND_TEMP_3,
HeliosEasyControlsBindingConstants.SENSOR_NAME_HUMIDITY_AND_TEMP_4,
HeliosEasyControlsBindingConstants.SENSOR_NAME_HUMIDITY_AND_TEMP_5,
HeliosEasyControlsBindingConstants.SENSOR_NAME_HUMIDITY_AND_TEMP_6,
HeliosEasyControlsBindingConstants.SENSOR_NAME_HUMIDITY_AND_TEMP_7,
HeliosEasyControlsBindingConstants.SENSOR_NAME_HUMIDITY_AND_TEMP_8,
HeliosEasyControlsBindingConstants.CO2_CONTROL_STATUS,
HeliosEasyControlsBindingConstants.VOC_CONTROL_STATUS);
}

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.modbus.helioseasycontrols.internal;
import org.eclipse.jdt.annotation.NonNullByDefault;
/**
* The {@link HeliosEasyControlsConfiguration} class contains fields mapping thing configuration parameters.
*
* @author Bernhard Bauer - Initial contribution
*/
@NonNullByDefault
public class HeliosEasyControlsConfiguration {
/**
* The binding's refresh interval
*/
private int refreshInterval;
public int getRefreshInterval() {
return refreshInterval;
}
public void setRefreshInterval(int refreshInterval) {
this.refreshInterval = refreshInterval;
}
}

View File

@@ -0,0 +1,791 @@
/**
* 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.modbus.helioseasycontrols.internal;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.lang.reflect.Type;
import java.nio.charset.StandardCharsets;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.util.Collection;
import java.util.Collections;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.binding.modbus.handler.ModbusEndpointThingHandler;
import org.openhab.core.library.types.DateTimeType;
import org.openhab.core.library.types.DecimalType;
import org.openhab.core.library.types.OnOffType;
import org.openhab.core.library.types.QuantityType;
import org.openhab.core.library.types.StringType;
import org.openhab.core.library.unit.SIUnits;
import org.openhab.core.library.unit.SmartHomeUnits;
import org.openhab.core.thing.Bridge;
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.ThingHandler;
import org.openhab.core.thing.binding.ThingHandlerService;
import org.openhab.core.types.Command;
import org.openhab.core.types.RefreshType;
import org.openhab.core.types.State;
import org.openhab.io.transport.modbus.ModbusBitUtilities;
import org.openhab.io.transport.modbus.ModbusCommunicationInterface;
import org.openhab.io.transport.modbus.ModbusReadFunctionCode;
import org.openhab.io.transport.modbus.ModbusReadRequestBlueprint;
import org.openhab.io.transport.modbus.ModbusRegister;
import org.openhab.io.transport.modbus.ModbusRegisterArray;
import org.openhab.io.transport.modbus.ModbusWriteRegisterRequestBlueprint;
import org.openhab.io.transport.modbus.endpoint.ModbusSlaveEndpoint;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
/**
* The {@link HeliosEasyControlsHandler} is responsible for handling commands, which are
* sent to one of the channels.
*
* @author Bernhard Bauer - Initial contribution
*/
@NonNullByDefault
public class HeliosEasyControlsHandler extends BaseThingHandler {
private final Logger logger = LoggerFactory.getLogger(HeliosEasyControlsHandler.class);
private @Nullable HeliosEasyControlsConfiguration config;
private @Nullable ScheduledFuture<?> pollingJob;
private @Nullable Map<String, HeliosVariable> variableMap;
/**
* This flag is used to ensure read requests (consisting of a write and subsequent read) are not influenced by
* another transaction
*/
private final Map<ModbusSlaveEndpoint, Semaphore> transactionLocks = new ConcurrentHashMap<>();
private final Gson gson = new Gson();
private @Nullable ModbusCommunicationInterface comms;
private int dateFormat = -1;
private ZonedDateTime sysDate = ZonedDateTime.now(); // initialize with local system time as a best guess
// before reading from device
private class BypassDate {
// initialization to avoid issues when updating before all variables were read
private int month = 1;
private int day = 1;
public void setMonth(int month) {
this.month = month;
}
public void setDay(int day) {
this.day = day;
}
public DateTimeType toDateTimeType() {
return new DateTimeType(ZonedDateTime.of(1900, this.month, this.day, 0, 0, 0, 0, ZoneId.of("UTC+00:00")));
}
}
private @Nullable BypassDate bypassFrom, bypassTo;
public HeliosEasyControlsHandler(Thing thing) {
super(thing);
}
/**
* Reads variable definitions from JSON file and store them in variableMap
*/
private void readVariableDefinition() {
Type vMapType = new TypeToken<Map<String, HeliosVariable>>() {
}.getType();
try (InputStreamReader jsonFile = new InputStreamReader(
getClass().getResourceAsStream(HeliosEasyControlsBindingConstants.VARIABLES_DEFINITION_FILE));
BufferedReader reader = new BufferedReader(jsonFile)) {
this.variableMap = gson.fromJson(reader, vMapType);
} catch (IOException e) {
this.handleError("Error reading variable definition file", ThingStatusDetail.CONFIGURATION_ERROR);
}
if (variableMap != null) {
// add the name to the variable itself
for (Map.Entry<String, HeliosVariable> entry : this.variableMap.entrySet()) {
entry.getValue().setName(entry.getKey()); // workaround to set the variable name inside the
// HeliosVariable object
if (!entry.getValue().isOk()) {
this.handleError("Variables definition file contains inconsistent data",
ThingStatusDetail.CONFIGURATION_ERROR);
}
}
} else {
this.handleError("Variables definition file not found or of illegal format",
ThingStatusDetail.CONFIGURATION_ERROR);
}
}
/**
* Get the endpoint handler from the bridge this handler is connected to
* Checks that we're connected to the right type of bridge
*
* @return the endpoint handler or null if the bridge does not exist
*/
private @Nullable ModbusEndpointThingHandler getEndpointThingHandler() {
Bridge bridge = getBridge();
if (bridge == null) {
logger.debug("Bridge is null");
return null;
}
if (bridge.getStatus() != ThingStatus.ONLINE) {
logger.debug("Bridge is not online");
return null;
}
ThingHandler handler = bridge.getHandler();
if (handler == null) {
logger.debug("Bridge handler is null");
return null;
}
if (handler instanceof ModbusEndpointThingHandler) {
return (ModbusEndpointThingHandler) handler;
} else {
logger.debug("Unexpected bridge handler: {}", handler);
return null;
}
}
/**
* Get a reference to the modbus endpoint
*/
private void connectEndpoint() {
if (this.comms != null) {
return;
}
ModbusEndpointThingHandler slaveEndpointThingHandler = getEndpointThingHandler();
if (slaveEndpointThingHandler == null) {
@SuppressWarnings("null")
String label = Optional.ofNullable(getBridge()).map(b -> b.getLabel()).orElse("<null>");
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.BRIDGE_OFFLINE,
String.format("Bridge '%s' is offline", label));
logger.debug("No bridge handler available -- aborting init for {}", label);
return;
}
comms = slaveEndpointThingHandler.getCommunicationInterface();
if (comms == null) {
@SuppressWarnings("null")
String label = Optional.ofNullable(getBridge()).map(b -> b.getLabel()).orElse("<null>");
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.BRIDGE_OFFLINE,
String.format("Bridge '%s' not completely initialized", label));
logger.debug("Bridge not initialized fully (no endpoint) -- aborting init for {}", this);
return;
}
}
@Override
public void initialize() {
this.config = getConfigAs(HeliosEasyControlsConfiguration.class);
this.readVariableDefinition();
this.connectEndpoint();
if ((this.comms != null) && (this.variableMap != null) && (this.config != null)) {
this.transactionLocks.putIfAbsent(this.comms.getEndpoint(), new Semaphore(1, true));
updateStatus(ThingStatus.UNKNOWN);
// background initialization
scheduler.execute(() -> {
readValue(HeliosEasyControlsBindingConstants.DATE_FORMAT);
// status will be updated to ONLINE by the read callback function (via processResponse)
});
// poll for status updates regularly
HeliosEasyControlsConfiguration config = this.config;
if (config != null) {
this.pollingJob = scheduler.scheduleWithFixedDelay(() -> {
if (variableMap != null) {
for (Map.Entry<String, HeliosVariable> entry : variableMap.entrySet()) {
if (this.isProperty(entry.getKey()) || isLinked(entry.getValue().getGroupAndName())
|| HeliosEasyControlsBindingConstants.ALWAYS_UPDATE_VARIABLES
.contains(entry.getKey())) {
readValue(entry.getKey());
}
}
} else {
handleError("Variable definition is null", ThingStatusDetail.CONFIGURATION_ERROR);
}
}, config.getRefreshInterval(), config.getRefreshInterval(), TimeUnit.MILLISECONDS);
}
} else { // at least one null assertion has failed, let's log the problem and update the thing status
if (this.comms == null) {
this.handleError("Modbus communication interface is unavailable",
ThingStatusDetail.COMMUNICATION_ERROR);
}
if (this.variableMap == null) {
this.handleError("Variable definition is unavailable", ThingStatusDetail.CONFIGURATION_ERROR);
}
if (this.config == null) {
this.handleError("Binding configuration is unavailable", ThingStatusDetail.CONFIGURATION_ERROR);
}
}
}
@Override
public void dispose() {
if (this.pollingJob != null) {
this.pollingJob.cancel(true);
}
this.comms = null;
}
@Override
public void handleCommand(ChannelUID channelUID, Command command) {
String channelId = channelUID.getIdWithoutGroup();
if (command instanceof RefreshType) {
if (channelId.equals(HeliosEasyControlsBindingConstants.SYS_DATE)) {
scheduler.submit(() -> readValue(HeliosEasyControlsBindingConstants.DATE));
scheduler.submit(() -> readValue(HeliosEasyControlsBindingConstants.TIME));
} else if (channelId.equals(HeliosEasyControlsBindingConstants.BYPASS_FROM)) {
scheduler.submit(() -> readValue(HeliosEasyControlsBindingConstants.BYPASS_FROM_DAY));
scheduler.submit(() -> readValue(HeliosEasyControlsBindingConstants.BYPASS_FROM_MONTH));
} else if (channelId.equals(HeliosEasyControlsBindingConstants.BYPASS_TO)) {
scheduler.submit(() -> readValue(HeliosEasyControlsBindingConstants.BYPASS_TO_DAY));
scheduler.submit(() -> readValue(HeliosEasyControlsBindingConstants.BYPASS_TO_MONTH));
} else {
scheduler.submit(() -> readValue(channelId));
}
} else { // write command
String value = null;
if (command instanceof OnOffType) {
value = command == OnOffType.ON ? "1" : "0";
} else if (command instanceof DateTimeType) {
ZonedDateTime d = ((DateTimeType) command).getZonedDateTime();
if (channelId.equals(HeliosEasyControlsBindingConstants.SYS_DATE)) {
setSysDateTime(d);
} else if (channelId.equals(HeliosEasyControlsBindingConstants.BYPASS_FROM)) {
this.setBypass(true, d.getDayOfMonth(), d.getMonthValue());
} else if (channelId.equals(HeliosEasyControlsBindingConstants.BYPASS_TO)) {
this.setBypass(false, d.getDayOfMonth(), d.getMonthValue());
} else {
value = formatDate(channelId, ((DateTimeType) command).getZonedDateTime());
}
} else if ((command instanceof DecimalType) || (command instanceof StringType)) {
value = command.toString();
} else if (command instanceof QuantityType<?>) {
// convert item's unit to the Helios device's unit
Map<String, HeliosVariable> variableMap = this.variableMap;
if (variableMap != null) {
String unit = variableMap.get(channelId).getUnit();
QuantityType<?> val = (QuantityType<?>) command;
if (unit != null) {
switch (unit) {
case HeliosVariable.UNIT_DAY:
val = val.toUnit(SmartHomeUnits.DAY);
break;
case HeliosVariable.UNIT_HOUR:
val = val.toUnit(SmartHomeUnits.HOUR);
break;
case HeliosVariable.UNIT_MIN:
val = val.toUnit(SmartHomeUnits.MINUTE);
break;
case HeliosVariable.UNIT_SEC:
val = val.toUnit(SmartHomeUnits.SECOND);
break;
case HeliosVariable.UNIT_VOLT:
val = val.toUnit(SmartHomeUnits.VOLT);
break;
case HeliosVariable.UNIT_PERCENT:
val = val.toUnit(SmartHomeUnits.PERCENT);
break;
case HeliosVariable.UNIT_PPM:
val = val.toUnit(SmartHomeUnits.PARTS_PER_MILLION);
break;
case HeliosVariable.UNIT_TEMP:
val = val.toUnit(SIUnits.CELSIUS);
break;
}
value = val != null ? String.valueOf(val.doubleValue()) : null; // ignore the UoM
}
}
}
if (value != null) {
final String v = value;
scheduler.submit(() -> {
try {
writeValue(channelId, v);
if (variableMap != null) {
updateState(variableMap.get(channelId), v);
updateStatus(ThingStatus.ONLINE);
}
} catch (HeliosException e) {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
"Writing value " + v + "to channel " + channelId + " failed: " + e.getMessage());
}
});
}
}
}
@Override
public Collection<Class<? extends ThingHandlerService>> getServices() {
return Collections.singleton(HeliosEasyControlsActions.class);
}
/**
* Checks if the provided variable name is a property
*
* @param variableName The variable's name
* @return true if the variable is a property
*/
private boolean isProperty(String variableName) {
return HeliosEasyControlsBindingConstants.PROPERTY_NAMES.contains(variableName);
}
/**
* Writes a variable value to the Helios device
*
* @param variableName The variable name
* @param value The new value
* @return The value if the transaction succeeded, <tt>null</tt> otherwise
* @throws HeliosException Thrown if the variable is read-only or the provided value is out of range
*/
public void writeValue(String variableName, String value) throws HeliosException {
if (this.variableMap == null) {
this.handleError("Variable definition is unavailable.", ThingStatusDetail.CONFIGURATION_ERROR);
return;
} else {
Map<String, HeliosVariable> variableMap = this.variableMap;
if (variableMap != null) {
HeliosVariable v = variableMap.get(variableName);
if (!v.hasWriteAccess()) {
throw new HeliosException("Variable " + variableName + " is read-only");
} else if (!v.isInAllowedRange(value)) {
throw new HeliosException(
"Value " + value + " is outside of allowed range of variable " + variableName);
} else if (this.comms != null) {
// write to device
String payload = v.getVariableString() + "=" + value;
ModbusCommunicationInterface comms = this.comms;
if (comms != null) {
final Semaphore lock = transactionLocks.get(comms.getEndpoint());
try {
lock.acquire();
comms.submitOneTimeWrite(
new ModbusWriteRegisterRequestBlueprint(HeliosEasyControlsBindingConstants.UNIT_ID,
HeliosEasyControlsBindingConstants.START_ADDRESS,
new ModbusRegisterArray(preparePayload(payload)), true,
HeliosEasyControlsBindingConstants.MAX_TRIES),
result -> {
lock.release();
updateStatus(ThingStatus.ONLINE);
}, failureInfo -> {
lock.release();
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
"Error writing to device: " + failureInfo.getCause().getMessage());
});
} catch (InterruptedException e) {
logger.warn(
"{} encountered Exception when trying to lock Semaphore for writing variable {} to the device: {}",
HeliosEasyControlsHandler.class.getSimpleName(), variableName, e.getMessage());
}
}
} else { // comms is null
this.handleError("Modbus communication interface is null", ThingStatusDetail.COMMUNICATION_ERROR);
}
}
}
}
/**
* Read a variable from the Helios device
*
* @param variableName The variable name
* @return The value
*/
public void readValue(String variableName) {
Map<String, HeliosVariable> variableMap = this.variableMap;
ModbusCommunicationInterface comms = this.comms;
if ((comms != null) && (variableMap != null)) {
final Semaphore lock = transactionLocks.get(comms.getEndpoint());
HeliosVariable v = variableMap.get(variableName);
if (v.hasReadAccess()) {
try {
lock.acquire(); // will block until lock is available
} catch (InterruptedException e) {
logger.warn("{} encountered Exception when trying to read variable {} from the device: {}",
HeliosEasyControlsHandler.class.getSimpleName(), variableName, e.getMessage());
return;
}
// write variable name to register
String payload = v.getVariableString();
comms.submitOneTimeWrite(new ModbusWriteRegisterRequestBlueprint(
HeliosEasyControlsBindingConstants.UNIT_ID, HeliosEasyControlsBindingConstants.START_ADDRESS,
new ModbusRegisterArray(preparePayload(payload)), true,
HeliosEasyControlsBindingConstants.MAX_TRIES), result -> {
comms.submitOneTimePoll(
new ModbusReadRequestBlueprint(HeliosEasyControlsBindingConstants.UNIT_ID,
ModbusReadFunctionCode.READ_MULTIPLE_REGISTERS,
HeliosEasyControlsBindingConstants.START_ADDRESS, v.getCount(),
HeliosEasyControlsBindingConstants.MAX_TRIES),
pollResult -> {
lock.release();
Optional<ModbusRegisterArray> registers = pollResult.getRegisters();
if (registers.isPresent()) {
processResponse(v, registers.get());
}
}, failureInfo -> {
lock.release();
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
"Error reading from device: " + failureInfo.getCause().getMessage());
});
}, failureInfo -> {
lock.release();
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
"Error writing to device: " + failureInfo.getCause().getMessage());
});
}
} else {
if (this.comms == null) {
this.handleError("Modbus communication interface is unavailable",
ThingStatusDetail.COMMUNICATION_ERROR);
}
if (variableMap == null) {
this.handleError("Variable definition is unavailable", ThingStatusDetail.CONFIGURATION_ERROR);
}
}
}
private void updateSysDate(DateTimeType dateTime) {
this.updateSysDateTime(dateTime.getZonedDateTime(), true, sysDate.getOffset().getTotalSeconds() / 60 / 60);
}
private void updateSysTime(DateTimeType dateTime) {
this.updateSysDateTime(dateTime.getZonedDateTime(), false, sysDate.getOffset().getTotalSeconds() / 60 / 60);
}
private void updateUtcOffset(int utcOffset) {
this.updateSysDateTime(this.sysDate, true, sysDate.getOffset().getTotalSeconds() / 60 / 60);
}
private void updateSysDateTime(ZonedDateTime dateTime, boolean updateDate, int utcOffset) {
ZonedDateTime sysDate = this.sysDate;
sysDate = ZonedDateTime.of(updateDate ? dateTime.getYear() : sysDate.getYear(),
updateDate ? dateTime.getMonthValue() : sysDate.getMonthValue(),
updateDate ? dateTime.getDayOfMonth() : sysDate.getDayOfMonth(),
updateDate ? sysDate.getHour() : dateTime.getHour(),
updateDate ? sysDate.getMinute() : dateTime.getMinute(),
updateDate ? sysDate.getSecond() : dateTime.getSecond(), 0,
ZoneId.of("UTC" + (utcOffset >= 0 ? "+" : "") + String.format("%02d", utcOffset) + ":00"));
updateState("general#" + HeliosEasyControlsBindingConstants.SYS_DATE, new DateTimeType(sysDate));
this.sysDate = sysDate;
}
private void setSysDateTime(ZonedDateTime date) {
try {
this.writeValue(HeliosEasyControlsBindingConstants.DATE,
this.formatDate(HeliosEasyControlsBindingConstants.DATE, date));
this.writeValue(HeliosEasyControlsBindingConstants.TIME,
date.getHour() + ":" + date.getMinute() + ":" + date.getSecond());
this.writeValue(HeliosEasyControlsBindingConstants.TIME_ZONE_DIFFERENCE_TO_GMT,
Integer.toString(date.getOffset().getTotalSeconds() / 60 / 60));
} catch (HeliosException e) {
logger.warn("{} encountered Exception when trying to set system date: {}",
HeliosEasyControlsHandler.class.getSimpleName(), e.getMessage());
}
}
protected void setSysDateTime() {
this.setSysDateTime(ZonedDateTime.now());
}
private void updateBypass(boolean from, boolean month, int val) {
BypassDate bypassDate = from ? this.bypassFrom : this.bypassTo;
if (bypassDate == null) {
bypassDate = new BypassDate();
}
if (month) {
bypassDate.setMonth(val);
} else {
bypassDate.setDay(val);
}
updateState("unitConfig#" + (from ? HeliosEasyControlsBindingConstants.BYPASS_FROM
: HeliosEasyControlsBindingConstants.BYPASS_TO), bypassDate.toDateTimeType());
if (from) {
this.bypassFrom = bypassDate;
} else {
this.bypassTo = bypassDate;
}
}
protected void setBypass(boolean from, int day, int month) {
try {
this.writeValue(from ? HeliosEasyControlsBindingConstants.BYPASS_FROM_DAY
: HeliosEasyControlsBindingConstants.BYPASS_TO_DAY, Integer.toString(day));
this.writeValue(from ? HeliosEasyControlsBindingConstants.BYPASS_FROM_MONTH
: HeliosEasyControlsBindingConstants.BYPASS_TO_MONTH, Integer.toString(month));
} catch (HeliosException e) {
logger.warn("{} encountered Exception when trying to set bypass period: {}",
HeliosEasyControlsHandler.class.getSimpleName(), e.getMessage());
}
}
/**
* Formats the provided date to a string in the device's configured date format
*
* @param variableName the variable name
* @param date the date to be formatted
* @return a string in the device's configured date format
*/
public String formatDate(String variableName, ZonedDateTime date) {
String y = Integer.toString(date.getYear());
String m = Integer.toString(date.getMonthValue());
if (m.length() == 1) {
m = "0" + m;
}
String d = Integer.toString(date.getDayOfMonth());
if (d.length() == 1) {
d = "0" + d;
}
if (variableName.equals(HeliosEasyControlsBindingConstants.DATE)) { // fixed format for writing the system date
return d + "." + m + "." + y;
} else {
switch (this.dateFormat) {
case 0: // dd.mm.yyyy
return d + "." + m + "." + y;
case 1: // mm.dd.yyyy
return m + "." + d + "." + y;
case 2: // yyyy.mm.dd
return y + "." + m + "." + d;
default:
return d + "." + m + "." + y;
}
}
}
/**
* Returns a DateTimeType object based on the provided String and the device's configured date format
*
* @param date The date string read from the device
* @return A DateTimeType object representing the date or time specified
*/
private DateTimeType toDateTime(String date) {
String[] dateTimeParts = null;
String dateTime = date;
dateTimeParts = date.split("\\."); // try to split date components
if (dateTimeParts.length == 1) { // time
return DateTimeType.valueOf(date);
} else if (dateTimeParts.length == 3) { // date - we'll try the device's date format
switch (this.dateFormat) {
case 0: // dd.mm.yyyy
dateTime = dateTimeParts[2] + "-" + dateTimeParts[1] + "-" + dateTimeParts[0];
break;
case 1: // mm.dd.yyyy
dateTime = dateTimeParts[2] + "-" + dateTimeParts[0] + "-" + dateTimeParts[1];
break;
case 2: // yyyy.mm.dd
dateTime = dateTimeParts[0] + "-" + dateTimeParts[1] + "-" + dateTimeParts[2];
break;
default:
dateTime = dateTimeParts[2] + "-" + dateTimeParts[1] + "-" + dateTimeParts[0];
break;
}
return DateTimeType.valueOf(dateTime);
}
// falling back to default date format (apparently using the configured format has failed)
dateTime = dateTimeParts[2] + "-" + dateTimeParts[1] + "-" + dateTimeParts[0];
return DateTimeType.valueOf(dateTime);
}
private @Nullable QuantityType<?> toQuantityType(String value, @Nullable String unit) {
if (unit == null) {
return null;
} else if (unit.equals(HeliosVariable.UNIT_DAY)) {
return new QuantityType<>(Integer.parseInt(value), SmartHomeUnits.DAY);
} else if (unit.equals(HeliosVariable.UNIT_HOUR)) {
return new QuantityType<>(Integer.parseInt(value), SmartHomeUnits.HOUR);
} else if (unit.equals(HeliosVariable.UNIT_MIN)) {
return new QuantityType<>(Integer.parseInt(value), SmartHomeUnits.MINUTE);
} else if (unit.equals(HeliosVariable.UNIT_SEC)) {
return new QuantityType<>(Integer.parseInt(value), SmartHomeUnits.SECOND);
} else if (unit.equals(HeliosVariable.UNIT_VOLT)) {
return new QuantityType<>(Float.parseFloat(value), SmartHomeUnits.VOLT);
} else if (unit.equals(HeliosVariable.UNIT_PERCENT)) {
return new QuantityType<>(Float.parseFloat(value), SmartHomeUnits.PERCENT);
} else if (unit.equals(HeliosVariable.UNIT_PPM)) {
return new QuantityType<>(Float.parseFloat(value), SmartHomeUnits.PARTS_PER_MILLION);
} else if (unit.equals(HeliosVariable.UNIT_TEMP)) {
return new QuantityType<>(Float.parseFloat(value), SIUnits.CELSIUS);
} else {
return null;
}
}
/**
* Prepares the payload for the request
*
* @param payload The String representation of the payload
* @return The Register representation of the payload
*/
private ModbusRegister[] preparePayload(String payload) {
// determine number of registers
int l = (payload.length() + 1) / 2; // +1 because we need to include at least one termination symbol 0x00
if ((payload.length() + 1) % 2 != 0) {
l++;
}
ModbusRegister reg[] = new ModbusRegister[l];
byte[] b = payload.getBytes();
int ch = 0;
for (int i = 0; i < reg.length; i++) {
byte b1 = ch < b.length ? b[ch] : (byte) 0x00; // terminate with 0x00 if at the end of the payload
ch++;
byte b2 = ch < b.length ? b[ch] : (byte) 0x00;
ch++;
reg[i] = new ModbusRegister(b1, b2);
}
return reg;
}
/**
* Decodes the Helios device' response and updates the channel with the actual value of the variable
*
* @param response The registers received from the Helios device
* @return The value or <tt>null</tt> if an error occurred
*/
private void processResponse(HeliosVariable v, ModbusRegisterArray registers) {
String r = ModbusBitUtilities
.extractStringFromRegisters(registers, 0, registers.size() * 2, StandardCharsets.US_ASCII).toString();
String[] parts = r.split("=", 2); // remove the part "vXXXX=" from the string
// making sure we have a proper response and the response matches the requested variable
if ((parts.length == 2) && (v.getVariableString().equals(parts[0]))) {
if (this.isProperty(v.getName())) {
try {
updateProperty(v.getName(), v.formatPropertyValue(parts[1]));
} catch (HeliosException e) {
logger.warn("{} encountered Exception when trying to update property: {}",
HeliosEasyControlsHandler.class.getSimpleName(), e.getMessage());
}
} else {
this.updateState(v, parts[1]);
}
} else { // another variable was read
logger.warn("{} tried to read value from variable {} and the result provided by the device was {}",
HeliosEasyControlsHandler.class.getSimpleName(), v.getName(), r);
}
}
private void updateState(HeliosVariable v, String value) {
String variableType = v.getType();
// System date and time
if (v.getName().equals(HeliosEasyControlsBindingConstants.DATE)) {
this.updateSysDate(this.toDateTime(value));
} else if (v.getName().equals(HeliosEasyControlsBindingConstants.TIME)) {
this.updateSysTime(this.toDateTime(value));
} else if (v.getName().equals(HeliosEasyControlsBindingConstants.TIME_ZONE_DIFFERENCE_TO_GMT)) {
this.updateUtcOffset(Integer.parseInt(value));
// Bypass
} else if (v.getName().equals(HeliosEasyControlsBindingConstants.BYPASS_FROM_DAY)) {
this.updateBypass(true, false, Integer.parseInt(value));
} else if (v.getName().equals(HeliosEasyControlsBindingConstants.BYPASS_FROM_MONTH)) {
this.updateBypass(true, true, Integer.parseInt(value));
} else if (v.getName().equals(HeliosEasyControlsBindingConstants.BYPASS_TO_DAY)) {
this.updateBypass(false, false, Integer.parseInt(value));
} else if (v.getName().equals(HeliosEasyControlsBindingConstants.BYPASS_TO_MONTH)) {
this.updateBypass(false, true, Integer.parseInt(value));
} else {
Channel channel = getThing().getChannel(v.getGroupAndName());
String itemType;
if (channel != null) {
itemType = channel.getAcceptedItemType();
if (itemType != null) {
if (itemType.startsWith("Number:")) {
itemType = "Number";
}
switch (itemType) {
case "Number":
if (((variableType.equals(HeliosVariable.TYPE_INTEGER))
|| (variableType == HeliosVariable.TYPE_FLOAT)) && (!value.equals("-"))) {
State state = null;
if (v.getUnit() == null) {
state = DecimalType.valueOf(value);
} else { // QuantityType
state = this.toQuantityType(value, v.getUnit());
}
if (state != null) {
updateState(v.getGroupAndName(), state);
updateStatus(ThingStatus.ONLINE);
// update date format and UTC offset upon read
if (v.getName().equals(HeliosEasyControlsBindingConstants.DATE_FORMAT)) {
this.dateFormat = Integer.parseInt(value);
}
}
}
break;
case "Switch":
if (variableType.equals(HeliosVariable.TYPE_INTEGER)) {
updateState(v.getGroupAndName(), value.equals("1") ? OnOffType.ON : OnOffType.OFF);
}
break;
case "String":
if (variableType.equals(HeliosVariable.TYPE_STRING)) {
updateState(v.getGroupAndName(), StringType.valueOf(value));
}
break;
case "DateTime":
if (variableType.equals(HeliosVariable.TYPE_STRING)) {
updateState(v.getGroupAndName(), toDateTime(value));
}
break;
}
} else { // itemType was null
logger.warn("{} couldn't determine item type of variable {}",
HeliosEasyControlsHandler.class.getSimpleName(), v.getName());
}
} else { // channel was null
logger.warn("{} couldn't find channel for variable {}", HeliosEasyControlsHandler.class.getSimpleName(),
v.getName());
}
}
}
/**
* Logs an error (as a warning entry) and updates the thing status
*
* @param errorMsg The error message to be logged and provided with the Thing's status update
* @param status The Thing's new status
*/
private void handleError(String errorMsg, ThingStatusDetail status) {
updateStatus(ThingStatus.OFFLINE, status, errorMsg);
}
}

View File

@@ -0,0 +1,55 @@
/**
* Copyright (c) 2010-2020 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.modbus.helioseasycontrols.internal;
import static org.openhab.binding.modbus.helioseasycontrols.internal.HeliosEasyControlsBindingConstants.THING_TYPE_HELIOS_VENTILATION_EASY_CONTROLS;
import java.util.Collections;
import java.util.Set;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
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;
/**
* The {@link HeliosEasyControlsHandlerFactory} is responsible for creating things and thing
* handlers.
*
* @author Bernhard Bauer - Initial contribution
*/
@NonNullByDefault
@Component(configurationPid = "binding.helioseasycontrols", service = ThingHandlerFactory.class)
public class HeliosEasyControlsHandlerFactory extends BaseThingHandlerFactory {
private static final Set<ThingTypeUID> SUPPORTED_THING_TYPES_UIDS = Collections
.singleton(THING_TYPE_HELIOS_VENTILATION_EASY_CONTROLS);
@Override
public boolean supportsThingType(ThingTypeUID thingTypeUID) {
return SUPPORTED_THING_TYPES_UIDS.contains(thingTypeUID);
}
@Override
protected @Nullable ThingHandler createHandler(Thing thing) {
ThingTypeUID thingTypeUID = thing.getThingTypeUID();
if (THING_TYPE_HELIOS_VENTILATION_EASY_CONTROLS.equals(thingTypeUID)) {
return new HeliosEasyControlsHandler(thing);
}
return null;
}
}

View File

@@ -0,0 +1,31 @@
/**
* Copyright (c) 2010-2020 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.modbus.helioseasycontrols.internal;
import org.eclipse.jdt.annotation.NonNullByDefault;
/**
* This class represents an exception specific to the HeliosEasyControls protocol.
*
* @author Bernhard Bauer - Initial contribution
* @version 2.0
*/
@NonNullByDefault
public class HeliosException extends Exception {
private static final long serialVersionUID = -7256846679824295950L;
public HeliosException(String msg) {
super(msg);
}
}

View File

@@ -0,0 +1,531 @@
/**
* 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.modbus.helioseasycontrols.internal;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
/**
* This class represents a variable of the Helios modbus.
*
* @author Bernhard Bauer - Initial contribution
* @version 2.0
*/
@NonNullByDefault
public class HeliosVariable implements Comparable<HeliosVariable> {
/**
* Read access
*/
public static final String ACCESS_R = "R";
/**
* Write access
*/
public static final String ACCESS_W = "W";
/**
* Read and write access
*/
public static final String ACCESS_RW = "RW";
/**
* Integer type
*/
public static final String TYPE_INTEGER = "int";
/**
* Float type
*/
public static final String TYPE_FLOAT = "float";
/**
* String type
*/
public static final String TYPE_STRING = "string";
/**
* Unit Volt
*/
public static final String UNIT_VOLT = "V";
/**
* Unit %
*/
public static final String UNIT_PERCENT = "%";
/**
* Unit ppm
*/
public static final String UNIT_PPM = "ppm";
/**
* Unit degrees Celsius
*/
public static final String UNIT_TEMP = "°C";
/**
* Unit day
*/
public static final String UNIT_DAY = "d";
/**
* Unit hour
*/
public static final String UNIT_HOUR = "h";
/**
* Unit minute
*/
public static final String UNIT_MIN = "min";
/**
* Unit second
*/
public static final String UNIT_SEC = "s";
/**
* The variable number
*/
private int variable;
/**
* The variable name
*/
private String name;
/**
* The variable group
*/
private @Nullable String group;
/**
* The access to the variable
*/
private String access;
/**
* The length of the variable (number of chars)
*/
private int length;
/**
* The register count for this variable
*/
private int count;
/**
* The variable type
*/
private String type;
/**
* The variable's unit
*/
private @Nullable String unit;
/**
* The minimal value (or null if not applicable)
*/
private @Nullable Double minVal;
/**
* The maximum value (or null if not applicable)
*/
private @Nullable Double maxVal;
/**
* Constructor to set the member variables
*
* @param variable The variable's number
* @param name The variable's name
* @param group The variable's group
* @param access Access possibilities
* @param length Number of expected characters when writing to / reading from Modbus
* @param count Exact number of characters to write to Modbus
* @param type Variable type (string, integer or float)
* @param unit Variable's unit
* @param minVal Minimum value (only applicable for numeric values)
* @param maxVal Maximum value (only applicable for numeric values)
*/
public HeliosVariable(int variable, String name, @Nullable String group, String access, int length, int count,
String type, @Nullable String unit, @Nullable Double minVal, @Nullable Double maxVal) {
this.variable = variable;
this.name = name;
this.group = group;
this.access = access;
this.length = length;
this.count = count;
this.type = type;
this.unit = unit;
this.minVal = minVal;
this.maxVal = maxVal;
}
/**
* Constructor to set the member variables
*
* @param variable The variable's number
* @param name The variable's name
* @param group The variable's group
* @param access Access possibilities
* @param length Number of expected characters when writing to / reading from Modbus
* @param count Exact number of characters to write to Modbus
* @param type Variable type (string, integer or float)
* @param unit Variable's unit
*/
public HeliosVariable(int variable, String name, @Nullable String group, String access, int length, int count,
String type, String unit) {
this(variable, name, group, access, length, count, type, unit, null, null);
}
/**
* Constructor to set the member variables
*
* @param variable The variable's number
* @param name The variable's name
* @param group The variable's group
* @param access Access possibilities
* @param length Number of expected characters when writing to / reading from Modbus
* @param count Exact number of characters to write to Modbus
* @param type Variable type (string, integer or float)
*/
public HeliosVariable(int variable, String name, @Nullable String group, String access, int length, int count,
String type) {
this(variable, name, group, access, length, count, type, null, null, null);
}
/**
* Getter for variable
*
* @return variable
*/
public int getVariable() {
return this.variable;
}
/**
* Returns a formatted string representation for the variable
*
* @return String The string representation for the variable (e.g. 'v00020' for variable number 20)
*/
public String getVariableString() {
return String.format("v%05d", variable);
}
/**
* Setter for name
*
*/
public void setName(String name) {
this.name = name;
}
/**
* Getter for name
*
* @return name
*/
public String getName() {
return this.name;
}
/**
* Getter for group
*
* @return group
*/
public @Nullable String getGroup() {
return this.group;
}
/**
* Getter for access
*
* @return access
*/
public String getAccess() {
return this.access;
}
/**
* Getter for length
*
* @return length
*/
public int getLength() {
return this.length;
}
/**
* Getter for count
*
* @return count
*/
public int getCount() {
return this.count;
}
/**
* Getter for the type
*/
public String getType() {
return this.type;
}
/**
* Getter for the unit
*/
public @Nullable String getUnit() {
return this.unit;
}
/**
* Getter for minimum value
*
* @return minimum value
*/
public @Nullable Double getMinVal() {
return this.minVal;
}
/**
* Getter for maximum value
*
* @return maximum value
*/
public @Nullable Double getMaxVal() {
return this.maxVal;
}
/**
* Returns the variable's name and prefixes the group, separated by a # if available
*
* @return the variable's name and prefixes the group, separated by a # if available
*/
public String getGroupAndName() {
return this.group != null ? this.group + "#" + this.name : this.name;
}
/**
* Checks if the variable's data are consistent
*
* @return true if the variable contains consistent data
*/
public boolean isOk() {
boolean check;
// this.access has one of the allowed values
check = (this.access.equals(HeliosVariable.ACCESS_R)) || (this.access.equals(HeliosVariable.ACCESS_W))
|| (this.access.equals(HeliosVariable.ACCESS_RW));
// this.type has one of the allowed values
check = check && ((this.type.equals(HeliosVariable.TYPE_STRING))
|| (this.type.equals(HeliosVariable.TYPE_INTEGER)) || (this.type.equals(HeliosVariable.TYPE_FLOAT)));
// this.minValue and this.maxValue are either not set or minValue is less than maxValue
Double minVal = this.getMinVal();
Double maxVal = this.getMaxVal();
check = check && (((minVal == null) && (maxVal == null))
|| ((minVal != null) && (maxVal != null) && (minVal <= maxVal)));
// length is set
check = check && (this.length > 0);
// count is set
check = check && (this.count > 0);
return check;
}
/**
* Checks if the variable has write access
*
* @return true if the variable has write access
*/
public boolean hasWriteAccess() {
return (this.access.equals(HeliosVariable.ACCESS_W)) || (this.access.equals(HeliosVariable.ACCESS_RW));
}
/**
* Checks if the variable has read access
*
* @return true if the variable has read access
*/
public boolean hasReadAccess() {
return (this.access.equals(HeliosVariable.ACCESS_R)) || (this.access.equals(HeliosVariable.ACCESS_RW));
}
/**
* Checks if the provided value is within the accepted range
*
* @param value The value as a string
* @return true if the value is within the accepted range
*/
public boolean isInAllowedRange(String value) {
Double minVal = this.getMinVal();
Double maxVal = this.getMaxVal();
if ((minVal != null) && (maxVal != null)) { // min and max value are set
try {
if (this.type.equals(HeliosVariable.TYPE_INTEGER)) {
// using long becuase some variable are specified with a max of 2^32-1
// parsing double to allow floating point values to be processed as well
long l = new Double(value).longValue();
return (minVal.longValue() <= l) && (maxVal.longValue() >= l);
} else if (this.type.equals(HeliosVariable.TYPE_FLOAT)) {
double d = Double.parseDouble(value);
return (minVal <= d) && (maxVal >= d);
}
} catch (NumberFormatException e) {
return false;
}
} else {
return true; // no range to check
}
return false;
}
/**
* Depending on the type of variable this method formats the provided value according to the interpretation of its
* value
*
* @param value The value to format
* @return The formatted value
* @throws HeliosException if the provided value doesn't fit to the variable
*/
public String formatPropertyValue(String value) throws HeliosException {
switch (this.getName()) {
case HeliosEasyControlsBindingConstants.DATE_FORMAT:
switch (value) {
case "0":
return "dd.mm.yyyy";
case "1":
return "mm.dd.yyyy";
case "2":
return "yyyy.mm.dd";
}
throw new HeliosException(this.createErrorMessage(value));
case HeliosEasyControlsBindingConstants.UNIT_CONFIG:
return value.equals("1") ? "DIBt" : "PHI";
case HeliosEasyControlsBindingConstants.KWL_BE:
case HeliosEasyControlsBindingConstants.KWL_BEC:
return value.equals("1") ? "On" : "Off";
case HeliosEasyControlsBindingConstants.EXTERNAL_CONTACT:
case HeliosEasyControlsBindingConstants.FUNCTION_TYPE_KWL_EM:
return "Function " + value;
case HeliosEasyControlsBindingConstants.HEAT_EXCHANGER_TYPE:
switch (value) {
case "0":
return "Plastic";
case "1":
return "Aluminium";
case "2":
return "Enthalpy";
}
throw new HeliosException(this.createErrorMessage(value));
case HeliosEasyControlsBindingConstants.OFFSET_EXTRACT_AIR:
case HeliosEasyControlsBindingConstants.VOLTAGE_FAN_STAGE_1_EXTRACT_AIR:
case HeliosEasyControlsBindingConstants.VOLTAGE_FAN_STAGE_2_EXTRACT_AIR:
case HeliosEasyControlsBindingConstants.VOLTAGE_FAN_STAGE_3_EXTRACT_AIR:
case HeliosEasyControlsBindingConstants.VOLTAGE_FAN_STAGE_4_EXTRACT_AIR:
case HeliosEasyControlsBindingConstants.VOLTAGE_FAN_STAGE_1_SUPPLY_AIR:
case HeliosEasyControlsBindingConstants.VOLTAGE_FAN_STAGE_2_SUPPLY_AIR:
case HeliosEasyControlsBindingConstants.VOLTAGE_FAN_STAGE_3_SUPPLY_AIR:
case HeliosEasyControlsBindingConstants.VOLTAGE_FAN_STAGE_4_SUPPLY_AIR:
return this.getUnit() != null ? value + this.getUnit() : value;
case HeliosEasyControlsBindingConstants.ASSIGNMENT_FAN_STAGES:
return value.equals("0") ? "0...10V" : "stepped";
case HeliosEasyControlsBindingConstants.FAN_STAGE_STEPPED_0TO2V:
case HeliosEasyControlsBindingConstants.FAN_STAGE_STEPPED_2TO4V:
case HeliosEasyControlsBindingConstants.FAN_STAGE_STEPPED_4TO6V:
case HeliosEasyControlsBindingConstants.FAN_STAGE_STEPPED_6TO8V:
case HeliosEasyControlsBindingConstants.FAN_STAGE_STEPPED_8TO10V:
case HeliosEasyControlsBindingConstants.SENSOR_NAME_HUMIDITY_AND_TEMP_1:
case HeliosEasyControlsBindingConstants.SENSOR_NAME_HUMIDITY_AND_TEMP_2:
case HeliosEasyControlsBindingConstants.SENSOR_NAME_HUMIDITY_AND_TEMP_3:
case HeliosEasyControlsBindingConstants.SENSOR_NAME_HUMIDITY_AND_TEMP_4:
case HeliosEasyControlsBindingConstants.SENSOR_NAME_HUMIDITY_AND_TEMP_5:
case HeliosEasyControlsBindingConstants.SENSOR_NAME_HUMIDITY_AND_TEMP_6:
case HeliosEasyControlsBindingConstants.SENSOR_NAME_HUMIDITY_AND_TEMP_7:
case HeliosEasyControlsBindingConstants.SENSOR_NAME_HUMIDITY_AND_TEMP_8:
return value;
case HeliosEasyControlsBindingConstants.VHZ_TYPE:
switch (value) {
case "1":
return "EH-basis";
case "2":
return "EH-EWR";
case "3":
return "SEWT";
case "4":
return "LEWT";
}
throw new HeliosException(this.createErrorMessage(value));
case HeliosEasyControlsBindingConstants.KWL_FTF_CONFIG_0:
case HeliosEasyControlsBindingConstants.KWL_FTF_CONFIG_1:
case HeliosEasyControlsBindingConstants.KWL_FTF_CONFIG_2:
case HeliosEasyControlsBindingConstants.KWL_FTF_CONFIG_3:
case HeliosEasyControlsBindingConstants.KWL_FTF_CONFIG_4:
case HeliosEasyControlsBindingConstants.KWL_FTF_CONFIG_5:
case HeliosEasyControlsBindingConstants.KWL_FTF_CONFIG_6:
case HeliosEasyControlsBindingConstants.KWL_FTF_CONFIG_7:
switch (value) {
case "1":
return "Relative Humidity";
case "2":
return "Temperature";
case "3":
return "Combined";
}
throw new HeliosException(this.createErrorMessage(value));
case HeliosEasyControlsBindingConstants.SENSOR_CONFIG_KWL_FTF_1:
case HeliosEasyControlsBindingConstants.SENSOR_CONFIG_KWL_FTF_2:
case HeliosEasyControlsBindingConstants.SENSOR_CONFIG_KWL_FTF_3:
case HeliosEasyControlsBindingConstants.SENSOR_CONFIG_KWL_FTF_4:
case HeliosEasyControlsBindingConstants.SENSOR_CONFIG_KWL_FTF_5:
case HeliosEasyControlsBindingConstants.SENSOR_CONFIG_KWL_FTF_6:
case HeliosEasyControlsBindingConstants.SENSOR_CONFIG_KWL_FTF_7:
case HeliosEasyControlsBindingConstants.SENSOR_CONFIG_KWL_FTF_8:
return value.equals("0") ? "No sensor" : "Sensor installed";
case HeliosEasyControlsBindingConstants.HUMIDITY_CONTROL_STATUS:
case HeliosEasyControlsBindingConstants.CO2_CONTROL_STATUS:
case HeliosEasyControlsBindingConstants.VOC_CONTROL_STATUS:
switch (value) {
case "0":
return "Off";
case "1":
return "Stepped";
case "2":
return "Continuous";
}
throw new HeliosException(this.createErrorMessage(value));
default:
return value;
}
}
private String createErrorMessage(String value) {
return "Illegal value for variable " + this.getName() + ": " + value;
}
@Override
public int compareTo(HeliosVariable v) {
return getVariable() - v.getVariable();
}
@Override
public String toString() {
return this.getVariableString() + ": " + this.getName() + " (" + this.getAccess() + ", " + this.getType()
+ (this.getMinVal() != null ? "[" + this.getMinVal() + "," + this.getMaxVal() + "]" : ")");
}
}

View File

@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<binding:binding id="modbus" 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>HeliosEasyControls Binding</name>
<description>This is the binding for a Helios ventilation system with easyControls using a Modbus TCP implementation.</description>
<author>Bernhard Bauer</author>
</binding:binding>

View File

@@ -0,0 +1,658 @@
<?xml version="1.0" encoding="UTF-8"?>
<thing:thing-descriptions bindingId="modbus"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:thing="https://openhab.org/schemas/thing-description/v1.0.0"
xsi:schemaLocation="https://openhab.org/schemas/thing-description/v1.0.0 https://openhab.org/schemas/thing-description-1.0.0.xsd">
<thing-type id="helios-easycontrols">
<supported-bridge-type-refs>
<bridge-type-ref id="tcp"/>
</supported-bridge-type-refs>
<label>Helios Ventilation</label>
<description>Supports controlling a Helios Heat-Recovery Ventilation Device with easyControls using the Modbus Gateway
TCP</description>
<category>HVAC</category>
<channel-groups>
<channel-group id="general" typeId="general"/>
<channel-group id="operation" typeId="operation"/>
<channel-group id="unitConfig" typeId="unitConfig"/>
<channel-group id="profiles" typeId="profiles"/>
<channel-group id="humidityControl" typeId="humidityControl"/>
<channel-group id="co2Control" typeId="co2Control"/>
<channel-group id="vocControl" typeId="vocControl"/>
</channel-groups>
<config-description>
<parameter name="refreshInterval" type="integer" unit="ms" min="30000">
<label>Refresh Interval</label>
<description>Refresh interval</description>
<default>60000</default>
</parameter>
</config-description>
</thing-type>
<!-- Channel Group Types -->
<channel-group-type id="general">
<label>General</label>
<description>General Parameters / Status Information</description>
<channels>
<!-- General Status Infos -->
<channel id="preHeaterStatus" typeId="onOff">
<label>Pre-Heater Status</label>
<description>Pre-Heater Status</description>
</channel>
<channel id="bypassStatus" typeId="bypassStatus"/>
<!-- Temperatures -->
<channel id="nhzDuctSensor" typeId="temperature">
<label>After Heater Duct Temperature</label>
</channel>
<channel id="nhzReturnSensor" typeId="temperature">
<label>After Heater Return Temperature</label>
</channel>
<channel id="vhzDuctSensor" typeId="temperature">
<label>Pre-Heater Duct Temperature</label>
</channel>
<channel id="temperatureOutsideAir" typeId="temperature">
<label>Outside Air Temperature</label>
</channel>
<channel id="temperatureSupplyAir" typeId="temperature">
<label>Supply Air Temperature</label>
</channel>
<channel id="temperatureOutgoingAir" typeId="temperature">
<label>Outgoing Air Temperature</label>
</channel>
<channel id="temperatureExtractAir" typeId="temperature">
<label>Extract Air Temperature</label>
</channel>
<!-- RPM -->
<channel id="supplyAirRpm" typeId="rpm">
<label>Supply Air Fan RPM</label>
</channel>
<channel id="extractAirRpm" typeId="rpm">
<label>Extract Air Fan RPM</label>
</channel>
<!-- Filter Change -->
<channel id="filterChangeRemainingTime" typeId="filterChangeRemainingTime"/>
<!-- Operating Hours -->
<channel id="operatingHoursSupplyAirVent" typeId="operatingHours">
<label>Operating Hours Supply Air Fan</label>
</channel>
<channel id="operatingHoursExtractAirVent" typeId="operatingHours">
<label>Operating Hours Extract Air Fan</label>
</channel>
<channel id="operatingHoursVhz" typeId="operatingHours">
<label>Operating Hours Pre-Heater</label>
</channel>
<channel id="operatingHoursNhz" typeId="operatingHours">
<label>Operating Hours After Heater</label>
</channel>
<!-- Power -->
<channel id="outputPowerVhz" typeId="outputPower">
<label>Output Power Pre-Heater</label>
</channel>
<channel id="outputPowerNhz" typeId="outputPower">
<label>Output Power After Heater</label>
</channel>
<!-- Infos / Warnings / Errors -->
<channel id="errors" typeId="errors"/>
<channel id="warnings" typeId="warnings"/>
<channel id="infos" typeId="infos"/>
<channel id="noOfErrors" typeId="noOfErrors"/>
<channel id="noOfWarnings" typeId="noOfWarnings"/>
<channel id="noOfInfos" typeId="noOfInfos"/>
<channel id="errorsMsg" typeId="message"/>
<channel id="warningsMsg" typeId="message"/>
<channel id="infosMsg" typeId="message"/>
<channel id="statusFlags" typeId="message"/>
<!-- System Settings -->
<channel id="sysdate" typeId="sysdate"/>
<channel id="summerWinter" typeId="summerWinter"/>
<!-- Software / Firmware -->
<channel id="autoSwUpdate" typeId="enableDisable">
<label>Automatic SW Updates</label>
<description>Indicates if automatic software updates are enabled</description>
</channel>
<channel id="accessHeliosPortal" typeId="enableDisable">
<label>Access Helios Portal</label>
<description>Indicates if access to Helios portal is enabled</description>
</channel>
</channels>
</channel-group-type>
<channel-group-type id="operation">
<label>Operation</label>
<description>Control of operating mode</description>
<channels>
<!-- Party Mode -->
<channel id="partyModeDuration" typeId="duration">
<label>Party Mode Duration</label>
<description>Party mode duration (in minutes)</description>
</channel>
<channel id="partyModeFanStage" typeId="fanStage">
<label>Party Mode Fan Stage</label>
<description>Party mode fan stage</description>
</channel>
<channel id="partyModeRemainingTime" typeId="remainingTime">
<label>Party Mode Remaining Time</label>
<description>Party mode remaining time</description>
</channel>
<channel id="partyModeStatus" typeId="onOff">
<label>Party Mode Status</label>
<description>Party mode status</description>
</channel>
<!-- Standby Mode -->
<channel id="standbyModeDuration" typeId="duration">
<label>Standby Mode Duration</label>
<description>Standby mode duration (in minutes)</description>
</channel>
<channel id="standbyModeFanStage" typeId="fanStage">
<label>Standby Mode Fan Stage</label>
<description>Standby mode fan stage</description>
</channel>
<channel id="standbyModeRemainingTime" typeId="remainingTime">
<label>Standby Mode Remaining Time</label>
<description>Standby mode remaining time</description>
</channel>
<channel id="standbyModeStatus" typeId="onOff">
<label>Standby Mode Status</label>
<description>Standby mode status</description>
</channel>
<!-- Holiday Programme -->
<channel id="holidayProgramme" typeId="holidayProgramme"/>
<channel id="holidayProgrammeFanStage" typeId="fanStage"/>
<channel id="holidayProgrammeStart" typeId="date">
<label>Holiday Programme Start</label>
<description>Holiday programme start</description>
</channel>
<channel id="holidayProgrammeEnd" typeId="date">
<label>Holiday Programme End</label>
<description>Holiday programme end</description>
</channel>
<channel id="holidayProgrammeInterval" typeId="holidayProgrammeInterval"/>
<channel id="holidayProgrammeActivationTime" typeId="holidayProgrammeActivationTime"/>
<!-- Operating Mode / Fan Stage -->
<channel id="operatingMode" typeId="operatingMode"/>
<channel id="fanStage" typeId="fanStage"/>
<channel id="percentageFanStage" typeId="percentage">
<label>Percentage Fan Stage</label>
<description>Fan stage in percent</description>
</channel>
<channel id="extractAirFanStage" typeId="fanStage"/>
<channel id="supplyAirFanStage" typeId="fanStage"/>
</channels>
</channel-group-type>
<channel-group-type id="unitConfig">
<label>Unit Config</label>
<description>Configuration parameters of the ventilation unit</description>
<channels>
<!-- Fan Stage Configuration -->
<channel id="minFanStage" typeId="minFanStage"/>
<!-- Bypass Configuration -->
<channel id="bypassRoomTemperature" typeId="bypassRoomTemperature"/>
<channel id="bypassMinOutsideTemperature" typeId="bypassMinOutsideTemperature"/>
<channel id="bypassFrom" typeId="bypass"/>
<channel id="bypassTo" typeId="bypass"/>
<!-- Comfort Temperature -->
<channel id="comfortTemp" typeId="comfortTemp"/>
<!-- Error Output Function -->
<channel id="errorOutputFunction" typeId="errorOutputFunction"/>
<!-- Filter Change -->
<channel id="filterChange" typeId="filterChange"/>
<channel id="filterChangeInterval" typeId="filterChangeInterval"/>
<!-- System Components and Extensions -->
<channel id="runOnTimeVhzNhz" typeId="runOnTimeVhzNhz"/>
</channels>
</channel-group-type>
<channel-group-type id="profiles">
<label>Profiles</label>
<description>Profiles for Device Operation</description>
<channels>
<channel id="weekProfileNhz" typeId="weekProfileNhz"/>
</channels>
</channel-group-type>
<channel-group-type id="humidityControl">
<label>Humidity Control</label>
<description>Config of Sensors for Humidity and/or Temperature Control</description>
<channels>
<channel id="humidityControlSetValue" typeId="humidityControlSetValue"/>
<channel id="humidityControlSteps" typeId="humidityControlSteps"/>
<channel id="humidityStopTime" typeId="humidityStopTime"/>
<!-- External Humidity Sensors -->
<channel id="externalSensorKwlFtfHumidity1" typeId="sensorValue"/>
<channel id="externalSensorKwlFtfHumidity2" typeId="sensorValue"/>
<channel id="externalSensorKwlFtfHumidity3" typeId="sensorValue"/>
<channel id="externalSensorKwlFtfHumidity4" typeId="sensorValue"/>
<channel id="externalSensorKwlFtfHumidity5" typeId="sensorValue"/>
<channel id="externalSensorKwlFtfHumidity6" typeId="sensorValue"/>
<channel id="externalSensorKwlFtfHumidity7" typeId="sensorValue"/>
<channel id="externalSensorKwlFtfHumidity8" typeId="sensorValue"/>
<!-- External Temperature Sensors -->
<channel id="externalSensorKwlFtfTemperature1" typeId="temperature"/>
<channel id="externalSensorKwlFtfTemperature2" typeId="temperature"/>
<channel id="externalSensorKwlFtfTemperature3" typeId="temperature"/>
<channel id="externalSensorKwlFtfTemperature4" typeId="temperature"/>
<channel id="externalSensorKwlFtfTemperature5" typeId="temperature"/>
<channel id="externalSensorKwlFtfTemperature6" typeId="temperature"/>
<channel id="externalSensorKwlFtfTemperature7" typeId="temperature"/>
<channel id="externalSensorKwlFtfTemperature8" typeId="temperature"/>
</channels>
</channel-group-type>
<channel-group-type id="co2Control">
<label>CO2 Control</label>
<description>Config of Sensors for CO2 Control</description>
<channels>
<channel id="co2ControlSetValue" typeId="ppmControlSetValue">
<label>CO2 Control Status</label>
<description>CO2 control status</description>
</channel>
<channel id="co2ControlSteps" typeId="ppmControlSteps">
<label>CO2 Control Steps</label>
<description>CO2 control steps (in ppm)</description>
</channel>
<!-- External CO2 Sensors -->
<channel id="externalSensorKwlCo21" typeId="sensorValue"/>
<channel id="externalSensorKwlCo22" typeId="sensorValue"/>
<channel id="externalSensorKwlCo23" typeId="sensorValue"/>
<channel id="externalSensorKwlCo24" typeId="sensorValue"/>
<channel id="externalSensorKwlCo25" typeId="sensorValue"/>
<channel id="externalSensorKwlCo26" typeId="sensorValue"/>
<channel id="externalSensorKwlCo27" typeId="sensorValue"/>
<channel id="externalSensorKwlCo28" typeId="sensorValue"/>
</channels>
</channel-group-type>
<channel-group-type id="vocControl">
<label>VOC Control</label>
<description>Config of Sensors for VOC Control</description>
<channels>
<channel id="vocControlSetValue" typeId="ppmControlSetValue">
<label>VOC Control Status</label>
<description>VOC control status</description>
</channel>
<channel id="vocControlSteps" typeId="ppmControlSteps">
<label>CO2 Control Steps</label>
<description>CO2 control steps (in ppm)</description>
</channel>
<!-- External CO2 Sensors -->
<channel id="externalSensorKwlVoc1" typeId="sensorValue"/>
<channel id="externalSensorKwlVoc2" typeId="sensorValue"/>
<channel id="externalSensorKwlVoc3" typeId="sensorValue"/>
<channel id="externalSensorKwlVoc4" typeId="sensorValue"/>
<channel id="externalSensorKwlVoc5" typeId="sensorValue"/>
<channel id="externalSensorKwlVoc6" typeId="sensorValue"/>
<channel id="externalSensorKwlVoc7" typeId="sensorValue"/>
<channel id="externalSensorKwlVoc8" typeId="sensorValue"/>
</channels>
</channel-group-type>
<!-- Channel Types -->
<channel-type id="sysdate" advanced="true">
<item-type>DateTime</item-type>
<label>System Date and Time</label>
<description>The KWL's system date and time</description>
<category>Time</category>
</channel-type>
<channel-type id="summerWinter" advanced="true">
<item-type>Number</item-type>
<label>Summertime / Wintertime</label>
<description>Indicates if summertime or wintertime is active</description>
<category>Time</category>
<state>
<options>
<option value="0">Wintertime</option>
<option value="1">Summertime</option>
</options>
</state>
</channel-type>
<channel-type id="enableDisable">
<item-type>Switch</item-type>
<label>Enable/Disable</label>
<description>Used for functionality that can be enabled or disabled</description>
</channel-type>
<channel-type id="minFanStage" advanced="true">
<item-type>Number</item-type>
<label>Minimum Fan Stage</label>
<description>Minimum fan stage (0 or 1)</description>
<category>HVAC</category>
<state min="0" max="1" step="1" readOnly="false"/>
</channel-type>
<channel-type id="onOff">
<item-type>Switch</item-type>
<label>On/Off</label>
<description>Used for configurations that can be on or off</description>
</channel-type>
<channel-type id="humidityControlSetValue" advanced="true">
<item-type>Number:Dimensionless</item-type>
<label>Humidity Control Set Value</label>
<description>Humidity control set value (in percent)</description>
<category>Humidity</category>
<state min="20" max="80" step="1" pattern="%d %unit%" readOnly="false"/>
</channel-type>
<channel-type id="humidityControlSteps" advanced="true">
<item-type>Number:Dimensionless</item-type>
<label>Humidity Control Steps</label>
<description>Humidity control steps (in percent)</description>
<category>Humidity</category>
<state min="5" max="20" step="1" pattern="%d %unit%" readOnly="false"/>
</channel-type>
<channel-type id="humidityStopTime" advanced="true">
<item-type>Number:Time</item-type>
<label>Humidity Stop Time</label>
<description>Humidity stop time in hours (0-24)</description>
<category>Humidity</category>
<state min="0" max="24" step="1" pattern="%d %unit%" readOnly="false"/>
</channel-type>
<channel-type id="ppmControlSetValue" advanced="true">
<item-type>Number:Dimensionless</item-type>
<label>Control Set Value</label>
<description>Control set value (in ppm)</description>
<category>Gas</category>
<state min="300" max="2000" step="1" pattern="%d %unit%" readOnly="false"/>
</channel-type>
<channel-type id="ppmControlSteps" advanced="true">
<item-type>Number:Dimensionless</item-type>
<label>Control Steps</label>
<description>Control steps (in ppm)</description>
<category>Gas</category>
<state min="50" max="400" step="1" pattern="%d %unit%" readOnly="false"/>
</channel-type>
<channel-type id="comfortTemp" advanced="true">
<item-type>Number:Temperature</item-type>
<label>Comfort Temperature</label>
<description>Comfort temperature</description>
<category>Temperature</category>
<state min="10" max="25" step="0.1" pattern="%.1f %unit%" readOnly="false"/>
</channel-type>
<channel-type id="duration" advanced="false">
<item-type>Number:Time</item-type>
<label>Duration</label>
<description>Duration for operating mode (in minutes)</description>
<state min="5" max="180" step="1" pattern="%d %unit%" readOnly="false"/>
</channel-type>
<channel-type id="fanStage" advanced="false">
<item-type>Number</item-type>
<label>Fan Stage</label>
<description>Fan stage</description>
<category>HVAC</category>
<state min="0" max="4" step="1" pattern="%d" readOnly="false"/>
</channel-type>
<channel-type id="remainingTime" advanced="false">
<item-type>Number:Time</item-type>
<label>Remaining Time</label>
<description>Remaining time for operating mode (in minutes)</description>
<state min="0" max="180" step="1" pattern="%d %unit%" readOnly="true"/>
</channel-type>
<channel-type id="operatingMode" advanced="false">
<item-type>Number</item-type>
<label>Operating Mode</label>
<description>Operating mode (automatic/manual)</description>
<state>
<options>
<option value="0">Automatic</option>
<option value="1">Manual</option>
</options>
</state>
</channel-type>
<channel-type id="percentage" advanced="false">
<item-type>Number:Dimensionless</item-type>
<label>Percentage</label>
<description>Percentage</description>
<state min="0" max="100" step="1" pattern="%d %unit%" readOnly="true"/>
</channel-type>
<channel-type id="temperature" advanced="false">
<item-type>Number:Temperature</item-type>
<label>Temperature</label>
<description>Temperature in °C</description>
<category>Temperature</category>
<state min="-27" max="9998.9" step="0.1" pattern="%.1f %unit%" readOnly="true"/>
</channel-type>
<channel-type id="sensorValue" advanced="false">
<item-type>Number:Dimensionless</item-type>
<label>Sensor Value</label>
<description>Measurement of a sensor</description>
<state min="0" max="9998.9" step="0.1" pattern="%.1f %unit%" readOnly="true"/>
</channel-type>
<channel-type id="weekProfileNhz" advanced="true">
<item-type>Number</item-type>
<label>Week Profile Afterheater</label>
<description>Week profile afterheater</description>
<state>
<options>
<option value="0">Standard 1</option>
<option value="1">Standard 2</option>
<option value="2">Fixed value</option>
<option value="3">Individual 1</option>
<option value="4">Individual 2</option>
<option value="5">NA</option>
<option value="6">Off</option>
</options>
</state>
</channel-type>
<channel-type id="rpm" advanced="false">
<item-type>Number</item-type>
<label>RPM</label>
<description>RPM</description>
<state min="0" max="9999" step="1" pattern="%d rpm" readOnly="true"/>
</channel-type>
<channel-type id="holidayProgramme" advanced="false">
<item-type>Number</item-type>
<label>Holiday Programme</label>
<description>Holiday programme</description>
<category>Vacation</category>
<state>
<options>
<option value="0">Off</option>
<option value="1">Interval</option>
<option value="2">Constant</option>
</options>
</state>
</channel-type>
<channel-type id="date" advanced="false">
<item-type>DateTime</item-type>
<label>Date</label>
<description>Date</description>
</channel-type>
<channel-type id="holidayProgrammeInterval" advanced="true">
<item-type>Number:Time</item-type>
<label>Holiday Programme Interval</label>
<description>Holiday programme interval in hours</description>
<category>Vacation</category>
<state min="1" max="24" step="1" pattern="%d %unit%" readOnly="false"/>
</channel-type>
<channel-type id="holidayProgrammeActivationTime" advanced="true">
<item-type>Number:Time</item-type>
<label>Holiday Programme Activation Time</label>
<description>Holiday programme activation time in minutes</description>
<category>Vacation</category>
<state min="5" max="300" step="1" pattern="%d %unit%" readOnly="false"/>
</channel-type>
<channel-type id="runOnTimeVhzNhz" advanced="true">
<item-type>Number:Time</item-type>
<label>Stopping Time Preheater/Afterheater</label>
<description>Stopping time preheater/afterheater in seconds</description>
<category>Heating</category>
<state min="60" max="120" step="1" pattern="%d %unit%" readOnly="false"/>
</channel-type>
<channel-type id="errorOutputFunction" advanced="true">
<item-type>Number</item-type>
<label>Error Output Function</label>
<description>Error output function (collective error or just error)</description>
<state>
<options>
<option value="1">Collective error</option>
<option value="2">Only error</option>
</options>
</state>
</channel-type>
<channel-type id="filterChange" advanced="false">
<item-type>Number</item-type>
<label>Filter Change</label>
<description>Filter change</description>
<state>
<options>
<option value="0">No</option>
<option value="1">Yes</option>
</options>
</state>
</channel-type>
<channel-type id="filterChangeInterval" advanced="true">
<item-type>Number:Time</item-type>
<label>Filter Change Interval</label>
<description>Filter change interval in months</description>
<state min="1" max="12" step="1" pattern="%d %unit%" readOnly="false"/>
</channel-type>
<channel-type id="filterChangeRemainingTime" advanced="true">
<item-type>Number:Time</item-type>
<label>Filter Change Remaining Time</label>
<description>Filter change remaining time in minutes</description>
<state min="1" max="550000" step="1" pattern="%d %unit%" readOnly="true"/>
</channel-type>
<channel-type id="bypassRoomTemperature" advanced="true">
<item-type>Number</item-type>
<label>Bypass Room Temperature</label>
<description>Bypass room temperature</description>
<category>Temperature</category>
<state min="10" max="40" step="1" pattern="%d %unit%" readOnly="false"/>
</channel-type>
<channel-type id="bypassMinOutsideTemperature" advanced="true">
<item-type>Number</item-type>
<label>Bypass Minimum Outside Temperature</label>
<description>Bypass minimum outside temperature</description>
<category>Temperature</category>
<state min="5" max="20" step="1" pattern="%d %unit%" readOnly="false"/>
</channel-type>
<channel-type id="offsetExtractAir" advanced="true">
<item-type>Number</item-type>
<label>Offset Extract Air</label>
<description>Offset extract air</description>
<category>HVAC</category>
<state pattern="%.1f" readOnly="false"/>
</channel-type>
<channel-type id="operatingHours" advanced="false">
<item-type>Number</item-type>
<label>Operating Hours</label>
<description>Operating hours (in minutes)</description>
<category>Time</category>
<state min="0" max="100000000" step="1" pattern="%d" readOnly="true"/>
</channel-type>
<channel-type id="outputPower" advanced="false">
<item-type>Number</item-type>
<label>Output Power</label>
<description>Output power of preheater/afterheater (in percent)</description>
<category>Energy</category>
<state min="0" max="100000000" step="1" pattern="%d %unit%" readOnly="true"/>
</channel-type>
<channel-type id="errors" advanced="false">
<item-type>Number</item-type>
<label>Errors</label>
<description>Errors as integer value</description>
<state min="0" max="4294967295" step="1" pattern="%d" readOnly="true"/>
</channel-type>
<channel-type id="warnings" advanced="false">
<item-type>Number</item-type>
<label>Warnings</label>
<description>Warnings as integer value</description>
<state min="0" max="255" step="1" pattern="%d" readOnly="true"/>
</channel-type>
<channel-type id="infos" advanced="false">
<item-type>Number</item-type>
<label>Infos</label>
<description>Infos as integer value</description>
<state min="0" max="255" step="1" pattern="%d" readOnly="true"/>
</channel-type>
<channel-type id="noOfErrors" advanced="false">
<item-type>Number</item-type>
<label>Number of Errors</label>
<description>Number of bit-coded errors</description>
<state min="0" max="32" step="1" pattern="%d" readOnly="true"/>
</channel-type>
<channel-type id="noOfWarnings" advanced="false">
<item-type>Number</item-type>
<label>Number of Warnings</label>
<description>Number of bit-coded warnings</description>
<state min="0" max="8" step="1" pattern="%d" readOnly="true"/>
</channel-type>
<channel-type id="noOfInfos" advanced="false">
<item-type>Number</item-type>
<label>Number of Infos</label>
<description>Number of bit-coded infos</description>
<state min="0" max="8" step="1" pattern="%d" readOnly="true"/>
</channel-type>
<channel-type id="message" advanced="false">
<item-type>String</item-type>
<label>Errors / Warnings / Infos</label>
<description>Errors / warnings / infos as string</description>
<state readOnly="true"/>
</channel-type>
<channel-type id="sensorConfig" advanced="false">
<item-type>Switch</item-type>
<label>Sensor Configuration</label>
<description>Sensor configuration (installed or not)</description>
</channel-type>
<channel-type id="bypassStatus" advanced="true">
<item-type>Switch</item-type>
<label>Bypass Status</label>
<description>Status of the bypass</description>
</channel-type>
<channel-type id="bypass" advanced="true">
<item-type>DateTime</item-type>
<label>Bypass Active from/to (Day and Month)</label>
<description>Bypass will be active/deactivated from that day and month on</description>
<category>Time</category>
</channel-type>
</thing:thing-descriptions>

View File

@@ -0,0 +1,189 @@
{
"articleDescription": {"group": "general", "variable": 0, "access": "RW", "length": 31, "count": 20, "type": "string"},
"refNo": {"group": "general", "variable": 1, "access": "RW", "length": 16, "count": 12, "type": "string"},
"macAddress": {"group": "general", "variable": 2, "access": "R", "length": 18, "count": 13, "type": "string"},
"language": {"group": "general", "variable": 3, "access": "RW", "length": 2, "count": 5, "type": "string"},
"date": {"group": "general", "variable": 4, "access": "RW", "length": 10, "count": 9, "type": "string"},
"time": {"group": "general", "variable": 5, "access": "RW", "length": 10, "count": 9, "type": "string"},
"summerWinter": {"group": "general", "variable": 6, "access": "RW", "length": 1, "count": 5, "type": "int"},
"autoSwUpdate": {"group": "general", "variable": 7, "access": "RW", "length": 1, "count": 5, "type": "int"},
"accessHeliosPortal": {"group": "general", "variable": 8, "access": "RW", "length": 1, "count": 5, "type": "int"},
"voltageFanStage1ExtractAir": {"group": "unitConfig", "variable": 12, "access": "RW", "length": 3, "count": 6, "type": "float", "unit": "V", "minVal": 1.6, "maxVal": 10.0},
"voltageFanStage2ExtractAir": {"group": "unitConfig", "variable": 13, "access": "RW", "length": 3, "count": 6, "type": "float", "unit": "V", "minVal": 1.6, "maxVal": 10.0},
"voltageFanStage3ExtractAir": {"group": "unitConfig", "variable": 14, "access": "RW", "length": 3, "count": 6, "type": "float", "unit": "V", "minVal": 1.6, "maxVal": 10.0},
"voltageFanStage4ExtractAir": {"group": "unitConfig", "variable": 15, "access": "RW", "length": 3, "count": 6, "type": "float", "unit": "V", "minVal": 1.6, "maxVal": 10.0},
"voltageFanStage1SupplyAir": {"group": "unitConfig", "variable": 16, "access": "RW", "length": 3, "count": 6, "type": "float", "unit": "V", "minVal": 1.6, "maxVal": 10.0},
"voltageFanStage2SupplyAir": {"group": "unitConfig", "variable": 17, "access": "RW", "length": 3, "count": 6, "type": "float", "unit": "V", "minVal": 1.6, "maxVal": 10.0},
"voltageFanStage3SupplyAir": {"group": "unitConfig", "variable": 18, "access": "RW", "length": 3, "count": 6, "type": "float", "unit": "V", "minVal": 1.6, "maxVal": 10.0},
"voltageFanStage4SupplyAir": {"group": "unitConfig", "variable": 19, "access": "RW", "length": 3, "count": 6, "type": "float", "unit": "V", "minVal": 1.6, "maxVal": 10.0},
"minFanStage": {"group": "unitConfig", "variable": 20, "access": "RW", "length": 1, "count": 5, "type": "int", "minVal": 0, "maxVal": 1},
"kwlBe": {"group": "unitConfig", "variable": 21, "access": "RW", "length": 1, "count": 5, "type": "int", "minVal": 0, "maxVal": 1},
"kwlBec": {"group": "unitConfig", "variable": 22, "access": "RW", "length": 1, "count": 5, "type": "int", "minVal": 0, "maxVal": 1},
"unitConfig": {"group": "unitConfig", "variable": 23, "access": "RW", "length": 1, "count": 5, "type": "int", "minVal": 0, "maxVal": 1},
"preHeaterStatus": {"group": "general", "variable": 24, "access": "RW", "length": 1, "count": 5, "type": "int", "minVal": 0, "maxVal": 1},
"kwlFtfConfig0": {"group": "humidityControl", "variable": 25, "access": "RW", "length": 1, "count": 5, "type": "int", "minVal": 1, "maxVal": 3},
"kwlFtfConfig1": {"group": "humidityControl", "variable": 26, "access": "RW", "length": 1, "count": 5, "type": "int", "minVal": 1, "maxVal": 3},
"kwlFtfConfig2": {"group": "humidityControl", "variable": 27, "access": "RW", "length": 1, "count": 5, "type": "int", "minVal": 1, "maxVal": 3},
"kwlFtfConfig3": {"group": "humidityControl", "variable": 28, "access": "RW", "length": 1, "count": 5, "type": "int", "minVal": 1, "maxVal": 3},
"kwlFtfConfig4": {"group": "humidityControl", "variable": 29, "access": "RW", "length": 1, "count": 5, "type": "int", "minVal": 1, "maxVal": 3},
"kwlFtfConfig5": {"group": "humidityControl", "variable": 30, "access": "RW", "length": 1, "count": 5, "type": "int", "minVal": 1, "maxVal": 3},
"kwlFtfConfig6": {"group": "humidityControl", "variable": 31, "access": "RW", "length": 1, "count": 5, "type": "int", "minVal": 1, "maxVal": 3},
"kwlFtfConfig7": {"group": "humidityControl", "variable": 32, "access": "RW", "length": 1, "count": 5, "type": "int", "minVal": 1, "maxVal": 3},
"humidityControlStatus": {"group": "humidityControl", "variable": 33, "access": "RW", "length": 1, "count": 5, "type": "int", "minVal": 0, "maxVal": 2},
"humidityControlSetValue": {"group": "humidityControl", "variable": 34, "access": "RW", "length": 2, "count": 5, "type": "int", "unit": "%", "minVal": 20, "maxVal": 80},
"humidityControlSteps": {"group": "humidityControl", "variable": 35, "access": "RW", "length": 2, "count": 5, "type": "int", "unit": "%", "minVal": 5, "maxVal": 20},
"humidityStopTime": {"group": "humidityControl", "variable": 36, "access": "RW", "length": 2, "count": 5, "type": "int", "unit": "h", "minVal": 0, "maxVal": 24},
"co2ControlStatus": {"group": "co2Control", "variable": 37, "access": "RW", "length": 1, "count": 5, "type": "int", "minVal": 0, "maxVal": 2},
"co2ControlSetValue": {"group": "co2Control", "variable": 38, "access": "RW", "length": 4, "count": 6, "type": "int", "unit": "ppm", "minVal": 300, "maxVal": 2000},
"co2ControlSteps": {"group": "co2Control", "variable": 39, "access": "RW", "length": 3, "count": 6, "type": "int", "unit": "ppm", "minVal": 50, "maxVal": 400},
"vocControlStatus": {"group": "vocControl", "variable": 40, "access": "RW", "length": 1, "count": 5, "type": "int", "minVal": 0, "maxVal": 2},
"vocControlSetValue": {"group": "vocControl", "variable": 41, "access": "RW", "length": 4, "count": 6, "type": "int", "unit": "ppm", "minVal": 300, "maxVal": 2000},
"vocControlSteps": {"group": "vocControl", "variable": 42, "access": "RW", "length": 3, "count": 6, "type": "int", "unit": "ppm", "minVal": 50, "maxVal": 400},
"comfortTemp": {"group": "unitConfig", "variable": 43, "access": "RW", "length": 4, "count": 6, "type": "int", "unit": "°C", "minVal": 10, "maxVal": 25},
"timeZoneDifferenceToGmt": {"group": "general", "variable": 51, "access": "RW", "length": 3, "count": 6, "type": "int", "unit": "h", "minVal": -12, "maxVal": 14},
"dateFormat": {"group": "general", "variable": 52, "access": "RW", "length": 1, "count": 5, "type": "int", "minVal": 0, "maxVal": 2},
"heatExchangerType": {"group": "unitConfig", "variable": 53, "access": "RW", "length": 1, "count": 5, "type": "int", "minVal": 1, "maxVal": 3},
"partyModeDuration": {"group": "operation", "variable": 91, "access": "RW", "length": 3, "count": 6, "type": "int", "unit": "min", "minVal": 5, "maxVal": 180},
"partyModeFanStage": {"group": "operation", "variable": 92, "access": "RW", "length": 3, "count": 5, "type": "int", "minVal": 0, "maxVal": 4},
"partyModeRemainingTime": {"group": "operation", "variable": 93, "access": "R", "length": 3, "count": 6, "type": "int", "unit": "min", "minVal": 0, "maxVal": 180},
"partyModeStatus": {"group": "operation", "variable": 94, "access": "RW", "length": 1, "count": 5, "type": "int", "minVal": 0, "maxVal": 1},
"standbyModeDuration": {"group": "operation", "variable": 96, "access": "RW", "length": 3, "count": 6, "type": "int", "unit": "min", "minVal": 5, "maxVal": 180},
"standbyModeFanStage": {"group": "operation", "variable": 97, "access": "RW", "length": 1, "count": 5, "type": "int", "minVal": 0, "maxVal": 4},
"standbyModeRemainingTime": {"group": "operation", "variable": 98, "access": "R", "length": 3, "count": 6, "type": "int", "unit": "min", "minVal": 0, "maxVal": 180},
"standbyModeStatus": {"group": "operation", "variable": 99, "access": "RW", "length": 1, "count": 5, "type": "int", "minVal": 0, "maxVal": 1},
"operatingMode": {"group": "operation", "variable": 101, "access": "RW", "length": 1, "count": 5, "type": "int", "minVal": 0, "maxVal": 1},
"fanStage": {"group": "operation", "variable": 102, "access": "RW", "length": 1, "count": 5, "type": "int", "minVal": 0, "maxVal": 4},
"percentageFanStage": {"group": "operation", "variable": 103, "access": "R", "length": 3, "count": 6, "type": "int", "unit": "%", "minVal": 0, "maxVal": 100},
"temperatureOutsideAir": {"group": "general", "variable": 104, "access": "R", "length": 7, "count": 8, "type": "int", "unit": "°C", "minVal": -27, "maxVal": 9998},
"temperatureSupplyAir": {"group": "general", "variable": 105, "access": "R", "length": 7, "count": 8, "type": "int", "unit": "°C", "minVal": -27, "maxVal": 9998},
"temperatureOutgoingAir": {"group": "general", "variable": 106, "access": "R", "length": 7, "count": 8, "type": "int", "unit": "°C", "minVal": -27, "maxVal": 9998},
"temperatureExtractAir": {"group": "general", "variable": 107, "access": "R", "length": 7, "count": 8, "type": "int", "unit": "°C", "minVal": -27, "maxVal": 9998},
"vhzDuctSensor": {"group": "general", "variable": 108, "access": "R", "length": 7, "count": 8, "type": "int", "unit": "°C", "minVal": -27, "maxVal": 9998},
"nhzReturnSensor": {"group": "general", "variable": 110, "access": "R", "length": 7, "count": 8, "type": "int", "unit": "°C", "minVal": -27, "maxVal": 9998},
"externalSensorKwlFtfHumidity1": {"group": "humidityControl", "variable": 111, "access": "R", "length": 4, "count": 6, "type": "int", "unit": "%", "minVal": 0, "maxVal": 9998},
"externalSensorKwlFtfHumidity2": {"group": "humidityControl", "variable": 112, "access": "R", "length": 4, "count": 6, "type": "int", "unit": "%", "minVal": 0, "maxVal": 9998},
"externalSensorKwlFtfHumidity3": {"group": "humidityControl", "variable": 113, "access": "R", "length": 4, "count": 6, "type": "int", "unit": "%", "minVal": 0, "maxVal": 9998},
"externalSensorKwlFtfHumidity4": {"group": "humidityControl", "variable": 114, "access": "R", "length": 4, "count": 6, "type": "int", "unit": "%", "minVal": 0, "maxVal": 9998},
"externalSensorKwlFtfHumidity5": {"group": "humidityControl", "variable": 115, "access": "R", "length": 4, "count": 6, "type": "int", "unit": "%", "minVal": 0, "maxVal": 9998},
"externalSensorKwlFtfHumidity6": {"group": "humidityControl", "variable": 116, "access": "R", "length": 4, "count": 6, "type": "int", "unit": "%", "minVal": 0, "maxVal": 9998},
"externalSensorKwlFtfHumidity7": {"group": "humidityControl", "variable": 117, "access": "R", "length": 4, "count": 6, "type": "int", "unit": "%", "minVal": 0, "maxVal": 9998},
"externalSensorKwlFtfHumidity8": {"group": "humidityControl", "variable": 118, "access": "R", "length": 4, "count": 6, "type": "int", "unit": "%", "minVal": 0, "maxVal": 9998},
"externalSensorKwlFtfTemperature1": {"group": "humidityControl", "variable": 119, "access": "R", "length": 7, "count": 8, "type": "int", "unit": "°C", "minVal": -27, "maxVal": 9998},
"externalSensorKwlFtfTemperature2": {"group": "humidityControl", "variable": 120, "access": "R", "length": 7, "count": 8, "type": "int", "unit": "°C", "minVal": -27, "maxVal": 9998},
"externalSensorKwlFtfTemperature3": {"group": "humidityControl", "variable": 121, "access": "R", "length": 7, "count": 8, "type": "int", "unit": "°C", "minVal": -27, "maxVal": 9998},
"externalSensorKwlFtfTemperature4": {"group": "humidityControl", "variable": 122, "access": "R", "length": 7, "count": 8, "type": "int", "unit": "°C", "minVal": -27, "maxVal": 9998},
"externalSensorKwlFtfTemperature5": {"group": "humidityControl", "variable": 123, "access": "R", "length": 7, "count": 8, "type": "int", "unit": "°C", "minVal": -27, "maxVal": 9998},
"externalSensorKwlFtfTemperature6": {"group": "humidityControl", "variable": 124, "access": "R", "length": 7, "count": 8, "type": "int", "unit": "°C", "minVal": -27, "maxVal": 9998},
"externalSensorKwlFtfTemperature7": {"group": "humidityControl", "variable": 125, "access": "R", "length": 7, "count": 8, "type": "int", "unit": "°C", "minVal": -27, "maxVal": 9998},
"externalSensorKwlFtfTemperature8": {"group": "humidityControl", "variable": 126, "access": "R", "length": 7, "count": 8, "type": "int", "unit": "°C", "minVal": -27, "maxVal": 9998},
"externalSensorKwlCo21": {"group": "co2Control", "variable": 128, "access": "R", "length": 4, "count": 6, "type": "int", "unit": "ppm", "minVal": 0, "maxVal": 9998},
"externalSensorKwlCo22": {"group": "co2Control", "variable": 129, "access": "R", "length": 4, "count": 6, "type": "int", "unit": "ppm", "minVal": 0, "maxVal": 9998},
"externalSensorKwlCo23": {"group": "co2Control", "variable": 130, "access": "R", "length": 4, "count": 6, "type": "int", "unit": "ppm", "minVal": 0, "maxVal": 9998},
"externalSensorKwlCo24": {"group": "co2Control", "variable": 131, "access": "R", "length": 4, "count": 6, "type": "int", "unit": "ppm", "minVal": 0, "maxVal": 9998},
"externalSensorKwlCo25": {"group": "co2Control", "variable": 132, "access": "R", "length": 4, "count": 6, "type": "int", "unit": "ppm", "minVal": 0, "maxVal": 9998},
"externalSensorKwlCo26": {"group": "co2Control", "variable": 133, "access": "R", "length": 4, "count": 6, "type": "int", "unit": "ppm", "minVal": 0, "maxVal": 9998},
"externalSensorKwlCo27": {"group": "co2Control", "variable": 134, "access": "R", "length": 4, "count": 6, "type": "int", "unit": "ppm", "minVal": 0, "maxVal": 9998},
"externalSensorKwlCo28": {"group": "co2Control", "variable": 135, "access": "R", "length": 4, "count": 6, "type": "int", "unit": "ppm", "minVal": 0, "maxVal": 9998},
"externalSensorKwlVoc1": {"group": "vocControl", "variable": 136, "access": "R", "length": 4, "count": 6, "type": "int", "unit": "ppm", "minVal": 0, "maxVal": 9998},
"externalSensorKwlVoc2": {"group": "vocControl", "variable": 137, "access": "R", "length": 4, "count": 6, "type": "int", "unit": "ppm", "minVal": 0, "maxVal": 9998},
"externalSensorKwlVoc3": {"group": "vocControl", "variable": 138, "access": "R", "length": 4, "count": 6, "type": "int", "unit": "ppm", "minVal": 0, "maxVal": 9998},
"externalSensorKwlVoc4": {"group": "vocControl", "variable": 139, "access": "R", "length": 4, "count": 6, "type": "int", "unit": "ppm", "minVal": 0, "maxVal": 9998},
"externalSensorKwlVoc5": {"group": "vocControl", "variable": 140, "access": "R", "length": 4, "count": 6, "type": "int", "unit": "ppm", "minVal": 0, "maxVal": 9998},
"externalSensorKwlVoc6": {"group": "vocControl", "variable": 141, "access": "R", "length": 4, "count": 6, "type": "int", "unit": "ppm", "minVal": 0, "maxVal": 9998},
"externalSensorKwlVoc7": {"group": "vocControl", "variable": 142, "access": "R", "length": 4, "count": 6, "type": "int", "unit": "ppm", "minVal": 0, "maxVal": 9998},
"externalSensorKwlVoc8": {"group": "vocControl", "variable": 143, "access": "R", "length": 4, "count": 6, "type": "int", "unit": "ppm", "minVal": 0, "maxVal": 9998},
"nhzDuctSensor": {"group": "general", "variable": 146, "access": "R", "length": 7, "count": 8, "type": "int", "unit": "°C", "minVal": -27, "maxVal": 9998},
"weekProfileNhz": {"group": "profiles", "variable": 201, "access": "RW", "length": 1, "count": 5, "type": "int", "minVal": 0, "maxVal": 6},
"serNo": {"group": "general", "variable": 303, "access": "RW", "length": 16, "count": 12, "type": "string"},
"prodCode": {"group": "general", "variable": 304, "access": "RW", "length": 13, "count": 11, "type": "string"},
"supplyAirRpm": {"group": "general", "variable": 348, "access": "R", "length": 4, "count": 6, "type": "int", "minVal": 0, "maxVal": 9999},
"extractAirRpm": {"group": "general", "variable": 349, "access": "R", "length": 4, "count": 6, "type": "int", "minVal": 0, "maxVal": 9999},
"logout": {"group": "general", "variable": 403, "access": "W", "length": 1, "count": 5, "type": "int", "minVal": 1, "maxVal": 1},
"holidayProgramme": {"group": "operation", "variable": 601, "access": "RW", "length": 1, "count": 5, "type": "int", "minVal": 0, "maxVal": 2},
"holidayProgrammeFanStage": {"group": "operation", "variable": 602, "access": "RW", "length": 1, "count": 5, "type": "int", "minVal": 1, "maxVal": 4},
"holidayProgrammeStart": {"group": "operation", "variable": 603, "access": "RW", "length": 10, "count": 9, "type": "string"},
"holidayProgrammeEnd": {"group": "operation", "variable": 604, "access": "RW", "length": 10, "count": 9, "type": "string"},
"holidayProgrammeInterval": {"group": "operation", "variable": 605, "access": "RW", "length": 2, "count": 5, "type": "int", "unit": "h", "minVal": 1, "maxVal": 24},
"holidayProgrammeActivationTime": {"group": "operation", "variable": 606, "access": "RW", "length": 3, "count": 6, "type": "int", "unit": "min", "minVal": 5, "maxVal": 300},
"vhzType": {"group": "unitConfig", "variable": 1010, "access": "RW", "length": 1, "count": 5, "type": "int", "minVal": 1, "maxVal": 4},
"functionTypeKwlEm": {"group": "unitConfig", "variable": 1017, "access": "RW", "length": 1, "count": 5, "type": "int", "minVal": 1, "maxVal": 2},
"runOnTimeVhzNhz": {"group": "unitConfig", "variable": 1019, "access": "RW", "length": 3, "count": 6, "type": "int", "unit": "s", "minVal": 60, "maxVal": 120},
"externalContact": {"group": "unitConfig", "variable": 1020, "access": "RW", "length": 1, "count": 5, "type": "int", "minVal": 1, "maxVal": 6},
"errorOutputFunction": {"group": "unitConfig", "variable": 1021, "access": "RW", "length": 1, "count": 5, "type": "int", "minVal": 1, "maxVal": 2},
"filterChange": {"group": "unitConfig", "variable": 1031, "access": "RW", "length": 1, "count": 5, "type": "int", "minVal": 0, "maxVal": 1},
"filterChangeInterval": {"group": "unitConfig", "variable": 1032, "access": "RW", "length": 2, "count": 5, "type": "int", "minVal": 0, "maxVal": 12},
"filterChangeRemainingTime": {"group": "general", "variable": 1033, "access": "R", "length": 10, "count": 9, "type": "int", "unit": "min", "minVal": 2, "maxVal": 4294967295},
"filterChangeReset": {"group": "general", "variable": 1034, "access": "W", "length": 1, "count": 5, "type": "int", "minVal": 0, "maxVal": 1},
"bypassRoomTemperature": {"group": "unitConfig", "variable": 1035, "access": "RW", "length": 2, "count": 5, "type": "int", "unit": "°C", "minVal": 10, "maxVal": 40},
"bypassMinOutsideTemperature": {"group": "unitConfig", "variable": 1036, "access": "RW", "length": 2, "count": 5, "type": "int", "unit": "°C", "minVal": 5, "maxVal": 20},
"tbd": {"group": "general", "variable": 1037, "access": "RW", "length": 2, "count": 5, "type": "int", "unit": "°C", "minVal": 3, "maxVal": 10},
"factorySettingWzu": {"group": "general", "variable": 1041, "access": "RW", "length": 1, "count": 5, "type": "int", "minVal": 1, "maxVal": 1},
"factoryReset": {"group": "general", "variable": 1042, "access": "RW", "length": 1, "count": 5, "type": "int", "minVal": 1, "maxVal": 1},
"supplyAirFanStage": {"group": "operation", "variable": 1050, "access": "RW", "length": 1, "count": 5, "type": "int", "minVal": 1, "maxVal": 4},
"extractAirFanStage": {"group": "operation", "variable": 1051, "access": "RW", "length": 1, "count": 5, "type": "int", "minVal": 1, "maxVal": 4},
"fanStageStepped0to2v": {"group": "unitConfig", "variable": 1061, "access": "RW", "length": 1, "count": 5, "type": "int", "minVal": 0, "maxVal": 2},
"fanStageStepped2to4v": {"group": "unitConfig", "variable": 1062, "access": "RW", "length": 1, "count": 5, "type": "int", "minVal": 0, "maxVal": 4},
"fanStageStepped4to6v": {"group": "unitConfig", "variable": 1063, "access": "RW", "length": 1, "count": 5, "type": "int", "minVal": 0, "maxVal": 4},
"fanStageStepped6to8v": {"group": "unitConfig", "variable": 1064, "access": "RW", "length": 1, "count": 5, "type": "int", "minVal": 0, "maxVal": 4},
"fanStageStepped8to10v": {"group": "unitConfig", "variable": 1065, "access": "RW", "length": 1, "count": 5, "type": "int", "minVal": 0, "maxVal": 4},
"offsetExtractAir": {"group": "unitConfig", "variable": 1066, "access": "RW", "length": 10, "count": 9, "type": "float"},
"assignmentFanStages": {"group": "unitConfig", "variable": 1068, "access": "RW", "length": 1, "count": 5, "type": "int", "minVal": 0, "maxVal": 1},
"sensorNameHumidityAndTemp1": {"group": "humidityControl", "variable": 1071, "access": "RW", "length": 15, "count": 12, "type": "string"},
"sensorNameHumidityAndTemp2": {"group": "humidityControl", "variable": 1072, "access": "RW", "length": 15, "count": 12, "type": "string"},
"sensorNameHumidityAndTemp3": {"group": "humidityControl", "variable": 1073, "access": "RW", "length": 15, "count": 12, "type": "string"},
"sensorNameHumidityAndTemp4": {"group": "humidityControl", "variable": 1074, "access": "RW", "length": 15, "count": 12, "type": "string"},
"sensorNameHumidityAndTemp5": {"group": "humidityControl", "variable": 1075, "access": "RW", "length": 15, "count": 12, "type": "string"},
"sensorNameHumidityAndTemp6": {"group": "humidityControl", "variable": 1076, "access": "RW", "length": 15, "count": 12, "type": "string"},
"sensorNameHumidityAndTemp7": {"group": "humidityControl", "variable": 1077, "access": "RW", "length": 15, "count": 12, "type": "string"},
"sensorNameHumidityAndTemp8": {"group": "humidityControl", "variable": 1078, "access": "RW", "length": 15, "count": 12, "type": "string"},
"sensorNameCo21": {"group": "co2Control", "variable": 1081, "access": "RW", "length": 15, "count": 12, "type": "string"},
"sensorNameCo22": {"group": "co2Control", "variable": 1082, "access": "RW", "length": 15, "count": 12, "type": "string"},
"sensorNameCo23": {"group": "co2Control", "variable": 1083, "access": "RW", "length": 15, "count": 12, "type": "string"},
"sensorNameCo24": {"group": "co2Control", "variable": 1084, "access": "RW", "length": 15, "count": 12, "type": "string"},
"sensorNameCo25": {"group": "co2Control", "variable": 1085, "access": "RW", "length": 15, "count": 12, "type": "string"},
"sensorNameCo26": {"group": "co2Control", "variable": 1086, "access": "RW", "length": 15, "count": 12, "type": "string"},
"sensorNameCo27": {"group": "co2Control", "variable": 1087, "access": "RW", "length": 15, "count": 12, "type": "string"},
"sensorNameCo28": {"group": "co2Control", "variable": 1088, "access": "RW", "length": 15, "count": 12, "type": "string"},
"sensorNameVoc1": {"group": "vocControl", "variable": 1091, "access": "RW", "length": 15, "count": 12, "type": "string"},
"sensorNameVoc2": {"group": "vocControl", "variable": 1092, "access": "RW", "length": 15, "count": 12, "type": "string"},
"sensorNameVoc3": {"group": "vocControl", "variable": 1093, "access": "RW", "length": 15, "count": 12, "type": "string"},
"sensorNameVoc4": {"group": "vocControl", "variable": 1094, "access": "RW", "length": 15, "count": 12, "type": "string"},
"sensorNameVoc5": {"group": "vocControl", "variable": 1095, "access": "RW", "length": 15, "count": 12, "type": "string"},
"sensorNameVoc6": {"group": "vocControl", "variable": 1096, "access": "RW", "length": 15, "count": 12, "type": "string"},
"sensorNameVoc7": {"group": "vocControl", "variable": 1097, "access": "RW", "length": 15, "count": 12, "type": "string"},
"sensorNameVoc8": {"group": "vocControl", "variable": 1098, "access": "RW", "length": 15, "count": 12, "type": "string"},
"softwareVersionBasis": {"group": "general", "variable": 1101, "access": "R", "length": 5, "count": 7, "type": "float", "minVal": 0.0, "maxVal": 99.99},
"operatingHoursSupplyAirVent": {"group": "general", "variable": 1103, "access": "R", "length": 10, "count": 9, "type": "int", "unit": "min", "minVal": 0, "maxVal": 4294967295},
"operatingHoursExtractAirVent": {"group": "general", "variable": 1104, "access": "R", "length": 10, "count": 9, "type": "int", "unit": "min", "minVal": 0, "maxVal": 4294967295},
"operatingHoursVhz": {"group": "general", "variable": 1105, "access": "R", "length": 10, "count": 9, "type": "int", "unit": "min", "minVal": 0, "maxVal": 4294967295},
"operatingHoursNhz": {"group": "general", "variable": 1106, "access": "R", "length": 10, "count": 9, "type": "int", "unit": "min", "minVal": 0, "maxVal": 4294967295},
"outputPowerVhz": {"group": "general", "variable": 1108, "access": "R", "length": 10, "count": 9, "type": "int", "unit": "%", "minVal": 0, "maxVal": 4294967295},
"outputPowerNhz": {"group": "general", "variable": 1109, "access": "R", "length": 10, "count": 9, "type": "int", "unit": "%", "minVal": 0, "maxVal": 4294967295},
"resetFlag": {"group": "general", "variable": 1120, "access": "W", "length": 1, "count": 5, "type": "int", "minVal": 1, "maxVal": 1},
"errors": {"group": "general", "variable": 1123, "access": "R", "length": 10, "count": 9, "type": "int", "minVal": 0, "maxVal": 4294967295},
"warnings": {"group": "general", "variable": 1124, "access": "R", "length": 3, "count": 6, "type": "int", "minVal": 0, "maxVal": 255},
"infos": {"group": "general", "variable": 1125, "access": "R", "length": 3, "count": 6, "type": "int", "minVal": 0, "maxVal": 255},
"noOfErrors": {"group": "general", "variable": 1300, "access": "R", "length": 2, "count": 5, "type": "int", "minVal": 0, "maxVal": 32},
"noOfWarnings": {"group": "general", "variable": 1301, "access": "R", "length": 1, "count": 5, "type": "int", "minVal": 0, "maxVal": 8},
"noOfInfos": {"group": "general", "variable": 1302, "access": "R", "length": 1, "count": 5, "type": "int", "minVal": 0, "maxVal": 8},
"errorsMsg": {"group": "general", "variable": 1303, "access": "R", "length": 32, "count": 20, "type": "string"},
"warningsMsg": {"group": "general", "variable": 1304, "access": "R", "length": 8, "count": 8, "type": "string"},
"infosMsg": {"group": "general", "variable": 1305, "access": "R", "length": 8, "count": 8, "type": "string"},
"statusFlags": {"group": "general", "variable": 1306, "access": "R", "length": 32, "count": 20, "type": "string"},
"globalManualWebUpdate": {"group": "general", "variable": 2013, "access": "RW", "length": 1, "count": 5, "type": "int", "minVal": 1, "maxVal": 1},
"portalGlobalsErrorForWeb": {"group": "general", "variable": 2014, "access": "R", "length": 3, "count": 6, "type": "int", "minVal": 1, "maxVal": 255},
"clearError": {"group": "general", "variable": 2015, "access": "W", "length": 1, "count": 5, "type": "int", "minVal": 1, "maxVal": 1},
"sensorConfigKwlFtf1": {"group": "humidityControl", "variable": 2020, "access": "R", "length": 1, "count": 5, "type": "int", "minVal": 0, "maxVal": 1},
"sensorConfigKwlFtf2": {"group": "humidityControl", "variable": 2021, "access": "R", "length": 1, "count": 5, "type": "int", "minVal": 0, "maxVal": 1},
"sensorConfigKwlFtf3": {"group": "humidityControl", "variable": 2022, "access": "R", "length": 1, "count": 5, "type": "int", "minVal": 0, "maxVal": 1},
"sensorConfigKwlFtf4": {"group": "humidityControl", "variable": 2023, "access": "R", "length": 1, "count": 5, "type": "int", "minVal": 0, "maxVal": 1},
"sensorConfigKwlFtf5": {"group": "humidityControl", "variable": 2024, "access": "R", "length": 1, "count": 5, "type": "int", "minVal": 0, "maxVal": 1},
"sensorConfigKwlFtf6": {"group": "humidityControl", "variable": 2025, "access": "R", "length": 1, "count": 5, "type": "int", "minVal": 0, "maxVal": 1},
"sensorConfigKwlFtf7": {"group": "humidityControl", "variable": 2026, "access": "R", "length": 1, "count": 5, "type": "int", "minVal": 0, "maxVal": 1},
"sensorConfigKwlFtf8": {"group": "humidityControl", "variable": 2027, "access": "R", "length": 1, "count": 5, "type": "int", "minVal": 0, "maxVal": 1},
"bypassStatus": {"group": "general", "variable": 2119, "access": "R", "length": 1, "count": 5, "type": "int", "minVal": 0, "maxVal": 1},
"bypassFromDay": {"group": "unitConfig", "variable": 2120, "access": "RW", "length": 2, "count": 5, "type": "int", "minVal": 1, "maxVal": 31},
"bypassFromMonth": {"group": "unitConfig", "variable": 2121, "access": "RW", "length": 2, "count": 5, "type": "int", "minVal": 1, "maxVal": 12},
"bypassToDay": {"group": "unitConfig", "variable": 2128, "access": "RW", "length": 2, "count": 5, "type": "int", "minVal": 1, "maxVal": 31},
"bypassToMonth": {"group": "unitConfig", "variable": 2129, "access": "RW", "length": 2, "count": 5, "type": "int", "minVal": 1, "maxVal": 12}
}