Skip to content

Commit 00aa991

Browse files
bruesteldarkscout
authored andcommitted
[homeconnect] Add cleaning robot support (openhab#20733)
- Introduce cleaning robot thing type with automatic device type detection (Roxxter vs. Spotless series) based on available programs. Signed-off-by: Jonas Brüstel <openhab@bruestel.net>
1 parent 0940aa0 commit 00aa991

9 files changed

Lines changed: 779 additions & 75 deletions

File tree

bundles/org.openhab.binding.homeconnect/README.md

Lines changed: 98 additions & 70 deletions
Large diffs are not rendered by default.

bundles/org.openhab.binding.homeconnect/src/main/java/org/openhab/binding/homeconnect/internal/HomeConnectBindingConstants.java

Lines changed: 48 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ public class HomeConnectBindingConstants {
4646
public static final ThingTypeUID THING_TYPE_COFFEE_MAKER = new ThingTypeUID(BINDING_ID, "coffeemaker");
4747
public static final ThingTypeUID THING_TYPE_HOOD = new ThingTypeUID(BINDING_ID, "hood");
4848
public static final ThingTypeUID THING_TYPE_COOKTOP = new ThingTypeUID(BINDING_ID, "hob");
49+
public static final ThingTypeUID THING_TYPE_CLEANING_ROBOT = new ThingTypeUID(BINDING_ID, "cleaningrobot");
4950

5051
// Setting
5152
public static final String SETTING_POWER_STATE = "BSH.Common.Setting.PowerState";
@@ -59,6 +60,7 @@ public class HomeConnectBindingConstants {
5960
public static final String SETTING_REFRIGERATOR_SETPOINT_TEMPERATURE = "Refrigeration.FridgeFreezer.Setting.SetpointTemperatureRefrigerator";
6061
public static final String SETTING_REFRIGERATOR_SUPER_MODE = "Refrigeration.FridgeFreezer.Setting.SuperModeRefrigerator";
6162
public static final String SETTING_FREEZER_SUPER_MODE = "Refrigeration.FridgeFreezer.Setting.SuperModeFreezer";
63+
public static final String SETTING_CURRENT_MAP = "ConsumerProducts.CleaningRobot.Setting.CurrentMap";
6264

6365
// Status
6466
public static final String STATUS_DOOR_STATE = "BSH.Common.Status.DoorState";
@@ -67,6 +69,7 @@ public class HomeConnectBindingConstants {
6769
public static final String STATUS_REMOTE_CONTROL_START_ALLOWED = "BSH.Common.Status.RemoteControlStartAllowed";
6870
public static final String STATUS_REMOTE_CONTROL_ACTIVE = "BSH.Common.Status.RemoteControlActive";
6971
public static final String STATUS_LOCAL_CONTROL_ACTIVE = "BSH.Common.Status.LocalControlActive";
72+
public static final String STATUS_BATTERY_LEVEL = "BSH.Common.Status.BatteryLevel";
7073

7174
// SSE Event types
7275
public static final String EVENT_ELAPSED_PROGRAM_TIME = "BSH.Common.Option.ElapsedProgramTime";
@@ -106,6 +109,8 @@ public class HomeConnectBindingConstants {
106109
public static final String EVENT_AMBIENT_LIGHT_BRIGHTNESS_STATE = SETTING_AMBIENT_LIGHT_BRIGHTNESS;
107110
public static final String EVENT_AMBIENT_LIGHT_COLOR_STATE = SETTING_AMBIENT_LIGHT_COLOR;
108111
public static final String EVENT_AMBIENT_LIGHT_CUSTOM_COLOR_STATE = SETTING_AMBIENT_LIGHT_CUSTOM_COLOR;
112+
public static final String EVENT_BATTERY_LEVEL = STATUS_BATTERY_LEVEL;
113+
public static final String EVENT_CURRENT_MAP = SETTING_CURRENT_MAP;
109114

110115
// Channel IDs
111116
public static final String CHANNEL_DOOR_STATE = "door_state";
@@ -155,16 +160,18 @@ public class HomeConnectBindingConstants {
155160
public static final String CHANNEL_AMBIENT_LIGHT_BRIGHTNESS_STATE = "ambient_light_brightness_state";
156161
public static final String CHANNEL_AMBIENT_LIGHT_COLOR_STATE = "ambient_light_color_state";
157162
public static final String CHANNEL_AMBIENT_LIGHT_CUSTOM_COLOR_STATE = "ambient_light_custom_color_state";
163+
public static final String CHANNEL_BATTERY_LEVEL = "battery_level";
158164

159165
// List of all supported devices
160166
public static final Set<ThingTypeUID> SUPPORTED_DEVICE_THING_TYPES_UIDS = Set.of(THING_TYPE_API_BRIDGE,
161167
THING_TYPE_DISHWASHER, THING_TYPE_OVEN, THING_TYPE_WASHER, THING_TYPE_DRYER, THING_TYPE_WASHER_DRYER,
162-
THING_TYPE_FRIDGE_FREEZER, THING_TYPE_COFFEE_MAKER, THING_TYPE_HOOD, THING_TYPE_COOKTOP);
168+
THING_TYPE_FRIDGE_FREEZER, THING_TYPE_COFFEE_MAKER, THING_TYPE_HOOD, THING_TYPE_COOKTOP,
169+
THING_TYPE_CLEANING_ROBOT);
163170

164171
// Discoverable devices
165172
public static final Set<ThingTypeUID> DISCOVERABLE_DEVICE_THING_TYPES_UIDS = Set.of(THING_TYPE_DISHWASHER,
166173
THING_TYPE_OVEN, THING_TYPE_WASHER, THING_TYPE_DRYER, THING_TYPE_WASHER_DRYER, THING_TYPE_FRIDGE_FREEZER,
167-
THING_TYPE_COFFEE_MAKER, THING_TYPE_HOOD, THING_TYPE_COOKTOP);
174+
THING_TYPE_COFFEE_MAKER, THING_TYPE_HOOD, THING_TYPE_COOKTOP, THING_TYPE_CLEANING_ROBOT);
168175

169176
// List of state values
170177
public static final String STATE_POWER_OFF = "BSH.Common.EnumType.PowerState.Off";
@@ -240,6 +247,28 @@ public class HomeConnectBindingConstants {
240247
public static final String PROGRAM_HOOD_AUTOMATIC = "Cooking.Common.Program.Hood.Automatic";
241248
public static final String PROGRAM_HOOD_VENTING = "Cooking.Common.Program.Hood.Venting";
242249
public static final String PROGRAM_HOOD_DELAYED_SHUT_OFF = "Cooking.Common.Program.Hood.DelayedShutOff";
250+
public static final String PROGRAM_CLEANING_ROBOT_GO_HOME = "ConsumerProducts.CleaningRobot.Program.Basic.GoHome";
251+
public static final String PROGRAM_CLEANING_ROBOT_CLEAN_MAP = "ConsumerProducts.CleaningRobot.Program.Cleaning.CleanMap";
252+
253+
// Cleaning robot options
254+
public static final String OPTION_CLEANING_MODE = "ConsumerProducts.CleaningRobot.Option.CleaningMode";
255+
public static final String OPTION_SUCTION_POWER = "ConsumerProducts.CleaningRobot.Option.SuctionPower";
256+
public static final String OPTION_WATER_FLOW_RATE = "ConsumerProducts.CleaningRobot.Option.WaterFlowRate";
257+
public static final String OPTION_CLEANING_PASSES = "ConsumerProducts.CleaningRobot.Option.CleaningPasses";
258+
public static final String OPTION_CARPET_BOOST = "ConsumerProducts.CleaningRobot.Option.CarpetBoostEnabled";
259+
public static final String OPTION_CLEANING_SPEED = "ConsumerProducts.CleaningRobot.Option.CleaningSpeed";
260+
public static final String OPTION_MOP_EXTENSION = "ConsumerProducts.CleaningRobot.Option.MopExtensionEnabled";
261+
262+
// Cleaning robot cleaning modes
263+
public static final String CLEANING_MODE_PREFIX = "ConsumerProducts.CleaningRobot.EnumType.CleaningMode.";
264+
public static final String CLEANING_MODE_SILENT = CLEANING_MODE_PREFIX + "Silent";
265+
public static final String CLEANING_MODE_STANDARD = CLEANING_MODE_PREFIX + "Standard";
266+
public static final String CLEANING_MODE_POWER = CLEANING_MODE_PREFIX + "Power";
267+
public static final String CLEANING_MODE_INTELLIGENT = CLEANING_MODE_PREFIX + "IntelligentMode";
268+
public static final String CLEANING_MODE_VACUUM_ONLY = CLEANING_MODE_PREFIX + "VacuumOnly";
269+
public static final String CLEANING_MODE_MOP_ONLY = CLEANING_MODE_PREFIX + "MopOnly";
270+
public static final String CLEANING_MODE_VACUUM_AND_MOP = CLEANING_MODE_PREFIX + "VacuumAndMop";
271+
public static final String CLEANING_MODE_MOP_AFTER_VACUUM = CLEANING_MODE_PREFIX + "MopAfterVacuum";
243272

244273
// Network and oAuth constants
245274
public static final String API_BASE_URL = "https://api.home-connect.com";
@@ -272,6 +301,23 @@ public class HomeConnectBindingConstants {
272301
public static final String COMMAND_VENTING_INTENSIVE_2 = "ventingIntensive2";
273302
public static final String COMMAND_AUTOMATIC = "automatic";
274303
public static final String COMMAND_DELAYED_SHUT_OFF = "delayed";
304+
public static final String COMMAND_PAUSE = "pause";
305+
public static final String COMMAND_RESUME = "resume";
306+
public static final String COMMAND_GO_HOME = "gohome";
307+
308+
// Home Connect API commands
309+
public static final String API_COMMAND_PAUSE = "BSH.Common.Command.PauseCommand";
310+
public static final String API_COMMAND_RESUME = "BSH.Common.Command.ResumeCommand";
311+
312+
// Channel IDs (cleaning robot)
313+
public static final String CHANNEL_CLEANING_MODE_STATE = "cleaning_mode_state";
314+
public static final String CHANNEL_SUCTION_POWER_STATE = "suction_power_state";
315+
public static final String CHANNEL_WATER_FLOW_RATE_STATE = "water_flow_rate_state";
316+
public static final String CHANNEL_CLEANING_PASSES_STATE = "cleaning_passes_state";
317+
public static final String CHANNEL_CARPET_BOOST = "carpet_boost";
318+
public static final String CHANNEL_CLEANING_SPEED_STATE = "cleaning_speed_state";
319+
public static final String CHANNEL_MOP_EXTENSION = "mop_extension";
320+
public static final String CHANNEL_CURRENT_MAP = "current_map";
275321

276322
// light
277323
public static final int BRIGHTNESS_MIN = 10;

bundles/org.openhab.binding.homeconnect/src/main/java/org/openhab/binding/homeconnect/internal/client/HomeConnectApiClient.java

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -515,6 +515,48 @@ public Data getDoorState(String haId)
515515
return getStatus(haId, STATUS_DOOR_STATE);
516516
}
517517

518+
/**
519+
* Get battery level of device.
520+
*
521+
* @param haId home appliance id
522+
* @return {@link Data}
523+
* @throws CommunicationException API communication exception
524+
* @throws AuthorizationException oAuth authorization exception
525+
* @throws ApplianceOfflineException appliance is not connected to the cloud
526+
*/
527+
public Data getBatteryLevel(String haId)
528+
throws CommunicationException, AuthorizationException, ApplianceOfflineException {
529+
return getStatus(haId, STATUS_BATTERY_LEVEL);
530+
}
531+
532+
/**
533+
* Get current map of cleaning robot.
534+
*
535+
* @param haId home appliance id
536+
* @return {@link Data}
537+
* @throws CommunicationException API communication exception
538+
* @throws AuthorizationException oAuth authorization exception
539+
* @throws ApplianceOfflineException appliance is not connected to the cloud
540+
*/
541+
public Data getCurrentMap(String haId)
542+
throws CommunicationException, AuthorizationException, ApplianceOfflineException {
543+
return getSetting(haId, SETTING_CURRENT_MAP);
544+
}
545+
546+
/**
547+
* Set current map of cleaning robot.
548+
*
549+
* @param haId home appliance id
550+
* @param map map value (e.g. ConsumerProducts.CleaningRobot.EnumType.AvailableMaps.Map1)
551+
* @throws CommunicationException API communication exception
552+
* @throws AuthorizationException oAuth authorization exception
553+
* @throws ApplianceOfflineException appliance is not connected to the cloud
554+
*/
555+
public void setCurrentMap(String haId, String map)
556+
throws CommunicationException, AuthorizationException, ApplianceOfflineException {
557+
putSettings(haId, new Data(SETTING_CURRENT_MAP, map, null));
558+
}
559+
518560
/**
519561
* Get operation state of device.
520562
*
@@ -652,6 +694,21 @@ public void stopProgram(String haId)
652694
sendDelete(haId, BASE_PATH + haId + "/programs/active");
653695
}
654696

697+
/**
698+
* Send a command to the active program.
699+
*
700+
* @param haId home appliance id
701+
* @param commandKey the command key (e.g. BSH.Common.Command.PauseCommand)
702+
* @throws CommunicationException API communication exception
703+
* @throws AuthorizationException oAuth authorization exception
704+
* @throws ApplianceOfflineException appliance is not connected to the cloud
705+
*/
706+
public void putCommand(String haId, String commandKey)
707+
throws CommunicationException, AuthorizationException, ApplianceOfflineException {
708+
putData(haId, BASE_PATH + haId + "/commands/" + commandKey, new Data(commandKey, Boolean.TRUE.toString(), null),
709+
VALUE_TYPE_BOOLEAN);
710+
}
711+
655712
public List<AvailableProgram> getPrograms(String haId)
656713
throws CommunicationException, AuthorizationException, ApplianceOfflineException {
657714
return getAvailablePrograms(haId, BASE_PATH + haId + "/programs");

bundles/org.openhab.binding.homeconnect/src/main/java/org/openhab/binding/homeconnect/internal/discovery/HomeConnectDiscoveryService.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,8 @@ protected synchronized void stopScan() {
130130
thingTypeUID = THING_TYPE_COOKTOP;
131131
} else if (THING_TYPE_WASHER.getId().equalsIgnoreCase(appliance.getType())) {
132132
thingTypeUID = THING_TYPE_WASHER;
133+
} else if (THING_TYPE_CLEANING_ROBOT.getId().equalsIgnoreCase(appliance.getType())) {
134+
thingTypeUID = THING_TYPE_CLEANING_ROBOT;
133135
}
134136

135137
return thingTypeUID;

bundles/org.openhab.binding.homeconnect/src/main/java/org/openhab/binding/homeconnect/internal/factory/HomeConnectHandlerFactory.java

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
import org.eclipse.jdt.annotation.Nullable;
2121
import org.eclipse.jetty.client.HttpClient;
2222
import org.openhab.binding.homeconnect.internal.handler.HomeConnectBridgeHandler;
23+
import org.openhab.binding.homeconnect.internal.handler.HomeConnectCleaningRobotHandler;
2324
import org.openhab.binding.homeconnect.internal.handler.HomeConnectCoffeeMakerHandler;
2425
import org.openhab.binding.homeconnect.internal.handler.HomeConnectCooktopHandler;
2526
import org.openhab.binding.homeconnect.internal.handler.HomeConnectDishwasherHandler;
@@ -32,6 +33,8 @@
3233
import org.openhab.binding.homeconnect.internal.servlet.HomeConnectServlet;
3334
import org.openhab.binding.homeconnect.internal.type.HomeConnectDynamicStateDescriptionProvider;
3435
import org.openhab.core.auth.client.oauth2.OAuthFactory;
36+
import org.openhab.core.i18n.LocaleProvider;
37+
import org.openhab.core.i18n.TranslationProvider;
3538
import org.openhab.core.io.net.http.HttpClientFactory;
3639
import org.openhab.core.thing.Bridge;
3740
import org.openhab.core.thing.Thing;
@@ -60,19 +63,24 @@ public class HomeConnectHandlerFactory extends BaseThingHandlerFactory {
6063
private final OAuthFactory oAuthFactory;
6164
private final HomeConnectDynamicStateDescriptionProvider dynamicStateDescriptionProvider;
6265
private final HomeConnectServlet homeConnectServlet;
66+
private final TranslationProvider i18nProvider;
67+
private final LocaleProvider localeProvider;
6368

6469
@Activate
6570
public HomeConnectHandlerFactory(@Reference HttpClientFactory httpClientFactory,
6671
@Reference ClientBuilder clientBuilder, @Reference SseEventSourceFactory eventSourceFactory,
6772
@Reference OAuthFactory oAuthFactory,
6873
@Reference HomeConnectDynamicStateDescriptionProvider dynamicStateDescriptionProvider,
69-
@Reference HomeConnectServlet homeConnectServlet) {
74+
@Reference HomeConnectServlet homeConnectServlet, @Reference TranslationProvider i18nProvider,
75+
@Reference LocaleProvider localeProvider) {
7076
this.httpClient = httpClientFactory.getCommonHttpClient();
7177
this.clientBuilder = clientBuilder;
7278
this.eventSourceFactory = eventSourceFactory;
7379
this.oAuthFactory = oAuthFactory;
7480
this.dynamicStateDescriptionProvider = dynamicStateDescriptionProvider;
7581
this.homeConnectServlet = homeConnectServlet;
82+
this.i18nProvider = i18nProvider;
83+
this.localeProvider = localeProvider;
7684
}
7785

7886
@Override
@@ -105,6 +113,9 @@ public boolean supportsThingType(ThingTypeUID thingTypeUID) {
105113
return new HomeConnectHoodHandler(thing, dynamicStateDescriptionProvider);
106114
} else if (THING_TYPE_COOKTOP.equals(thingTypeUID)) {
107115
return new HomeConnectCooktopHandler(thing, dynamicStateDescriptionProvider);
116+
} else if (THING_TYPE_CLEANING_ROBOT.equals(thingTypeUID)) {
117+
return new HomeConnectCleaningRobotHandler(thing, dynamicStateDescriptionProvider, i18nProvider,
118+
localeProvider);
108119
}
109120

110121
return null;

bundles/org.openhab.binding.homeconnect/src/main/java/org/openhab/binding/homeconnect/internal/handler/AbstractHomeConnectThingHandler.java

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1008,6 +1008,17 @@ protected EventHandler defaultPercentHandler(String channelId) {
10081008
.ifPresent(channel -> updateState(channel.getUID(), new PercentType(event.getValueAsInt())));
10091009
}
10101010

1011+
protected EventHandler defaultStringEventHandler(String channelId) {
1012+
return event -> getLinkedChannel(channelId).ifPresent(channel -> {
1013+
String value = event.getValue();
1014+
if (value != null) {
1015+
updateState(channel.getUID(), new StringType(value));
1016+
} else {
1017+
updateState(channel.getUID(), UnDefType.UNDEF);
1018+
}
1019+
});
1020+
}
1021+
10111022
protected ChannelUpdateHandler defaultDoorStateChannelUpdateHandler() {
10121023
return (channelUID, cache) -> updateState(channelUID, cache.putIfAbsentAndGet(channelUID, () -> {
10131024
Optional<HomeConnectApiClient> apiClient = getApiClient();
@@ -1427,13 +1438,17 @@ protected void processProgramOptions(List<Option> options) {
14271438
Map.of(CHANNEL_WASHER_TEMPERATURE, OPTION_WASHER_TEMPERATURE, CHANNEL_WASHER_SPIN_SPEED,
14281439
OPTION_WASHER_SPIN_SPEED, CHANNEL_WASHER_IDOS1_LEVEL, OPTION_WASHER_IDOS_1_DOSING_LEVEL,
14291440
CHANNEL_WASHER_IDOS2_LEVEL, OPTION_WASHER_IDOS_2_DOSING_LEVEL, CHANNEL_DRYER_DRYING_TARGET,
1430-
OPTION_DRYER_DRYING_TARGET)
1441+
OPTION_DRYER_DRYING_TARGET, CHANNEL_CLEANING_MODE_STATE, OPTION_CLEANING_MODE,
1442+
CHANNEL_SUCTION_POWER_STATE, OPTION_SUCTION_POWER, CHANNEL_WATER_FLOW_RATE_STATE,
1443+
OPTION_WATER_FLOW_RATE, CHANNEL_CLEANING_PASSES_STATE, OPTION_CLEANING_PASSES,
1444+
CHANNEL_CLEANING_SPEED_STATE, OPTION_CLEANING_SPEED)
14311445
.forEach((channel, option) -> setStringChannelFromOption(channel, options, option, UnDefType.UNDEF));
14321446

14331447
Map.of(CHANNEL_WASHER_IDOS1, OPTION_WASHER_IDOS_1_ACTIVE, CHANNEL_WASHER_IDOS2, OPTION_WASHER_IDOS_2_ACTIVE,
14341448
CHANNEL_WASHER_LESS_IRONING, OPTION_WASHER_LESS_IRONING, CHANNEL_WASHER_PRE_WASH,
14351449
OPTION_WASHER_PRE_WASH, CHANNEL_WASHER_SOAK, OPTION_WASHER_SOAK, CHANNEL_WASHER_RINSE_HOLD,
1436-
OPTION_WASHER_RINSE_HOLD)
1450+
OPTION_WASHER_RINSE_HOLD, CHANNEL_CARPET_BOOST, OPTION_CARPET_BOOST, CHANNEL_MOP_EXTENSION,
1451+
OPTION_MOP_EXTENSION)
14371452
.forEach((channel, option) -> setOnOffChannelFromOption(channel, options, option, OnOffType.OFF));
14381453

14391454
setStringChannelFromOption(CHANNEL_HOOD_INTENSIVE_LEVEL, options, OPTION_HOOD_INTENSIVE_LEVEL,

0 commit comments

Comments
 (0)