mirror of
https://github.com/openhab/openhab-addons.git
synced 2025-01-10 15:11:59 +01:00
[mqtt.homeassistant] Add missing climate properties (#17659)
* Added support for humidity and preset_modes Signed-off-by: Václav Čejka <V.Cejka@seznam.cz> Signed-off-by: VasekCejka <150804231+VasekCejka@users.noreply.github.com>
This commit is contained in:
parent
ed93eb572c
commit
f4250b77f3
@ -33,6 +33,7 @@ import org.openhab.binding.mqtt.homeassistant.internal.config.dto.AbstractChanne
|
||||
import org.openhab.core.library.types.StringType;
|
||||
import org.openhab.core.library.unit.ImperialUnits;
|
||||
import org.openhab.core.library.unit.SIUnits;
|
||||
import org.openhab.core.library.unit.Units;
|
||||
import org.openhab.core.types.Command;
|
||||
import org.openhab.core.types.State;
|
||||
|
||||
@ -43,6 +44,7 @@ import com.google.gson.annotations.SerializedName;
|
||||
*
|
||||
* @author David Graeff - Initial contribution
|
||||
* @author Anton Kharuzhy - Implementation
|
||||
* @author Vaclav Cejka - added support for humidity and preset_modes
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class Climate extends AbstractComponent<Climate.ChannelConfiguration> {
|
||||
@ -50,13 +52,16 @@ public class Climate extends AbstractComponent<Climate.ChannelConfiguration> {
|
||||
public static final String AUX_CH_ID = "aux";
|
||||
public static final String AWAY_MODE_CH_ID = "away-mode";
|
||||
public static final String AWAY_MODE_CH_ID_DEPRECATED = "awayMode";
|
||||
public static final String CURRENT_HUMIDITY_CH_ID = "current-humidity";
|
||||
public static final String CURRENT_TEMPERATURE_CH_ID = "current-temperature";
|
||||
public static final String CURRENT_TEMPERATURE_CH_ID_DEPRECATED = "currentTemperature";
|
||||
public static final String FAN_MODE_CH_ID = "fan-mode";
|
||||
public static final String FAN_MODE_CH_ID_DEPRECATED = "fanMode";
|
||||
public static final String HOLD_CH_ID = "hold";
|
||||
public static final String MODE_CH_ID = "mode";
|
||||
public static final String PRESET_MODE_CH_ID = "preset-mode";
|
||||
public static final String SWING_CH_ID = "swing";
|
||||
public static final String TARGET_HUMIDITY_CH_ID = "target-humidity";
|
||||
public static final String TEMPERATURE_CH_ID = "temperature";
|
||||
public static final String TEMPERATURE_HIGH_CH_ID = "temperature-high";
|
||||
public static final String TEMPERATURE_HIGH_CH_ID_DEPRECATED = "temperatureHigh";
|
||||
@ -120,6 +125,11 @@ public class Climate extends AbstractComponent<Climate.ChannelConfiguration> {
|
||||
@SerializedName("away_mode_state_topic")
|
||||
protected @Nullable String awayModeStateTopic;
|
||||
|
||||
@SerializedName("current_humidity_template")
|
||||
protected @Nullable String currentHumidityTemplate;
|
||||
@SerializedName("current_humidity_topic")
|
||||
protected @Nullable String currentHumidityTopic;
|
||||
|
||||
@SerializedName("current_temperature_template")
|
||||
protected @Nullable String currentTemperatureTemplate;
|
||||
@SerializedName("current_temperature_topic")
|
||||
@ -158,6 +168,18 @@ public class Climate extends AbstractComponent<Climate.ChannelConfiguration> {
|
||||
protected @Nullable String modeStateTopic;
|
||||
protected List<String> modes = Arrays.asList("auto", "off", "cool", "heat", "dry", "fan_only");
|
||||
|
||||
@SerializedName("preset_mode_command_template")
|
||||
protected @Nullable String presetModeCommandTemplate;
|
||||
@SerializedName("preset_mode_command_topic")
|
||||
protected @Nullable String presetModeCommandTopic;
|
||||
@SerializedName("preset_mode_state_topic")
|
||||
protected @Nullable String presetModeStateTopic;
|
||||
@SerializedName("preset_mode_value_template")
|
||||
protected @Nullable String presetModeStateTemplate;
|
||||
@SerializedName("preset_modes")
|
||||
protected List<String> presetModes = List.of(); // defaults heavily depend on the
|
||||
// type of the device
|
||||
|
||||
@SerializedName("swing_command_template")
|
||||
protected @Nullable String swingCommandTemplate;
|
||||
@SerializedName("swing_command_topic")
|
||||
@ -169,6 +191,15 @@ public class Climate extends AbstractComponent<Climate.ChannelConfiguration> {
|
||||
@SerializedName("swing_modes")
|
||||
protected List<String> swingModes = Arrays.asList("on", "off");
|
||||
|
||||
@SerializedName("target_humidity_command_template")
|
||||
protected @Nullable String targetHumidityCommandTemplate;
|
||||
@SerializedName("target_humidity_command_topic")
|
||||
protected @Nullable String targetHumidityCommandTopic;
|
||||
@SerializedName("target_humidity_state_template")
|
||||
protected @Nullable String targetHumidityStateTemplate;
|
||||
@SerializedName("target_humidity_state_topic")
|
||||
protected @Nullable String targetHumidityStateTopic;
|
||||
|
||||
@SerializedName("temperature_command_template")
|
||||
protected @Nullable String temperatureCommandTemplate;
|
||||
@SerializedName("temperature_command_topic")
|
||||
@ -199,6 +230,11 @@ public class Climate extends AbstractComponent<Climate.ChannelConfiguration> {
|
||||
@SerializedName("power_command_topic")
|
||||
protected @Nullable String powerCommandTopic;
|
||||
|
||||
@SerializedName("max_humidity")
|
||||
protected BigDecimal maxHumidity = new BigDecimal(99);
|
||||
@SerializedName("min_humidity")
|
||||
protected BigDecimal minHumidity = new BigDecimal(30);
|
||||
|
||||
protected Integer initial = 21;
|
||||
@SerializedName("max_temp")
|
||||
protected @Nullable BigDecimal maxTemp;
|
||||
@ -236,6 +272,10 @@ public class Climate extends AbstractComponent<Climate.ChannelConfiguration> {
|
||||
channelConfiguration.awayModeCommandTopic, channelConfiguration.awayModeStateTemplate,
|
||||
channelConfiguration.awayModeStateTopic, commandFilter);
|
||||
|
||||
buildOptionalChannel(CURRENT_HUMIDITY_CH_ID, ComponentChannelType.NUMBER,
|
||||
new NumberValue(new BigDecimal(0), new BigDecimal(100), null, Units.PERCENT), updateListener, null,
|
||||
null, channelConfiguration.currentHumidityTemplate, channelConfiguration.currentHumidityTopic, null);
|
||||
|
||||
buildOptionalChannel(newStyleChannels ? CURRENT_TEMPERATURE_CH_ID : CURRENT_TEMPERATURE_CH_ID_DEPRECATED,
|
||||
ComponentChannelType.NUMBER,
|
||||
new NumberValue(null, null, precision, channelConfiguration.temperatureUnit.getUnit()), updateListener,
|
||||
@ -260,11 +300,23 @@ public class Climate extends AbstractComponent<Climate.ChannelConfiguration> {
|
||||
channelConfiguration.modeCommandTemplate, channelConfiguration.modeCommandTopic,
|
||||
channelConfiguration.modeStateTemplate, channelConfiguration.modeStateTopic, commandFilter);
|
||||
|
||||
buildOptionalChannel(PRESET_MODE_CH_ID, ComponentChannelType.STRING,
|
||||
new TextValue(channelConfiguration.presetModes.toArray(new String[0])), updateListener,
|
||||
channelConfiguration.presetModeCommandTemplate, channelConfiguration.presetModeCommandTopic,
|
||||
channelConfiguration.presetModeStateTemplate, channelConfiguration.presetModeStateTopic, commandFilter);
|
||||
|
||||
buildOptionalChannel(SWING_CH_ID, ComponentChannelType.STRING,
|
||||
new TextValue(channelConfiguration.swingModes.toArray(new String[0])), updateListener,
|
||||
channelConfiguration.swingCommandTemplate, channelConfiguration.swingCommandTopic,
|
||||
channelConfiguration.swingStateTemplate, channelConfiguration.swingStateTopic, commandFilter);
|
||||
|
||||
buildOptionalChannel(TARGET_HUMIDITY_CH_ID, ComponentChannelType.NUMBER,
|
||||
new NumberValue(channelConfiguration.minHumidity, channelConfiguration.maxHumidity, null,
|
||||
Units.PERCENT),
|
||||
updateListener, channelConfiguration.targetHumidityCommandTemplate,
|
||||
channelConfiguration.targetHumidityCommandTopic, channelConfiguration.targetHumidityStateTemplate,
|
||||
channelConfiguration.targetHumidityStateTopic, commandFilter);
|
||||
|
||||
buildOptionalChannel(TEMPERATURE_CH_ID, ComponentChannelType.NUMBER,
|
||||
new NumberValue(channelConfiguration.minTemp, channelConfiguration.maxTemp,
|
||||
channelConfiguration.tempStep, channelConfiguration.temperatureUnit.getUnit()),
|
||||
|
@ -28,6 +28,7 @@ import org.openhab.core.library.types.QuantityType;
|
||||
import org.openhab.core.library.types.StringType;
|
||||
import org.openhab.core.library.unit.ImperialUnits;
|
||||
import org.openhab.core.library.unit.SIUnits;
|
||||
import org.openhab.core.library.unit.Units;
|
||||
|
||||
/**
|
||||
* Tests for {@link Climate}
|
||||
@ -320,6 +321,82 @@ public class ClimateTests extends AbstractComponentTests {
|
||||
assertPublished("zigbee2mqtt/th1/power", "OFF");
|
||||
}
|
||||
|
||||
@SuppressWarnings("null")
|
||||
@Test
|
||||
public void testClimateWithPresetMode() {
|
||||
var component = discoverComponent(configTopicToMqtt(CONFIG_TOPIC),
|
||||
"""
|
||||
{
|
||||
"action_template": "{% set values = {None:None,'idle':'idle','heat':'heating','cool':'cooling','fan_only':'fan'} %}{{ values[value_json.running_state] }}",
|
||||
"action_topic": "zigbee2mqtt/th2",
|
||||
"current_temperature_template": "{{ value_json.local_temperature }}",
|
||||
"current_temperature_topic": "zigbee2mqtt/th2",
|
||||
"json_attributes_topic": "zigbee2mqtt/th2",
|
||||
"max_temp": "35",
|
||||
"min_temp": "5",
|
||||
"mode_command_topic": "zigbee2mqtt/th2/set/system_mode",
|
||||
"mode_state_template": "{{ value_json.system_mode }}",
|
||||
"mode_state_topic": "zigbee2mqtt/th2",
|
||||
"modes": ["auto","heat","off"],
|
||||
"name": "th2",
|
||||
"preset_mode_command_topic": "zigbee2mqtt/th2/set/preset",
|
||||
"preset_mode_state_topic": "zigbee2mqtt/th2",
|
||||
"preset_mode_value_template": "{{ value_json.preset }}",
|
||||
"preset_modes": ["auto","manual","off","on"],
|
||||
"temp_step": 0.5,
|
||||
"temperature_command_topic": "zigbee2mqtt/th2/set/current_heating_setpoint",
|
||||
"temperature_state_template": "{{ value_json.current_heating_setpoint }}",
|
||||
"temperature_state_topic": "zigbee2mqtt/th2",
|
||||
"temperature_unit": "C"
|
||||
}
|
||||
""");
|
||||
|
||||
assertThat(component.channels.size(), is(6));
|
||||
|
||||
assertChannel(component, Climate.PRESET_MODE_CH_ID, "zigbee2mqtt/th2", "zigbee2mqtt/th2/set/preset", "th2",
|
||||
TextValue.class);
|
||||
|
||||
publishMessage("zigbee2mqtt/th2", """
|
||||
{"running_state": "heat",
|
||||
"local_temperature": "22.2", "preset": "manual", "system_mode": "heat",
|
||||
"current_heating_setpoint": "24"}
|
||||
""");
|
||||
assertState(component, Climate.MODE_CH_ID, new StringType("heat"));
|
||||
assertState(component, Climate.TEMPERATURE_CH_ID, new QuantityType<>(24, SIUnits.CELSIUS));
|
||||
assertState(component, Climate.PRESET_MODE_CH_ID, new StringType("manual"));
|
||||
component.getChannel(Climate.PRESET_MODE_CH_ID).getState().publishValue(new StringType("on"));
|
||||
assertPublished("zigbee2mqtt/th2/set/preset", "on");
|
||||
}
|
||||
|
||||
@SuppressWarnings("null")
|
||||
@Test
|
||||
public void testClimateHumidity() {
|
||||
var component = discoverComponent(configTopicToMqtt(CONFIG_TOPIC), """
|
||||
{
|
||||
"current_humidity_template": "{{ value_json.humidity }}",
|
||||
"current_humidity_topic": "zigbee2mqtt/th2",
|
||||
"max_humidity": "70",
|
||||
"min_humidity": "30",
|
||||
"target_humidity_command_topic": "zigbee2mqtt/th2/set/humidity_setpoint",
|
||||
"target_humidity_state_template": "{{ value_json.humidity_setpoint }}",
|
||||
"target_humidity_state_topic": "zigbee2mqtt/th2",
|
||||
"name": "th2"
|
||||
}
|
||||
""");
|
||||
|
||||
assertThat(component.channels.size(), is(2));
|
||||
|
||||
assertChannel(component, Climate.CURRENT_HUMIDITY_CH_ID, "zigbee2mqtt/th2", "", "th2", NumberValue.class);
|
||||
assertChannel(component, Climate.TARGET_HUMIDITY_CH_ID, "zigbee2mqtt/th2",
|
||||
"zigbee2mqtt/th2/set/humidity_setpoint", "th2", NumberValue.class);
|
||||
|
||||
publishMessage("zigbee2mqtt/th2", """
|
||||
{"humidity": "55", "humidity_setpoint": "50"}\
|
||||
""");
|
||||
assertState(component, Climate.CURRENT_HUMIDITY_CH_ID, new QuantityType<>(55, Units.PERCENT));
|
||||
assertState(component, Climate.TARGET_HUMIDITY_CH_ID, new QuantityType<>(50, Units.PERCENT));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Set<String> getConfigTopics() {
|
||||
return Set.of(CONFIG_TOPIC);
|
||||
|
Loading…
Reference in New Issue
Block a user