Use localized labels for discovery results (#16250)

Signed-off-by: Jacob Laursen <jacob-github@vindvejr.dk>
Signed-off-by: Ciprian Pascu <contact@ciprianpascu.ro>
This commit is contained in:
Jacob Laursen 2024-01-10 00:03:14 +01:00 committed by Ciprian Pascu
parent ef59934e9c
commit 6b86dabbd9
5 changed files with 108 additions and 104 deletions

View File

@ -14,9 +14,6 @@ package org.openhab.binding.miele.internal;
import static org.openhab.binding.miele.internal.MieleBindingConstants.*;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;
@ -24,7 +21,6 @@ import java.util.stream.Stream;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.eclipse.jetty.client.HttpClient;
import org.openhab.binding.miele.internal.discovery.MieleApplianceDiscoveryService;
import org.openhab.binding.miele.internal.handler.CoffeeMachineHandler;
import org.openhab.binding.miele.internal.handler.DishwasherHandler;
import org.openhab.binding.miele.internal.handler.FridgeFreezerHandler;
@ -37,7 +33,6 @@ import org.openhab.binding.miele.internal.handler.OvenHandler;
import org.openhab.binding.miele.internal.handler.TumbleDryerHandler;
import org.openhab.binding.miele.internal.handler.WashingMachineHandler;
import org.openhab.core.config.core.Configuration;
import org.openhab.core.config.discovery.DiscoveryService;
import org.openhab.core.i18n.LocaleProvider;
import org.openhab.core.i18n.TimeZoneProvider;
import org.openhab.core.i18n.TranslationProvider;
@ -49,7 +44,6 @@ import org.openhab.core.thing.ThingUID;
import org.openhab.core.thing.binding.BaseThingHandlerFactory;
import org.openhab.core.thing.binding.ThingHandler;
import org.openhab.core.thing.binding.ThingHandlerFactory;
import org.osgi.framework.ServiceRegistration;
import org.osgi.service.component.ComponentContext;
import org.osgi.service.component.annotations.Activate;
import org.osgi.service.component.annotations.Component;
@ -76,10 +70,8 @@ public class MieleHandlerFactory extends BaseThingHandlerFactory {
private final LocaleProvider localeProvider;
private final TimeZoneProvider timeZoneProvider;
private Map<ThingUID, ServiceRegistration<?>> discoveryServiceRegs = new HashMap<>();
@Activate
public MieleHandlerFactory(@Reference final HttpClientFactory httpClientFactory,
public MieleHandlerFactory(final @Reference HttpClientFactory httpClientFactory,
final @Reference TranslationProvider i18nProvider, final @Reference LocaleProvider localeProvider,
final @Reference TimeZoneProvider timeZoneProvider, ComponentContext componentContext) {
this.httpClient = httpClientFactory.getCommonHttpClient();
@ -111,9 +103,7 @@ public class MieleHandlerFactory extends BaseThingHandlerFactory {
@Override
protected @Nullable ThingHandler createHandler(Thing thing) {
if (MieleBridgeHandler.SUPPORTED_THING_TYPES.contains(thing.getThingTypeUID())) {
MieleBridgeHandler handler = new MieleBridgeHandler((Bridge) thing, httpClient);
registerApplianceDiscoveryService(handler);
return handler;
return new MieleBridgeHandler((Bridge) thing, httpClient);
} else if (MieleApplianceHandler.SUPPORTED_THING_TYPES.contains(thing.getThingTypeUID())) {
if (thing.getThingTypeUID().equals(THING_TYPE_HOOD)) {
return new HoodHandler(thing, i18nProvider, localeProvider, timeZoneProvider);
@ -169,27 +159,4 @@ public class MieleHandlerFactory extends BaseThingHandlerFactory {
}
return thingUID;
}
private synchronized void registerApplianceDiscoveryService(MieleBridgeHandler bridgeHandler) {
MieleApplianceDiscoveryService discoveryService = new MieleApplianceDiscoveryService(bridgeHandler);
discoveryService.activate();
this.discoveryServiceRegs.put(bridgeHandler.getThing().getUID(),
bundleContext.registerService(DiscoveryService.class.getName(), discoveryService, new Hashtable<>()));
}
@Override
protected synchronized void removeHandler(ThingHandler thingHandler) {
if (thingHandler instanceof MieleBridgeHandler) {
ServiceRegistration<?> serviceReg = this.discoveryServiceRegs.remove(thingHandler.getThing().getUID());
if (serviceReg != null) {
// remove discovery service, if bridge handler is removed
MieleApplianceDiscoveryService service = (MieleApplianceDiscoveryService) bundleContext
.getService(serviceReg.getReference());
serviceReg.unregister();
if (service != null) {
service.deactivate();
}
}
}
}
}

View File

@ -14,7 +14,7 @@ package org.openhab.binding.miele.internal.discovery;
import static org.openhab.binding.miele.internal.MieleBindingConstants.*;
import java.util.Date;
import java.time.Instant;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@ -27,45 +27,62 @@ import org.openhab.binding.miele.internal.api.dto.HomeDevice;
import org.openhab.binding.miele.internal.handler.DiscoveryListener;
import org.openhab.binding.miele.internal.handler.MieleApplianceHandler;
import org.openhab.binding.miele.internal.handler.MieleBridgeHandler;
import org.openhab.core.config.discovery.AbstractDiscoveryService;
import org.openhab.core.config.discovery.AbstractThingHandlerDiscoveryService;
import org.openhab.core.config.discovery.DiscoveryResult;
import org.openhab.core.config.discovery.DiscoveryResultBuilder;
import org.openhab.core.i18n.LocaleProvider;
import org.openhab.core.i18n.TranslationProvider;
import org.openhab.core.thing.Thing;
import org.openhab.core.thing.ThingTypeUID;
import org.openhab.core.thing.ThingUID;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Reference;
import org.osgi.service.component.annotations.ServiceScope;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* The {@link MieleApplianceDiscoveryService} tracks appliances that are
* associated with the Miele@Home gateway
* associated with the Miele@home gateway
*
* @author Karel Goderis - Initial contribution
* @author Martin Lepsy - Added protocol information in order so support WiFi devices
* @author Martin Lepsy - Added protocol information in order to support WiFi devices
* @author Jacob Laursen - Fixed multicast and protocol support (ZigBee/LAN)
*/
@Component(scope = ServiceScope.PROTOTYPE, service = MieleApplianceDiscoveryService.class)
@NonNullByDefault
public class MieleApplianceDiscoveryService extends AbstractDiscoveryService implements DiscoveryListener {
public class MieleApplianceDiscoveryService extends AbstractThingHandlerDiscoveryService<MieleBridgeHandler>
implements DiscoveryListener {
private final Logger logger = LoggerFactory.getLogger(MieleApplianceDiscoveryService.class);
private static final int SEARCH_TIME = 60;
private static final int SEARCH_TIME_SECONDS = 60;
private MieleBridgeHandler mieleBridgeHandler;
public MieleApplianceDiscoveryService(MieleBridgeHandler mieleBridgeHandler) {
super(MieleApplianceHandler.SUPPORTED_THING_TYPES, SEARCH_TIME, false);
this.mieleBridgeHandler = mieleBridgeHandler;
public MieleApplianceDiscoveryService() {
super(MieleBridgeHandler.class, MieleApplianceHandler.SUPPORTED_THING_TYPES, SEARCH_TIME_SECONDS, false);
}
public void activate() {
mieleBridgeHandler.registerDiscoveryListener(this);
@Reference(unbind = "-")
public void bindTranslationProvider(TranslationProvider translationProvider) {
this.i18nProvider = translationProvider;
}
@Reference(unbind = "-")
public void bindLocaleProvider(LocaleProvider localeProvider) {
this.localeProvider = localeProvider;
}
@Override
public void deactivate() {
removeOlderResults(new Date().getTime());
mieleBridgeHandler.unregisterDiscoveryListener(this);
public void initialize() {
thingHandler.registerDiscoveryListener(this);
super.initialize();
}
@Override
public void dispose() {
super.dispose();
removeOlderResults(Instant.now().toEpochMilli());
thingHandler.unregisterDiscoveryListener(this);
}
@Override
@ -75,9 +92,9 @@ public class MieleApplianceDiscoveryService extends AbstractDiscoveryService imp
@Override
public void startScan() {
List<HomeDevice> appliances = mieleBridgeHandler.getHomeDevicesEmptyOnFailure();
for (HomeDevice l : appliances) {
onApplianceAddedInternal(l);
List<HomeDevice> appliances = thingHandler.getHomeDevicesEmptyOnFailure();
for (HomeDevice appliance : appliances) {
onApplianceAddedInternal(appliance);
}
}
@ -94,45 +111,49 @@ public class MieleApplianceDiscoveryService extends AbstractDiscoveryService imp
private void onApplianceAddedInternal(HomeDevice appliance) {
ThingUID thingUID = getThingUID(appliance);
if (thingUID != null) {
ThingUID bridgeUID = mieleBridgeHandler.getThing().getUID();
Map<String, Object> properties = new HashMap<>(9);
FullyQualifiedApplianceIdentifier applianceIdentifier = appliance.getApplianceIdentifier();
String vendor = appliance.Vendor;
if (vendor != null) {
properties.put(Thing.PROPERTY_VENDOR, vendor);
}
properties.put(Thing.PROPERTY_MODEL_ID, appliance.getApplianceModel());
properties.put(Thing.PROPERTY_SERIAL_NUMBER, appliance.getSerialNumber());
properties.put(Thing.PROPERTY_FIRMWARE_VERSION, appliance.getFirmwareVersion());
String protocolAdapterName = appliance.ProtocolAdapterName;
if (protocolAdapterName != null) {
properties.put(PROPERTY_PROTOCOL_ADAPTER, protocolAdapterName);
}
properties.put(APPLIANCE_ID, applianceIdentifier.getApplianceId());
String deviceClass = appliance.getDeviceClass();
if (deviceClass != null) {
properties.put(PROPERTY_DEVICE_CLASS, deviceClass);
}
String connectionType = appliance.getConnectionType();
if (connectionType != null) {
properties.put(PROPERTY_CONNECTION_TYPE, connectionType);
}
String connectionBaudRate = appliance.getConnectionBaudRate();
if (connectionBaudRate != null) {
properties.put(PROPERTY_CONNECTION_BAUD_RATE, connectionBaudRate);
}
DiscoveryResult discoveryResult = DiscoveryResultBuilder.create(thingUID).withProperties(properties)
.withBridge(bridgeUID).withLabel(deviceClass != null ? deviceClass : appliance.getApplianceModel())
.withRepresentationProperty(APPLIANCE_ID).build();
thingDiscovered(discoveryResult);
} else {
if (thingUID == null) {
logger.debug("Discovered an unsupported appliance of vendor '{}' with id {}", appliance.Vendor,
appliance.UID);
return;
}
ThingUID bridgeUID = thingHandler.getThing().getUID();
Map<String, Object> properties = new HashMap<>(9);
FullyQualifiedApplianceIdentifier applianceIdentifier = appliance.getApplianceIdentifier();
String vendor = appliance.Vendor;
if (vendor != null) {
properties.put(Thing.PROPERTY_VENDOR, vendor);
}
properties.put(Thing.PROPERTY_MODEL_ID, appliance.getApplianceModel());
properties.put(Thing.PROPERTY_SERIAL_NUMBER, appliance.getSerialNumber());
properties.put(Thing.PROPERTY_FIRMWARE_VERSION, appliance.getFirmwareVersion());
String protocolAdapterName = appliance.ProtocolAdapterName;
if (protocolAdapterName != null) {
properties.put(PROPERTY_PROTOCOL_ADAPTER, protocolAdapterName);
}
properties.put(APPLIANCE_ID, applianceIdentifier.getApplianceId());
String deviceClass = appliance.getDeviceClass();
if (deviceClass != null) {
properties.put(PROPERTY_DEVICE_CLASS, deviceClass);
}
String connectionType = appliance.getConnectionType();
if (connectionType != null) {
properties.put(PROPERTY_CONNECTION_TYPE, connectionType);
}
String connectionBaudRate = appliance.getConnectionBaudRate();
if (connectionBaudRate != null) {
properties.put(PROPERTY_CONNECTION_BAUD_RATE, connectionBaudRate);
}
String label = deviceClass != null
? "@text/discovery." + getThingTypeUidFromDeviceClass(deviceClass).getId() + ".label [\""
+ appliance.getApplianceModel() + "\"]"
: appliance.getApplianceModel();
DiscoveryResult discoveryResult = DiscoveryResultBuilder.create(thingUID).withProperties(properties)
.withBridge(bridgeUID).withLabel(label).withRepresentationProperty(APPLIANCE_ID).build();
thingDiscovered(discoveryResult);
}
@Override
@ -145,33 +166,32 @@ public class MieleApplianceDiscoveryService extends AbstractDiscoveryService imp
}
private @Nullable ThingUID getThingUID(HomeDevice appliance) {
ThingUID bridgeUID = mieleBridgeHandler.getThing().getUID();
String modelId = appliance.getDeviceClass();
ThingUID bridgeUID = thingHandler.getThing().getUID();
String deviceClass = appliance.getDeviceClass();
if (deviceClass == null) {
return null;
}
if (modelId != null) {
ThingTypeUID thingTypeUID = getThingTypeUidFromModelId(modelId);
ThingTypeUID thingTypeUID = getThingTypeUidFromDeviceClass(deviceClass);
if (getSupportedThingTypes().contains(thingTypeUID)) {
return new ThingUID(thingTypeUID, bridgeUID, appliance.getApplianceIdentifier().getId());
} else {
return null;
}
if (getSupportedThingTypes().contains(thingTypeUID)) {
return new ThingUID(thingTypeUID, bridgeUID, appliance.getApplianceIdentifier().getId());
} else {
return null;
}
}
private ThingTypeUID getThingTypeUidFromModelId(String modelId) {
private ThingTypeUID getThingTypeUidFromDeviceClass(String deviceClass) {
/*
* Coffee machine CVA 6805 is reported as CoffeeSystem, but thing type is
* coffeemachine. At least until it is known if any models are actually reported
* as CoffeeMachine, we need this special mapping.
*/
if (MIELE_DEVICE_CLASS_COFFEE_SYSTEM.equals(modelId)) {
if (MIELE_DEVICE_CLASS_COFFEE_SYSTEM.equals(deviceClass)) {
return THING_TYPE_COFFEEMACHINE;
}
String thingTypeId = modelId.replaceAll("[^a-zA-Z0-9_]", "_").toLowerCase();
String thingTypeId = deviceClass.replaceAll("[^a-zA-Z0-9_]", "_").toLowerCase();
return new ThingTypeUID(BINDING_ID, thingTypeId);
}

View File

@ -27,6 +27,7 @@ import java.net.URISyntaxException;
import java.net.UnknownHostException;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Enumeration;
import java.util.IllformedLocaleException;
import java.util.Iterator;
@ -51,6 +52,7 @@ import org.openhab.binding.miele.internal.MieleGatewayCommunicationController;
import org.openhab.binding.miele.internal.api.dto.DeviceClassObject;
import org.openhab.binding.miele.internal.api.dto.DeviceProperty;
import org.openhab.binding.miele.internal.api.dto.HomeDevice;
import org.openhab.binding.miele.internal.discovery.MieleApplianceDiscoveryService;
import org.openhab.binding.miele.internal.exceptions.MieleRpcException;
import org.openhab.core.common.NamedThreadFactory;
import org.openhab.core.config.core.Configuration;
@ -60,6 +62,7 @@ import org.openhab.core.thing.ThingStatus;
import org.openhab.core.thing.ThingStatusDetail;
import org.openhab.core.thing.ThingTypeUID;
import org.openhab.core.thing.binding.BaseBridgeHandler;
import org.openhab.core.thing.binding.ThingHandlerService;
import org.openhab.core.types.Command;
import org.openhab.core.types.RefreshType;
import org.slf4j.Logger;
@ -134,6 +137,11 @@ public class MieleBridgeHandler extends BaseBridgeHandler {
schedulePollingAndEventListener();
}
@Override
public Collection<Class<? extends ThingHandlerService>> getServices() {
return Set.of(MieleApplianceDiscoveryService.class);
}
private boolean validateConfig(Configuration config) {
if (config.get(HOST) == null || ((String) config.get(HOST)).isBlank()) {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.OFFLINE.CONFIGURATION_ERROR,

View File

@ -39,7 +39,7 @@ thing-type.miele.washingmachine.description = This is a Miele@home compatible wa
thing-type.miele.washingmachine.channel.target.label = Temperature
thing-type.miele.washingmachine.channel.target.description = Temperature of the selected program (10 °C = cold)
thing-type.miele.xgw3000.label = Miele XGW3000
thing-type.miele.xgw3000.description = The Miele bridge represents the Miele@home XGW3000 gateway.
thing-type.miele.xgw3000.description = The Miele bridge represents the Miele@home XGW 3000 gateway.
# thing types config
@ -136,6 +136,15 @@ offline.configuration-error.uid-not-set = Appliance ID is not set
# discovery result
discovery.xgw3000.label = Miele XGW 3000
discovery.coffeemachine.label = Coffee Machine ({0})
discovery.dishwasher.label = Dishwasher ({0})
discovery.fridge.label = Fridge ({0})
discovery.fridgefreezer.label = Fridge Freezer ({0})
discovery.hob.label = Hob ({0})
discovery.hood.label = Hood ({0})
discovery.oven.label = Oven ({0})
discovery.tumbledryer.label = Tumbledryer ({0})
discovery.washingmachine.label = Washing Machine ({0})
# miele states

View File

@ -7,7 +7,7 @@
<!-- Miele Bridge -->
<bridge-type id="xgw3000">
<label>Miele XGW3000</label>
<description>The Miele bridge represents the Miele@home XGW3000 gateway.</description>
<description>The Miele bridge represents the Miele@home XGW 3000 gateway.</description>
<properties>
<property name="vendor">Miele</property>