Skip to content

Commit

Permalink
[hdpowerview] Fix discovery to use serial number as representation pr…
Browse files Browse the repository at this point in the history
…operty (#18200)

Signed-off-by: Andrew Fiddian-Green <[email protected]>
  • Loading branch information
andrewfg authored Feb 11, 2025
1 parent 6a840f7 commit eb6a56d
Show file tree
Hide file tree
Showing 6 changed files with 249 additions and 78 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -87,4 +87,8 @@ public class HDPowerViewBindingConstants {
public static final String PROPERTY_NAME = "name";
public static final String PROPERTY_POWER_TYPE = "powerType";
public static final String PROPERTY_BLE_NAME = "bleName";

// keys for hub/gateway label translation
public static final String LABEL_KEY_HUB = "discovery.hub.label";
public static final String LABEL_KEY_GATEWAY = "discovery.gateway.label";
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@

import static org.openhab.binding.hdpowerview.internal.HDPowerViewBindingConstants.*;

import java.util.Arrays;
import java.util.Set;

import javax.jmdns.ServiceInfo;
Expand All @@ -24,6 +25,7 @@
import org.openhab.core.config.discovery.DiscoveryResult;
import org.openhab.core.config.discovery.DiscoveryResultBuilder;
import org.openhab.core.config.discovery.mdns.MDNSDiscoveryParticipant;
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;
Expand All @@ -39,20 +41,21 @@
@Component
public class GatewayDiscoveryParticipant implements MDNSDiscoveryParticipant {

private static final String LABEL_KEY = "discovery.gateway.label";

private final Logger logger = LoggerFactory.getLogger(GatewayDiscoveryParticipant.class);

@Override
public @Nullable DiscoveryResult createResult(ServiceInfo service) {
for (String host : service.getHostAddresses()) {
if (VALID_IP_V4_ADDRESS.matcher(host).matches()) {
ThingUID thingUID = new ThingUID(THING_TYPE_GATEWAY, host.replace('.', '_'));
ThingUID thingUID = getThingUID(service);
if (thingUID != null) {
String serial = thingUID.getId();
String host = getIpV4Address(service);
if (host != null) {
String label = String.format("@text/%s [\"%s\"]", LABEL_KEY_GATEWAY, host);
DiscoveryResult hub = DiscoveryResultBuilder.create(thingUID)
.withProperty(HDPowerViewHubConfiguration.HOST, host)
.withRepresentationProperty(HDPowerViewHubConfiguration.HOST)
.withLabel(String.format("@text/%s [\"%s\"]", LABEL_KEY, host)).build();
logger.debug("mDNS discovered Gen 3 gateway on host '{}'", host);
.withProperty(Thing.PROPERTY_SERIAL_NUMBER, serial)
.withRepresentationProperty(Thing.PROPERTY_SERIAL_NUMBER).withLabel(label).build();
logger.debug("mDNS discovered Gen 3 gateway '{}' on host '{}'", thingUID, host);
return hub;
}
}
Expand All @@ -71,11 +74,20 @@ public Set<ThingTypeUID> getSupportedThingTypeUIDs() {

@Override
public @Nullable ThingUID getThingUID(ServiceInfo service) {
for (String host : service.getHostAddresses()) {
if (VALID_IP_V4_ADDRESS.matcher(host).matches()) {
return new ThingUID(THING_TYPE_GATEWAY, host.replace('.', '_'));
String host = getIpV4Address(service);
if (host != null) {
String serial = service.getPropertyString("sn");
if (serial != null) {
return new ThingUID(THING_TYPE_GATEWAY, serial);
} else {
logger.debug("Error discovering gateway 'missing serial number'");
}
}
return null;
}

private static @Nullable String getIpV4Address(ServiceInfo service) {
return Arrays.stream(service.getHostAddresses()).filter(host -> VALID_IP_V4_ADDRESS.matcher(host).matches())
.findFirst().orElse(null);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,16 @@
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.binding.hdpowerview.internal.config.HDPowerViewHubConfiguration;
import org.openhab.binding.hdpowerview.internal.exceptions.HubException;
import org.openhab.core.config.discovery.AbstractDiscoveryService;
import org.openhab.core.config.discovery.DiscoveryResult;
import org.openhab.core.config.discovery.DiscoveryResultBuilder;
import org.openhab.core.config.discovery.DiscoveryService;
import org.openhab.core.thing.Thing;
import org.openhab.core.thing.ThingUID;
import org.osgi.service.component.annotations.Activate;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Reference;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

Expand All @@ -46,10 +50,13 @@ public class HDPowerViewHubDiscoveryService extends AbstractDiscoveryService {

private final Runnable scanner;
private @Nullable ScheduledFuture<?> backgroundFuture;
private final HDPowerviewPropertyGetter propertyGetter;

public HDPowerViewHubDiscoveryService() {
@Activate
public HDPowerViewHubDiscoveryService(@Reference HDPowerviewPropertyGetter propertyGetter) {
super(Set.of(THING_TYPE_HUB), 60, true);
scanner = createScanner();
this.propertyGetter = propertyGetter;
}

@Override
Expand Down Expand Up @@ -83,17 +90,20 @@ private Runnable createScanner() {
NbtAddress address = NbtAddress.getByName(netBiosName);
if (address != null) {
String host = address.getInetAddress().getHostAddress();
ThingUID thingUID = new ThingUID(THING_TYPE_HUB, host.replace('.', '_'));
String serial = propertyGetter.getSerialNumberApiV1(host);
ThingUID thingUID = new ThingUID(THING_TYPE_HUB, serial);
String label = String.format("@text/%s [\"%s\", \"%s\"]", LABEL_KEY_HUB, "1", host);
DiscoveryResult hub = DiscoveryResultBuilder.create(thingUID)
.withProperty(HDPowerViewHubConfiguration.HOST, host)
.withRepresentationProperty(HDPowerViewHubConfiguration.HOST)
.withLabel("PowerView Hub (" + host + ")").build();
logger.debug("NetBios discovered hub on host '{}'", host);
.withProperty(Thing.PROPERTY_SERIAL_NUMBER, serial)
.withRepresentationProperty(Thing.PROPERTY_SERIAL_NUMBER).withLabel(label).build();
logger.debug("NetBios discovered Gen 1 hub '{}' on host '{}'", thingUID, host);
thingDiscovered(hub);
}
} catch (HubException e) {
logger.debug("Error discovering hub", e);
} catch (UnknownHostException e) {
// Nothing to do here - the host couldn't be found, likely because it doesn't
// exist
// Nothing to do here - the host couldn't be found, likely because it doesn't exist
}
}
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,22 +14,19 @@

import static org.openhab.binding.hdpowerview.internal.HDPowerViewBindingConstants.*;

import java.util.Arrays;
import java.util.Set;

import javax.jmdns.ServiceInfo;

import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.eclipse.jetty.client.HttpClient;
import org.openhab.binding.hdpowerview.internal.HDPowerViewWebTargets;
import org.openhab.binding.hdpowerview.internal.config.HDPowerViewHubConfiguration;
import org.openhab.binding.hdpowerview.internal.dto.Firmware;
import org.openhab.binding.hdpowerview.internal.dto.HubFirmware;
import org.openhab.binding.hdpowerview.internal.exceptions.HubException;
import org.openhab.core.config.discovery.DiscoveryResult;
import org.openhab.core.config.discovery.DiscoveryResultBuilder;
import org.openhab.core.config.discovery.mdns.MDNSDiscoveryParticipant;
import org.openhab.core.io.net.http.HttpClientFactory;
import org.openhab.core.thing.Thing;
import org.openhab.core.thing.ThingTypeUID;
import org.openhab.core.thing.ThingUID;
import org.osgi.service.component.annotations.Activate;
Expand All @@ -47,14 +44,13 @@
@Component
public class HDPowerViewHubMDNSDiscoveryParticipant implements MDNSDiscoveryParticipant {

public static final String LABEL_KEY_HUB = "discovery.hub.label";

private final Logger logger = LoggerFactory.getLogger(HDPowerViewHubMDNSDiscoveryParticipant.class);
private final HttpClient httpClient;

private final HDPowerviewPropertyGetter propertyGetter;

@Activate
public HDPowerViewHubMDNSDiscoveryParticipant(@Reference HttpClientFactory httpClientFactory) {
httpClient = httpClientFactory.getCommonHttpClient();
public HDPowerViewHubMDNSDiscoveryParticipant(@Reference HDPowerviewPropertyGetter propertyGetter) {
this.propertyGetter = propertyGetter;
}

@Override
Expand All @@ -69,15 +65,23 @@ public String getServiceType() {

@Override
public @Nullable DiscoveryResult createResult(ServiceInfo service) {
for (String host : service.getHostAddresses()) {
if (VALID_IP_V4_ADDRESS.matcher(host).matches()) {
ThingUID thingUID = new ThingUID(THING_TYPE_HUB, host.replace('.', '_'));
String generation = this.getGeneration(host);
ThingUID thingUID = getThingUID(service);
if (thingUID != null) {
String serial = thingUID.getId();
String host = getIpV4Address(service);
if (host != null) {
String generation;
try {
generation = propertyGetter.getGenerationApiV1(host);
} catch (HubException e) {
generation = "1/2";
}
String label = String.format("@text/%s [\"%s\", \"%s\"]", LABEL_KEY_HUB, generation, host);
DiscoveryResult hub = DiscoveryResultBuilder.create(thingUID)
.withProperty(HDPowerViewHubConfiguration.HOST, host)
.withRepresentationProperty(HDPowerViewHubConfiguration.HOST)
.withLabel(String.format("@text/%s [\"%s\", \"%s\"]", LABEL_KEY_HUB, generation, host)).build();
logger.debug("mDNS discovered Gen {} hub on host '{}'", generation, host);
.withProperty(Thing.PROPERTY_SERIAL_NUMBER, serial)
.withRepresentationProperty(Thing.PROPERTY_SERIAL_NUMBER).withLabel(label).build();
logger.debug("mDNS discovered Gen {} hub '{}' on host '{}'", generation, thingUID, host);
return hub;
}
}
Expand All @@ -86,25 +90,20 @@ public String getServiceType() {

@Override
public @Nullable ThingUID getThingUID(ServiceInfo service) {
for (String host : service.getHostAddresses()) {
if (VALID_IP_V4_ADDRESS.matcher(host).matches()) {
return new ThingUID(THING_TYPE_HUB, host.replace('.', '_'));
String host = getIpV4Address(service);
if (host != null) {
try {
String serial = propertyGetter.getSerialNumberApiV1(host);
return new ThingUID(THING_TYPE_HUB, serial);
} catch (HubException e) {
logger.debug("Error discovering hub", e);
}
}
return null;
}

private String getGeneration(String host) {
var webTargets = new HDPowerViewWebTargets(httpClient, host);
try {
HubFirmware firmware = webTargets.getFirmwareVersions();
Firmware mainProcessor = firmware.mainProcessor;
if (mainProcessor != null) {
return String.valueOf(mainProcessor.revision);
}
} catch (HubException e) {
logger.debug("Failed to discover hub firmware versions", e);
}
return "1/2";
private static @Nullable String getIpV4Address(ServiceInfo service) {
return Arrays.stream(service.getHostAddresses()).filter(host -> VALID_IP_V4_ADDRESS.matcher(host).matches())
.findFirst().orElse(null);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,17 @@
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.binding.hdpowerview.internal.config.HDPowerViewHubConfiguration;
import org.openhab.binding.hdpowerview.internal.exceptions.HubException;
import org.openhab.core.config.discovery.DiscoveryResult;
import org.openhab.core.config.discovery.DiscoveryResultBuilder;
import org.openhab.core.config.discovery.sddp.SddpDevice;
import org.openhab.core.config.discovery.sddp.SddpDiscoveryParticipant;
import org.openhab.core.thing.Thing;
import org.openhab.core.thing.ThingTypeUID;
import org.openhab.core.thing.ThingUID;
import org.osgi.service.component.annotations.Activate;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Reference;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

Expand All @@ -38,53 +42,58 @@
@Component
public class HDPowerViewSddpDiscoveryParticipant implements SddpDiscoveryParticipant {

private static final String LABEL_KEY_GATEWAY = "discovery.gateway.label";

private static final String HUNTER_DOUGLAS = "hunterdouglas:";
private static final String POWERVIEW_HUB_ID = "hub:powerview";
private static final String POWERVIEW_GEN3_ID = "powerview:gen3:gateway";

private final Logger logger = LoggerFactory.getLogger(HDPowerViewSddpDiscoveryParticipant.class);

private final HDPowerviewPropertyGetter propertyGetter;

@Activate
public HDPowerViewSddpDiscoveryParticipant(@Reference HDPowerviewPropertyGetter propertyGetter) {
this.propertyGetter = propertyGetter;
}

@Override
public Set<ThingTypeUID> getSupportedThingTypeUIDs() {
return Set.of(THING_TYPE_HUB, THING_TYPE_GATEWAY);
}

@Override
public @Nullable DiscoveryResult createResult(SddpDevice device) {
final ThingUID thingUID = getThingUID(device);
ThingUID thingUID = getThingUID(device);
if (thingUID != null) {
try {
int generation = getGeneration(device);
String label = generation == 3 //
? String.format("@text/%s [\"%s\"]", LABEL_KEY_GATEWAY, device.ipAddress)
: String.format("@text/%s [\"%s\", \"%s\"]",
HDPowerViewHubMDNSDiscoveryParticipant.LABEL_KEY_HUB, generation, device.ipAddress);

DiscoveryResult hub = DiscoveryResultBuilder.create(thingUID)
.withProperty(HDPowerViewHubConfiguration.HOST, device.ipAddress)
.withRepresentationProperty(HDPowerViewHubConfiguration.HOST).withLabel(label).build();
logger.debug("SDDP discovered Gen {} hub/gateway '{}' on host '{}'", generation, thingUID,
device.ipAddress);
return hub;
} catch (IllegalArgumentException e) {
// error already logged, so fall through
}
String serial = thingUID.getId();
String host = device.ipAddress;
int generation = getGeneration(device);
String label = generation < 3 //
? String.format("@text/%s [\"%s\", \"%s\"]", LABEL_KEY_HUB, generation, host)
: String.format("@text/%s [\"%s\"]", LABEL_KEY_GATEWAY, host);
DiscoveryResult hub = DiscoveryResultBuilder.create(thingUID)
.withProperty(HDPowerViewHubConfiguration.HOST, host)
.withProperty(Thing.PROPERTY_SERIAL_NUMBER, serial)
.withRepresentationProperty(Thing.PROPERTY_SERIAL_NUMBER).withLabel(label).build();
logger.debug("SDDP discovered Gen {} hub/gateway '{}' on host '{}'", generation, thingUID, host);
return hub;
}
return null;
}

@Override
public @Nullable ThingUID getThingUID(SddpDevice device) {
if (device.type.startsWith(HUNTER_DOUGLAS)) {
try {
if (VALID_IP_V4_ADDRESS.matcher(device.ipAddress).matches()) {
return new ThingUID(getGeneration(device) == 3 ? THING_TYPE_GATEWAY : THING_TYPE_HUB,
device.ipAddress.replace('.', '_'));
String host = device.ipAddress;
if (VALID_IP_V4_ADDRESS.matcher(host).matches()) {
try {
int generation = getGeneration(device);
String serial = generation < 3 //
? propertyGetter.getSerialNumberApiV1(host)
: propertyGetter.getSerialNumberApiV3(host);
return new ThingUID(generation < 3 ? THING_TYPE_HUB : THING_TYPE_GATEWAY, serial);
} catch (HubException | IllegalArgumentException e) {
logger.debug("Error discovering hub/gateway", e);
}
} catch (IllegalArgumentException e) {
// error already logged, so fall through
}
}
return null;
Expand All @@ -103,8 +112,6 @@ private int getGeneration(SddpDevice device) throws IllegalArgumentException {
if (device.type.contains(POWERVIEW_HUB_ID)) {
return device.type.endsWith("v2") ? 2 : 1;
}
final IllegalArgumentException e = new IllegalArgumentException("Device has unexpected 'type' property");
logger.debug("{}", e.getMessage());
throw e;
throw new IllegalArgumentException("Device has unexpected 'type' property");
}
}
Loading

0 comments on commit eb6a56d

Please sign in to comment.