Skip to content

Commit

Permalink
Use localized labels for discovery results (openhab#16250)
Browse files Browse the repository at this point in the history
Signed-off-by: Jacob Laursen <[email protected]>
  • Loading branch information
jlaur authored Jan 9, 2024
1 parent a2868bb commit cc0e802
Show file tree
Hide file tree
Showing 5 changed files with 107 additions and 103 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -14,17 +14,13 @@

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;

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;
Expand All @@ -37,7 +33,6 @@
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;
Expand All @@ -49,7 +44,6 @@
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;
Expand All @@ -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();
Expand Down Expand Up @@ -111,9 +103,7 @@ public boolean supportsThingType(ThingTypeUID thingTypeUID) {
@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);
Expand Down Expand Up @@ -169,27 +159,4 @@ private ThingUID getApplianceUID(ThingTypeUID thingTypeUID, @Nullable ThingUID t
}
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();
}
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@

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;
Expand All @@ -27,45 +27,62 @@
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() {
super(MieleBridgeHandler.class, MieleApplianceHandler.SUPPORTED_THING_TYPES, SEARCH_TIME_SECONDS, false);
}

public MieleApplianceDiscoveryService(MieleBridgeHandler mieleBridgeHandler) {
super(MieleApplianceHandler.SUPPORTED_THING_TYPES, SEARCH_TIME, false);
this.mieleBridgeHandler = mieleBridgeHandler;
@Reference(unbind = "-")
public void bindTranslationProvider(TranslationProvider translationProvider) {
this.i18nProvider = translationProvider;
}

public void activate() {
mieleBridgeHandler.registerDiscoveryListener(this);
@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
Expand All @@ -75,9 +92,9 @@ public Set<ThingTypeUID> getSupportedThingTypes() {

@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);
}
}

Expand All @@ -94,45 +111,49 @@ public void onApplianceAdded(HomeDevice appliance) {

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
Expand All @@ -145,33 +166,32 @@ public void onApplianceRemoved(HomeDevice appliance) {
}

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);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
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;
Expand All @@ -51,6 +52,7 @@
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;
Expand All @@ -60,6 +62,7 @@
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;
Expand Down Expand Up @@ -134,6 +137,11 @@ public void initialize() {
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,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -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

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand Down

0 comments on commit cc0e802

Please sign in to comment.