[mqtt.homeassistant] I18n well known commands and states (#18443)
Signed-off-by: Cody Cutrer <cody@cutrer.us>pull/18450/head
parent
45258e2ec4
commit
1608b202ab
|
@ -15,18 +15,29 @@ package org.openhab.binding.mqtt.generic;
|
|||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.binding.mqtt.generic.internal.MqttThingHandlerFactory;
|
||||
import org.openhab.binding.mqtt.generic.internal.handler.GenericMQTTThingHandler;
|
||||
import org.openhab.core.i18n.I18nUtil;
|
||||
import org.openhab.core.i18n.TranslationProvider;
|
||||
import org.openhab.core.thing.Channel;
|
||||
import org.openhab.core.thing.ChannelUID;
|
||||
import org.openhab.core.thing.type.DynamicCommandDescriptionProvider;
|
||||
import org.openhab.core.thing.type.DynamicStateDescriptionProvider;
|
||||
import org.openhab.core.types.CommandDescription;
|
||||
import org.openhab.core.types.CommandDescriptionBuilder;
|
||||
import org.openhab.core.types.CommandOption;
|
||||
import org.openhab.core.types.StateDescription;
|
||||
import org.openhab.core.types.StateDescriptionFragmentBuilder;
|
||||
import org.openhab.core.types.StateOption;
|
||||
import org.openhab.core.util.BundleResolver;
|
||||
import org.osgi.framework.Bundle;
|
||||
import org.osgi.service.component.annotations.Activate;
|
||||
import org.osgi.service.component.annotations.Component;
|
||||
import org.osgi.service.component.annotations.Reference;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
|
@ -49,6 +60,16 @@ public class MqttChannelStateDescriptionProvider
|
|||
private final Map<ChannelUID, CommandDescription> commandDescriptions = new ConcurrentHashMap<>();
|
||||
private final Logger logger = LoggerFactory.getLogger(MqttChannelStateDescriptionProvider.class);
|
||||
|
||||
private final TranslationProvider i18nProvider;
|
||||
private final BundleResolver bundleResolver;
|
||||
|
||||
@Activate
|
||||
public MqttChannelStateDescriptionProvider(@Reference TranslationProvider i18nProvider,
|
||||
@Reference BundleResolver bundleResolver) {
|
||||
this.i18nProvider = i18nProvider;
|
||||
this.bundleResolver = bundleResolver;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a state description for a channel. This description will be used when preparing the channel state by
|
||||
* the framework for presentation. A previous description, if existed, will be replaced.
|
||||
|
@ -88,6 +109,13 @@ public class MqttChannelStateDescriptionProvider
|
|||
StateDescription description = stateDescriptions.get(channel.getUID());
|
||||
if (description != null) {
|
||||
logger.trace("Providing state description for channel {}", channel.getUID());
|
||||
if (description.getOptions().stream().anyMatch(option -> I18nUtil.isConstant(option.getLabel()))) {
|
||||
StateDescriptionFragmentBuilder builder = StateDescriptionFragmentBuilder.create(description);
|
||||
builder.withOptions(description.getOptions().stream().map(option -> {
|
||||
return new StateOption(option.getValue(), translateLabel(option.getLabel(), locale));
|
||||
}).collect(Collectors.toList()));
|
||||
description = builder.build().toStateDescription();
|
||||
}
|
||||
}
|
||||
return description;
|
||||
}
|
||||
|
@ -96,7 +124,16 @@ public class MqttChannelStateDescriptionProvider
|
|||
public @Nullable CommandDescription getCommandDescription(Channel channel,
|
||||
@Nullable CommandDescription originalCommandDescription, @Nullable Locale locale) {
|
||||
CommandDescription description = commandDescriptions.get(channel.getUID());
|
||||
if (description != null) {
|
||||
logger.trace("Providing command description for channel {}", channel.getUID());
|
||||
if (description.getCommandOptions().stream().anyMatch(option -> I18nUtil.isConstant(option.getLabel()))) {
|
||||
CommandDescriptionBuilder builder = CommandDescriptionBuilder.create();
|
||||
builder.withCommandOptions(description.getCommandOptions().stream().map(option -> {
|
||||
return new CommandOption(option.getCommand(), translateLabel(option.getLabel(), locale));
|
||||
}).collect(Collectors.toList()));
|
||||
description = builder.build();
|
||||
}
|
||||
}
|
||||
return description;
|
||||
}
|
||||
|
||||
|
@ -109,4 +146,20 @@ public class MqttChannelStateDescriptionProvider
|
|||
stateDescriptions.remove(channel);
|
||||
commandDescriptions.remove(channel);
|
||||
}
|
||||
|
||||
private @Nullable String translateLabel(@Nullable String label, @Nullable Locale locale) {
|
||||
if (label == null) {
|
||||
return null;
|
||||
}
|
||||
if (!I18nUtil.isConstant(label)) {
|
||||
return label;
|
||||
}
|
||||
Bundle bundle = bundleResolver.resolveBundle(getClass());
|
||||
|
||||
String translatedLabel = i18nProvider.getText(bundle, I18nUtil.stripConstant(label), null, locale);
|
||||
if (translatedLabel != null) {
|
||||
return translatedLabel;
|
||||
}
|
||||
return label;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -41,9 +41,49 @@ import org.openhab.core.types.UnDefType;
|
|||
public class TextValue extends Value {
|
||||
private final @Nullable Map<String, String> states;
|
||||
private final @Nullable Map<String, String> commands;
|
||||
private final @Nullable Map<String, String> stateLabels;
|
||||
private final @Nullable Map<String, String> commandLabels;
|
||||
|
||||
protected @Nullable String nullValue = null;
|
||||
|
||||
/**
|
||||
* Create a string value with a limited number of allowed states and commands.
|
||||
*
|
||||
* @param states Allowed states. The key is the value that is received from MQTT,
|
||||
* and the value is how matching values will be presented in openHAB.
|
||||
* @param commands Allowed commands. The key is the value that will be received by
|
||||
* openHAB, and the value is how matching commands will be sent to MQTT.
|
||||
* @param stateLabels Labels for the states in the StateDescription. If a state is not found in this map, the state
|
||||
* itself is used as label.
|
||||
* Keys are the openHAB state, not the MQTT state.
|
||||
* @param commandLabels Labels for the commands in the CommandDescription. If a command is not found in this map,
|
||||
* the command itself is used as label.
|
||||
*/
|
||||
public TextValue(Map<String, String> states, Map<String, String> commands, Map<String, String> stateLabels,
|
||||
Map<String, String> commandLabels) {
|
||||
super(CoreItemFactory.STRING, List.of(StringType.class));
|
||||
if (!states.isEmpty()) {
|
||||
this.states = new LinkedHashMap(states);
|
||||
} else {
|
||||
this.states = null;
|
||||
}
|
||||
if (!commands.isEmpty()) {
|
||||
this.commands = new LinkedHashMap(commands);
|
||||
} else {
|
||||
this.commands = null;
|
||||
}
|
||||
if (!stateLabels.isEmpty()) {
|
||||
this.stateLabels = Map.copyOf(stateLabels);
|
||||
} else {
|
||||
this.stateLabels = null;
|
||||
}
|
||||
if (!commandLabels.isEmpty()) {
|
||||
this.commandLabels = Map.copyOf(commandLabels);
|
||||
} else {
|
||||
this.commandLabels = null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a string value with a limited number of allowed states and commands.
|
||||
*
|
||||
|
@ -64,6 +104,8 @@ public class TextValue extends Value {
|
|||
} else {
|
||||
this.commands = null;
|
||||
}
|
||||
this.stateLabels = null;
|
||||
this.commandLabels = null;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -90,6 +132,8 @@ public class TextValue extends Value {
|
|||
} else {
|
||||
this.commands = null;
|
||||
}
|
||||
this.stateLabels = null;
|
||||
this.commandLabels = null;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -106,6 +150,8 @@ public class TextValue extends Value {
|
|||
super(CoreItemFactory.STRING, List.of(StringType.class));
|
||||
this.states = null;
|
||||
this.commands = null;
|
||||
this.stateLabels = null;
|
||||
this.commandLabels = null;
|
||||
}
|
||||
|
||||
public void setNullValue(@Nullable String nullValue) {
|
||||
|
@ -159,7 +205,13 @@ public class TextValue extends Value {
|
|||
StateDescriptionFragmentBuilder builder = super.createStateDescription(readOnly);
|
||||
final Map<String, String> states = this.states;
|
||||
if (states != null) {
|
||||
states.forEach((ohState, mqttState) -> builder.withOption(new StateOption(ohState, ohState)));
|
||||
states.forEach((ohState, mqttState) -> {
|
||||
String label = ohState;
|
||||
if (stateLabels != null) {
|
||||
label = stateLabels.getOrDefault(ohState, ohState);
|
||||
}
|
||||
builder.withOption(new StateOption(ohState, label));
|
||||
});
|
||||
}
|
||||
return builder;
|
||||
}
|
||||
|
@ -170,7 +222,11 @@ public class TextValue extends Value {
|
|||
final Map<String, String> commands = this.commands;
|
||||
if (commands != null) {
|
||||
for (String command : commands.keySet()) {
|
||||
builder.withCommandOption(new CommandOption(command, command));
|
||||
String label = command;
|
||||
if (commandLabels != null) {
|
||||
label = commandLabels.getOrDefault(command, command);
|
||||
}
|
||||
builder.withCommandOption(new CommandOption(command, label));
|
||||
}
|
||||
}
|
||||
return builder;
|
||||
|
|
|
@ -21,6 +21,7 @@ import org.eclipse.jdt.annotation.Nullable;
|
|||
import org.openhab.binding.mqtt.generic.MqttChannelStateDescriptionProvider;
|
||||
import org.openhab.binding.mqtt.generic.MqttChannelTypeProvider;
|
||||
import org.openhab.binding.mqtt.homeassistant.internal.HomeAssistantJinjaFunctionLibrary;
|
||||
import org.openhab.binding.mqtt.homeassistant.internal.HomeAssistantStateDescriptionProvider;
|
||||
import org.openhab.binding.mqtt.homeassistant.internal.handler.HomeAssistantThingHandler;
|
||||
import org.openhab.core.i18n.UnitProvider;
|
||||
import org.openhab.core.thing.Thing;
|
||||
|
@ -55,7 +56,7 @@ public class MqttThingHandlerFactory extends BaseThingHandlerFactory {
|
|||
|
||||
@Activate
|
||||
public MqttThingHandlerFactory(final @Reference MqttChannelTypeProvider typeProvider,
|
||||
final @Reference MqttChannelStateDescriptionProvider stateDescriptionProvider,
|
||||
final @Reference HomeAssistantStateDescriptionProvider stateDescriptionProvider,
|
||||
final @Reference ChannelTypeRegistry channelTypeRegistry, final @Reference UnitProvider unitProvider) {
|
||||
this.typeProvider = typeProvider;
|
||||
this.stateDescriptionProvider = stateDescriptionProvider;
|
||||
|
|
|
@ -0,0 +1,40 @@
|
|||
/*
|
||||
* Copyright (c) 2010-2025 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;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.binding.mqtt.generic.MqttChannelStateDescriptionProvider;
|
||||
import org.openhab.core.i18n.TranslationProvider;
|
||||
import org.openhab.core.thing.type.DynamicCommandDescriptionProvider;
|
||||
import org.openhab.core.thing.type.DynamicStateDescriptionProvider;
|
||||
import org.openhab.core.util.BundleResolver;
|
||||
import org.osgi.service.component.annotations.Activate;
|
||||
import org.osgi.service.component.annotations.Component;
|
||||
import org.osgi.service.component.annotations.Reference;
|
||||
|
||||
/**
|
||||
* This subclass exists solely so that the I18n provider can find the correct bundle
|
||||
* for translations.
|
||||
*
|
||||
* @author Cody Cutrer - Initial contribution
|
||||
*/
|
||||
@Component(service = { DynamicStateDescriptionProvider.class, DynamicCommandDescriptionProvider.class,
|
||||
HomeAssistantStateDescriptionProvider.class })
|
||||
@NonNullByDefault
|
||||
public class HomeAssistantStateDescriptionProvider extends MqttChannelStateDescriptionProvider {
|
||||
@Activate
|
||||
public HomeAssistantStateDescriptionProvider(@Reference TranslationProvider i18nProvider,
|
||||
@Reference BundleResolver bundleResolver) {
|
||||
super(i18nProvider, bundleResolver);
|
||||
}
|
||||
}
|
|
@ -66,6 +66,23 @@ public class AlarmControlPanel extends AbstractComponent<AlarmControlPanel.Chann
|
|||
public static final String STATE_PENDING = "pending";
|
||||
public static final String STATE_TRIGGERED = "triggered";
|
||||
|
||||
private static final Map<String, String> COMMAND_LABELS = Map.of(PAYLOAD_ARM_AWAY,
|
||||
"@text/command.alarm-control-panel.arm-away", PAYLOAD_ARM_HOME,
|
||||
"@text/command.alarm-control-panel.arm-home", PAYLOAD_ARM_NIGHT,
|
||||
"@text/command.alarm-control-panel.arm-night", PAYLOAD_ARM_VACATION,
|
||||
"@text/command.alarm-control-panel.arm-vacation", PAYLOAD_ARM_CUSTOM_BYPASS,
|
||||
"@text/command.alarm-control-panel.arm-custom-bypass", PAYLOAD_DISARM,
|
||||
"@text/command.alarm-control-panel.disarm", PAYLOAD_TRIGGER, "@text/command.alarm-control-panel.trigger");
|
||||
private static final Map<String, String> STATE_LABELS = Map.of(STATE_ARMED_AWAY,
|
||||
"@text/state.alarm-control-panel.armed-away", STATE_ARMED_CUSTOM_BYPASS,
|
||||
"@text/state.alarm-control-panel.armed-custom-bypass", STATE_ARMED_HOME,
|
||||
"@text/state.alarm-control-panel.armed-home", STATE_ARMED_NIGHT,
|
||||
"@text/state.alarm-control-panel.armed-night", STATE_ARMED_VACATION,
|
||||
"@text/state.alarm-control-panel.armed-vacation", STATE_ARMING, "@text/state.alarm-control-panel.arming",
|
||||
STATE_DISARMED, "@text/state.alarm-control-panel.disarmed", STATE_DISARMING,
|
||||
"@text/state.alarm-control-panel.disarming", STATE_PENDING, "@text/state.alarm-control-panel.pending",
|
||||
STATE_TRIGGERED, "@text/state.alarm-control-panel.triggered");
|
||||
|
||||
/**
|
||||
* Configuration class for MQTT component
|
||||
*/
|
||||
|
@ -140,7 +157,7 @@ public class AlarmControlPanel extends AbstractComponent<AlarmControlPanel.Chann
|
|||
commandEnum.put(PAYLOAD_TRIGGER, channelConfiguration.payloadTrigger);
|
||||
}
|
||||
|
||||
TextValue value = new TextValue(stateEnum, commandEnum);
|
||||
TextValue value = new TextValue(stateEnum, commandEnum, STATE_LABELS, COMMAND_LABELS);
|
||||
var builder = buildChannel(STATE_CHANNEL_ID, ComponentChannelType.STRING, value, getName(),
|
||||
componentConfiguration.getUpdateListener())
|
||||
.stateTopic(channelConfiguration.stateTopic, channelConfiguration.getValueTemplate());
|
||||
|
|
|
@ -34,6 +34,8 @@ public class Button extends AbstractComponent<Button.ChannelConfiguration> {
|
|||
|
||||
public static final String PAYLOAD_PRESS = "PRESS";
|
||||
|
||||
private static final Map<String, String> COMMAND_LABELS = Map.of(PAYLOAD_PRESS, "@text/command.button.press");
|
||||
|
||||
/**
|
||||
* Configuration class for MQTT component
|
||||
*/
|
||||
|
@ -54,7 +56,8 @@ public class Button extends AbstractComponent<Button.ChannelConfiguration> {
|
|||
public Button(ComponentFactory.ComponentConfiguration componentConfiguration) {
|
||||
super(componentConfiguration, ChannelConfiguration.class);
|
||||
|
||||
TextValue value = new TextValue(Map.of(), Map.of(PAYLOAD_PRESS, channelConfiguration.payloadPress));
|
||||
TextValue value = new TextValue(Map.of(), Map.of(PAYLOAD_PRESS, channelConfiguration.payloadPress), Map.of(),
|
||||
COMMAND_LABELS);
|
||||
|
||||
buildChannel(BUTTON_CHANNEL_ID, ComponentChannelType.STRING, value, getName(),
|
||||
componentConfiguration.getUpdateListener())
|
||||
|
|
|
@ -13,9 +13,11 @@
|
|||
package org.openhab.binding.mqtt.homeassistant.internal.component;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Arrays;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import javax.measure.quantity.Temperature;
|
||||
|
||||
|
@ -66,6 +68,33 @@ public class Climate extends AbstractComponent<Climate.ChannelConfiguration> {
|
|||
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 String FAN_MODE_AUTO = "auto";
|
||||
private static final String FAN_MODE_LOW = "low";
|
||||
private static final String FAN_MODE_MEDIUM = "medium";
|
||||
private static final String FAN_MODE_HIGH = "high";
|
||||
|
||||
private static final Map<String, String> FAN_MODE_LABELS = Map.of(FAN_MODE_AUTO,
|
||||
"@text/state.climate.fan-mode.auto", FAN_MODE_LOW, "@text/state.climate.fan-mode.low", FAN_MODE_MEDIUM,
|
||||
"@text/state.climate.fan-mode.medium", FAN_MODE_HIGH, "@text/state.climate.fan-mode.high");
|
||||
|
||||
private static final String MODE_AUTO = "auto";
|
||||
private static final String MODE_OFF = "off";
|
||||
private static final String MODE_COOL = "cool";
|
||||
private static final String MODE_HEAT = "heat";
|
||||
private static final String MODE_DRY = "dry";
|
||||
private static final String MODE_FAN_ONLY = "fan_only";
|
||||
|
||||
private static final Map<String, String> MODE_LABELS = Map.of(MODE_AUTO, "@text/state.climate.mode.auto", MODE_OFF,
|
||||
"@text/state.climate.mode.off", MODE_COOL, "@text/state.climate.mode.cool", MODE_HEAT,
|
||||
"@text/state.climate.mode.heat", MODE_DRY, "@text/state.climate.mode.dry", MODE_FAN_ONLY,
|
||||
"@text/state.climate.mode.fan-only");
|
||||
|
||||
private static final String SWING_MODE_ON = "on";
|
||||
private static final String SWING_MODE_OFF = "off";
|
||||
|
||||
private static final Map<String, String> SWING_MODE_LABELS = Map.of(SWING_MODE_ON,
|
||||
"@text/state.climate.swing-mode.on", SWING_MODE_OFF, "@text/state.climate.swing-mode.off");
|
||||
|
||||
/**
|
||||
* Configuration class for MQTT component
|
||||
*/
|
||||
|
@ -114,7 +143,7 @@ public class Climate extends AbstractComponent<Climate.ChannelConfiguration> {
|
|||
@SerializedName("fan_mode_state_topic")
|
||||
protected @Nullable String fanModeStateTopic;
|
||||
@SerializedName("fan_modes")
|
||||
protected List<String> fanModes = Arrays.asList("auto", "low", "medium", "high");
|
||||
protected List<String> fanModes = List.of(FAN_MODE_AUTO, FAN_MODE_LOW, FAN_MODE_MEDIUM, FAN_MODE_HIGH);
|
||||
|
||||
@SerializedName("hold_command_template")
|
||||
protected @Nullable String holdCommandTemplate;
|
||||
|
@ -136,7 +165,7 @@ public class Climate extends AbstractComponent<Climate.ChannelConfiguration> {
|
|||
protected @Nullable String modeStateTemplate;
|
||||
@SerializedName("mode_state_topic")
|
||||
protected @Nullable String modeStateTopic;
|
||||
protected List<String> modes = Arrays.asList("auto", "off", "cool", "heat", "dry", "fan_only");
|
||||
protected List<String> modes = List.of(MODE_AUTO, MODE_OFF, MODE_COOL, MODE_HEAT, MODE_DRY, MODE_FAN_ONLY);
|
||||
|
||||
@SerializedName("preset_mode_command_template")
|
||||
protected @Nullable String presetModeCommandTemplate;
|
||||
|
@ -159,7 +188,7 @@ public class Climate extends AbstractComponent<Climate.ChannelConfiguration> {
|
|||
@SerializedName("swing_state_topic")
|
||||
protected @Nullable String swingStateTopic;
|
||||
@SerializedName("swing_modes")
|
||||
protected List<String> swingModes = Arrays.asList("on", "off");
|
||||
protected List<String> swingModes = List.of(SWING_MODE_ON, SWING_MODE_OFF);
|
||||
|
||||
@SerializedName("target_humidity_command_template")
|
||||
protected @Nullable String targetHumidityCommandTemplate;
|
||||
|
@ -258,8 +287,10 @@ public class Climate extends AbstractComponent<Climate.ChannelConfiguration> {
|
|||
channelConfiguration.currentTemperatureTemplate, channelConfiguration.currentTemperatureTopic,
|
||||
commandFilter);
|
||||
|
||||
Map<String, String> modes = channelConfiguration.fanModes.stream()
|
||||
.collect(Collectors.toMap(m -> m, m -> m, (a, b) -> a, LinkedHashMap::new));
|
||||
buildOptionalChannel(FAN_MODE_CH_ID, ComponentChannelType.STRING,
|
||||
new TextValue(channelConfiguration.fanModes.toArray(new String[0])), updateListener,
|
||||
new TextValue(modes, modes, FAN_MODE_LABELS, FAN_MODE_LABELS), updateListener,
|
||||
channelConfiguration.fanModeCommandTemplate, channelConfiguration.fanModeCommandTopic,
|
||||
channelConfiguration.fanModeStateTemplate, channelConfiguration.fanModeStateTopic, commandFilter);
|
||||
|
||||
|
@ -271,8 +302,10 @@ public class Climate extends AbstractComponent<Climate.ChannelConfiguration> {
|
|||
channelConfiguration.holdStateTemplate, channelConfiguration.holdStateTopic, commandFilter);
|
||||
}
|
||||
|
||||
modes = channelConfiguration.modes.stream()
|
||||
.collect(Collectors.toMap(m -> m, m -> m, (a, b) -> a, LinkedHashMap::new));
|
||||
buildOptionalChannel(MODE_CH_ID, ComponentChannelType.STRING,
|
||||
new TextValue(channelConfiguration.modes.toArray(new String[0])), updateListener,
|
||||
new TextValue(modes, modes, MODE_LABELS, MODE_LABELS), updateListener,
|
||||
channelConfiguration.modeCommandTemplate, channelConfiguration.modeCommandTopic,
|
||||
channelConfiguration.modeStateTemplate, channelConfiguration.modeStateTopic, commandFilter);
|
||||
|
||||
|
@ -281,8 +314,10 @@ public class Climate extends AbstractComponent<Climate.ChannelConfiguration> {
|
|||
channelConfiguration.presetModeCommandTemplate, channelConfiguration.presetModeCommandTopic,
|
||||
channelConfiguration.presetModeStateTemplate, channelConfiguration.presetModeStateTopic, commandFilter);
|
||||
|
||||
modes = channelConfiguration.swingModes.stream()
|
||||
.collect(Collectors.toMap(m -> m, m -> m, (a, b) -> a, LinkedHashMap::new));
|
||||
buildOptionalChannel(SWING_CH_ID, ComponentChannelType.STRING,
|
||||
new TextValue(channelConfiguration.swingModes.toArray(new String[0])), updateListener,
|
||||
new TextValue(modes, modes, SWING_MODE_LABELS, SWING_MODE_LABELS), updateListener,
|
||||
channelConfiguration.swingCommandTemplate, channelConfiguration.swingCommandTopic,
|
||||
channelConfiguration.swingStateTemplate, channelConfiguration.swingStateTopic, commandFilter);
|
||||
|
||||
|
|
|
@ -54,6 +54,10 @@ public class Cover extends AbstractComponent<Cover.ChannelConfiguration> {
|
|||
public static final String STATE_OPENING = "opening";
|
||||
public static final String STATE_STOPPED = "stopped";
|
||||
|
||||
private static final Map<String, String> STATE_LABELS = Map.of(STATE_CLOSED, "@text/state.cover.closed",
|
||||
STATE_CLOSING, "@text/state.cover.closing", STATE_OPEN, "@text/state.cover.open", STATE_OPENING,
|
||||
"@text/state.cover.opening", STATE_STOPPED, "@text/state.cover.stopped");
|
||||
|
||||
/**
|
||||
* Configuration class for MQTT component
|
||||
*/
|
||||
|
@ -121,7 +125,7 @@ public class Cover extends AbstractComponent<Cover.ChannelConfiguration> {
|
|||
states.put(channelConfiguration.stateOpen, STATE_OPEN);
|
||||
states.put(channelConfiguration.stateOpening, STATE_OPENING);
|
||||
states.put(channelConfiguration.stateStopped, STATE_STOPPED);
|
||||
TextValue value = new TextValue(states, Map.of());
|
||||
TextValue value = new TextValue(states, Map.of(), STATE_LABELS, Map.of());
|
||||
buildChannel(STATE_CHANNEL_ID, ComponentChannelType.STRING, value, "State",
|
||||
componentConfiguration.getUpdateListener()).stateTopic(stateTopic).isAdvanced(true).build();
|
||||
}
|
||||
|
|
|
@ -44,12 +44,19 @@ public class Lock extends AbstractComponent<Lock.ChannelConfiguration> {
|
|||
public static final String PAYLOAD_UNLOCK = "UNLOCK";
|
||||
public static final String PAYLOAD_OPEN = "OPEN";
|
||||
|
||||
private static final Map<String, String> COMMAND_LABELS = Map.of(PAYLOAD_LOCK, "@text/command.lock.lock",
|
||||
PAYLOAD_UNLOCK, "@text/command.lock.unlock", PAYLOAD_OPEN, "@text/command.lock.open");
|
||||
|
||||
public static final String STATE_JAMMED = "JAMMED";
|
||||
public static final String STATE_LOCKED = "LOCKED";
|
||||
public static final String STATE_LOCKING = "LOCKING";
|
||||
public static final String STATE_UNLOCKED = "UNLOCKED";
|
||||
public static final String STATE_UNLOCKING = "UNLOCKING";
|
||||
|
||||
private static final Map<String, String> STATE_LABELS = Map.of(STATE_JAMMED, "@text/state.lock.jammed",
|
||||
STATE_LOCKED, "@text/state.lock.locked", STATE_LOCKING, "@text/state.lock.locking", STATE_UNLOCKED,
|
||||
"@text/state.lock.unlocked", STATE_UNLOCKING, "@text/state.lock.unlocking");
|
||||
|
||||
/**
|
||||
* Configuration class for MQTT component
|
||||
*/
|
||||
|
@ -121,7 +128,7 @@ public class Lock extends AbstractComponent<Lock.ChannelConfiguration> {
|
|||
states.put(channelConfiguration.stateLocking, STATE_LOCKING);
|
||||
states.put(channelConfiguration.stateUnlocking, STATE_UNLOCKING);
|
||||
states.put(channelConfiguration.stateJammed, STATE_JAMMED);
|
||||
stateValue = new TextValue(states, commands);
|
||||
stateValue = new TextValue(states, commands, STATE_LABELS, COMMAND_LABELS);
|
||||
|
||||
buildChannel(STATE_CHANNEL_ID, ComponentChannelType.STRING, stateValue, "State",
|
||||
componentConfiguration.getUpdateListener())
|
||||
|
|
|
@ -57,6 +57,11 @@ public class Vacuum extends AbstractComponent<Vacuum.ChannelConfiguration> {
|
|||
public static final String PAYLOAD_START = "start";
|
||||
public static final String PAYLOAD_STOP = "stop";
|
||||
|
||||
private static final Map<String, String> COMMAND_LABELS = Map.of(PAYLOAD_CLEAN_SPOT,
|
||||
"@text/command.vacuum.clean-spot", PAYLOAD_LOCATE, "@text/command.vacuum.locate", PAYLOAD_PAUSE,
|
||||
"@text/command.vacuum.pause", PAYLOAD_RETURN_TO_BASE, "@text/command.vacuum.return-to-base", PAYLOAD_START,
|
||||
"@text/command.vacuum.start", PAYLOAD_STOP, "@text/command.vacuum.stop");
|
||||
|
||||
public static final String STATE_CLEANING = "cleaning";
|
||||
public static final String STATE_DOCKED = "docked";
|
||||
public static final String STATE_PAUSED = "paused";
|
||||
|
@ -64,6 +69,11 @@ public class Vacuum extends AbstractComponent<Vacuum.ChannelConfiguration> {
|
|||
public static final String STATE_RETURNING = "returning";
|
||||
public static final String STATE_ERROR = "error";
|
||||
|
||||
private static final Map<String, String> STATE_LABELS = Map.of(STATE_CLEANING, "@text/state.vacuum.cleaning",
|
||||
STATE_DOCKED, "@text/state.vacuum.docked", STATE_PAUSED, "@text/state.vacuum.paused", STATE_IDLE,
|
||||
"@text/state.vacuum.idle", STATE_RETURNING, "@text/state.vacuum.returning", STATE_ERROR,
|
||||
"@text/state.vacuum.error");
|
||||
|
||||
public static final String COMMAND_CH_ID = "command";
|
||||
public static final String FAN_SPEED_CH_ID = "fan-speed";
|
||||
public static final String CUSTOM_COMMAND_CH_ID = "custom-command";
|
||||
|
@ -143,8 +153,9 @@ public class Vacuum extends AbstractComponent<Vacuum.ChannelConfiguration> {
|
|||
addPayloadToList(supportedFeatures, FEATURE_STOP, PAYLOAD_STOP, channelConfiguration.payloadStop, commands);
|
||||
addPayloadToList(supportedFeatures, FEATURE_PAUSE, PAYLOAD_PAUSE, channelConfiguration.payloadPause, commands);
|
||||
|
||||
buildOptionalChannel(COMMAND_CH_ID, ComponentChannelType.STRING, new TextValue(Map.of(), commands),
|
||||
updateListener, null, channelConfiguration.commandTopic, null, null, "Command");
|
||||
buildOptionalChannel(COMMAND_CH_ID, ComponentChannelType.STRING,
|
||||
new TextValue(Map.of(), commands, Map.of(), COMMAND_LABELS), updateListener, null,
|
||||
channelConfiguration.commandTopic, null, null, "Command");
|
||||
|
||||
final var fanSpeedList = channelConfiguration.fanSpeedList;
|
||||
if (supportedFeatures.contains(FEATURE_FAN_SPEED) && fanSpeedList != null && !fanSpeedList.isEmpty()) {
|
||||
|
@ -170,10 +181,11 @@ public class Vacuum extends AbstractComponent<Vacuum.ChannelConfiguration> {
|
|||
|
||||
if (supportedFeatures.contains(FEATURE_STATUS)) {
|
||||
// state key is mandatory
|
||||
buildOptionalChannel(STATE_CH_ID, ComponentChannelType.STRING,
|
||||
new TextValue(new String[] { STATE_CLEANING, STATE_DOCKED, STATE_PAUSED, STATE_IDLE,
|
||||
STATE_RETURNING, STATE_ERROR }),
|
||||
updateListener, null, null, STATE_TEMPLATE, channelConfiguration.stateTopic, "State");
|
||||
buildOptionalChannel(STATE_CH_ID, ComponentChannelType.STRING, new TextValue(
|
||||
Map.of(STATE_CLEANING, STATE_CLEANING, STATE_DOCKED, STATE_DOCKED, STATE_PAUSED, STATE_PAUSED,
|
||||
STATE_IDLE, STATE_IDLE, STATE_RETURNING, STATE_RETURNING, STATE_ERROR, STATE_ERROR),
|
||||
Map.of(), STATE_LABELS, Map.of()), updateListener, null, null, STATE_TEMPLATE,
|
||||
channelConfiguration.stateTopic, "State");
|
||||
if (supportedFeatures.contains(FEATURE_BATTERY)) {
|
||||
buildOptionalChannel(BATTERY_LEVEL_CH_ID, ComponentChannelType.DIMMER,
|
||||
new PercentageValue(BigDecimal.ZERO, BigDecimal.valueOf(100), BigDecimal.ONE, null, null, null),
|
||||
|
|
|
@ -62,11 +62,18 @@ public class Valve extends AbstractComponent<Valve.ChannelConfiguration> impleme
|
|||
public static final String PAYLOAD_CLOSE = "CLOSE";
|
||||
public static final String PAYLOAD_STOP = "STOP";
|
||||
|
||||
private static final Map<String, String> COMMAND_LABELS = Map.of(PAYLOAD_OPEN, "@text/command.valve.open",
|
||||
PAYLOAD_CLOSE, "@text/command.valve.close", PAYLOAD_STOP, "@text/command.valve.stop");
|
||||
|
||||
public static final String STATE_OPEN = "open";
|
||||
public static final String STATE_OPENING = "opening";
|
||||
public static final String STATE_CLOSED = "closed";
|
||||
public static final String STATE_CLOSING = "closing";
|
||||
|
||||
private static final Map<String, String> STATE_LABELS = Map.of(STATE_OPEN, "@text/state.valve.open", STATE_OPENING,
|
||||
"@text/state.valve.opening", STATE_CLOSED, "@text/state.valve.closed", STATE_CLOSING,
|
||||
"@text/state.valve.closing");
|
||||
|
||||
private static final String FORMAT_INTEGER = "%.0f";
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(Valve.class);
|
||||
|
|
|
@ -14,7 +14,9 @@ package org.openhab.binding.mqtt.homeassistant.internal.component;
|
|||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import javax.measure.quantity.Temperature;
|
||||
|
@ -55,6 +57,12 @@ public class WaterHeater extends AbstractComponent<WaterHeater.ChannelConfigurat
|
|||
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);
|
||||
|
||||
private static final Map<String, String> MODE_LABELS = Map.of(MODE_OFF, "@text/state.water-heater.mode.off",
|
||||
MODE_ECO, "@text/state.water-heater.mode.eco", MODE_ELECTRIC, "@text/state.water-heater.mode.electric",
|
||||
MODE_GAS, "@text/state.water-heater.mode.gas", MODE_HEAT_PUMP, "@text/state.water-heater.mode.heat-pump",
|
||||
MODE_HIGH_DEMAND, "@text/state.water-heater.mode.high-demand", MODE_PERFORMANCE,
|
||||
"@text/state.water-heater.mode.performance");
|
||||
|
||||
public static final String TEMPERATURE_UNIT_C = "C";
|
||||
public static final String TEMPERATURE_UNIT_F = "F";
|
||||
|
||||
|
@ -153,8 +161,10 @@ public class WaterHeater extends AbstractComponent<WaterHeater.ChannelConfigurat
|
|||
}
|
||||
|
||||
if (channelConfiguration.modeCommandTopic != null | channelConfiguration.modeStateTopic != null) {
|
||||
Map<String, String> modes = channelConfiguration.modes.stream()
|
||||
.collect(Collectors.toMap(m -> m, m -> m, (a, b) -> a, LinkedHashMap::new));
|
||||
buildChannel(MODE_CHANNEL_ID, ComponentChannelType.STRING,
|
||||
new TextValue(channelConfiguration.modes.toArray(new String[0])), "Mode",
|
||||
new TextValue(modes, modes, MODE_LABELS, MODE_LABELS), "Mode",
|
||||
componentConfiguration.getUpdateListener())
|
||||
.stateTopic(channelConfiguration.modeStateTopic, channelConfiguration.modeStateTemplate,
|
||||
channelConfiguration.getValueTemplate())
|
||||
|
|
|
@ -58,3 +58,74 @@ thing-type.config.mqtt.homeassistant-updatable.doUpdate.description = Request th
|
|||
|
||||
binding.config.mqtt.homeassistant-status.label = Publish Online Status
|
||||
binding.config.mqtt.homeassistant-status.description = Publish <tt>online</tt> to <tt>homeassistant/status</tt> when discovering Home Assistant things in order to trigger devices to publish up-to-date discovery information. If you also run Home Assistant <i>and</i> other services that depend on knowing if Home Assistant is not running, then it's possible for those services to be out-of-sync with the actual status of Home Assistant, and you may want to disable this.
|
||||
|
||||
# command and state labels
|
||||
|
||||
command.alarm-control-panel.arm-away = Arm Away
|
||||
command.alarm-control-panel.arm-home = Arm Home
|
||||
command.alarm-control-panel.arm-night = Arm Night
|
||||
command.alarm-control-panel.arm-vacation = Arm Vacation
|
||||
command.alarm-control-panel.custom-bypass = Custom Bypass
|
||||
command.alarm-control-panel.disarm = Disarm
|
||||
command.alarm-control-panel.trigger = Trigger
|
||||
command.button.press = Press
|
||||
command.lock.lock = Lock
|
||||
command.lock.unlock = Unlock
|
||||
command.lock.open = Open
|
||||
command.vacuum.clean-spot = Clean Spot
|
||||
command.vacuum.locate = Locate
|
||||
command.vacuum.pause = Pause
|
||||
command.vacuum.return-to-base = Return to Base
|
||||
command.vacuum.start = Start
|
||||
command.vacuum.stop = Stop
|
||||
command.valve.open = Open
|
||||
command.valve.close = Close
|
||||
command.valve.stop = Stop
|
||||
state.alarm-control-panel.armed-away = Armed Away
|
||||
state.alarm-control-panel.armed-custom-bypass = Armed Custom Bypass
|
||||
state.alarm-control-panel.armed-home = Armed Home
|
||||
state.alarm-control-panel.armed-night = Armed Night
|
||||
state.alarm-control-panel.armed-vacation = Armed Vacation
|
||||
state.alarm-control-panel.arming = Arming
|
||||
state.alarm-control-panel.disarmed = Disarmed
|
||||
state.alarm-control-panel.pending = Pending
|
||||
state.alarm-control-panel.triggered = Triggered
|
||||
state.climate.fan-mode.auto = Auto
|
||||
state.climate.fan-mode.low = Low
|
||||
state.climate.fan-mode.medium = Medium
|
||||
state.climate.fan-mode.high = High
|
||||
state.climate.mode.auto = Auto
|
||||
state.climate.mode.off = Off
|
||||
state.climate.mode.cool = Cool
|
||||
state.climate.mode.heat = Heat
|
||||
state.climate.mode.dry = Dry
|
||||
state.climate.mode.fan_only = Fan Only
|
||||
state.climate.swing-mode.on = On
|
||||
state.climate.swing-mode.off = Off
|
||||
state.cover.closed = Closed
|
||||
state.cover.closing = Closing
|
||||
state.cover.open = Open
|
||||
state.cover.opening = Opening
|
||||
state.cover.stopped = Stopped
|
||||
state.lock.jammed = Jammed
|
||||
state.lock.locked = Locked
|
||||
state.lock.locking = Locking
|
||||
state.lock.unlocked = Unlocked
|
||||
state.lock.unlocking = Unlocking
|
||||
state.vacuum.cleaning = Cleaning
|
||||
state.vacuum.docked = Docked
|
||||
state.vacuum.paused = Paused
|
||||
state.vacuum.idle = Idle
|
||||
state.vacuum.returning = Returning
|
||||
state.vacuum.error = Error
|
||||
state.valve.open = Open
|
||||
state.valve.opening = Opening
|
||||
state.valve.closed = Closed
|
||||
state.valve.closing = Closing
|
||||
state.water-heater.mode.off = Off
|
||||
state.water-heater.mode.eco = Eco
|
||||
state.water-heater.mode.electric = Electric
|
||||
state.water-heater.mode.gas = Gas
|
||||
state.water-heater.mode.heat-pump = Heat Pump
|
||||
state.water-heater.mode.high-demand = High Demand
|
||||
state.water-heater.mode.performance = Performance
|
||||
|
|
|
@ -39,6 +39,7 @@ import org.openhab.binding.mqtt.generic.MqttChannelStateDescriptionProvider;
|
|||
import org.openhab.binding.mqtt.generic.MqttChannelTypeProvider;
|
||||
import org.openhab.binding.mqtt.handler.BrokerHandler;
|
||||
import org.openhab.binding.mqtt.homeassistant.generic.internal.MqttBindingConstants;
|
||||
import org.openhab.core.i18n.TranslationProvider;
|
||||
import org.openhab.core.io.transport.mqtt.MqttBrokerConnection;
|
||||
import org.openhab.core.io.transport.mqtt.MqttMessageSubscriber;
|
||||
import org.openhab.core.test.java.JavaTest;
|
||||
|
@ -58,6 +59,7 @@ import org.openhab.core.thing.type.ThingTypeBuilder;
|
|||
import org.openhab.core.thing.type.ThingTypeRegistry;
|
||||
import org.openhab.core.transform.TransformationHelper;
|
||||
import org.openhab.core.transform.TransformationService;
|
||||
import org.openhab.core.util.BundleResolver;
|
||||
import org.osgi.framework.BundleContext;
|
||||
import org.osgi.framework.ServiceReference;
|
||||
|
||||
|
@ -100,6 +102,8 @@ public abstract class AbstractHomeAssistantTests extends JavaTest {
|
|||
private @Mock @NonNullByDefault({}) TransformationService transformationService1Mock;
|
||||
|
||||
private @Mock @NonNullByDefault({}) BundleContext bundleContextMock;
|
||||
private @Mock @NonNullByDefault({}) TranslationProvider translationProvider;
|
||||
private @Mock @NonNullByDefault({}) BundleResolver bundleResolver;
|
||||
private @Mock @NonNullByDefault({}) ServiceReference<TransformationService> serviceRefMock;
|
||||
|
||||
private @NonNullByDefault({}) TransformationHelper transformationHelper;
|
||||
|
@ -114,7 +118,7 @@ public abstract class AbstractHomeAssistantTests extends JavaTest {
|
|||
when(thingTypeRegistry.getThingType(MqttBindingConstants.HOMEASSISTANT_MQTT_THING)).thenReturn(HA_THING_TYPE);
|
||||
|
||||
channelTypeProvider = spy(new MqttChannelTypeProvider(thingTypeRegistry, new VolatileStorageService()));
|
||||
stateDescriptionProvider = spy(new MqttChannelStateDescriptionProvider());
|
||||
stateDescriptionProvider = spy(new MqttChannelStateDescriptionProvider(translationProvider, bundleResolver));
|
||||
channelTypeRegistry = spy(new ChannelTypeRegistry());
|
||||
|
||||
setupConnection();
|
||||
|
|
|
@ -28,14 +28,15 @@ import org.mockito.Mockito;
|
|||
import org.mockito.junit.jupiter.MockitoExtension;
|
||||
import org.mockito.junit.jupiter.MockitoSettings;
|
||||
import org.mockito.quality.Strictness;
|
||||
import org.openhab.binding.mqtt.generic.MqttChannelStateDescriptionProvider;
|
||||
import org.openhab.binding.mqtt.generic.MqttChannelTypeProvider;
|
||||
import org.openhab.binding.mqtt.homeassistant.generic.internal.MqttThingHandlerFactory;
|
||||
import org.openhab.binding.mqtt.homeassistant.internal.component.AbstractComponent;
|
||||
import org.openhab.core.i18n.TranslationProvider;
|
||||
import org.openhab.core.i18n.UnitProvider;
|
||||
import org.openhab.core.test.storage.VolatileStorageService;
|
||||
import org.openhab.core.thing.type.ChannelTypeRegistry;
|
||||
import org.openhab.core.thing.type.ThingTypeRegistry;
|
||||
import org.openhab.core.util.BundleResolver;
|
||||
|
||||
/**
|
||||
* @author Jochen Klein - Initial contribution
|
||||
|
@ -48,12 +49,15 @@ public class HomeAssistantChannelTransformationTests {
|
|||
protected @Mock @NonNullByDefault({}) UnitProvider unitProvider;
|
||||
|
||||
protected @NonNullByDefault({}) HomeAssistantChannelTransformation transformation;
|
||||
private @Mock @NonNullByDefault({}) BundleResolver bundleResolver;
|
||||
private @Mock @NonNullByDefault({}) TranslationProvider translationProvider;
|
||||
|
||||
@BeforeEach
|
||||
public void beforeEachChannelTransformationTest() {
|
||||
MqttChannelTypeProvider channelTypeProvider = new MqttChannelTypeProvider(thingTypeRegistry,
|
||||
new VolatileStorageService());
|
||||
MqttChannelStateDescriptionProvider stateDescriptionProvider = new MqttChannelStateDescriptionProvider();
|
||||
HomeAssistantStateDescriptionProvider stateDescriptionProvider = new HomeAssistantStateDescriptionProvider(
|
||||
translationProvider, bundleResolver);
|
||||
ChannelTypeRegistry channelTypeRegistry = new ChannelTypeRegistry();
|
||||
MqttThingHandlerFactory thingHandlerFactory = new MqttThingHandlerFactory(channelTypeProvider,
|
||||
stateDescriptionProvider, channelTypeRegistry, unitProvider);
|
||||
|
|
|
@ -60,6 +60,7 @@ import org.openhab.binding.mqtt.homie.internal.homie300.Property;
|
|||
import org.openhab.binding.mqtt.homie.internal.homie300.PropertyAttributes;
|
||||
import org.openhab.binding.mqtt.homie.internal.homie300.PropertyAttributes.DataTypeEnum;
|
||||
import org.openhab.core.config.core.Configuration;
|
||||
import org.openhab.core.i18n.TranslationProvider;
|
||||
import org.openhab.core.io.transport.mqtt.MqttBrokerConnection;
|
||||
import org.openhab.core.library.types.StringType;
|
||||
import org.openhab.core.test.storage.VolatileStorageService;
|
||||
|
@ -77,6 +78,7 @@ import org.openhab.core.thing.type.ChannelTypeRegistry;
|
|||
import org.openhab.core.thing.type.ThingTypeBuilder;
|
||||
import org.openhab.core.thing.type.ThingTypeRegistry;
|
||||
import org.openhab.core.types.RefreshType;
|
||||
import org.openhab.core.util.BundleResolver;
|
||||
|
||||
/**
|
||||
* Tests cases for {@link HomieThingHandler}.
|
||||
|
@ -96,13 +98,16 @@ public class HomieThingHandlerTests {
|
|||
private @Mock @NonNullByDefault({}) ThingTypeRegistry thingTypeRegistryMock;
|
||||
private @Mock @NonNullByDefault({}) ChannelTypeRegistry channelTypeRegistryMock;
|
||||
private @Mock @NonNullByDefault({}) ChannelType channelTypeMock;
|
||||
private @Mock @NonNullByDefault({}) BundleResolver bundleResolver;
|
||||
private @Mock @NonNullByDefault({}) TranslationProvider translationProvider;
|
||||
|
||||
private @NonNullByDefault({}) Thing thing;
|
||||
private @NonNullByDefault({}) HomieThingHandler thingHandler;
|
||||
|
||||
private final MqttChannelTypeProvider channelTypeProvider = spy(
|
||||
new MqttChannelTypeProvider(thingTypeRegistryMock, new VolatileStorageService()));
|
||||
private final MqttChannelStateDescriptionProvider stateDescriptionProvider = new MqttChannelStateDescriptionProvider();
|
||||
private final MqttChannelStateDescriptionProvider stateDescriptionProvider = new MqttChannelStateDescriptionProvider(
|
||||
translationProvider, bundleResolver);
|
||||
|
||||
private final String deviceID = ThingChannelConstants.TEST_HOMIE_THING.getId();
|
||||
private final String deviceTopic = "homie/" + deviceID;
|
||||
|
|
Loading…
Reference in New Issue