2 * Copyright (c) 2010-2023 Contributors to the openHAB project
4 * See the NOTICE file(s) distributed with this work for additional
7 * This program and the accompanying materials are made available under the
8 * terms of the Eclipse Public License 2.0 which is available at
9 * http://www.eclipse.org/legal/epl-2.0
11 * SPDX-License-Identifier: EPL-2.0
13 package org.openhab.binding.mqtt.homeassistant.internal.component;
15 import static org.hamcrest.CoreMatchers.is;
16 import static org.hamcrest.MatcherAssert.assertThat;
20 import org.eclipse.jdt.annotation.NonNullByDefault;
21 import org.junit.jupiter.api.Test;
22 import org.openhab.binding.mqtt.generic.values.OnOffValue;
23 import org.openhab.binding.mqtt.generic.values.PercentageValue;
24 import org.openhab.binding.mqtt.generic.values.TextValue;
25 import org.openhab.core.library.types.OnOffType;
26 import org.openhab.core.library.types.PercentType;
27 import org.openhab.core.library.types.StringType;
28 import org.openhab.core.types.UnDefType;
31 * Tests for {@link Vacuum}
33 * @author Anton Kharuzhy - Initial contribution
36 public class VacuumTests extends AbstractComponentTests {
37 public static final String CONFIG_TOPIC = "vacuum/rockrobo_vacuum";
39 @SuppressWarnings("null")
41 public void testRoborockValetudo() {
43 var component = discoverComponent(configTopicToMqtt(CONFIG_TOPIC), "{" +
44 "\"name\":\"Rockrobo\"," +
45 "\"unique_id\":\"rockrobo_vacuum\"," +
46 "\"schema\":\"state\"," +
48 " \"manufacturer\":\"Roborock\"," +
49 " \"model\":\"v1\"," +
50 " \"name\":\"rockrobo\"," +
51 " \"identifiers\":[\"rockrobo\"]," +
52 " \"sw_version\":\"0.9.9\"" +
54 "\"supported_features\":[\"start\",\"pause\",\"stop\",\"return_home\",\"battery\",\"status\"," +
55 " \"locate\",\"clean_spot\",\"fan_speed\",\"send_command\"]," +
56 "\"command_topic\":\"valetudo/rockrobo/command\"," +
57 "\"state_topic\":\"valetudo/rockrobo/state\"," +
58 "\"set_fan_speed_topic\":\"valetudo/rockrobo/set_fan_speed\"," +
59 "\"fan_speed_list\":[\"min\",\"medium\",\"high\",\"max\",\"mop\"]," +
60 "\"send_command_topic\":\"valetudo/rockrobo/custom_command\"," +
61 "\"json_attributes_topic\":\"valetudo/rockrobo/attributes\"" +
65 assertThat(component.channels.size(), is(6)); // command, state, fan speed, send command, battery, json attrs
66 assertThat(component.getName(), is("Rockrobo"));
67 assertChannel(component, Vacuum.COMMAND_CH_ID, "", "valetudo/rockrobo/command", "Rockrobo", TextValue.class);
68 assertChannel(component, Vacuum.STATE_CH_ID, "valetudo/rockrobo/state", "", "Rockrobo", TextValue.class);
69 assertChannel(component, Vacuum.FAN_SPEED_CH_ID, "valetudo/rockrobo/state", "valetudo/rockrobo/set_fan_speed",
70 "Rockrobo", TextValue.class);
71 assertChannel(component, Vacuum.CUSTOM_COMMAND_CH_ID, "", "valetudo/rockrobo/custom_command", "Rockrobo",
73 assertChannel(component, Vacuum.BATTERY_LEVEL_CH_ID, "valetudo/rockrobo/state", "", "Rockrobo",
74 PercentageValue.class);
75 assertChannel(component, Vacuum.JSON_ATTRIBUTES_CH_ID, "valetudo/rockrobo/attributes", "", "Rockrobo",
78 assertState(component, Vacuum.STATE_CH_ID, UnDefType.UNDEF);
79 assertState(component, Vacuum.FAN_SPEED_CH_ID, UnDefType.UNDEF);
80 assertState(component, Vacuum.BATTERY_LEVEL_CH_ID, UnDefType.UNDEF);
81 assertState(component, Vacuum.JSON_ATTRIBUTES_CH_ID, UnDefType.UNDEF);
85 publishMessage("valetudo/rockrobo/attributes", jsonValue = "{" +
86 "\"mainBrush\":\"245.1\"," +
87 "\"sideBrush\":\"145.1\"," +
88 "\"filter\":\"95.1\"," +
89 "\"sensor\":\"0.0\"," +
90 "\"currentCleanTime\":\"52.0\"," +
91 "\"currentCleanArea\":\"46.7\"," +
92 "\"cleanTime\":\"54.9\"," +
93 "\"cleanArea\":\"3280.9\"," +
94 "\"cleanCount\":84," +
95 "\"last_run_stats\":{" +
96 " \"startTime\":1633257319000," +
97 " \"endTime\":1633260439000," +
98 " \"duration\":3120," +
99 " \"area\":\"46.7\"," +
100 " \"errorCode\":0," +
101 " \"errorDescription\":\"No error\"," +
102 " \"finishedFlag\":true" +
104 "\"last_bin_out\":2147483647000," +
105 "\"state\":\"docked\"," +
106 "\"valetudo_state\":{" +
108 " \"name\":\"Charging\"" +
110 "\"last_bin_full\":0" +
115 publishMessage("valetudo/rockrobo/state", "{" +
116 "\"state\":\"docked\"," +
117 "\"battery_level\":100," +
118 "\"fan_speed\":\"max\"" +
122 assertState(component, Vacuum.STATE_CH_ID, new StringType(Vacuum.STATE_DOCKED));
123 assertState(component, Vacuum.FAN_SPEED_CH_ID, new StringType("max"));
124 assertState(component, Vacuum.BATTERY_LEVEL_CH_ID, new PercentType(100));
125 assertState(component, Vacuum.JSON_ATTRIBUTES_CH_ID, new StringType(jsonValue));
127 component.getChannel(Vacuum.COMMAND_CH_ID).getState().publishValue(new StringType("start"));
128 assertPublished("valetudo/rockrobo/command", "start");
131 publishMessage("valetudo/rockrobo/state", "{" +
132 "\"state\":\"cleaning\"," +
133 "\"battery_level\":99," +
134 "\"fan_speed\":\"max\"" +
138 assertState(component, Vacuum.STATE_CH_ID, new StringType(Vacuum.STATE_CLEANING));
139 assertState(component, Vacuum.FAN_SPEED_CH_ID, new StringType("max"));
140 assertState(component, Vacuum.BATTERY_LEVEL_CH_ID, new PercentType(99));
141 assertState(component, Vacuum.JSON_ATTRIBUTES_CH_ID, new StringType(jsonValue));
143 component.getChannel(Vacuum.FAN_SPEED_CH_ID).getState().publishValue(new StringType("medium"));
144 assertPublished("valetudo/rockrobo/set_fan_speed", "medium");
147 publishMessage("valetudo/rockrobo/state", "{" +
148 "\"state\":\"returning\"," +
149 "\"battery_level\":80," +
150 "\"fan_speed\":\"medium\"" +
154 assertState(component, Vacuum.STATE_CH_ID, new StringType(Vacuum.STATE_RETURNING));
155 assertState(component, Vacuum.FAN_SPEED_CH_ID, new StringType("medium"));
156 assertState(component, Vacuum.BATTERY_LEVEL_CH_ID, new PercentType(80));
157 assertState(component, Vacuum.JSON_ATTRIBUTES_CH_ID, new StringType(jsonValue));
160 @SuppressWarnings("null")
162 public void testLegacySchema() {
164 var component = discoverComponent(configTopicToMqtt(CONFIG_TOPIC), "{" +
165 "\"name\":\"Rockrobo\"," +
166 "\"unique_id\":\"rockrobo_vacuum\"," +
168 " \"manufacturer\":\"Roborock\"," +
169 " \"model\":\"v1\"," +
170 " \"name\":\"rockrobo\"," +
171 " \"identifiers\":[\"rockrobo\"]," +
172 " \"sw_version\":\"0.9.9\"" +
174 "\"supported_features\":[\"turn_on\", \"turn_off\",\"pause\",\"stop\",\"return_home\",\"battery\",\"status\"," +
175 " \"locate\",\"clean_spot\",\"fan_speed\",\"send_command\"]," +
176 "\"command_topic\":\"vacuum/command\"," +
177 "\"battery_level_topic\":\"vacuum/state\"," +
178 "\"battery_level_template\":\"{{ value_json.battery_level }}\"," +
179 "\"charging_topic\":\"vacuum/state\"," +
180 "\"charging_template\":\"{{ value_json.charging }}\"," +
181 "\"cleaning_topic\":\"vacuum/state\"," +
182 "\"cleaning_template\":\"{{ value_json.cleaning }}\"," +
183 "\"docked_topic\":\"vacuum/state\"," +
184 "\"docked_template\":\"{{ value_json.docked }}\"," +
185 "\"error_topic\":\"vacuum/state\"," +
186 "\"error_template\":\"{{ value_json.error }}\"," +
187 "\"fan_speed_topic\":\"vacuum/state\"," +
188 "\"set_fan_speed_topic\":\"vacuum/set_fan_speed\"," +
189 "\"fan_speed_template\":\"{{ value_json.fan_speed }}\"," +
190 "\"fan_speed_list\":[\"min\",\"medium\",\"high\",\"max\"]," +
191 "\"send_command_topic\":\"vacuum/send_command\"" +
195 assertThat(component.channels.size(), is(8)); // command, battery, charging, cleaning, docked, error,
196 // fan speed, send command
197 assertThat(component.getName(), is("Rockrobo"));
198 assertChannel(component, Vacuum.COMMAND_CH_ID, "", "vacuum/command", "Rockrobo", TextValue.class);
199 assertChannel(component, Vacuum.BATTERY_LEVEL_CH_ID, "vacuum/state", "", "Rockrobo", PercentageValue.class);
200 assertChannel(component, Vacuum.CHARGING_CH_ID, "vacuum/state", "", "Rockrobo", OnOffValue.class);
201 assertChannel(component, Vacuum.CLEANING_CH_ID, "vacuum/state", "", "Rockrobo", OnOffValue.class);
202 assertChannel(component, Vacuum.DOCKED_CH_ID, "vacuum/state", "", "Rockrobo", OnOffValue.class);
203 assertChannel(component, Vacuum.ERROR_CH_ID, "vacuum/state", "", "Rockrobo", TextValue.class);
204 assertChannel(component, Vacuum.FAN_SPEED_CH_ID, "vacuum/state", "vacuum/set_fan_speed", "Rockrobo",
206 assertChannel(component, Vacuum.CUSTOM_COMMAND_CH_ID, "", "vacuum/send_command", "Rockrobo", TextValue.class);
209 publishMessage("vacuum/state", "{" +
210 "\"battery_level\": 61," +
211 "\"docked\": true," +
212 "\"cleaning\": false," +
213 "\"charging\": true," +
214 "\"fan_speed\": \"off\"," +
215 "\"error\": \"Error message\"" +
219 assertState(component, Vacuum.BATTERY_LEVEL_CH_ID, new PercentType(61));
220 assertState(component, Vacuum.DOCKED_CH_ID, OnOffType.ON);
221 assertState(component, Vacuum.CLEANING_CH_ID, OnOffType.OFF);
222 assertState(component, Vacuum.CHARGING_CH_ID, OnOffType.ON);
223 assertState(component, Vacuum.FAN_SPEED_CH_ID, new StringType("off"));
224 assertState(component, Vacuum.ERROR_CH_ID, new StringType("Error message"));
226 component.getChannel(Vacuum.COMMAND_CH_ID).getState().publishValue(new StringType("turn_on"));
227 assertPublished("vacuum/command", "turn_on");
230 publishMessage("vacuum/state", "{" +
231 "\"battery_level\": 55," +
232 "\"docked\": false," +
233 "\"cleaning\": true," +
234 "\"charging\": false," +
235 "\"fan_speed\": \"medium\"," +
240 assertState(component, Vacuum.BATTERY_LEVEL_CH_ID, new PercentType(55));
241 assertState(component, Vacuum.DOCKED_CH_ID, OnOffType.OFF);
242 assertState(component, Vacuum.CLEANING_CH_ID, OnOffType.ON);
243 assertState(component, Vacuum.CHARGING_CH_ID, OnOffType.OFF);
244 assertState(component, Vacuum.FAN_SPEED_CH_ID, new StringType("medium"));
245 assertState(component, Vacuum.ERROR_CH_ID, new StringType(""));
247 component.getChannel(Vacuum.FAN_SPEED_CH_ID).getState().publishValue(new StringType("high"));
248 assertPublished("vacuum/set_fan_speed", "high");
250 component.getChannel(Vacuum.CUSTOM_COMMAND_CH_ID).getState().publishValue(new StringType("custom_command"));
251 assertPublished("vacuum/send_command", "custom_command");
255 protected Set<String> getConfigTopics() {
256 return Set.of(CONFIG_TOPIC);