From 76315ac83dfb47b64a4b0324055dedc2e7776d87 Mon Sep 17 00:00:00 2001 From: Cody Cutrer Date: Fri, 25 Oct 2024 09:53:35 -0500 Subject: [PATCH] [mqtt.homeassistant] drop support for legacy schema vacuums (#17617) Home Assistant dropped it in 2024.2. See https://github.com/home-assistant/core/pull/107274 Signed-off-by: Cody Cutrer Signed-off-by: Ciprian Pascu --- .../internal/component/Vacuum.java | 205 ++++-------------- .../internal/component/VacuumTests.java | 105 --------- 2 files changed, 41 insertions(+), 269 deletions(-) diff --git a/bundles/org.openhab.binding.mqtt.homeassistant/src/main/java/org/openhab/binding/mqtt/homeassistant/internal/component/Vacuum.java b/bundles/org.openhab.binding.mqtt.homeassistant/src/main/java/org/openhab/binding/mqtt/homeassistant/internal/component/Vacuum.java index 857eb04f2c3..e1de17965ec 100644 --- a/bundles/org.openhab.binding.mqtt.homeassistant/src/main/java/org/openhab/binding/mqtt/homeassistant/internal/component/Vacuum.java +++ b/bundles/org.openhab.binding.mqtt.homeassistant/src/main/java/org/openhab/binding/mqtt/homeassistant/internal/component/Vacuum.java @@ -14,15 +14,11 @@ package org.openhab.binding.mqtt.homeassistant.internal.component; import java.math.BigDecimal; import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; import java.util.List; -import java.util.stream.Collectors; import org.eclipse.jdt.annotation.NonNullByDefault; import org.eclipse.jdt.annotation.Nullable; import org.openhab.binding.mqtt.generic.ChannelStateUpdateListener; -import org.openhab.binding.mqtt.generic.values.OnOffValue; import org.openhab.binding.mqtt.generic.values.PercentageValue; import org.openhab.binding.mqtt.generic.values.TextValue; import org.openhab.binding.mqtt.generic.values.Value; @@ -42,27 +38,17 @@ import com.google.gson.annotations.SerializedName; */ @NonNullByDefault public class Vacuum extends AbstractComponent { - public static final String SCHEMA_LEGACY = "legacy"; - public static final String SCHEMA_STATE = "state"; - - public static final String TRUE = "true"; - public static final String FALSE = "false"; - public static final String OFF = "off"; - - public static final String FEATURE_TURN_ON = "turn_on"; // Begin cleaning - public static final String FEATURE_TURN_OFF = "turn_off"; // Turn the Vacuum off - public static final String FEATURE_RETURN_HOME = "return_home"; // Return to base/dock public static final String FEATURE_START = "start"; - public static final String FEATURE_STOP = "stop"; // Stop the Vacuum - public static final String FEATURE_CLEAN_SPOT = "clean_spot"; // Initialize a spot cleaning cycle - public static final String FEATURE_LOCATE = "locate"; // Locate the vacuum (typically by playing a song) - public static final String FEATURE_PAUSE = "pause"; // Pause the vacuum + public static final String FEATURE_STOP = "stop"; + public static final String FEATURE_PAUSE = "pause"; + public static final String FEATURE_RETURN_HOME = "return_home"; // Return to base/dock public static final String FEATURE_BATTERY = "battery"; public static final String FEATURE_STATUS = "status"; + public static final String FEATURE_LOCATE = "locate"; // Locate the vacuum (typically by playing a song) + public static final String FEATURE_CLEAN_SPOT = "clean_spot"; // Initialize a spot cleaning cycle public static final String FEATURE_FAN_SPEED = "fan_speed"; public static final String FEATURE_SEND_COMMAND = "send_command"; - // State Schema only public static final String STATE_CLEANING = "cleaning"; public static final String STATE_DOCKED = "docked"; public static final String STATE_PAUSED = "paused"; @@ -77,25 +63,12 @@ public class Vacuum extends AbstractComponent { public static final String CUSTOM_COMMAND_CH_ID_DEPRECATED = "customCommand"; public static final String BATTERY_LEVEL_CH_ID = "battery-level"; public static final String BATTERY_LEVEL_CH_ID_DEPRECATED = "batteryLevel"; - public static final String CHARGING_CH_ID = "charging"; - public static final String CLEANING_CH_ID = "cleaning"; - public static final String DOCKED_CH_ID = "docked"; - public static final String ERROR_CH_ID = "error"; public static final String JSON_ATTRIBUTES_CH_ID = "json-attributes"; public static final String JSON_ATTRIBUTES_CH_ID_DEPRECATED = "jsonAttributes"; public static final String STATE_CH_ID = "state"; - public static final List LEGACY_DEFAULT_FEATURES = List.of(FEATURE_TURN_ON, FEATURE_TURN_OFF, FEATURE_STOP, - FEATURE_RETURN_HOME, FEATURE_BATTERY, FEATURE_STATUS, FEATURE_CLEAN_SPOT); - public static final List LEGACY_SUPPORTED_FEATURES = List.of(FEATURE_TURN_ON, FEATURE_TURN_OFF, - FEATURE_PAUSE, FEATURE_STOP, FEATURE_RETURN_HOME, FEATURE_BATTERY, FEATURE_STATUS, FEATURE_LOCATE, - FEATURE_CLEAN_SPOT, FEATURE_FAN_SPEED, FEATURE_SEND_COMMAND); - - public static final List STATE_DEFAULT_FEATURES = List.of(FEATURE_START, FEATURE_STOP, FEATURE_RETURN_HOME, - FEATURE_STATUS, FEATURE_BATTERY, FEATURE_CLEAN_SPOT); - public static final List STATE_SUPPORTED_FEATURES = List.of(FEATURE_START, FEATURE_STOP, FEATURE_PAUSE, - FEATURE_RETURN_HOME, FEATURE_BATTERY, FEATURE_STATUS, FEATURE_LOCATE, FEATURE_CLEAN_SPOT, FEATURE_FAN_SPEED, - FEATURE_SEND_COMMAND); + private static final String STATE_TEMPLATE = "{{ value_json.state }}"; + private static final String OFF = "off"; private static final Logger LOGGER = LoggerFactory.getLogger(Vacuum.class); @@ -107,36 +80,9 @@ public class Vacuum extends AbstractComponent { super("MQTT Vacuum"); } - // Legacy and Common MQTT vacuum configuration section. - - @SerializedName("battery_level_template") - protected @Nullable String batteryLevelTemplate; - @SerializedName("battery_level_topic") - protected @Nullable String batteryLevelTopic; - - @SerializedName("charging_template") - protected @Nullable String chargingTemplate; - @SerializedName("charging_topic") - protected @Nullable String chargingTopic; - - @SerializedName("cleaning_template") - protected @Nullable String cleaningTemplate; - @SerializedName("cleaning_topic") - protected @Nullable String cleaningTopic; - @SerializedName("command_topic") protected @Nullable String commandTopic; - @SerializedName("docked_template") - protected @Nullable String dockedTemplate; - @SerializedName("docked_topic") - protected @Nullable String dockedTopic; - - @SerializedName("error_template") - protected @Nullable String errorTemplate; - @SerializedName("error_topic") - protected @Nullable String errorTopic; - @SerializedName("fan_speed_list") protected @Nullable List fanSpeedList; @SerializedName("fan_speed_template") @@ -145,22 +91,17 @@ public class Vacuum extends AbstractComponent { protected @Nullable String fanSpeedTopic; @SerializedName("payload_clean_spot") - protected @Nullable String payloadCleanSpot = "clean_spot"; + protected String payloadCleanSpot = "clean_spot"; @SerializedName("payload_locate") - protected @Nullable String payloadLocate = "locate"; + protected String payloadLocate = "locate"; + @SerializedName("payload_pause") + protected String payloadPause = "pause"; @SerializedName("payload_return_to_base") - protected @Nullable String payloadReturnToBase = "return_to_base"; - @SerializedName("payload_start_pause") - protected @Nullable String payloadStartPause = "start_pause"; // Legacy only + protected String payloadReturnToBase = "return_to_base"; + @SerializedName("payload_start") + protected String payloadStart = "start"; @SerializedName("payload_stop") - protected @Nullable String payloadStop = "stop"; - @SerializedName("payload_turn_off") - protected @Nullable String payloadTurnOff = "turn_off"; - @SerializedName("payload_turn_on") - protected @Nullable String payloadTurnOn = "turn_on"; - - @SerializedName("schema") - protected Schema schema = Schema.LEGACY; + protected String payloadStop = "stop"; @SerializedName("send_command_topic") protected @Nullable String sendCommandTopic; @@ -169,15 +110,8 @@ public class Vacuum extends AbstractComponent { protected @Nullable String setFanSpeedTopic; @SerializedName("supported_features") - protected @Nullable List supportedFeatures; - - // State MQTT vacuum configuration section. - - // Start/Pause replaced by 2 payloads - @SerializedName("payload_pause") - protected @Nullable String payloadPause = "pause"; - @SerializedName("payload_start") - protected @Nullable String payloadStart = "start"; + protected List supportedFeatures = List.of(FEATURE_START, FEATURE_STOP, FEATURE_RETURN_HOME, + FEATURE_STATUS, FEATURE_BATTERY, FEATURE_CLEAN_SPOT); @SerializedName("state_topic") protected @Nullable String stateTopic; @@ -197,104 +131,55 @@ public class Vacuum extends AbstractComponent { super(componentConfiguration, ChannelConfiguration.class, newStyleChannels); final ChannelStateUpdateListener updateListener = componentConfiguration.getUpdateListener(); - final var allowedSupportedFeatures = channelConfiguration.schema == Schema.LEGACY ? LEGACY_SUPPORTED_FEATURES - : STATE_SUPPORTED_FEATURES; final var supportedFeatures = channelConfiguration.supportedFeatures; - final var configSupportedFeatures = supportedFeatures == null - ? channelConfiguration.schema == Schema.LEGACY ? LEGACY_DEFAULT_FEATURES : STATE_DEFAULT_FEATURES - : supportedFeatures; - List deviceSupportedFeatures = Collections.emptyList(); - - if (!configSupportedFeatures.isEmpty()) { - deviceSupportedFeatures = allowedSupportedFeatures.stream().filter(configSupportedFeatures::contains) - .collect(Collectors.toList()); - } - if (deviceSupportedFeatures.size() != configSupportedFeatures.size()) { - LOGGER.warn("Vacuum discovery config has unsupported or duplicated features. Supported: {}, provided: {}", - Arrays.toString(allowedSupportedFeatures.toArray()), - Arrays.toString(configSupportedFeatures.toArray())); - } final List commands = new ArrayList<>(); - addPayloadToList(deviceSupportedFeatures, FEATURE_CLEAN_SPOT, channelConfiguration.payloadCleanSpot, commands); - addPayloadToList(deviceSupportedFeatures, FEATURE_LOCATE, channelConfiguration.payloadLocate, commands); - addPayloadToList(deviceSupportedFeatures, FEATURE_RETURN_HOME, channelConfiguration.payloadReturnToBase, - commands); - addPayloadToList(deviceSupportedFeatures, FEATURE_STOP, channelConfiguration.payloadStop, commands); - addPayloadToList(deviceSupportedFeatures, FEATURE_TURN_OFF, channelConfiguration.payloadTurnOff, commands); - addPayloadToList(deviceSupportedFeatures, FEATURE_TURN_ON, channelConfiguration.payloadTurnOn, commands); - - if (channelConfiguration.schema == Schema.LEGACY) { - addPayloadToList(deviceSupportedFeatures, FEATURE_PAUSE, channelConfiguration.payloadStartPause, commands); - } else { - addPayloadToList(deviceSupportedFeatures, FEATURE_PAUSE, channelConfiguration.payloadPause, commands); - addPayloadToList(deviceSupportedFeatures, FEATURE_START, channelConfiguration.payloadStart, commands); - } + addPayloadToList(supportedFeatures, FEATURE_CLEAN_SPOT, channelConfiguration.payloadCleanSpot, commands); + addPayloadToList(supportedFeatures, FEATURE_LOCATE, channelConfiguration.payloadLocate, commands); + addPayloadToList(supportedFeatures, FEATURE_RETURN_HOME, channelConfiguration.payloadReturnToBase, commands); + addPayloadToList(supportedFeatures, FEATURE_START, channelConfiguration.payloadStart, commands); + addPayloadToList(supportedFeatures, FEATURE_STOP, channelConfiguration.payloadStop, commands); + addPayloadToList(supportedFeatures, FEATURE_PAUSE, channelConfiguration.payloadPause, commands); buildOptionalChannel(COMMAND_CH_ID, ComponentChannelType.STRING, new TextValue(commands.toArray(new String[0])), updateListener, null, channelConfiguration.commandTopic, null, null); final var fanSpeedList = channelConfiguration.fanSpeedList; - if (deviceSupportedFeatures.contains(FEATURE_FAN_SPEED) && fanSpeedList != null && !fanSpeedList.isEmpty()) { + if (supportedFeatures.contains(FEATURE_FAN_SPEED) && fanSpeedList != null && !fanSpeedList.isEmpty()) { + var fanSpeedCommandList = fanSpeedList.toArray(new String[0]); if (!fanSpeedList.contains(OFF)) { fanSpeedList.add(OFF); // Off value is used when cleaning if OFF } - var fanSpeedValue = new TextValue(fanSpeedList.toArray(new String[0])); - if (channelConfiguration.schema == Schema.LEGACY) { - buildOptionalChannel(newStyleChannels ? FAN_SPEED_CH_ID : FAN_SPEED_CH_ID_DEPRECATED, - ComponentChannelType.STRING, fanSpeedValue, updateListener, null, - channelConfiguration.setFanSpeedTopic, channelConfiguration.fanSpeedTemplate, - channelConfiguration.fanSpeedTopic); - } else if (deviceSupportedFeatures.contains(FEATURE_STATUS)) { + var fanSpeedValue = new TextValue(fanSpeedList.toArray(new String[0]), fanSpeedCommandList); + if (supportedFeatures.contains(FEATURE_STATUS)) { buildOptionalChannel(newStyleChannels ? FAN_SPEED_CH_ID : FAN_SPEED_CH_ID_DEPRECATED, ComponentChannelType.STRING, fanSpeedValue, updateListener, null, channelConfiguration.setFanSpeedTopic, "{{ value_json.fan_speed }}", channelConfiguration.stateTopic); } else { - LOGGER.info("Status feature is disabled, unable to get fan speed."); buildOptionalChannel(newStyleChannels ? FAN_SPEED_CH_ID : FAN_SPEED_CH_ID_DEPRECATED, ComponentChannelType.STRING, fanSpeedValue, updateListener, null, channelConfiguration.setFanSpeedTopic, null, null); } } - if (deviceSupportedFeatures.contains(FEATURE_SEND_COMMAND)) { + if (supportedFeatures.contains(FEATURE_SEND_COMMAND)) { buildOptionalChannel(newStyleChannels ? CUSTOM_COMMAND_CH_ID : CUSTOM_COMMAND_CH_ID_DEPRECATED, ComponentChannelType.STRING, new TextValue(), updateListener, null, channelConfiguration.sendCommandTopic, null, null); } - if (channelConfiguration.schema == Schema.LEGACY) { - // I assume, that if these topics defined in config, then we don't need to check features - buildOptionalChannel(newStyleChannels ? BATTERY_LEVEL_CH_ID : BATTERY_LEVEL_CH_ID_DEPRECATED, - ComponentChannelType.DIMMER, - new PercentageValue(BigDecimal.ZERO, BigDecimal.valueOf(100), BigDecimal.ONE, null, null), - updateListener, null, null, channelConfiguration.batteryLevelTemplate, - channelConfiguration.batteryLevelTopic); - buildOptionalChannel(CHARGING_CH_ID, ComponentChannelType.SWITCH, new OnOffValue(TRUE, FALSE), - updateListener, null, null, channelConfiguration.chargingTemplate, - channelConfiguration.chargingTopic); - buildOptionalChannel(CLEANING_CH_ID, ComponentChannelType.SWITCH, new OnOffValue(TRUE, FALSE), - updateListener, null, null, channelConfiguration.cleaningTemplate, - channelConfiguration.cleaningTopic); - buildOptionalChannel(DOCKED_CH_ID, ComponentChannelType.SWITCH, new OnOffValue(TRUE, FALSE), updateListener, - null, null, channelConfiguration.dockedTemplate, channelConfiguration.dockedTopic); - buildOptionalChannel(ERROR_CH_ID, ComponentChannelType.STRING, new TextValue(), updateListener, null, null, - channelConfiguration.errorTemplate, channelConfiguration.errorTopic); - } else { - if (deviceSupportedFeatures.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, "{{ value_json.state }}", channelConfiguration.stateTopic); - if (deviceSupportedFeatures.contains(FEATURE_BATTERY)) { - buildOptionalChannel(newStyleChannels ? BATTERY_LEVEL_CH_ID : BATTERY_LEVEL_CH_ID_DEPRECATED, - ComponentChannelType.DIMMER, - new PercentageValue(BigDecimal.ZERO, BigDecimal.valueOf(100), BigDecimal.ONE, null, null), - updateListener, null, null, "{{ value_json.battery_level }}", - channelConfiguration.stateTopic); - } + 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); + if (supportedFeatures.contains(FEATURE_BATTERY)) { + buildOptionalChannel(newStyleChannels ? BATTERY_LEVEL_CH_ID : BATTERY_LEVEL_CH_ID_DEPRECATED, + ComponentChannelType.DIMMER, + new PercentageValue(BigDecimal.ZERO, BigDecimal.valueOf(100), BigDecimal.ONE, null, null), + updateListener, null, null, "{{ value_json.battery_level }}", channelConfiguration.stateTopic); } } @@ -318,17 +203,9 @@ public class Vacuum extends AbstractComponent { return null; } - private void addPayloadToList(List supportedFeatures, String feature, @Nullable String payload, - List list) { - if (supportedFeatures.contains(feature) && payload != null && !payload.isEmpty()) { + private void addPayloadToList(List supportedFeatures, String feature, String payload, List list) { + if (supportedFeatures.contains(feature) && !payload.isEmpty()) { list.add(payload); } } - - public enum Schema { - @SerializedName("legacy") - LEGACY, - @SerializedName("state") - STATE - } } diff --git a/bundles/org.openhab.binding.mqtt.homeassistant/src/test/java/org/openhab/binding/mqtt/homeassistant/internal/component/VacuumTests.java b/bundles/org.openhab.binding.mqtt.homeassistant/src/test/java/org/openhab/binding/mqtt/homeassistant/internal/component/VacuumTests.java index 3611ad95ec8..60490f930f6 100644 --- a/bundles/org.openhab.binding.mqtt.homeassistant/src/test/java/org/openhab/binding/mqtt/homeassistant/internal/component/VacuumTests.java +++ b/bundles/org.openhab.binding.mqtt.homeassistant/src/test/java/org/openhab/binding/mqtt/homeassistant/internal/component/VacuumTests.java @@ -19,10 +19,8 @@ import java.util.Set; import org.eclipse.jdt.annotation.NonNullByDefault; import org.junit.jupiter.api.Test; -import org.openhab.binding.mqtt.generic.values.OnOffValue; import org.openhab.binding.mqtt.generic.values.PercentageValue; import org.openhab.binding.mqtt.generic.values.TextValue; -import org.openhab.core.library.types.OnOffType; import org.openhab.core.library.types.PercentType; import org.openhab.core.library.types.StringType; import org.openhab.core.types.UnDefType; @@ -167,109 +165,6 @@ public class VacuumTests extends AbstractComponentTests { assertState(component, Vacuum.JSON_ATTRIBUTES_CH_ID_DEPRECATED, new StringType(jsonValue)); } - @SuppressWarnings("null") - @Test - public void testLegacySchema() { - // @formatter:off - var component = discoverComponent(configTopicToMqtt(CONFIG_TOPIC), """ - {\ - "name":"Rockrobo",\ - "unique_id":"rockrobo_vacuum",\ - "device":{\ - "manufacturer":"Roborock",\ - "model":"v1",\ - "name":"rockrobo",\ - "identifiers":["rockrobo"],\ - "sw_version":"0.9.9"\ - },\ - "supported_features":["turn_on", "turn_off","pause","stop","return_home","battery","status",\ - "locate","clean_spot","fan_speed","send_command"],\ - "command_topic":"vacuum/command",\ - "battery_level_topic":"vacuum/state",\ - "battery_level_template":"{{ value_json.battery_level }}",\ - "charging_topic":"vacuum/state",\ - "charging_template":"{{ value_json.charging }}",\ - "cleaning_topic":"vacuum/state",\ - "cleaning_template":"{{ value_json.cleaning }}",\ - "docked_topic":"vacuum/state",\ - "docked_template":"{{ value_json.docked }}",\ - "error_topic":"vacuum/state",\ - "error_template":"{{ value_json.error }}",\ - "fan_speed_topic":"vacuum/state",\ - "set_fan_speed_topic":"vacuum/set_fan_speed",\ - "fan_speed_template":"{{ value_json.fan_speed }}",\ - "fan_speed_list":["min","medium","high","max"],\ - "send_command_topic":"vacuum/send_command"\ - }\ - """); - // @formatter:on - - assertThat(component.channels.size(), is(8)); // command, battery, charging, cleaning, docked, error, - // fan speed, send command - assertThat(component.getName(), is("Rockrobo")); - assertChannel(component, Vacuum.COMMAND_CH_ID, "", "vacuum/command", "Rockrobo", TextValue.class); - assertChannel(component, Vacuum.BATTERY_LEVEL_CH_ID_DEPRECATED, "vacuum/state", "", "Rockrobo", - PercentageValue.class); - assertChannel(component, Vacuum.CHARGING_CH_ID, "vacuum/state", "", "Rockrobo", OnOffValue.class); - assertChannel(component, Vacuum.CLEANING_CH_ID, "vacuum/state", "", "Rockrobo", OnOffValue.class); - assertChannel(component, Vacuum.DOCKED_CH_ID, "vacuum/state", "", "Rockrobo", OnOffValue.class); - assertChannel(component, Vacuum.ERROR_CH_ID, "vacuum/state", "", "Rockrobo", TextValue.class); - assertChannel(component, Vacuum.FAN_SPEED_CH_ID_DEPRECATED, "vacuum/state", "vacuum/set_fan_speed", "Rockrobo", - TextValue.class); - assertChannel(component, Vacuum.CUSTOM_COMMAND_CH_ID_DEPRECATED, "", "vacuum/send_command", "Rockrobo", - TextValue.class); - - // @formatter:off - publishMessage("vacuum/state", """ - {\ - "battery_level": 61,\ - "docked": true,\ - "cleaning": false,\ - "charging": true,\ - "fan_speed": "off",\ - "error": "Error message"\ - }\ - """); - // @formatter:on - - assertState(component, Vacuum.BATTERY_LEVEL_CH_ID_DEPRECATED, new PercentType(61)); - assertState(component, Vacuum.DOCKED_CH_ID, OnOffType.ON); - assertState(component, Vacuum.CLEANING_CH_ID, OnOffType.OFF); - assertState(component, Vacuum.CHARGING_CH_ID, OnOffType.ON); - assertState(component, Vacuum.FAN_SPEED_CH_ID_DEPRECATED, new StringType("off")); - assertState(component, Vacuum.ERROR_CH_ID, new StringType("Error message")); - - component.getChannel(Vacuum.COMMAND_CH_ID).getState().publishValue(new StringType("turn_on")); - assertPublished("vacuum/command", "turn_on"); - - // @formatter:off - publishMessage("vacuum/state", """ - {\ - "battery_level": 55,\ - "docked": false,\ - "cleaning": true,\ - "charging": false,\ - "fan_speed": "medium",\ - "error": ""\ - }\ - """); - // @formatter:on - - assertState(component, Vacuum.BATTERY_LEVEL_CH_ID_DEPRECATED, new PercentType(55)); - assertState(component, Vacuum.DOCKED_CH_ID, OnOffType.OFF); - assertState(component, Vacuum.CLEANING_CH_ID, OnOffType.ON); - assertState(component, Vacuum.CHARGING_CH_ID, OnOffType.OFF); - assertState(component, Vacuum.FAN_SPEED_CH_ID_DEPRECATED, new StringType("medium")); - assertState(component, Vacuum.ERROR_CH_ID, new StringType("")); - - component.getChannel(Vacuum.FAN_SPEED_CH_ID_DEPRECATED).getState().publishValue(new StringType("high")); - assertPublished("vacuum/set_fan_speed", "high"); - - component.getChannel(Vacuum.CUSTOM_COMMAND_CH_ID_DEPRECATED).getState() - .publishValue(new StringType("custom_command")); - assertPublished("vacuum/send_command", "custom_command"); - } - @Override protected Set getConfigTopics() { return Set.of(CONFIG_TOPIC);