Skip to content

Commit

Permalink
[hdpowerview] Add support for Generation 3 (openhab#13355)
Browse files Browse the repository at this point in the history
Signed-off-by: Andrew Fiddian-Green <software@whitebear.ch>
Signed-off-by: Matt Myers <mmyers75@icloud.com>
  • Loading branch information
andrewfg authored and matchews committed Aug 9, 2023
1 parent 1a0f438 commit 47b4e25
Show file tree
Hide file tree
Showing 36 changed files with 15,342 additions and 106 deletions.
200 changes: 123 additions & 77 deletions bundles/org.openhab.binding.hdpowerview/README.md

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
import java.util.Arrays;
import java.util.List;
import java.util.Set;
import java.util.regex.Pattern;

import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.core.thing.ThingTypeUID;
Expand Down Expand Up @@ -74,6 +75,17 @@ public class HDPowerViewBindingConstants {

public static final List<String> NETBIOS_NAMES = Arrays.asList("PDBU-Hub3.0", "PowerView-Hub");

public static final Pattern VALID_IP_V4_ADDRESS = Pattern
.compile("\\b((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)(\\.|$)){4}\\b");

// generation 3
public static final ThingTypeUID THING_TYPE_GATEWAY = new ThingTypeUID(BINDING_ID, "gateway");
public static final ThingTypeUID THING_TYPE_SHADE3 = new ThingTypeUID(BINDING_ID, "shade3");

public static final Set<ThingTypeUID> SUPPORTED_THING_TYPES_UIDS = Set.of(THING_TYPE_HUB, THING_TYPE_SHADE,
THING_TYPE_REPEATER);
THING_TYPE_REPEATER, THING_TYPE_GATEWAY, THING_TYPE_SHADE3);

public static final String PROPERTY_NAME = "name";
public static final String PROPERTY_POWER_TYPE = "powerType";
public static final String PROPERTY_BLE_NAME = "bleName";
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,18 @@

import java.util.Hashtable;

import javax.ws.rs.client.ClientBuilder;

import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.eclipse.jetty.client.HttpClient;
import org.openhab.binding.hdpowerview.internal.discovery.HDPowerViewDeviceDiscoveryService;
import org.openhab.binding.hdpowerview.internal.discovery.ShadeDiscoveryService;
import org.openhab.binding.hdpowerview.internal.handler.GatewayBridgeHandler;
import org.openhab.binding.hdpowerview.internal.handler.HDPowerViewHubHandler;
import org.openhab.binding.hdpowerview.internal.handler.HDPowerViewRepeaterHandler;
import org.openhab.binding.hdpowerview.internal.handler.HDPowerViewShadeHandler;
import org.openhab.binding.hdpowerview.internal.handler.ShadeThingHandler;
import org.openhab.core.config.discovery.DiscoveryService;
import org.openhab.core.i18n.LocaleProvider;
import org.openhab.core.i18n.TranslationProvider;
Expand All @@ -35,6 +40,7 @@
import org.osgi.service.component.annotations.Activate;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Reference;
import org.osgi.service.jaxrs.client.SseEventSourceFactory;

/**
* The {@link HDPowerViewHandlerFactory} is responsible for creating things and thing
Expand All @@ -48,15 +54,20 @@ public class HDPowerViewHandlerFactory extends BaseThingHandlerFactory {

private final HttpClient httpClient;
private final HDPowerViewTranslationProvider translationProvider;
private final ClientBuilder clientBuilder;
private final SseEventSourceFactory eventSourceFactory;

@Activate
public HDPowerViewHandlerFactory(@Reference HttpClientFactory httpClientFactory,
final @Reference TranslationProvider i18nProvider, final @Reference LocaleProvider localeProvider,
final @Reference ClientBuilder clientBuilder, final @Reference SseEventSourceFactory eventSourceFactory,
ComponentContext componentContext) {
super.activate(componentContext);
this.httpClient = httpClientFactory.getCommonHttpClient();
this.translationProvider = new HDPowerViewTranslationProvider(getBundleContext().getBundle(), i18nProvider,
localeProvider);
this.clientBuilder = clientBuilder;
this.eventSourceFactory = eventSourceFactory;
}

@Override
Expand All @@ -67,8 +78,14 @@ public boolean supportsThingType(ThingTypeUID thingTypeUID) {
@Override
protected @Nullable ThingHandler createHandler(Thing thing) {
ThingTypeUID thingTypeUID = thing.getThingTypeUID();

if (HDPowerViewBindingConstants.THING_TYPE_HUB.equals(thingTypeUID)) {
if (HDPowerViewBindingConstants.THING_TYPE_GATEWAY.equals(thingTypeUID)) {
GatewayBridgeHandler handler = new GatewayBridgeHandler((Bridge) thing, httpClient, translationProvider,
clientBuilder, eventSourceFactory);
registerService(new ShadeDiscoveryService(handler));
return handler;
} else if (HDPowerViewBindingConstants.THING_TYPE_SHADE3.equals(thingTypeUID)) {
return new ShadeThingHandler(thing);
} else if (HDPowerViewBindingConstants.THING_TYPE_HUB.equals(thingTypeUID)) {
HDPowerViewHubHandler handler = new HDPowerViewHubHandler((Bridge) thing, httpClient, translationProvider);
registerService(new HDPowerViewDeviceDiscoveryService(handler));
return handler;
Expand All @@ -77,7 +94,6 @@ public boolean supportsThingType(ThingTypeUID thingTypeUID) {
} else if (HDPowerViewBindingConstants.THING_TYPE_REPEATER.equals(thingTypeUID)) {
return new HDPowerViewRepeaterHandler(thing);
}

return null;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -102,9 +102,9 @@ public class HDPowerViewWebTargets {
private final HttpClient httpClient;

/**
* private helper class for passing http url query parameters
* helper class for passing http url query parameters
*/
private static class Query {
public static class Query {
private final String key;
private final String value;

Expand Down Expand Up @@ -425,7 +425,7 @@ public ScheduledEvents getScheduledEvents()

/**
* Enables or disables a scheduled event in the hub.
*
*
* @param scheduledEventId id of the scheduled event to be enabled or disabled
* @param enable true to enable scheduled event, false to disable
* @throws HubInvalidResponseException if response is invalid
Expand Down Expand Up @@ -527,7 +527,7 @@ public RepeaterData identifyRepeater(int repeaterId)

/**
* Enables or disables blinking for a repeater
*
*
* @param repeaterId id of the repeater for which to be enable or disable blinking
* @param enable true to enable blinking, false to disable
* @return RepeaterData class instance
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,14 @@

import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.binding.hdpowerview.internal.GatewayWebTargets;
import org.openhab.binding.hdpowerview.internal.HDPowerViewBindingConstants;
import org.openhab.binding.hdpowerview.internal.HDPowerViewWebTargets;
import org.openhab.binding.hdpowerview.internal.dto.ShadeData;
import org.openhab.binding.hdpowerview.internal.dto.gen3.Shade;
import org.openhab.binding.hdpowerview.internal.dto.responses.RepeaterData;
import org.openhab.binding.hdpowerview.internal.exceptions.HubException;
import org.openhab.binding.hdpowerview.internal.handler.GatewayBridgeHandler;
import org.openhab.binding.hdpowerview.internal.handler.HDPowerViewHubHandler;
import org.openhab.core.io.console.Console;
import org.openhab.core.io.console.ConsoleCommandCompleter;
Expand Down Expand Up @@ -65,7 +68,7 @@ public void execute(String[] args, Console console) {
for (Thing thing : thingRegistry.getAll()) {
ThingHandler thingHandler = thing.getHandler();
if (thingHandler instanceof HDPowerViewHubHandler) {
console.println("API bridge: " + thing.getLabel());
console.println("Generation 1/2 API hub: " + thing.getLabel());
HDPowerViewWebTargets webTargets = ((HDPowerViewHubHandler) thingHandler).getWebTargets();

try {
Expand All @@ -87,6 +90,21 @@ public void execute(String[] args, Console console) {
} catch (HubException e) {
console.println("Error retrieving ID's: " + e.getMessage());
}
} else if (thingHandler instanceof GatewayBridgeHandler) {
console.println("Generation 3 API gateway: " + thing.getLabel());
GatewayWebTargets webTargets = ((GatewayBridgeHandler) thingHandler).getWebTargets();

try {
List<Shade> shades = webTargets.getShades();
if (!shades.isEmpty()) {
console.println(" - Shades:");
for (Shade shade : shades) {
console.println(" - ID: " + shade.getId() + " (" + shade.getName() + ")");
}
}
} catch (HubException e) {
console.println("Error retrieving ID's: " + e.getMessage());
}
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ public static class Type extends Base {
protected Type() {
}

protected Type(int type) {
public Type(int type) {
intValue = type;
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
/**
* Copyright (c) 2010-2023 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.hdpowerview.internal.discovery;

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

import java.util.Set;

import javax.jmdns.ServiceInfo;

import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.binding.hdpowerview.internal.config.HDPowerViewHubConfiguration;
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.ThingTypeUID;
import org.openhab.core.thing.ThingUID;
import org.osgi.service.component.annotations.Component;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
* Discovers HD PowerView Generation 3 Gateways by means of mDNS.
*
* @author Andrew Fiddian-Green - Initial contribution.
*/
@NonNullByDefault
@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('.', '_'));
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);
return hub;
}
}
return null;
}

@Override
public String getServiceType() {
return "_powerview-g3._tcp.local.";
}

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

@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('.', '_'));
}
}
return null;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ public class HDPowerViewDeviceDiscoveryService extends AbstractDiscoveryService
private final ShadeCapabilitiesDatabase db = new ShadeCapabilitiesDatabase();

public HDPowerViewDeviceDiscoveryService(HDPowerViewHubHandler hub) {
super(Collections.singleton(HDPowerViewBindingConstants.THING_TYPE_SHADE), 600, true);
super(Collections.singleton(HDPowerViewBindingConstants.THING_TYPE_SHADE), 60, true);
this.hub = hub;
this.scanner = createScanner();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@

import java.util.Collections;
import java.util.Set;
import java.util.regex.Pattern;

import javax.jmdns.ServiceInfo;

Expand All @@ -41,10 +40,9 @@
@Component
public class HDPowerViewHubDiscoveryParticipant implements MDNSDiscoveryParticipant {

private final Logger logger = LoggerFactory.getLogger(HDPowerViewHubDiscoveryParticipant.class);
private static final String LABEL_KEY = "discovery.hub.label";

private static final Pattern VALID_IP_V4_ADDRESS = Pattern
.compile("\\b((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)(\\.|$)){4}\\b");
private final Logger logger = LoggerFactory.getLogger(HDPowerViewHubDiscoveryParticipant.class);

@Override
public Set<ThingTypeUID> getSupportedThingTypeUIDs() {
Expand All @@ -64,8 +62,8 @@ public String getServiceType() {
DiscoveryResult hub = DiscoveryResultBuilder.create(thingUID)
.withProperty(HDPowerViewHubConfiguration.HOST, host)
.withRepresentationProperty(HDPowerViewHubConfiguration.HOST)
.withLabel("PowerView Hub (" + host + ")").build();
logger.debug("mDNS discovered hub on host '{}'", host);
.withLabel(String.format("@text/%s [\"%s\"]", LABEL_KEY, host)).build();
logger.debug("mDNS discovered Gen 1/2 hub on host '{}'", host);
return hub;
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ public class HDPowerViewHubDiscoveryService extends AbstractDiscoveryService {
private @Nullable ScheduledFuture<?> backgroundFuture;

public HDPowerViewHubDiscoveryService() {
super(Collections.singleton(THING_TYPE_HUB), 600, true);
super(Collections.singleton(THING_TYPE_HUB), 60, true);
scanner = createScanner();
}

Expand Down
Loading

0 comments on commit 47b4e25

Please sign in to comment.