mirror of
https://github.com/openhab/openhab-addons.git
synced 2025-01-10 15:11:59 +01:00
[mqtt.homeassistant] Implement WaterHeater (#17859)
* [mqtt.homeassistant] Implement WaterHeater Signed-off-by: Cody Cutrer <cody@cutrer.us>
This commit is contained in:
parent
f733c85343
commit
5d89c9a885
@ -22,6 +22,7 @@ import org.openhab.binding.mqtt.generic.MqttChannelStateDescriptionProvider;
|
|||||||
import org.openhab.binding.mqtt.generic.MqttChannelTypeProvider;
|
import org.openhab.binding.mqtt.generic.MqttChannelTypeProvider;
|
||||||
import org.openhab.binding.mqtt.homeassistant.internal.HomeAssistantJinjaFunctionLibrary;
|
import org.openhab.binding.mqtt.homeassistant.internal.HomeAssistantJinjaFunctionLibrary;
|
||||||
import org.openhab.binding.mqtt.homeassistant.internal.handler.HomeAssistantThingHandler;
|
import org.openhab.binding.mqtt.homeassistant.internal.handler.HomeAssistantThingHandler;
|
||||||
|
import org.openhab.core.i18n.UnitProvider;
|
||||||
import org.openhab.core.thing.Thing;
|
import org.openhab.core.thing.Thing;
|
||||||
import org.openhab.core.thing.ThingTypeUID;
|
import org.openhab.core.thing.ThingTypeUID;
|
||||||
import org.openhab.core.thing.binding.BaseThingHandlerFactory;
|
import org.openhab.core.thing.binding.BaseThingHandlerFactory;
|
||||||
@ -47,6 +48,7 @@ public class MqttThingHandlerFactory extends BaseThingHandlerFactory {
|
|||||||
private final MqttChannelStateDescriptionProvider stateDescriptionProvider;
|
private final MqttChannelStateDescriptionProvider stateDescriptionProvider;
|
||||||
private final ChannelTypeRegistry channelTypeRegistry;
|
private final ChannelTypeRegistry channelTypeRegistry;
|
||||||
private final Jinjava jinjava = new Jinjava();
|
private final Jinjava jinjava = new Jinjava();
|
||||||
|
private final UnitProvider unitProvider;
|
||||||
|
|
||||||
private static final Set<ThingTypeUID> SUPPORTED_THING_TYPES_UIDS = Stream
|
private static final Set<ThingTypeUID> SUPPORTED_THING_TYPES_UIDS = Stream
|
||||||
.of(MqttBindingConstants.HOMEASSISTANT_MQTT_THING).collect(Collectors.toSet());
|
.of(MqttBindingConstants.HOMEASSISTANT_MQTT_THING).collect(Collectors.toSet());
|
||||||
@ -54,10 +56,11 @@ public class MqttThingHandlerFactory extends BaseThingHandlerFactory {
|
|||||||
@Activate
|
@Activate
|
||||||
public MqttThingHandlerFactory(final @Reference MqttChannelTypeProvider typeProvider,
|
public MqttThingHandlerFactory(final @Reference MqttChannelTypeProvider typeProvider,
|
||||||
final @Reference MqttChannelStateDescriptionProvider stateDescriptionProvider,
|
final @Reference MqttChannelStateDescriptionProvider stateDescriptionProvider,
|
||||||
final @Reference ChannelTypeRegistry channelTypeRegistry) {
|
final @Reference ChannelTypeRegistry channelTypeRegistry, final @Reference UnitProvider unitProvider) {
|
||||||
this.typeProvider = typeProvider;
|
this.typeProvider = typeProvider;
|
||||||
this.stateDescriptionProvider = stateDescriptionProvider;
|
this.stateDescriptionProvider = stateDescriptionProvider;
|
||||||
this.channelTypeRegistry = channelTypeRegistry;
|
this.channelTypeRegistry = channelTypeRegistry;
|
||||||
|
this.unitProvider = unitProvider;
|
||||||
|
|
||||||
HomeAssistantJinjaFunctionLibrary.register(jinjava.getGlobalContext());
|
HomeAssistantJinjaFunctionLibrary.register(jinjava.getGlobalContext());
|
||||||
}
|
}
|
||||||
@ -78,7 +81,7 @@ public class MqttThingHandlerFactory extends BaseThingHandlerFactory {
|
|||||||
|
|
||||||
if (supportsThingType(thingTypeUID)) {
|
if (supportsThingType(thingTypeUID)) {
|
||||||
return new HomeAssistantThingHandler(thing, typeProvider, stateDescriptionProvider, channelTypeRegistry,
|
return new HomeAssistantThingHandler(thing, typeProvider, stateDescriptionProvider, channelTypeRegistry,
|
||||||
jinjava, 10000, 2000);
|
jinjava, unitProvider, 10000, 2000);
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -33,7 +33,8 @@ public enum ComponentChannelType {
|
|||||||
SWITCH("ha-switch"),
|
SWITCH("ha-switch"),
|
||||||
TRIGGER("ha-trigger"),
|
TRIGGER("ha-trigger"),
|
||||||
HUMIDITY("ha-humidity"),
|
HUMIDITY("ha-humidity"),
|
||||||
GPS_ACCURACY("ha-gps-accuracy");
|
GPS_ACCURACY("ha-gps-accuracy"),
|
||||||
|
TEMPERATURE("ha-temperature");
|
||||||
|
|
||||||
final ChannelTypeUID channelTypeUID;
|
final ChannelTypeUID channelTypeUID;
|
||||||
|
|
||||||
|
@ -30,6 +30,7 @@ import org.openhab.binding.mqtt.homeassistant.internal.component.AbstractCompone
|
|||||||
import org.openhab.binding.mqtt.homeassistant.internal.component.ComponentFactory;
|
import org.openhab.binding.mqtt.homeassistant.internal.component.ComponentFactory;
|
||||||
import org.openhab.binding.mqtt.homeassistant.internal.exception.ConfigurationException;
|
import org.openhab.binding.mqtt.homeassistant.internal.exception.ConfigurationException;
|
||||||
import org.openhab.binding.mqtt.homeassistant.internal.exception.UnsupportedComponentException;
|
import org.openhab.binding.mqtt.homeassistant.internal.exception.UnsupportedComponentException;
|
||||||
|
import org.openhab.core.i18n.UnitProvider;
|
||||||
import org.openhab.core.io.transport.mqtt.MqttBrokerConnection;
|
import org.openhab.core.io.transport.mqtt.MqttBrokerConnection;
|
||||||
import org.openhab.core.io.transport.mqtt.MqttMessageSubscriber;
|
import org.openhab.core.io.transport.mqtt.MqttMessageSubscriber;
|
||||||
import org.openhab.core.thing.ThingUID;
|
import org.openhab.core.thing.ThingUID;
|
||||||
@ -57,6 +58,7 @@ public class DiscoverComponents implements MqttMessageSubscriber {
|
|||||||
protected final CompletableFuture<@Nullable Void> discoverFinishedFuture = new CompletableFuture<>();
|
protected final CompletableFuture<@Nullable Void> discoverFinishedFuture = new CompletableFuture<>();
|
||||||
private final Gson gson;
|
private final Gson gson;
|
||||||
private final Jinjava jinjava;
|
private final Jinjava jinjava;
|
||||||
|
private final UnitProvider unitProvider;
|
||||||
|
|
||||||
private @Nullable ScheduledFuture<?> stopDiscoveryFuture;
|
private @Nullable ScheduledFuture<?> stopDiscoveryFuture;
|
||||||
private WeakReference<@Nullable MqttBrokerConnection> connectionRef = new WeakReference<>(null);
|
private WeakReference<@Nullable MqttBrokerConnection> connectionRef = new WeakReference<>(null);
|
||||||
@ -82,12 +84,13 @@ public class DiscoverComponents implements MqttMessageSubscriber {
|
|||||||
*/
|
*/
|
||||||
public DiscoverComponents(ThingUID thingUID, ScheduledExecutorService scheduler,
|
public DiscoverComponents(ThingUID thingUID, ScheduledExecutorService scheduler,
|
||||||
ChannelStateUpdateListener channelStateUpdateListener, AvailabilityTracker tracker, Gson gson,
|
ChannelStateUpdateListener channelStateUpdateListener, AvailabilityTracker tracker, Gson gson,
|
||||||
Jinjava jinjava, boolean newStyleChannels) {
|
Jinjava jinjava, UnitProvider unitProvider, boolean newStyleChannels) {
|
||||||
this.thingUID = thingUID;
|
this.thingUID = thingUID;
|
||||||
this.scheduler = scheduler;
|
this.scheduler = scheduler;
|
||||||
this.updateListener = channelStateUpdateListener;
|
this.updateListener = channelStateUpdateListener;
|
||||||
this.gson = gson;
|
this.gson = gson;
|
||||||
this.jinjava = jinjava;
|
this.jinjava = jinjava;
|
||||||
|
this.unitProvider = unitProvider;
|
||||||
this.tracker = tracker;
|
this.tracker = tracker;
|
||||||
this.newStyleChannels = newStyleChannels;
|
this.newStyleChannels = newStyleChannels;
|
||||||
}
|
}
|
||||||
@ -105,7 +108,7 @@ public class DiscoverComponents implements MqttMessageSubscriber {
|
|||||||
if (config.length() > 0) {
|
if (config.length() > 0) {
|
||||||
try {
|
try {
|
||||||
component = ComponentFactory.createComponent(thingUID, haID, config, updateListener, tracker, scheduler,
|
component = ComponentFactory.createComponent(thingUID, haID, config, updateListener, tracker, scheduler,
|
||||||
gson, jinjava, newStyleChannels);
|
gson, jinjava, unitProvider, newStyleChannels);
|
||||||
component.setConfigSeen();
|
component.setConfigSeen();
|
||||||
|
|
||||||
logger.trace("Found HomeAssistant component {}", haID);
|
logger.trace("Found HomeAssistant component {}", haID);
|
||||||
@ -119,8 +122,6 @@ public class DiscoverComponents implements MqttMessageSubscriber {
|
|||||||
} catch (ConfigurationException e) {
|
} catch (ConfigurationException e) {
|
||||||
logger.warn("HomeAssistant discover error: invalid configuration of thing {} component {}: {}",
|
logger.warn("HomeAssistant discover error: invalid configuration of thing {} component {}: {}",
|
||||||
haID.objectID, haID.component, e.getMessage());
|
haID.objectID, haID.component, e.getMessage());
|
||||||
} catch (Exception e) {
|
|
||||||
logger.warn("HomeAssistant discover error: {}", e.getMessage());
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (discoveredListener != null) {
|
if (discoveredListener != null) {
|
||||||
|
@ -12,6 +12,7 @@
|
|||||||
*/
|
*/
|
||||||
package org.openhab.binding.mqtt.homeassistant.internal.component;
|
package org.openhab.binding.mqtt.homeassistant.internal.component;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
@ -21,6 +22,9 @@ import java.util.concurrent.CompletableFuture;
|
|||||||
import java.util.concurrent.ScheduledExecutorService;
|
import java.util.concurrent.ScheduledExecutorService;
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
|
import javax.measure.Unit;
|
||||||
|
import javax.measure.quantity.Temperature;
|
||||||
|
|
||||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||||
import org.eclipse.jdt.annotation.Nullable;
|
import org.eclipse.jdt.annotation.Nullable;
|
||||||
import org.openhab.binding.mqtt.generic.AvailabilityTracker;
|
import org.openhab.binding.mqtt.generic.AvailabilityTracker;
|
||||||
@ -40,6 +44,8 @@ import org.openhab.binding.mqtt.homeassistant.internal.config.dto.Availability;
|
|||||||
import org.openhab.binding.mqtt.homeassistant.internal.config.dto.AvailabilityMode;
|
import org.openhab.binding.mqtt.homeassistant.internal.config.dto.AvailabilityMode;
|
||||||
import org.openhab.binding.mqtt.homeassistant.internal.config.dto.Device;
|
import org.openhab.binding.mqtt.homeassistant.internal.config.dto.Device;
|
||||||
import org.openhab.core.io.transport.mqtt.MqttBrokerConnection;
|
import org.openhab.core.io.transport.mqtt.MqttBrokerConnection;
|
||||||
|
import org.openhab.core.library.unit.ImperialUnits;
|
||||||
|
import org.openhab.core.library.unit.SIUnits;
|
||||||
import org.openhab.core.thing.Channel;
|
import org.openhab.core.thing.Channel;
|
||||||
import org.openhab.core.thing.ChannelUID;
|
import org.openhab.core.thing.ChannelUID;
|
||||||
import org.openhab.core.thing.binding.generic.ChannelTransformation;
|
import org.openhab.core.thing.binding.generic.ChannelTransformation;
|
||||||
@ -53,6 +59,7 @@ import org.openhab.core.types.CommandDescription;
|
|||||||
import org.openhab.core.types.StateDescription;
|
import org.openhab.core.types.StateDescription;
|
||||||
|
|
||||||
import com.google.gson.Gson;
|
import com.google.gson.Gson;
|
||||||
|
import com.google.gson.annotations.SerializedName;
|
||||||
import com.hubspot.jinjava.Jinjava;
|
import com.hubspot.jinjava.Jinjava;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -64,6 +71,29 @@ import com.hubspot.jinjava.Jinjava;
|
|||||||
*/
|
*/
|
||||||
@NonNullByDefault
|
@NonNullByDefault
|
||||||
public abstract class AbstractComponent<C extends AbstractChannelConfiguration> {
|
public abstract class AbstractComponent<C extends AbstractChannelConfiguration> {
|
||||||
|
public enum TemperatureUnit {
|
||||||
|
@SerializedName("C")
|
||||||
|
CELSIUS(SIUnits.CELSIUS, new BigDecimal("0.1")),
|
||||||
|
@SerializedName("F")
|
||||||
|
FAHRENHEIT(ImperialUnits.FAHRENHEIT, BigDecimal.ONE);
|
||||||
|
|
||||||
|
private final Unit<Temperature> unit;
|
||||||
|
private final BigDecimal defaultPrecision;
|
||||||
|
|
||||||
|
TemperatureUnit(Unit<Temperature> unit, BigDecimal defaultPrecision) {
|
||||||
|
this.unit = unit;
|
||||||
|
this.defaultPrecision = defaultPrecision;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Unit<Temperature> getUnit() {
|
||||||
|
return unit;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BigDecimal getDefaultPrecision() {
|
||||||
|
return defaultPrecision;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static final String JSON_ATTRIBUTES_CHANNEL_ID = "json-attributes";
|
public static final String JSON_ATTRIBUTES_CHANNEL_ID = "json-attributes";
|
||||||
|
|
||||||
// Component location fields
|
// Component location fields
|
||||||
|
@ -17,7 +17,6 @@ import java.util.Arrays;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.function.Predicate;
|
import java.util.function.Predicate;
|
||||||
|
|
||||||
import javax.measure.Unit;
|
|
||||||
import javax.measure.quantity.Temperature;
|
import javax.measure.quantity.Temperature;
|
||||||
|
|
||||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||||
@ -32,7 +31,6 @@ import org.openhab.binding.mqtt.homeassistant.internal.ComponentChannelType;
|
|||||||
import org.openhab.binding.mqtt.homeassistant.internal.config.dto.AbstractChannelConfiguration;
|
import org.openhab.binding.mqtt.homeassistant.internal.config.dto.AbstractChannelConfiguration;
|
||||||
import org.openhab.core.library.types.StringType;
|
import org.openhab.core.library.types.StringType;
|
||||||
import org.openhab.core.library.unit.ImperialUnits;
|
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.library.unit.Units;
|
||||||
import org.openhab.core.types.Command;
|
import org.openhab.core.types.Command;
|
||||||
import org.openhab.core.types.State;
|
import org.openhab.core.types.State;
|
||||||
@ -69,29 +67,6 @@ public class Climate extends AbstractComponent<Climate.ChannelConfiguration> {
|
|||||||
public static final String TEMPERATURE_LOW_CH_ID_DEPRECATED = "temperatureLow";
|
public static final String TEMPERATURE_LOW_CH_ID_DEPRECATED = "temperatureLow";
|
||||||
public static final String POWER_CH_ID = "power";
|
public static final String POWER_CH_ID = "power";
|
||||||
|
|
||||||
public enum TemperatureUnit {
|
|
||||||
@SerializedName("C")
|
|
||||||
CELSIUS(SIUnits.CELSIUS, new BigDecimal("0.1")),
|
|
||||||
@SerializedName("F")
|
|
||||||
FAHRENHEIT(ImperialUnits.FAHRENHEIT, BigDecimal.ONE);
|
|
||||||
|
|
||||||
private final Unit<Temperature> unit;
|
|
||||||
private final BigDecimal defaultPrecision;
|
|
||||||
|
|
||||||
TemperatureUnit(Unit<Temperature> unit, BigDecimal defaultPrecision) {
|
|
||||||
this.unit = unit;
|
|
||||||
this.defaultPrecision = defaultPrecision;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Unit<Temperature> getUnit() {
|
|
||||||
return unit;
|
|
||||||
}
|
|
||||||
|
|
||||||
public BigDecimal getDefaultPrecision() {
|
|
||||||
return defaultPrecision;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static final String ACTION_OFF = "off";
|
private static final String ACTION_OFF = "off";
|
||||||
private static final State ACTION_OFF_STATE = new StringType(ACTION_OFF);
|
private static final State ACTION_OFF_STATE = new StringType(ACTION_OFF);
|
||||||
private static final List<String> ACTION_MODES = List.of(ACTION_OFF, "heating", "cooling", "drying", "idle", "fan");
|
private static final List<String> ACTION_MODES = List.of(ACTION_OFF, "heating", "cooling", "drying", "idle", "fan");
|
||||||
@ -241,7 +216,7 @@ public class Climate extends AbstractComponent<Climate.ChannelConfiguration> {
|
|||||||
@SerializedName("min_temp")
|
@SerializedName("min_temp")
|
||||||
protected @Nullable BigDecimal minTemp;
|
protected @Nullable BigDecimal minTemp;
|
||||||
@SerializedName("temperature_unit")
|
@SerializedName("temperature_unit")
|
||||||
protected TemperatureUnit temperatureUnit = TemperatureUnit.CELSIUS; // System unit by default
|
protected @Nullable TemperatureUnit temperatureUnit;
|
||||||
@SerializedName("temp_step")
|
@SerializedName("temp_step")
|
||||||
protected BigDecimal tempStep = BigDecimal.ONE;
|
protected BigDecimal tempStep = BigDecimal.ONE;
|
||||||
protected @Nullable BigDecimal precision;
|
protected @Nullable BigDecimal precision;
|
||||||
@ -252,8 +227,16 @@ public class Climate extends AbstractComponent<Climate.ChannelConfiguration> {
|
|||||||
public Climate(ComponentFactory.ComponentConfiguration componentConfiguration, boolean newStyleChannels) {
|
public Climate(ComponentFactory.ComponentConfiguration componentConfiguration, boolean newStyleChannels) {
|
||||||
super(componentConfiguration, ChannelConfiguration.class, newStyleChannels);
|
super(componentConfiguration, ChannelConfiguration.class, newStyleChannels);
|
||||||
|
|
||||||
|
TemperatureUnit temperatureUnit = channelConfiguration.temperatureUnit;
|
||||||
|
if (channelConfiguration.temperatureUnit == null) {
|
||||||
|
if (ImperialUnits.FAHRENHEIT.equals(componentConfiguration.getUnitProvider().getUnit(Temperature.class))) {
|
||||||
|
temperatureUnit = TemperatureUnit.FAHRENHEIT;
|
||||||
|
} else {
|
||||||
|
temperatureUnit = TemperatureUnit.CELSIUS;
|
||||||
|
}
|
||||||
|
}
|
||||||
BigDecimal precision = channelConfiguration.precision != null ? channelConfiguration.precision
|
BigDecimal precision = channelConfiguration.precision != null ? channelConfiguration.precision
|
||||||
: channelConfiguration.temperatureUnit.getDefaultPrecision();
|
: temperatureUnit.getDefaultPrecision();
|
||||||
final ChannelStateUpdateListener updateListener = componentConfiguration.getUpdateListener();
|
final ChannelStateUpdateListener updateListener = componentConfiguration.getUpdateListener();
|
||||||
|
|
||||||
ComponentChannel actionChannel = buildOptionalChannel(ACTION_CH_ID, ComponentChannelType.STRING,
|
ComponentChannel actionChannel = buildOptionalChannel(ACTION_CH_ID, ComponentChannelType.STRING,
|
||||||
@ -277,9 +260,8 @@ public class Climate extends AbstractComponent<Climate.ChannelConfiguration> {
|
|||||||
null, channelConfiguration.currentHumidityTemplate, channelConfiguration.currentHumidityTopic, null);
|
null, channelConfiguration.currentHumidityTemplate, channelConfiguration.currentHumidityTopic, null);
|
||||||
|
|
||||||
buildOptionalChannel(newStyleChannels ? CURRENT_TEMPERATURE_CH_ID : CURRENT_TEMPERATURE_CH_ID_DEPRECATED,
|
buildOptionalChannel(newStyleChannels ? CURRENT_TEMPERATURE_CH_ID : CURRENT_TEMPERATURE_CH_ID_DEPRECATED,
|
||||||
ComponentChannelType.NUMBER,
|
ComponentChannelType.TEMPERATURE, new NumberValue(null, null, precision, temperatureUnit.getUnit()),
|
||||||
new NumberValue(null, null, precision, channelConfiguration.temperatureUnit.getUnit()), updateListener,
|
updateListener, null, null, channelConfiguration.currentTemperatureTemplate,
|
||||||
null, null, channelConfiguration.currentTemperatureTemplate,
|
|
||||||
channelConfiguration.currentTemperatureTopic, commandFilter);
|
channelConfiguration.currentTemperatureTopic, commandFilter);
|
||||||
|
|
||||||
buildOptionalChannel(newStyleChannels ? FAN_MODE_CH_ID : FAN_MODE_CH_ID_DEPRECATED, ComponentChannelType.STRING,
|
buildOptionalChannel(newStyleChannels ? FAN_MODE_CH_ID : FAN_MODE_CH_ID_DEPRECATED, ComponentChannelType.STRING,
|
||||||
@ -317,25 +299,25 @@ public class Climate extends AbstractComponent<Climate.ChannelConfiguration> {
|
|||||||
channelConfiguration.targetHumidityCommandTopic, channelConfiguration.targetHumidityStateTemplate,
|
channelConfiguration.targetHumidityCommandTopic, channelConfiguration.targetHumidityStateTemplate,
|
||||||
channelConfiguration.targetHumidityStateTopic, commandFilter);
|
channelConfiguration.targetHumidityStateTopic, commandFilter);
|
||||||
|
|
||||||
buildOptionalChannel(TEMPERATURE_CH_ID, ComponentChannelType.NUMBER,
|
buildOptionalChannel(TEMPERATURE_CH_ID, ComponentChannelType.TEMPERATURE,
|
||||||
new NumberValue(channelConfiguration.minTemp, channelConfiguration.maxTemp,
|
new NumberValue(channelConfiguration.minTemp, channelConfiguration.maxTemp,
|
||||||
channelConfiguration.tempStep, channelConfiguration.temperatureUnit.getUnit()),
|
channelConfiguration.tempStep, temperatureUnit.getUnit()),
|
||||||
updateListener, channelConfiguration.temperatureCommandTemplate,
|
updateListener, channelConfiguration.temperatureCommandTemplate,
|
||||||
channelConfiguration.temperatureCommandTopic, channelConfiguration.temperatureStateTemplate,
|
channelConfiguration.temperatureCommandTopic, channelConfiguration.temperatureStateTemplate,
|
||||||
channelConfiguration.temperatureStateTopic, commandFilter);
|
channelConfiguration.temperatureStateTopic, commandFilter);
|
||||||
|
|
||||||
buildOptionalChannel(newStyleChannels ? TEMPERATURE_HIGH_CH_ID : TEMPERATURE_HIGH_CH_ID_DEPRECATED,
|
buildOptionalChannel(newStyleChannels ? TEMPERATURE_HIGH_CH_ID : TEMPERATURE_HIGH_CH_ID_DEPRECATED,
|
||||||
ComponentChannelType.NUMBER,
|
ComponentChannelType.TEMPERATURE,
|
||||||
new NumberValue(channelConfiguration.minTemp, channelConfiguration.maxTemp,
|
new NumberValue(channelConfiguration.minTemp, channelConfiguration.maxTemp,
|
||||||
channelConfiguration.tempStep, channelConfiguration.temperatureUnit.getUnit()),
|
channelConfiguration.tempStep, temperatureUnit.getUnit()),
|
||||||
updateListener, channelConfiguration.temperatureHighCommandTemplate,
|
updateListener, channelConfiguration.temperatureHighCommandTemplate,
|
||||||
channelConfiguration.temperatureHighCommandTopic, channelConfiguration.temperatureHighStateTemplate,
|
channelConfiguration.temperatureHighCommandTopic, channelConfiguration.temperatureHighStateTemplate,
|
||||||
channelConfiguration.temperatureHighStateTopic, commandFilter);
|
channelConfiguration.temperatureHighStateTopic, commandFilter);
|
||||||
|
|
||||||
buildOptionalChannel(newStyleChannels ? TEMPERATURE_LOW_CH_ID : TEMPERATURE_LOW_CH_ID_DEPRECATED,
|
buildOptionalChannel(newStyleChannels ? TEMPERATURE_LOW_CH_ID : TEMPERATURE_LOW_CH_ID_DEPRECATED,
|
||||||
ComponentChannelType.NUMBER,
|
ComponentChannelType.TEMPERATURE,
|
||||||
new NumberValue(channelConfiguration.minTemp, channelConfiguration.maxTemp,
|
new NumberValue(channelConfiguration.minTemp, channelConfiguration.maxTemp,
|
||||||
channelConfiguration.tempStep, channelConfiguration.temperatureUnit.getUnit()),
|
channelConfiguration.tempStep, temperatureUnit.getUnit()),
|
||||||
updateListener, channelConfiguration.temperatureLowCommandTemplate,
|
updateListener, channelConfiguration.temperatureLowCommandTemplate,
|
||||||
channelConfiguration.temperatureLowCommandTopic, channelConfiguration.temperatureLowStateTemplate,
|
channelConfiguration.temperatureLowCommandTopic, channelConfiguration.temperatureLowStateTemplate,
|
||||||
channelConfiguration.temperatureLowStateTopic, commandFilter);
|
channelConfiguration.temperatureLowStateTopic, commandFilter);
|
||||||
|
@ -21,6 +21,7 @@ import org.openhab.binding.mqtt.homeassistant.internal.HaID;
|
|||||||
import org.openhab.binding.mqtt.homeassistant.internal.config.dto.AbstractChannelConfiguration;
|
import org.openhab.binding.mqtt.homeassistant.internal.config.dto.AbstractChannelConfiguration;
|
||||||
import org.openhab.binding.mqtt.homeassistant.internal.exception.ConfigurationException;
|
import org.openhab.binding.mqtt.homeassistant.internal.exception.ConfigurationException;
|
||||||
import org.openhab.binding.mqtt.homeassistant.internal.exception.UnsupportedComponentException;
|
import org.openhab.binding.mqtt.homeassistant.internal.exception.UnsupportedComponentException;
|
||||||
|
import org.openhab.core.i18n.UnitProvider;
|
||||||
import org.openhab.core.thing.ThingUID;
|
import org.openhab.core.thing.ThingUID;
|
||||||
|
|
||||||
import com.google.gson.Gson;
|
import com.google.gson.Gson;
|
||||||
@ -47,9 +48,10 @@ public class ComponentFactory {
|
|||||||
*/
|
*/
|
||||||
public static AbstractComponent<?> createComponent(ThingUID thingUID, HaID haID, String channelConfigurationJSON,
|
public static AbstractComponent<?> createComponent(ThingUID thingUID, HaID haID, String channelConfigurationJSON,
|
||||||
ChannelStateUpdateListener updateListener, AvailabilityTracker tracker, ScheduledExecutorService scheduler,
|
ChannelStateUpdateListener updateListener, AvailabilityTracker tracker, ScheduledExecutorService scheduler,
|
||||||
Gson gson, Jinjava jinjava, boolean newStyleChannels) throws ConfigurationException {
|
Gson gson, Jinjava jinjava, UnitProvider unitProvider, boolean newStyleChannels)
|
||||||
|
throws ConfigurationException {
|
||||||
ComponentConfiguration componentConfiguration = new ComponentConfiguration(thingUID, haID,
|
ComponentConfiguration componentConfiguration = new ComponentConfiguration(thingUID, haID,
|
||||||
channelConfigurationJSON, gson, jinjava, updateListener, tracker, scheduler);
|
channelConfigurationJSON, gson, jinjava, updateListener, tracker, scheduler, unitProvider);
|
||||||
switch (haID.component) {
|
switch (haID.component) {
|
||||||
case "alarm_control_panel":
|
case "alarm_control_panel":
|
||||||
return new AlarmControlPanel(componentConfiguration, newStyleChannels);
|
return new AlarmControlPanel(componentConfiguration, newStyleChannels);
|
||||||
@ -97,6 +99,8 @@ public class ComponentFactory {
|
|||||||
return new Vacuum(componentConfiguration, newStyleChannels);
|
return new Vacuum(componentConfiguration, newStyleChannels);
|
||||||
case "valve":
|
case "valve":
|
||||||
return new Valve(componentConfiguration, newStyleChannels);
|
return new Valve(componentConfiguration, newStyleChannels);
|
||||||
|
case "water_heater":
|
||||||
|
return new WaterHeater(componentConfiguration, newStyleChannels);
|
||||||
default:
|
default:
|
||||||
throw new UnsupportedComponentException("Component '" + haID + "' is unsupported!");
|
throw new UnsupportedComponentException("Component '" + haID + "' is unsupported!");
|
||||||
}
|
}
|
||||||
@ -111,6 +115,7 @@ public class ComponentFactory {
|
|||||||
private final Gson gson;
|
private final Gson gson;
|
||||||
private final Jinjava jinjava;
|
private final Jinjava jinjava;
|
||||||
private final ScheduledExecutorService scheduler;
|
private final ScheduledExecutorService scheduler;
|
||||||
|
private final UnitProvider unitProvider;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Provide a thingUID and HomeAssistant topic ID to determine the channel group UID and type.
|
* Provide a thingUID and HomeAssistant topic ID to determine the channel group UID and type.
|
||||||
@ -122,7 +127,7 @@ public class ComponentFactory {
|
|||||||
*/
|
*/
|
||||||
protected ComponentConfiguration(ThingUID thingUID, HaID haID, String configJSON, Gson gson, Jinjava jinjava,
|
protected ComponentConfiguration(ThingUID thingUID, HaID haID, String configJSON, Gson gson, Jinjava jinjava,
|
||||||
ChannelStateUpdateListener updateListener, AvailabilityTracker tracker,
|
ChannelStateUpdateListener updateListener, AvailabilityTracker tracker,
|
||||||
ScheduledExecutorService scheduler) {
|
ScheduledExecutorService scheduler, UnitProvider unitProvider) {
|
||||||
this.thingUID = thingUID;
|
this.thingUID = thingUID;
|
||||||
this.haID = haID;
|
this.haID = haID;
|
||||||
this.configJSON = configJSON;
|
this.configJSON = configJSON;
|
||||||
@ -131,6 +136,7 @@ public class ComponentFactory {
|
|||||||
this.updateListener = updateListener;
|
this.updateListener = updateListener;
|
||||||
this.tracker = tracker;
|
this.tracker = tracker;
|
||||||
this.scheduler = scheduler;
|
this.scheduler = scheduler;
|
||||||
|
this.unitProvider = unitProvider;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ThingUID getThingUID() {
|
public ThingUID getThingUID() {
|
||||||
@ -157,6 +163,10 @@ public class ComponentFactory {
|
|||||||
return jinjava;
|
return jinjava;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public UnitProvider getUnitProvider() {
|
||||||
|
return unitProvider;
|
||||||
|
}
|
||||||
|
|
||||||
public AvailabilityTracker getTracker() {
|
public AvailabilityTracker getTracker() {
|
||||||
return tracker;
|
return tracker;
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,190 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2010-2024 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.mqtt.homeassistant.internal.component;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
import javax.measure.quantity.Temperature;
|
||||||
|
|
||||||
|
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||||
|
import org.eclipse.jdt.annotation.Nullable;
|
||||||
|
import org.openhab.binding.mqtt.generic.values.NumberValue;
|
||||||
|
import org.openhab.binding.mqtt.generic.values.OnOffValue;
|
||||||
|
import org.openhab.binding.mqtt.generic.values.TextValue;
|
||||||
|
import org.openhab.binding.mqtt.homeassistant.internal.ComponentChannelType;
|
||||||
|
import org.openhab.binding.mqtt.homeassistant.internal.config.dto.AbstractChannelConfiguration;
|
||||||
|
import org.openhab.binding.mqtt.homeassistant.internal.exception.ConfigurationException;
|
||||||
|
import org.openhab.core.library.unit.ImperialUnits;
|
||||||
|
|
||||||
|
import com.google.gson.annotations.SerializedName;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A MQTT Humidifier, following the https://www.home-assistant.io/integrations/water_heater.mqtt/ specification.
|
||||||
|
*
|
||||||
|
* @author Cody Cutrer - Initial contribution
|
||||||
|
*/
|
||||||
|
@NonNullByDefault
|
||||||
|
public class WaterHeater extends AbstractComponent<WaterHeater.ChannelConfiguration> {
|
||||||
|
public static final String CURRENT_TEMPERATURE_CHANNEL_ID = "current-temperature";
|
||||||
|
public static final String MODE_CHANNEL_ID = "mode";
|
||||||
|
public static final String STATE_CHANNEL_ID = "state";
|
||||||
|
public static final String TARGET_TEMPERATURE_CHANNEL_ID = "target-temperature";
|
||||||
|
|
||||||
|
public static final String PLATFORM_WATER_HEATER = "water_heater";
|
||||||
|
|
||||||
|
public static final String MODE_OFF = "off";
|
||||||
|
public static final String MODE_ECO = "eco";
|
||||||
|
public static final String MODE_ELECTRIC = "electric";
|
||||||
|
public static final String MODE_GAS = "gas";
|
||||||
|
public static final String MODE_HEAT_PUMP = "heat_pump";
|
||||||
|
public static final String MODE_HIGH_DEMAND = "high_demand";
|
||||||
|
public static final String MODE_PERFORMANCE = "performance";
|
||||||
|
public static final List<String> DEFAULT_MODES = List.of(MODE_OFF, MODE_ECO, MODE_ELECTRIC, MODE_GAS,
|
||||||
|
MODE_HEAT_PUMP, MODE_HIGH_DEMAND, MODE_PERFORMANCE);
|
||||||
|
|
||||||
|
public static final String TEMPERATURE_UNIT_C = "C";
|
||||||
|
public static final String TEMPERATURE_UNIT_F = "F";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Configuration class for MQTT component
|
||||||
|
*/
|
||||||
|
static class ChannelConfiguration extends AbstractChannelConfiguration {
|
||||||
|
ChannelConfiguration() {
|
||||||
|
super("MQTT Humidifier");
|
||||||
|
}
|
||||||
|
|
||||||
|
protected @Nullable Boolean optimistic;
|
||||||
|
|
||||||
|
@SerializedName("power_command_topic")
|
||||||
|
protected @Nullable String powerCommandTopic;
|
||||||
|
@SerializedName("power_command_template")
|
||||||
|
protected @Nullable String powerCommandTemplate;
|
||||||
|
@SerializedName("current_temperature_topic")
|
||||||
|
protected @Nullable String currentTemperatureTopic;
|
||||||
|
@SerializedName("current_temperature_template")
|
||||||
|
protected @Nullable String currentTemperatureTemplate;
|
||||||
|
@SerializedName("temperature_command_topic")
|
||||||
|
protected @Nullable String temperatureCommandTopic;
|
||||||
|
@SerializedName("temperature_command_template")
|
||||||
|
protected @Nullable String temperatureCommandTemplate;
|
||||||
|
@SerializedName("temperature_state_topic")
|
||||||
|
protected @Nullable String temperatureStateTopic;
|
||||||
|
@SerializedName("temperature_state_template")
|
||||||
|
protected @Nullable String temperatureStateTemplate;
|
||||||
|
@SerializedName("mode_command_topic")
|
||||||
|
protected @Nullable String modeCommandTopic;
|
||||||
|
@SerializedName("mode_command_template")
|
||||||
|
protected @Nullable String modeCommandTemplate;
|
||||||
|
@SerializedName("mode_state_topic")
|
||||||
|
protected @Nullable String modeStateTopic;
|
||||||
|
@SerializedName("mode_state_template")
|
||||||
|
protected @Nullable String modeStateTemplate;
|
||||||
|
|
||||||
|
@SerializedName("device_class")
|
||||||
|
protected @Nullable String deviceClass;
|
||||||
|
protected String platform = "";
|
||||||
|
|
||||||
|
protected @Nullable Integer initial;
|
||||||
|
@SerializedName("min_temp")
|
||||||
|
protected @Nullable BigDecimal minTemp;
|
||||||
|
@SerializedName("max_temp")
|
||||||
|
protected @Nullable BigDecimal maxTemp;
|
||||||
|
protected @Nullable BigDecimal precision;
|
||||||
|
@SerializedName("temperature_unit")
|
||||||
|
protected @Nullable TemperatureUnit temperatureUnit;
|
||||||
|
|
||||||
|
@SerializedName("payload_on")
|
||||||
|
protected String payloadOn = "ON";
|
||||||
|
@SerializedName("payload_off")
|
||||||
|
protected String payloadOff = "OFF";
|
||||||
|
protected List<String> modes = DEFAULT_MODES;
|
||||||
|
}
|
||||||
|
|
||||||
|
public WaterHeater(ComponentFactory.ComponentConfiguration componentConfiguration, boolean newStyleChannels) {
|
||||||
|
super(componentConfiguration, ChannelConfiguration.class, newStyleChannels);
|
||||||
|
|
||||||
|
if (!PLATFORM_WATER_HEATER.equals(channelConfiguration.platform)) {
|
||||||
|
throw new ConfigurationException("platform must be " + PLATFORM_WATER_HEATER);
|
||||||
|
}
|
||||||
|
|
||||||
|
TemperatureUnit temperatureUnit = channelConfiguration.temperatureUnit;
|
||||||
|
if (channelConfiguration.temperatureUnit == null) {
|
||||||
|
if (ImperialUnits.FAHRENHEIT.equals(componentConfiguration.getUnitProvider().getUnit(Temperature.class))) {
|
||||||
|
temperatureUnit = TemperatureUnit.FAHRENHEIT;
|
||||||
|
} else {
|
||||||
|
temperatureUnit = TemperatureUnit.CELSIUS;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
BigDecimal precision = channelConfiguration.precision != null ? channelConfiguration.precision
|
||||||
|
: temperatureUnit.getDefaultPrecision();
|
||||||
|
|
||||||
|
List<String> onStates = new ArrayList<>(channelConfiguration.modes);
|
||||||
|
onStates.remove(MODE_OFF);
|
||||||
|
|
||||||
|
List<String> unsupportedModes = onStates.stream().filter(mode -> !DEFAULT_MODES.contains(mode))
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
if (!unsupportedModes.isEmpty()) {
|
||||||
|
throw new ConfigurationException("unsupported modes: " + unsupportedModes.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (channelConfiguration.powerCommandTopic != null) {
|
||||||
|
buildChannel(STATE_CHANNEL_ID, ComponentChannelType.SWITCH,
|
||||||
|
new OnOffValue(onStates.toArray(new String[0]), new String[] { MODE_OFF },
|
||||||
|
channelConfiguration.payloadOn, channelConfiguration.payloadOff),
|
||||||
|
"State", componentConfiguration.getUpdateListener())
|
||||||
|
.stateTopic(channelConfiguration.modeStateTopic, channelConfiguration.modeStateTemplate,
|
||||||
|
channelConfiguration.getValueTemplate())
|
||||||
|
.commandTopic(channelConfiguration.powerCommandTopic, channelConfiguration.isRetain(),
|
||||||
|
channelConfiguration.getQos(), channelConfiguration.powerCommandTemplate)
|
||||||
|
.inferOptimistic(channelConfiguration.optimistic).build();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (channelConfiguration.modeCommandTopic != null | channelConfiguration.modeStateTopic != null) {
|
||||||
|
buildChannel(MODE_CHANNEL_ID, ComponentChannelType.STRING,
|
||||||
|
new TextValue(channelConfiguration.modes.toArray(new String[0])), "Mode",
|
||||||
|
componentConfiguration.getUpdateListener())
|
||||||
|
.stateTopic(channelConfiguration.modeStateTopic, channelConfiguration.modeStateTemplate,
|
||||||
|
channelConfiguration.getValueTemplate())
|
||||||
|
.commandTopic(channelConfiguration.modeCommandTopic, channelConfiguration.isRetain(),
|
||||||
|
channelConfiguration.getQos(), channelConfiguration.modeCommandTemplate)
|
||||||
|
.inferOptimistic(channelConfiguration.optimistic).build();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (channelConfiguration.currentTemperatureTopic != null) {
|
||||||
|
buildChannel(CURRENT_TEMPERATURE_CHANNEL_ID, ComponentChannelType.TEMPERATURE,
|
||||||
|
new NumberValue(null, null, null, temperatureUnit.getUnit()), "Current Temperature",
|
||||||
|
componentConfiguration.getUpdateListener())
|
||||||
|
.stateTopic(channelConfiguration.currentTemperatureTopic,
|
||||||
|
channelConfiguration.currentTemperatureTemplate, channelConfiguration.getValueTemplate())
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (channelConfiguration.temperatureStateTopic != null
|
||||||
|
|| channelConfiguration.temperatureCommandTopic != null) {
|
||||||
|
buildChannel(TARGET_TEMPERATURE_CHANNEL_ID, ComponentChannelType.TEMPERATURE,
|
||||||
|
new NumberValue(channelConfiguration.minTemp, channelConfiguration.maxTemp, precision,
|
||||||
|
temperatureUnit.getUnit()),
|
||||||
|
"Target Temperature", componentConfiguration.getUpdateListener())
|
||||||
|
.stateTopic(channelConfiguration.temperatureStateTopic,
|
||||||
|
channelConfiguration.temperatureStateTemplate, channelConfiguration.getValueTemplate())
|
||||||
|
.commandTopic(channelConfiguration.temperatureCommandTopic, channelConfiguration.isRetain(),
|
||||||
|
channelConfiguration.getQos(), channelConfiguration.temperatureCommandTemplate)
|
||||||
|
.inferOptimistic(channelConfiguration.optimistic).build();
|
||||||
|
}
|
||||||
|
|
||||||
|
finalizeChannels();
|
||||||
|
}
|
||||||
|
}
|
@ -47,6 +47,7 @@ import org.openhab.binding.mqtt.homeassistant.internal.config.ChannelConfigurati
|
|||||||
import org.openhab.binding.mqtt.homeassistant.internal.exception.ConfigurationException;
|
import org.openhab.binding.mqtt.homeassistant.internal.exception.ConfigurationException;
|
||||||
import org.openhab.core.config.core.Configuration;
|
import org.openhab.core.config.core.Configuration;
|
||||||
import org.openhab.core.config.core.validation.ConfigValidationException;
|
import org.openhab.core.config.core.validation.ConfigValidationException;
|
||||||
|
import org.openhab.core.i18n.UnitProvider;
|
||||||
import org.openhab.core.io.transport.mqtt.MqttBrokerConnection;
|
import org.openhab.core.io.transport.mqtt.MqttBrokerConnection;
|
||||||
import org.openhab.core.thing.Channel;
|
import org.openhab.core.thing.Channel;
|
||||||
import org.openhab.core.thing.ChannelUID;
|
import org.openhab.core.thing.ChannelUID;
|
||||||
@ -95,6 +96,7 @@ public class HomeAssistantThingHandler extends AbstractMQTTThingHandler
|
|||||||
protected final MqttChannelStateDescriptionProvider stateDescriptionProvider;
|
protected final MqttChannelStateDescriptionProvider stateDescriptionProvider;
|
||||||
protected final ChannelTypeRegistry channelTypeRegistry;
|
protected final ChannelTypeRegistry channelTypeRegistry;
|
||||||
protected final Jinjava jinjava;
|
protected final Jinjava jinjava;
|
||||||
|
protected final UnitProvider unitProvider;
|
||||||
public final int attributeReceiveTimeout;
|
public final int attributeReceiveTimeout;
|
||||||
protected final DelayedBatchProcessing<Object> delayedProcessing;
|
protected final DelayedBatchProcessing<Object> delayedProcessing;
|
||||||
protected final DiscoverComponents discoverComponents;
|
protected final DiscoverComponents discoverComponents;
|
||||||
@ -123,20 +125,21 @@ public class HomeAssistantThingHandler extends AbstractMQTTThingHandler
|
|||||||
*/
|
*/
|
||||||
public HomeAssistantThingHandler(Thing thing, MqttChannelTypeProvider channelTypeProvider,
|
public HomeAssistantThingHandler(Thing thing, MqttChannelTypeProvider channelTypeProvider,
|
||||||
MqttChannelStateDescriptionProvider stateDescriptionProvider, ChannelTypeRegistry channelTypeRegistry,
|
MqttChannelStateDescriptionProvider stateDescriptionProvider, ChannelTypeRegistry channelTypeRegistry,
|
||||||
Jinjava jinjava, int subscribeTimeout, int attributeReceiveTimeout) {
|
Jinjava jinjava, UnitProvider unitProvider, int subscribeTimeout, int attributeReceiveTimeout) {
|
||||||
super(thing, subscribeTimeout);
|
super(thing, subscribeTimeout);
|
||||||
this.gson = new GsonBuilder().registerTypeAdapterFactory(new ChannelConfigurationTypeAdapterFactory()).create();
|
this.gson = new GsonBuilder().registerTypeAdapterFactory(new ChannelConfigurationTypeAdapterFactory()).create();
|
||||||
this.channelTypeProvider = channelTypeProvider;
|
this.channelTypeProvider = channelTypeProvider;
|
||||||
this.stateDescriptionProvider = stateDescriptionProvider;
|
this.stateDescriptionProvider = stateDescriptionProvider;
|
||||||
this.channelTypeRegistry = channelTypeRegistry;
|
this.channelTypeRegistry = channelTypeRegistry;
|
||||||
this.jinjava = jinjava;
|
this.jinjava = jinjava;
|
||||||
|
this.unitProvider = unitProvider;
|
||||||
this.attributeReceiveTimeout = attributeReceiveTimeout;
|
this.attributeReceiveTimeout = attributeReceiveTimeout;
|
||||||
this.delayedProcessing = new DelayedBatchProcessing<>(attributeReceiveTimeout, this, scheduler);
|
this.delayedProcessing = new DelayedBatchProcessing<>(attributeReceiveTimeout, this, scheduler);
|
||||||
|
|
||||||
newStyleChannels = "true".equals(thing.getProperties().get("newStyleChannels"));
|
newStyleChannels = "true".equals(thing.getProperties().get("newStyleChannels"));
|
||||||
|
|
||||||
this.discoverComponents = new DiscoverComponents(thing.getUID(), scheduler, this, this, gson, jinjava,
|
this.discoverComponents = new DiscoverComponents(thing.getUID(), scheduler, this, this, gson, jinjava,
|
||||||
newStyleChannels);
|
unitProvider, newStyleChannels);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -184,7 +187,8 @@ public class HomeAssistantThingHandler extends AbstractMQTTThingHandler
|
|||||||
String channelConfigurationJSON = (String) channelConfig.get("config");
|
String channelConfigurationJSON = (String) channelConfig.get("config");
|
||||||
try {
|
try {
|
||||||
AbstractComponent<?> component = ComponentFactory.createComponent(thingUID, haID,
|
AbstractComponent<?> component = ComponentFactory.createComponent(thingUID, haID,
|
||||||
channelConfigurationJSON, this, this, scheduler, gson, jinjava, newStyleChannels);
|
channelConfigurationJSON, this, this, scheduler, gson, jinjava, unitProvider,
|
||||||
|
newStyleChannels);
|
||||||
if (typeID.equals(MqttBindingConstants.HOMEASSISTANT_MQTT_THING)) {
|
if (typeID.equals(MqttBindingConstants.HOMEASSISTANT_MQTT_THING)) {
|
||||||
typeID = calculateThingTypeUID(component);
|
typeID = calculateThingTypeUID(component);
|
||||||
}
|
}
|
||||||
|
@ -30,6 +30,7 @@ channel-type.mqtt.ha-string-advanced.label = String
|
|||||||
channel-type.mqtt.ha-string.label = String
|
channel-type.mqtt.ha-string.label = String
|
||||||
channel-type.mqtt.ha-switch-advanced.label = Switch
|
channel-type.mqtt.ha-switch-advanced.label = Switch
|
||||||
channel-type.mqtt.ha-switch.label = Switch
|
channel-type.mqtt.ha-switch.label = Switch
|
||||||
|
channel-type.mqtt.ha-temperature.label = Temperature
|
||||||
channel-type.mqtt.ha-trigger-advanced.label = Trigger
|
channel-type.mqtt.ha-trigger-advanced.label = Trigger
|
||||||
channel-type.mqtt.ha-trigger.label = Trigger
|
channel-type.mqtt.ha-trigger.label = Trigger
|
||||||
|
|
||||||
|
@ -66,6 +66,12 @@
|
|||||||
<config-description-ref uri="channel-type:mqtt:ha-channel"/>
|
<config-description-ref uri="channel-type:mqtt:ha-channel"/>
|
||||||
</channel-type>
|
</channel-type>
|
||||||
|
|
||||||
|
<channel-type id="ha-temperature">
|
||||||
|
<item-type>Number:Temperature</item-type>
|
||||||
|
<label>Temperature</label>
|
||||||
|
<config-description-ref uri="channel-type:mqtt:ha-channel"/>
|
||||||
|
</channel-type>
|
||||||
|
|
||||||
<channel-type id="ha-trigger">
|
<channel-type id="ha-trigger">
|
||||||
<kind>trigger</kind>
|
<kind>trigger</kind>
|
||||||
<label>Trigger</label>
|
<label>Trigger</label>
|
||||||
|
@ -32,6 +32,7 @@ import org.openhab.binding.mqtt.generic.MqttChannelStateDescriptionProvider;
|
|||||||
import org.openhab.binding.mqtt.generic.MqttChannelTypeProvider;
|
import org.openhab.binding.mqtt.generic.MqttChannelTypeProvider;
|
||||||
import org.openhab.binding.mqtt.homeassistant.generic.internal.MqttThingHandlerFactory;
|
import org.openhab.binding.mqtt.homeassistant.generic.internal.MqttThingHandlerFactory;
|
||||||
import org.openhab.binding.mqtt.homeassistant.internal.component.AbstractComponent;
|
import org.openhab.binding.mqtt.homeassistant.internal.component.AbstractComponent;
|
||||||
|
import org.openhab.core.i18n.UnitProvider;
|
||||||
import org.openhab.core.test.storage.VolatileStorageService;
|
import org.openhab.core.test.storage.VolatileStorageService;
|
||||||
import org.openhab.core.thing.type.ChannelTypeRegistry;
|
import org.openhab.core.thing.type.ChannelTypeRegistry;
|
||||||
import org.openhab.core.thing.type.ThingTypeRegistry;
|
import org.openhab.core.thing.type.ThingTypeRegistry;
|
||||||
@ -44,6 +45,7 @@ import org.openhab.core.thing.type.ThingTypeRegistry;
|
|||||||
@NonNullByDefault
|
@NonNullByDefault
|
||||||
public class HomeAssistantChannelTransformationTests {
|
public class HomeAssistantChannelTransformationTests {
|
||||||
protected @Mock @NonNullByDefault({}) ThingTypeRegistry thingTypeRegistry;
|
protected @Mock @NonNullByDefault({}) ThingTypeRegistry thingTypeRegistry;
|
||||||
|
protected @Mock @NonNullByDefault({}) UnitProvider unitProvider;
|
||||||
|
|
||||||
protected @NonNullByDefault({}) HomeAssistantChannelTransformation transformation;
|
protected @NonNullByDefault({}) HomeAssistantChannelTransformation transformation;
|
||||||
|
|
||||||
@ -54,7 +56,7 @@ public class HomeAssistantChannelTransformationTests {
|
|||||||
MqttChannelStateDescriptionProvider stateDescriptionProvider = new MqttChannelStateDescriptionProvider();
|
MqttChannelStateDescriptionProvider stateDescriptionProvider = new MqttChannelStateDescriptionProvider();
|
||||||
ChannelTypeRegistry channelTypeRegistry = new ChannelTypeRegistry();
|
ChannelTypeRegistry channelTypeRegistry = new ChannelTypeRegistry();
|
||||||
MqttThingHandlerFactory thingHandlerFactory = new MqttThingHandlerFactory(channelTypeProvider,
|
MqttThingHandlerFactory thingHandlerFactory = new MqttThingHandlerFactory(channelTypeProvider,
|
||||||
stateDescriptionProvider, channelTypeRegistry);
|
stateDescriptionProvider, channelTypeRegistry, unitProvider);
|
||||||
|
|
||||||
AbstractComponent component = Mockito.mock(AbstractComponent.class);
|
AbstractComponent component = Mockito.mock(AbstractComponent.class);
|
||||||
HaID haID = new HaID("homeassistant/light/pool/light/config");
|
HaID haID = new HaID("homeassistant/light/pool/light/config");
|
||||||
|
@ -41,6 +41,7 @@ import org.openhab.binding.mqtt.homeassistant.internal.HaID;
|
|||||||
import org.openhab.binding.mqtt.homeassistant.internal.HandlerConfiguration;
|
import org.openhab.binding.mqtt.homeassistant.internal.HandlerConfiguration;
|
||||||
import org.openhab.binding.mqtt.homeassistant.internal.config.dto.AbstractChannelConfiguration;
|
import org.openhab.binding.mqtt.homeassistant.internal.config.dto.AbstractChannelConfiguration;
|
||||||
import org.openhab.binding.mqtt.homeassistant.internal.handler.HomeAssistantThingHandler;
|
import org.openhab.binding.mqtt.homeassistant.internal.handler.HomeAssistantThingHandler;
|
||||||
|
import org.openhab.core.i18n.UnitProvider;
|
||||||
import org.openhab.core.library.types.HSBType;
|
import org.openhab.core.library.types.HSBType;
|
||||||
import org.openhab.core.thing.Thing;
|
import org.openhab.core.thing.Thing;
|
||||||
import org.openhab.core.thing.ThingStatusInfo;
|
import org.openhab.core.thing.ThingStatusInfo;
|
||||||
@ -64,6 +65,7 @@ public abstract class AbstractComponentTests extends AbstractHomeAssistantTests
|
|||||||
|
|
||||||
private @Mock @NonNullByDefault({}) ThingHandlerCallback callbackMock;
|
private @Mock @NonNullByDefault({}) ThingHandlerCallback callbackMock;
|
||||||
private @NonNullByDefault({}) LatchThingHandler thingHandler;
|
private @NonNullByDefault({}) LatchThingHandler thingHandler;
|
||||||
|
protected @Mock @NonNullByDefault({}) UnitProvider unitProvider;
|
||||||
|
|
||||||
@BeforeEach
|
@BeforeEach
|
||||||
public void setupThingHandler() {
|
public void setupThingHandler() {
|
||||||
@ -84,7 +86,7 @@ public abstract class AbstractComponentTests extends AbstractHomeAssistantTests
|
|||||||
haThing.setProperty("newStyleChannels", "true");
|
haThing.setProperty("newStyleChannels", "true");
|
||||||
}
|
}
|
||||||
thingHandler = new LatchThingHandler(haThing, channelTypeProvider, stateDescriptionProvider,
|
thingHandler = new LatchThingHandler(haThing, channelTypeProvider, stateDescriptionProvider,
|
||||||
channelTypeRegistry, SUBSCRIBE_TIMEOUT, ATTRIBUTE_RECEIVE_TIMEOUT);
|
channelTypeRegistry, unitProvider, SUBSCRIBE_TIMEOUT, ATTRIBUTE_RECEIVE_TIMEOUT);
|
||||||
thingHandler.setConnection(bridgeConnection);
|
thingHandler.setConnection(bridgeConnection);
|
||||||
thingHandler.setCallback(callbackMock);
|
thingHandler.setCallback(callbackMock);
|
||||||
thingHandler = spy(thingHandler);
|
thingHandler = spy(thingHandler);
|
||||||
@ -341,9 +343,9 @@ public abstract class AbstractComponentTests extends AbstractHomeAssistantTests
|
|||||||
|
|
||||||
public LatchThingHandler(Thing thing, MqttChannelTypeProvider channelTypeProvider,
|
public LatchThingHandler(Thing thing, MqttChannelTypeProvider channelTypeProvider,
|
||||||
MqttChannelStateDescriptionProvider stateDescriptionProvider, ChannelTypeRegistry channelTypeRegistry,
|
MqttChannelStateDescriptionProvider stateDescriptionProvider, ChannelTypeRegistry channelTypeRegistry,
|
||||||
int subscribeTimeout, int attributeReceiveTimeout) {
|
UnitProvider unitProvider, int subscribeTimeout, int attributeReceiveTimeout) {
|
||||||
super(thing, channelTypeProvider, stateDescriptionProvider, channelTypeRegistry, new Jinjava(),
|
super(thing, channelTypeProvider, stateDescriptionProvider, channelTypeRegistry, new Jinjava(),
|
||||||
subscribeTimeout, attributeReceiveTimeout);
|
unitProvider, subscribeTimeout, attributeReceiveTimeout);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -0,0 +1,159 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2010-2024 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.mqtt.homeassistant.internal.component;
|
||||||
|
|
||||||
|
import static org.hamcrest.CoreMatchers.is;
|
||||||
|
import static org.hamcrest.MatcherAssert.assertThat;
|
||||||
|
import static org.mockito.Mockito.*;
|
||||||
|
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import javax.measure.quantity.Temperature;
|
||||||
|
|
||||||
|
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.openhab.binding.mqtt.generic.values.NumberValue;
|
||||||
|
import org.openhab.binding.mqtt.generic.values.OnOffValue;
|
||||||
|
import org.openhab.binding.mqtt.generic.values.TextValue;
|
||||||
|
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.ImperialUnits;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests for {@link WaterHeater}
|
||||||
|
*
|
||||||
|
* @author Cody Cutrer - Initial contribution
|
||||||
|
*/
|
||||||
|
@NonNullByDefault
|
||||||
|
public class WaterHeaterTests extends AbstractComponentTests {
|
||||||
|
public static final String CONFIG_TOPIC = "water_heater/boiler";
|
||||||
|
|
||||||
|
@SuppressWarnings("null")
|
||||||
|
@Test
|
||||||
|
public void test() {
|
||||||
|
when(unitProvider.getUnit(Temperature.class)).thenReturn(ImperialUnits.FAHRENHEIT);
|
||||||
|
|
||||||
|
var component = discoverComponent(configTopicToMqtt(CONFIG_TOPIC), """
|
||||||
|
{
|
||||||
|
"platform": "water_heater",
|
||||||
|
"name": "Boiler",
|
||||||
|
"modes": [
|
||||||
|
"off",
|
||||||
|
"eco",
|
||||||
|
"performance"
|
||||||
|
],
|
||||||
|
"mode_state_topic": "basement/boiler/mode",
|
||||||
|
"mode_command_topic": "basement/boiler/mode/set",
|
||||||
|
"mode_command_template": "{{ value if value==\\"off\\" else \\"on\\" }}",
|
||||||
|
"temperature_state_topic": "basement/boiler/temperature",
|
||||||
|
"temperature_command_topic": "basement/boiler/temperature/set",
|
||||||
|
"current_temperature_topic": "basement/boiler/current_temperature",
|
||||||
|
"precision": 1.0
|
||||||
|
}
|
||||||
|
""");
|
||||||
|
|
||||||
|
assertThat(component.channels.size(), is(3));
|
||||||
|
assertThat(component.getName(), is("Boiler"));
|
||||||
|
|
||||||
|
assertChannel(component, WaterHeater.MODE_CHANNEL_ID, "basement/boiler/mode", "basement/boiler/mode/set",
|
||||||
|
"Mode", TextValue.class);
|
||||||
|
assertChannel(component, WaterHeater.CURRENT_TEMPERATURE_CHANNEL_ID, "basement/boiler/current_temperature", "",
|
||||||
|
"Current Temperature", NumberValue.class);
|
||||||
|
assertChannel(component, WaterHeater.TARGET_TEMPERATURE_CHANNEL_ID, "basement/boiler/temperature",
|
||||||
|
"basement/boiler/temperature/set", "Target Temperature", NumberValue.class);
|
||||||
|
|
||||||
|
publishMessage("basement/boiler/mode", "eco");
|
||||||
|
assertState(component, WaterHeater.MODE_CHANNEL_ID, new StringType("eco"));
|
||||||
|
publishMessage("basement/boiler/mode", "invalid");
|
||||||
|
assertState(component, WaterHeater.MODE_CHANNEL_ID, new StringType("eco"));
|
||||||
|
|
||||||
|
publishMessage("basement/boiler/current_temperature", "120");
|
||||||
|
assertState(component, WaterHeater.CURRENT_TEMPERATURE_CHANNEL_ID,
|
||||||
|
new QuantityType<>(120, ImperialUnits.FAHRENHEIT));
|
||||||
|
publishMessage("basement/boiler/temperature", "125");
|
||||||
|
assertState(component, WaterHeater.TARGET_TEMPERATURE_CHANNEL_ID,
|
||||||
|
new QuantityType<>(125, ImperialUnits.FAHRENHEIT));
|
||||||
|
|
||||||
|
component.getChannel(WaterHeater.MODE_CHANNEL_ID).getState().publishValue(new StringType("eco"));
|
||||||
|
assertPublished("basement/boiler/mode/set", "on");
|
||||||
|
component.getChannel(WaterHeater.MODE_CHANNEL_ID).getState().publishValue(new StringType("off"));
|
||||||
|
assertPublished("basement/boiler/mode/set", "off");
|
||||||
|
|
||||||
|
component.getChannel(WaterHeater.TARGET_TEMPERATURE_CHANNEL_ID).getState().publishValue(new DecimalType(130));
|
||||||
|
assertPublished("basement/boiler/temperature/set", "130");
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("null")
|
||||||
|
@Test
|
||||||
|
public void testSynthesizedPowerState() {
|
||||||
|
when(unitProvider.getUnit(Temperature.class)).thenReturn(ImperialUnits.FAHRENHEIT);
|
||||||
|
|
||||||
|
var component = discoverComponent(configTopicToMqtt(CONFIG_TOPIC), """
|
||||||
|
{
|
||||||
|
"platform": "water_heater",
|
||||||
|
"name": "Boiler",
|
||||||
|
"modes": [
|
||||||
|
"off",
|
||||||
|
"eco",
|
||||||
|
"performance"
|
||||||
|
],
|
||||||
|
"mode_state_topic": "basement/boiler/mode",
|
||||||
|
"mode_command_topic": "basement/boiler/mode/set",
|
||||||
|
"temperature_state_topic": "basement/boiler/temperature",
|
||||||
|
"temperature_command_topic": "basement/boiler/temperature/set",
|
||||||
|
"current_temperature_topic": "basement/boiler/current_temperature",
|
||||||
|
"precision": 1.0,
|
||||||
|
"power_command_topic": "basement/boiler/power/set"
|
||||||
|
}
|
||||||
|
""");
|
||||||
|
|
||||||
|
assertThat(component.channels.size(), is(4));
|
||||||
|
assertThat(component.getName(), is("Boiler"));
|
||||||
|
|
||||||
|
assertChannel(component, WaterHeater.STATE_CHANNEL_ID, "basement/boiler/mode", "basement/boiler/power/set",
|
||||||
|
"State", OnOffValue.class);
|
||||||
|
assertChannel(component, WaterHeater.MODE_CHANNEL_ID, "basement/boiler/mode", "basement/boiler/mode/set",
|
||||||
|
"Mode", TextValue.class);
|
||||||
|
assertChannel(component, WaterHeater.CURRENT_TEMPERATURE_CHANNEL_ID, "basement/boiler/current_temperature", "",
|
||||||
|
"Current Temperature", NumberValue.class);
|
||||||
|
assertChannel(component, WaterHeater.TARGET_TEMPERATURE_CHANNEL_ID, "basement/boiler/temperature",
|
||||||
|
"basement/boiler/temperature/set", "Target Temperature", NumberValue.class);
|
||||||
|
|
||||||
|
publishMessage("basement/boiler/mode", "eco");
|
||||||
|
assertState(component, WaterHeater.MODE_CHANNEL_ID, new StringType("eco"));
|
||||||
|
assertState(component, WaterHeater.STATE_CHANNEL_ID, OnOffType.ON);
|
||||||
|
publishMessage("basement/boiler/mode", "invalid");
|
||||||
|
assertState(component, WaterHeater.MODE_CHANNEL_ID, new StringType("eco"));
|
||||||
|
assertState(component, WaterHeater.STATE_CHANNEL_ID, OnOffType.ON);
|
||||||
|
publishMessage("basement/boiler/mode", "off");
|
||||||
|
assertState(component, WaterHeater.MODE_CHANNEL_ID, new StringType("off"));
|
||||||
|
assertState(component, WaterHeater.STATE_CHANNEL_ID, OnOffType.OFF);
|
||||||
|
|
||||||
|
component.getChannel(WaterHeater.MODE_CHANNEL_ID).getState().publishValue(new StringType("eco"));
|
||||||
|
assertPublished("basement/boiler/mode/set", "eco");
|
||||||
|
component.getChannel(WaterHeater.MODE_CHANNEL_ID).getState().publishValue(new StringType("off"));
|
||||||
|
assertPublished("basement/boiler/mode/set", "off");
|
||||||
|
|
||||||
|
component.getChannel(WaterHeater.STATE_CHANNEL_ID).getState().publishValue(OnOffType.ON);
|
||||||
|
assertPublished("basement/boiler/power/set", "ON");
|
||||||
|
component.getChannel(WaterHeater.STATE_CHANNEL_ID).getState().publishValue(OnOffType.OFF);
|
||||||
|
assertPublished("basement/boiler/power/set", "OFF");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Set<String> getConfigTopics() {
|
||||||
|
return Set.of(CONFIG_TOPIC);
|
||||||
|
}
|
||||||
|
}
|
@ -38,6 +38,7 @@ import org.openhab.binding.mqtt.homeassistant.internal.component.Climate;
|
|||||||
import org.openhab.binding.mqtt.homeassistant.internal.component.Sensor;
|
import org.openhab.binding.mqtt.homeassistant.internal.component.Sensor;
|
||||||
import org.openhab.binding.mqtt.homeassistant.internal.component.Switch;
|
import org.openhab.binding.mqtt.homeassistant.internal.component.Switch;
|
||||||
import org.openhab.core.config.core.Configuration;
|
import org.openhab.core.config.core.Configuration;
|
||||||
|
import org.openhab.core.i18n.UnitProvider;
|
||||||
import org.openhab.core.library.CoreItemFactory;
|
import org.openhab.core.library.CoreItemFactory;
|
||||||
import org.openhab.core.thing.Channel;
|
import org.openhab.core.thing.Channel;
|
||||||
import org.openhab.core.thing.ChannelUID;
|
import org.openhab.core.thing.ChannelUID;
|
||||||
@ -72,6 +73,7 @@ public class HomeAssistantThingHandlerTests extends AbstractHomeAssistantTests {
|
|||||||
private @Mock @NonNullByDefault({}) ThingHandlerCallback callbackMock;
|
private @Mock @NonNullByDefault({}) ThingHandlerCallback callbackMock;
|
||||||
private @NonNullByDefault({}) HomeAssistantThingHandler thingHandler;
|
private @NonNullByDefault({}) HomeAssistantThingHandler thingHandler;
|
||||||
private @NonNullByDefault({}) HomeAssistantThingHandler nonSpyThingHandler;
|
private @NonNullByDefault({}) HomeAssistantThingHandler nonSpyThingHandler;
|
||||||
|
private @Mock @NonNullByDefault({}) UnitProvider unitProvider;
|
||||||
|
|
||||||
@BeforeEach
|
@BeforeEach
|
||||||
public void setup() {
|
public void setup() {
|
||||||
@ -87,7 +89,7 @@ public class HomeAssistantThingHandlerTests extends AbstractHomeAssistantTests {
|
|||||||
|
|
||||||
protected void setupThingHandler() {
|
protected void setupThingHandler() {
|
||||||
thingHandler = new HomeAssistantThingHandler(haThing, channelTypeProvider, stateDescriptionProvider,
|
thingHandler = new HomeAssistantThingHandler(haThing, channelTypeProvider, stateDescriptionProvider,
|
||||||
channelTypeRegistry, new Jinjava(), SUBSCRIBE_TIMEOUT, ATTRIBUTE_RECEIVE_TIMEOUT);
|
channelTypeRegistry, new Jinjava(), unitProvider, SUBSCRIBE_TIMEOUT, ATTRIBUTE_RECEIVE_TIMEOUT);
|
||||||
thingHandler.setConnection(bridgeConnection);
|
thingHandler.setConnection(bridgeConnection);
|
||||||
thingHandler.setCallback(callbackMock);
|
thingHandler.setCallback(callbackMock);
|
||||||
nonSpyThingHandler = thingHandler;
|
nonSpyThingHandler = thingHandler;
|
||||||
@ -409,7 +411,7 @@ public class HomeAssistantThingHandlerTests extends AbstractHomeAssistantTests {
|
|||||||
public void testDuplicateChannelIdNewStyleChannels() {
|
public void testDuplicateChannelIdNewStyleChannels() {
|
||||||
haThing.setProperty("newStyleChannels", "true");
|
haThing.setProperty("newStyleChannels", "true");
|
||||||
thingHandler = new HomeAssistantThingHandler(haThing, channelTypeProvider, stateDescriptionProvider,
|
thingHandler = new HomeAssistantThingHandler(haThing, channelTypeProvider, stateDescriptionProvider,
|
||||||
channelTypeRegistry, new Jinjava(), SUBSCRIBE_TIMEOUT, ATTRIBUTE_RECEIVE_TIMEOUT);
|
channelTypeRegistry, new Jinjava(), unitProvider, SUBSCRIBE_TIMEOUT, ATTRIBUTE_RECEIVE_TIMEOUT);
|
||||||
thingHandler.setConnection(bridgeConnection);
|
thingHandler.setConnection(bridgeConnection);
|
||||||
thingHandler.setCallback(callbackMock);
|
thingHandler.setCallback(callbackMock);
|
||||||
nonSpyThingHandler = thingHandler;
|
nonSpyThingHandler = thingHandler;
|
||||||
@ -466,7 +468,7 @@ public class HomeAssistantThingHandlerTests extends AbstractHomeAssistantTests {
|
|||||||
public void testDuplicateChannelIdNewStyleChannelsComplex() {
|
public void testDuplicateChannelIdNewStyleChannelsComplex() {
|
||||||
haThing.setProperty("newStyleChannels", "true");
|
haThing.setProperty("newStyleChannels", "true");
|
||||||
thingHandler = new HomeAssistantThingHandler(haThing, channelTypeProvider, stateDescriptionProvider,
|
thingHandler = new HomeAssistantThingHandler(haThing, channelTypeProvider, stateDescriptionProvider,
|
||||||
channelTypeRegistry, new Jinjava(), SUBSCRIBE_TIMEOUT, ATTRIBUTE_RECEIVE_TIMEOUT);
|
channelTypeRegistry, new Jinjava(), unitProvider, SUBSCRIBE_TIMEOUT, ATTRIBUTE_RECEIVE_TIMEOUT);
|
||||||
thingHandler.setConnection(bridgeConnection);
|
thingHandler.setConnection(bridgeConnection);
|
||||||
thingHandler.setCallback(callbackMock);
|
thingHandler.setCallback(callbackMock);
|
||||||
nonSpyThingHandler = thingHandler;
|
nonSpyThingHandler = thingHandler;
|
||||||
|
@ -41,6 +41,7 @@ import org.openhab.binding.mqtt.homeassistant.internal.DiscoverComponents.Compon
|
|||||||
import org.openhab.binding.mqtt.homeassistant.internal.HaID;
|
import org.openhab.binding.mqtt.homeassistant.internal.HaID;
|
||||||
import org.openhab.binding.mqtt.homeassistant.internal.HandlerConfiguration;
|
import org.openhab.binding.mqtt.homeassistant.internal.HandlerConfiguration;
|
||||||
import org.openhab.binding.mqtt.homeassistant.internal.config.ChannelConfigurationTypeAdapterFactory;
|
import org.openhab.binding.mqtt.homeassistant.internal.config.ChannelConfigurationTypeAdapterFactory;
|
||||||
|
import org.openhab.core.i18n.UnitProvider;
|
||||||
import org.openhab.core.io.transport.mqtt.MqttBrokerConnection;
|
import org.openhab.core.io.transport.mqtt.MqttBrokerConnection;
|
||||||
import org.openhab.core.test.java.JavaOSGiTest;
|
import org.openhab.core.test.java.JavaOSGiTest;
|
||||||
|
|
||||||
@ -81,9 +82,10 @@ public class DiscoverComponentsTest extends JavaOSGiTest {
|
|||||||
|
|
||||||
Gson gson = new GsonBuilder().registerTypeAdapterFactory(new ChannelConfigurationTypeAdapterFactory()).create();
|
Gson gson = new GsonBuilder().registerTypeAdapterFactory(new ChannelConfigurationTypeAdapterFactory()).create();
|
||||||
Jinjava jinjava = new Jinjava();
|
Jinjava jinjava = new Jinjava();
|
||||||
|
UnitProvider unitProvider = mock(UnitProvider.class);
|
||||||
|
|
||||||
DiscoverComponents discover = spy(new DiscoverComponents(ThingChannelConstants.TEST_HOME_ASSISTANT_THING,
|
DiscoverComponents discover = spy(new DiscoverComponents(ThingChannelConstants.TEST_HOME_ASSISTANT_THING,
|
||||||
scheduler, channelStateUpdateListener, availabilityTracker, gson, jinjava, true));
|
scheduler, channelStateUpdateListener, availabilityTracker, gson, jinjava, unitProvider, true));
|
||||||
|
|
||||||
HandlerConfiguration config = new HandlerConfiguration("homeassistant", List.of("switch/object"));
|
HandlerConfiguration config = new HandlerConfiguration("homeassistant", List.of("switch/object"));
|
||||||
|
|
||||||
|
@ -48,6 +48,7 @@ import org.openhab.binding.mqtt.homeassistant.internal.HaID;
|
|||||||
import org.openhab.binding.mqtt.homeassistant.internal.component.AbstractComponent;
|
import org.openhab.binding.mqtt.homeassistant.internal.component.AbstractComponent;
|
||||||
import org.openhab.binding.mqtt.homeassistant.internal.component.Switch;
|
import org.openhab.binding.mqtt.homeassistant.internal.component.Switch;
|
||||||
import org.openhab.binding.mqtt.homeassistant.internal.config.ChannelConfigurationTypeAdapterFactory;
|
import org.openhab.binding.mqtt.homeassistant.internal.config.ChannelConfigurationTypeAdapterFactory;
|
||||||
|
import org.openhab.core.i18n.UnitProvider;
|
||||||
import org.openhab.core.io.transport.mqtt.MqttBrokerConnection;
|
import org.openhab.core.io.transport.mqtt.MqttBrokerConnection;
|
||||||
import org.openhab.core.io.transport.mqtt.MqttConnectionObserver;
|
import org.openhab.core.io.transport.mqtt.MqttConnectionObserver;
|
||||||
import org.openhab.core.io.transport.mqtt.MqttConnectionState;
|
import org.openhab.core.io.transport.mqtt.MqttConnectionState;
|
||||||
@ -161,6 +162,7 @@ public class HomeAssistantMQTTImplementationTest extends MqttOSGiTest {
|
|||||||
@Test
|
@Test
|
||||||
public void parseHATree() throws Exception {
|
public void parseHATree() throws Exception {
|
||||||
MqttChannelTypeProvider channelTypeProvider = mock(MqttChannelTypeProvider.class);
|
MqttChannelTypeProvider channelTypeProvider = mock(MqttChannelTypeProvider.class);
|
||||||
|
UnitProvider unitProvider = mock(UnitProvider.class);
|
||||||
|
|
||||||
final Map<String, AbstractComponent<?>> haComponents = new HashMap<>();
|
final Map<String, AbstractComponent<?>> haComponents = new HashMap<>();
|
||||||
Gson gson = new GsonBuilder().registerTypeAdapterFactory(new ChannelConfigurationTypeAdapterFactory()).create();
|
Gson gson = new GsonBuilder().registerTypeAdapterFactory(new ChannelConfigurationTypeAdapterFactory()).create();
|
||||||
@ -168,7 +170,7 @@ public class HomeAssistantMQTTImplementationTest extends MqttOSGiTest {
|
|||||||
|
|
||||||
ScheduledExecutorService scheduler = new ScheduledThreadPoolExecutor(4);
|
ScheduledExecutorService scheduler = new ScheduledThreadPoolExecutor(4);
|
||||||
DiscoverComponents discover = spy(new DiscoverComponents(ThingChannelConstants.TEST_HOME_ASSISTANT_THING,
|
DiscoverComponents discover = spy(new DiscoverComponents(ThingChannelConstants.TEST_HOME_ASSISTANT_THING,
|
||||||
scheduler, channelStateUpdateListener, availabilityTracker, gson, jinjava, true));
|
scheduler, channelStateUpdateListener, availabilityTracker, gson, jinjava, unitProvider, true));
|
||||||
|
|
||||||
// The DiscoverComponents object calls ComponentDiscovered callbacks.
|
// The DiscoverComponents object calls ComponentDiscovered callbacks.
|
||||||
// In the following implementation we add the found component to the `haComponents` map
|
// In the following implementation we add the found component to the `haComponents` map
|
||||||
|
Loading…
Reference in New Issue
Block a user