2 * Copyright (c) 2010-2022 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.junit.jupiter.api.Test;
21 import org.openhab.binding.mqtt.generic.values.OnOffValue;
22 import org.openhab.binding.mqtt.generic.values.PercentageValue;
23 import org.openhab.binding.mqtt.generic.values.TextValue;
24 import org.openhab.core.library.types.OnOffType;
25 import org.openhab.core.library.types.PercentType;
26 import org.openhab.core.library.types.StringType;
27 import org.openhab.core.types.UnDefType;
30 * Tests for {@link Vacuum}
32 * @author Anton Kharuzhy - Initial contribution
34 @SuppressWarnings("ConstantConditions")
35 public class VacuumTests extends AbstractComponentTests {
36 public static final String CONFIG_TOPIC = "vacuum/rockrobo_vacuum";
39 public void testRoborockValetudo() {
41 var component = discoverComponent(configTopicToMqtt(CONFIG_TOPIC), "{" +
42 "\"name\":\"Rockrobo\"," +
43 "\"unique_id\":\"rockrobo_vacuum\"," +
44 "\"schema\":\"state\"," +
46 " \"manufacturer\":\"Roborock\"," +
47 " \"model\":\"v1\"," +
48 " \"name\":\"rockrobo\"," +
49 " \"identifiers\":[\"rockrobo\"]," +
50 " \"sw_version\":\"0.9.9\"" +
52 "\"supported_features\":[\"start\",\"pause\",\"stop\",\"return_home\",\"battery\",\"status\"," +
53 " \"locate\",\"clean_spot\",\"fan_speed\",\"send_command\"]," +
54 "\"command_topic\":\"valetudo/rockrobo/command\"," +
55 "\"state_topic\":\"valetudo/rockrobo/state\"," +
56 "\"set_fan_speed_topic\":\"valetudo/rockrobo/set_fan_speed\"," +
57 "\"fan_speed_list\":[\"min\",\"medium\",\"high\",\"max\",\"mop\"]," +
58 "\"send_command_topic\":\"valetudo/rockrobo/custom_command\"," +
59 "\"json_attributes_topic\":\"valetudo/rockrobo/attributes\"" +
63 assertThat(component.channels.size(), is(6)); // command, state, fan speed, send command, battery, json attrs
64 assertThat(component.getName(), is("Rockrobo"));
65 assertChannel(component, Vacuum.COMMAND_CH_ID, "", "valetudo/rockrobo/command", "Rockrobo", TextValue.class);
66 assertChannel(component, Vacuum.STATE_CH_ID, "valetudo/rockrobo/state", "", "Rockrobo", TextValue.class);
67 assertChannel(component, Vacuum.FAN_SPEED_CH_ID, "valetudo/rockrobo/state", "valetudo/rockrobo/set_fan_speed",
68 "Rockrobo", TextValue.class);
69 assertChannel(component, Vacuum.CUSTOM_COMMAND_CH_ID, "", "valetudo/rockrobo/custom_command", "Rockrobo",
71 assertChannel(component, Vacuum.BATTERY_LEVEL_CH_ID, "valetudo/rockrobo/state", "", "Rockrobo",
72 PercentageValue.class);
73 assertChannel(component, Vacuum.JSON_ATTRIBUTES_CH_ID, "valetudo/rockrobo/attributes", "", "Rockrobo",
76 assertState(component, Vacuum.STATE_CH_ID, UnDefType.UNDEF);
77 assertState(component, Vacuum.FAN_SPEED_CH_ID, UnDefType.UNDEF);
78 assertState(component, Vacuum.BATTERY_LEVEL_CH_ID, UnDefType.UNDEF);
79 assertState(component, Vacuum.JSON_ATTRIBUTES_CH_ID, UnDefType.UNDEF);
83 publishMessage("valetudo/rockrobo/attributes", jsonValue = "{" +
84 "\"mainBrush\":\"245.1\"," +
85 "\"sideBrush\":\"145.1\"," +
86 "\"filter\":\"95.1\"," +
87 "\"sensor\":\"0.0\"," +
88 "\"currentCleanTime\":\"52.0\"," +
89 "\"currentCleanArea\":\"46.7\"," +
90 "\"cleanTime\":\"54.9\"," +
91 "\"cleanArea\":\"3280.9\"," +
92 "\"cleanCount\":84," +
93 "\"last_run_stats\":{" +
94 " \"startTime\":1633257319000," +
95 " \"endTime\":1633260439000," +
96 " \"duration\":3120," +
97 " \"area\":\"46.7\"," +
99 " \"errorDescription\":\"No error\"," +
100 " \"finishedFlag\":true" +
102 "\"last_bin_out\":2147483647000," +
103 "\"state\":\"docked\"," +
104 "\"valetudo_state\":{" +
106 " \"name\":\"Charging\"" +
108 "\"last_bin_full\":0" +
113 publishMessage("valetudo/rockrobo/state", "{" +
114 "\"state\":\"docked\"," +
115 "\"battery_level\":100," +
116 "\"fan_speed\":\"max\"" +
120 assertState(component, Vacuum.STATE_CH_ID, new StringType(Vacuum.STATE_DOCKED));
121 assertState(component, Vacuum.FAN_SPEED_CH_ID, new StringType("max"));
122 assertState(component, Vacuum.BATTERY_LEVEL_CH_ID, new PercentType(100));
123 assertState(component, Vacuum.JSON_ATTRIBUTES_CH_ID, new StringType(jsonValue));
125 component.getChannel(Vacuum.COMMAND_CH_ID).getState().publishValue(new StringType("start"));
126 assertPublished("valetudo/rockrobo/command", "start");
129 publishMessage("valetudo/rockrobo/state", "{" +
130 "\"state\":\"cleaning\"," +
131 "\"battery_level\":99," +
132 "\"fan_speed\":\"max\"" +
136 assertState(component, Vacuum.STATE_CH_ID, new StringType(Vacuum.STATE_CLEANING));
137 assertState(component, Vacuum.FAN_SPEED_CH_ID, new StringType("max"));
138 assertState(component, Vacuum.BATTERY_LEVEL_CH_ID, new PercentType(99));
139 assertState(component, Vacuum.JSON_ATTRIBUTES_CH_ID, new StringType(jsonValue));
141 component.getChannel(Vacuum.FAN_SPEED_CH_ID).getState().publishValue(new StringType("medium"));
142 assertPublished("valetudo/rockrobo/set_fan_speed", "medium");
145 publishMessage("valetudo/rockrobo/state", "{" +
146 "\"state\":\"returning\"," +
147 "\"battery_level\":80," +
148 "\"fan_speed\":\"medium\"" +
152 assertState(component, Vacuum.STATE_CH_ID, new StringType(Vacuum.STATE_RETURNING));
153 assertState(component, Vacuum.FAN_SPEED_CH_ID, new StringType("medium"));
154 assertState(component, Vacuum.BATTERY_LEVEL_CH_ID, new PercentType(80));
155 assertState(component, Vacuum.JSON_ATTRIBUTES_CH_ID, new StringType(jsonValue));
159 public void testLegacySchema() {
161 var component = discoverComponent(configTopicToMqtt(CONFIG_TOPIC), "{" +
162 "\"name\":\"Rockrobo\"," +
163 "\"unique_id\":\"rockrobo_vacuum\"," +
165 " \"manufacturer\":\"Roborock\"," +
166 " \"model\":\"v1\"," +
167 " \"name\":\"rockrobo\"," +
168 " \"identifiers\":[\"rockrobo\"]," +
169 " \"sw_version\":\"0.9.9\"" +
171 "\"supported_features\":[\"turn_on\", \"turn_off\",\"pause\",\"stop\",\"return_home\",\"battery\",\"status\"," +
172 " \"locate\",\"clean_spot\",\"fan_speed\",\"send_command\"]," +
173 "\"command_topic\":\"vacuum/command\"," +
174 "\"battery_level_topic\":\"vacuum/state\"," +
175 "\"battery_level_template\":\"{{ value_json.battery_level }}\"," +
176 "\"charging_topic\":\"vacuum/state\"," +
177 "\"charging_template\":\"{{ value_json.charging }}\"," +
178 "\"cleaning_topic\":\"vacuum/state\"," +
179 "\"cleaning_template\":\"{{ value_json.cleaning }}\"," +
180 "\"docked_topic\":\"vacuum/state\"," +
181 "\"docked_template\":\"{{ value_json.docked }}\"," +
182 "\"error_topic\":\"vacuum/state\"," +
183 "\"error_template\":\"{{ value_json.error }}\"," +
184 "\"fan_speed_topic\":\"vacuum/state\"," +
185 "\"set_fan_speed_topic\":\"vacuum/set_fan_speed\"," +
186 "\"fan_speed_template\":\"{{ value_json.fan_speed }}\"," +
187 "\"fan_speed_list\":[\"min\",\"medium\",\"high\",\"max\"]," +
188 "\"send_command_topic\":\"vacuum/send_command\"" +
192 assertThat(component.channels.size(), is(8)); // command, battery, charging, cleaning, docked, error,
193 // fan speed, send command
194 assertThat(component.getName(), is("Rockrobo"));
195 assertChannel(component, Vacuum.COMMAND_CH_ID, "", "vacuum/command", "Rockrobo", TextValue.class);
196 assertChannel(component, Vacuum.BATTERY_LEVEL_CH_ID, "vacuum/state", "", "Rockrobo", PercentageValue.class);
197 assertChannel(component, Vacuum.CHARGING_CH_ID, "vacuum/state", "", "Rockrobo", OnOffValue.class);
198 assertChannel(component, Vacuum.CLEANING_CH_ID, "vacuum/state", "", "Rockrobo", OnOffValue.class);
199 assertChannel(component, Vacuum.DOCKED_CH_ID, "vacuum/state", "", "Rockrobo", OnOffValue.class);
200 assertChannel(component, Vacuum.ERROR_CH_ID, "vacuum/state", "", "Rockrobo", TextValue.class);
201 assertChannel(component, Vacuum.FAN_SPEED_CH_ID, "vacuum/state", "vacuum/set_fan_speed", "Rockrobo",
203 assertChannel(component, Vacuum.CUSTOM_COMMAND_CH_ID, "", "vacuum/send_command", "Rockrobo", TextValue.class);
206 publishMessage("vacuum/state", "{" +
207 "\"battery_level\": 61," +
208 "\"docked\": true," +
209 "\"cleaning\": false," +
210 "\"charging\": true," +
211 "\"fan_speed\": \"off\"," +
212 "\"error\": \"Error message\"" +
216 assertState(component, Vacuum.BATTERY_LEVEL_CH_ID, new PercentType(61));
217 assertState(component, Vacuum.DOCKED_CH_ID, OnOffType.ON);
218 assertState(component, Vacuum.CLEANING_CH_ID, OnOffType.OFF);
219 assertState(component, Vacuum.CHARGING_CH_ID, OnOffType.ON);
220 assertState(component, Vacuum.FAN_SPEED_CH_ID, new StringType("off"));
221 assertState(component, Vacuum.ERROR_CH_ID, new StringType("Error message"));
223 component.getChannel(Vacuum.COMMAND_CH_ID).getState().publishValue(new StringType("turn_on"));
224 assertPublished("vacuum/command", "turn_on");
227 publishMessage("vacuum/state", "{" +
228 "\"battery_level\": 55," +
229 "\"docked\": false," +
230 "\"cleaning\": true," +
231 "\"charging\": false," +
232 "\"fan_speed\": \"medium\"," +
237 assertState(component, Vacuum.BATTERY_LEVEL_CH_ID, new PercentType(55));
238 assertState(component, Vacuum.DOCKED_CH_ID, OnOffType.OFF);
239 assertState(component, Vacuum.CLEANING_CH_ID, OnOffType.ON);
240 assertState(component, Vacuum.CHARGING_CH_ID, OnOffType.OFF);
241 assertState(component, Vacuum.FAN_SPEED_CH_ID, new StringType("medium"));
242 assertState(component, Vacuum.ERROR_CH_ID, new StringType(""));
244 component.getChannel(Vacuum.FAN_SPEED_CH_ID).getState().publishValue(new StringType("high"));
245 assertPublished("vacuum/set_fan_speed", "high");
247 component.getChannel(Vacuum.CUSTOM_COMMAND_CH_ID).getState().publishValue(new StringType("custom_command"));
248 assertPublished("vacuum/send_command", "custom_command");
251 protected Set<String> getConfigTopics() {
252 return Set.of(CONFIG_TOPIC);