]> git.basschouten.com Git - openhab-addons.git/blob
d95927023c1aaa64b7367ef196f3dcc3be272e5e
[openhab-addons.git] /
1 /**
2  * Copyright (c) 2010-2024 Contributors to the openHAB project
3  *
4  * See the NOTICE file(s) distributed with this work for additional
5  * information.
6  *
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
10  *
11  * SPDX-License-Identifier: EPL-2.0
12  */
13 package org.openhab.binding.mielecloud.internal.discovery;
14
15 import static org.openhab.binding.mielecloud.internal.MieleCloudBindingConstants.*;
16 import static org.openhab.binding.mielecloud.internal.handler.MieleHandlerFactory.SUPPORTED_THING_TYPES;
17
18 import java.util.Map;
19 import java.util.Optional;
20
21 import org.eclipse.jdt.annotation.NonNullByDefault;
22 import org.eclipse.jdt.annotation.Nullable;
23 import org.openhab.binding.mielecloud.internal.handler.MieleBridgeHandler;
24 import org.openhab.binding.mielecloud.internal.webservice.api.DeviceState;
25 import org.openhab.binding.mielecloud.internal.webservice.api.json.DeviceType;
26 import org.openhab.core.config.discovery.AbstractThingHandlerDiscoveryService;
27 import org.openhab.core.config.discovery.DiscoveryResult;
28 import org.openhab.core.config.discovery.DiscoveryResultBuilder;
29 import org.openhab.core.config.discovery.DiscoveryService;
30 import org.openhab.core.thing.Thing;
31 import org.openhab.core.thing.ThingTypeUID;
32 import org.openhab.core.thing.ThingUID;
33 import org.osgi.service.component.annotations.Component;
34 import org.osgi.service.component.annotations.ServiceScope;
35 import org.slf4j.Logger;
36 import org.slf4j.LoggerFactory;
37
38 /**
39  * Discovery service for things linked to a Miele cloud account.
40  *
41  * @author Roland Edelhoff - Initial contribution
42  * @author Björn Lange - Do not directly listen to webservice events
43  */
44 @Component(scope = ServiceScope.PROTOTYPE, service = ThingDiscoveryService.class)
45 @NonNullByDefault
46 public class ThingDiscoveryService extends AbstractThingHandlerDiscoveryService<MieleBridgeHandler> {
47     private static final int BACKGROUND_DISCOVERY_TIMEOUT_IN_SECONDS = 5;
48
49     private final Logger logger = LoggerFactory.getLogger(this.getClass());
50
51     private boolean discoveringDevices = false;
52
53     /**
54      * Creates a new {@link ThingDiscoveryService}.
55      */
56     public ThingDiscoveryService() {
57         super(MieleBridgeHandler.class, SUPPORTED_THING_TYPES, BACKGROUND_DISCOVERY_TIMEOUT_IN_SECONDS);
58     }
59
60     @Nullable
61     private ThingUID getBridgeUid() {
62         var bridgeHandler = this.thingHandler;
63         if (bridgeHandler == null) {
64             return null;
65         } else {
66             return bridgeHandler.getThing().getUID();
67         }
68     }
69
70     @Override
71     protected void startScan() {
72     }
73
74     @Override
75     public void activate() {
76         super.activate(Map.of(DiscoveryService.CONFIG_PROPERTY_BACKGROUND_DISCOVERY, true));
77     }
78
79     @Override
80     public void dispose() {
81         super.dispose();
82         removeOlderResults(System.currentTimeMillis(), getBridgeUid());
83     }
84
85     /**
86      * Invoked when a device state update is received from the Miele cloud.
87      */
88     public void onDeviceStateUpdated(DeviceState deviceState) {
89         if (!discoveringDevices) {
90             return;
91         }
92
93         Optional<ThingTypeUID> thingTypeUid = getThingTypeUID(deviceState);
94         if (thingTypeUid.isPresent()) {
95             createDiscoveryResult(deviceState, thingTypeUid.get());
96         } else {
97             logger.debug("Unsupported Miele device type: {}", deviceState.getType().orElse("<Empty>"));
98         }
99     }
100
101     private void createDiscoveryResult(DeviceState deviceState, ThingTypeUID thingTypeUid) {
102         ThingUID thingUid = new ThingUID(thingTypeUid, thingHandler.getThing().getUID(),
103                 deviceState.getDeviceIdentifier());
104
105         DiscoveryResultBuilder discoveryResultBuilder = DiscoveryResultBuilder.create(thingUid)
106                 .withBridge(thingHandler.getThing().getUID()).withRepresentationProperty(Thing.PROPERTY_SERIAL_NUMBER)
107                 .withLabel(getLabel(deviceState));
108
109         ThingInformationExtractor.extractProperties(thingTypeUid, deviceState).entrySet()
110                 .forEach(entry -> discoveryResultBuilder.withProperty(entry.getKey(), entry.getValue()));
111
112         DiscoveryResult result = discoveryResultBuilder.build();
113
114         thingDiscovered(result);
115     }
116
117     private Optional<ThingTypeUID> getThingTypeUID(DeviceState deviceState) {
118         switch (deviceState.getRawType()) {
119             case COFFEE_SYSTEM:
120                 return Optional.of(THING_TYPE_COFFEE_SYSTEM);
121             case TUMBLE_DRYER:
122                 return Optional.of(THING_TYPE_DRYER);
123             case WASHING_MACHINE:
124                 return Optional.of(THING_TYPE_WASHING_MACHINE);
125             case WASHER_DRYER:
126                 return Optional.of(THING_TYPE_WASHER_DRYER);
127             case FREEZER:
128                 return Optional.of(THING_TYPE_FREEZER);
129             case FRIDGE:
130                 return Optional.of(THING_TYPE_FRIDGE);
131             case FRIDGE_FREEZER_COMBINATION:
132                 return Optional.of(THING_TYPE_FRIDGE_FREEZER);
133             case HOB_INDUCTION:
134             case HOB_HIGHLIGHT:
135                 return Optional.of(THING_TYPE_HOB);
136             case DISHWASHER:
137                 return Optional.of(THING_TYPE_DISHWASHER);
138             case OVEN:
139             case OVEN_MICROWAVE:
140             case STEAM_OVEN:
141             case STEAM_OVEN_COMBINATION:
142             case STEAM_OVEN_MICROWAVE_COMBINATION:
143             case DIALOGOVEN:
144                 return Optional.of(THING_TYPE_OVEN);
145             case WINE_CABINET:
146             case WINE_STORAGE_CONDITIONING_UNIT:
147             case WINE_CONDITIONING_UNIT:
148             case WINE_CABINET_FREEZER_COMBINATION:
149                 return Optional.of(THING_TYPE_WINE_STORAGE);
150             case HOOD:
151                 return Optional.of(THING_TYPE_HOOD);
152             case DISH_WARMER:
153                 return Optional.of(THING_TYPE_DISH_WARMER);
154             case VACUUM_CLEANER:
155                 return Optional.of(THING_TYPE_ROBOTIC_VACUUM_CLEANER);
156
157             default:
158                 if (deviceState.getRawType() != DeviceType.UNKNOWN) {
159                     logger.warn("Found no matching thing type for device type {}", deviceState.getRawType());
160                 }
161                 return Optional.empty();
162         }
163     }
164
165     @Override
166     protected void startBackgroundDiscovery() {
167         logger.debug("Starting background discovery");
168
169         removeOlderResults(System.currentTimeMillis(), getBridgeUid());
170         discoveringDevices = true;
171     }
172
173     @Override
174     protected void stopBackgroundDiscovery() {
175         logger.debug("Stopping background discovery");
176         discoveringDevices = false;
177     }
178
179     /**
180      * Invoked when a device is removed from the Miele cloud.
181      */
182     public void onDeviceRemoved(String deviceIdentifier) {
183         removeOlderResults(System.currentTimeMillis(), getBridgeUid());
184     }
185
186     private String getLabel(DeviceState deviceState) {
187         Optional<String> deviceName = deviceState.getDeviceName();
188         if (deviceName.isPresent()) {
189             return deviceName.get();
190         }
191
192         return ThingInformationExtractor.getDeviceAndTechType(deviceState).orElse("Miele Device");
193     }
194
195     @Override
196     public void initialize() {
197         thingHandler.setDiscoveryService(this);
198         super.initialize();
199     }
200 }