Skip to content

Commit

Permalink
[hue] Added configuration for port (openhab#4728)
Browse files Browse the repository at this point in the history
* Added configuration for port and protocol

Signed-off-by: Christoph Weitkamp <[email protected]>
  • Loading branch information
cweitkamp authored and jannegpriv committed Mar 3, 2019
1 parent 4e5cc0c commit cfc0a3c
Show file tree
Hide file tree
Showing 10 changed files with 80 additions and 33 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
import static org.hamcrest.CoreMatchers.equalTo;
import static org.junit.Assert.*;
import static org.openhab.binding.hue.internal.HueBindingConstants.*;
import static org.openhab.binding.hue.internal.config.HueBridgeConfig.HTTP;

import java.io.IOException;
import java.lang.reflect.Field;
Expand All @@ -37,7 +38,6 @@
import org.openhab.binding.hue.internal.exceptions.ApiException;
import org.openhab.binding.hue.internal.exceptions.LinkButtonException;
import org.openhab.binding.hue.internal.exceptions.UnauthorizedException;
import org.openhab.binding.hue.internal.handler.HueBridgeHandler;
import org.openhab.binding.hue.test.AbstractHueOSGiTest;

/**
Expand All @@ -49,7 +49,7 @@
*/
public class HueBridgeHandlerOSGiTest extends AbstractHueOSGiTest {

private final ThingTypeUID BRIDGE_THING_TYPE_UID = new ThingTypeUID("hue", "bridge");
private final ThingTypeUID BRIDGE_THING_TYPE_UID = new ThingTypeUID(BINDING_ID, "bridge");
private static final String TEST_USER_NAME = "eshTestUser";
private static final String DUMMY_HOST = "1.2.3.4";

Expand All @@ -76,7 +76,7 @@ public void assertThatANewUserIsAddedToConfigIfNotExistingYet() {
HueBridgeHandler hueBridgeHandler = getThingHandler(bridge, HueBridgeHandler.class);
hueBridgeHandler.thingUpdated(bridge);

injectBridge(hueBridgeHandler, new HueBridge(DUMMY_HOST, scheduler) {
injectBridge(hueBridgeHandler, new HueBridge(DUMMY_HOST, 80, HTTP, scheduler) {
@Override
public String link(String deviceType) throws IOException, ApiException {
return TEST_USER_NAME;
Expand All @@ -99,7 +99,7 @@ public void assertThatAnExistingUserIsUsedIfAuthenticationWasSuccessful() {
HueBridgeHandler hueBridgeHandler = getThingHandler(bridge, HueBridgeHandler.class);
hueBridgeHandler.thingUpdated(bridge);

injectBridge(hueBridgeHandler, new HueBridge(DUMMY_HOST, scheduler) {
injectBridge(hueBridgeHandler, new HueBridge(DUMMY_HOST, 80, HTTP, scheduler) {
@Override
public void authenticate(String userName) throws IOException, ApiException {
};
Expand All @@ -121,7 +121,7 @@ public void assertCorrectStatusIfAuthenticationFailedForOldUser() {
HueBridgeHandler hueBridgeHandler = getThingHandler(bridge, HueBridgeHandler.class);
hueBridgeHandler.thingUpdated(bridge);

injectBridge(hueBridgeHandler, new HueBridge(DUMMY_HOST, scheduler) {
injectBridge(hueBridgeHandler, new HueBridge(DUMMY_HOST, 80, HTTP, scheduler) {
@Override
public void authenticate(String userName) throws IOException, ApiException {
throw new UnauthorizedException();
Expand All @@ -145,7 +145,7 @@ public void verifyStatusIfLinkButtonIsNotPressed() {
HueBridgeHandler hueBridgeHandler = getThingHandler(bridge, HueBridgeHandler.class);
hueBridgeHandler.thingUpdated(bridge);

injectBridge(hueBridgeHandler, new HueBridge(DUMMY_HOST, scheduler) {
injectBridge(hueBridgeHandler, new HueBridge(DUMMY_HOST, 80, HTTP, scheduler) {
@Override
public String link(String deviceType) throws IOException, ApiException {
throw new LinkButtonException();
Expand All @@ -169,7 +169,7 @@ public void verifyStatusIfNewUserCannotBeCreated() {
HueBridgeHandler hueBridgeHandler = getThingHandler(bridge, HueBridgeHandler.class);
hueBridgeHandler.thingUpdated(bridge);

injectBridge(hueBridgeHandler, new HueBridge(DUMMY_HOST, scheduler) {
injectBridge(hueBridgeHandler, new HueBridge(DUMMY_HOST, 80, HTTP, scheduler) {
@Override
public String link(String deviceType) throws IOException, ApiException {
throw new ApiException();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ thing-type.hue.0302.description = Temperatursensor
# thing type configuration
thing-type.config.hue.bridge.ipAddress.label = IP-Adresse
thing-type.config.hue.bridge.ipAddress.description = Lokale IP-Adresse oder Hostname der Hue Bridge.
thing-type.config.hue.bridge.port.label = Port
thing-type.config.hue.bridge.port.description = Port der Hue Bridge.
thing-type.config.hue.bridge.userName.label = Benutzer
thing-type.config.hue.bridge.userName.description = Benutzer zur Authentifizierung an der Hue Bridge.
thing-type.config.hue.bridge.pollingInterval.label = Abfrageintervall
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,10 @@
<description>Network address of the Hue bridge.</description>
<required>true</required>
</parameter>
<parameter name="port" type="integer" required="false" min="0" max="65335">
<label>Port</label>
<description>Port of the Hue bridge.</description>
</parameter>
<parameter name="userName" type="text">
<context>password</context>
<label>Username</label>
Expand Down
1 change: 1 addition & 0 deletions addons/binding/org.openhab.binding.hue/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@ Bridge hue:bridge:1 [ ipAddress="192.168.0.64", userName="qwertzuiopasdfghjklyxc
| Parameter | Description |
|-----------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| ipAddress | Network address of the Hue bridge. **Mandatory** |
| port | Port of the Hue bridge. Optional, default value is 80 or 443, derived from protocol, otherwise user-defined. |
| userName | Name of a registered Hue bridge user, that allows to access the API. **Mandatory** |
| pollingInterval | Seconds between fetching light values from the Hue bridge. Optional, the default value is 10 (min="1", step="1"). |
| sensorPollingInterval | Milliseconds between fetching sensor-values from the Hue bridge. A higher value means more delay for the sensor values, but a too low value can cause congestion on the bridge. Optional, the default value is 500 (min="50", step="1"). |
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,8 @@ public class HueBindingConstants {

// Bridge config properties
public static final String HOST = "ipAddress";
public static final String PORT = "port";
public static final String PROTOCOL = "protocol";
public static final String USER_NAME = "userName";

// Light config properties
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,10 @@
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.Type;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
Expand All @@ -36,6 +39,8 @@
import org.openhab.binding.hue.internal.exceptions.InvalidCommandException;
import org.openhab.binding.hue.internal.exceptions.LinkButtonException;
import org.openhab.binding.hue.internal.exceptions.UnauthorizedException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
Expand All @@ -53,9 +58,13 @@
*/
@NonNullByDefault
public class HueBridge {

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

private static final String DATE_FORMAT = "yyyy-MM-dd'T'HH:mm:ss";

private final String ip;
private final String baseUrl;
private @Nullable String username;

private final Gson gson = new GsonBuilder().setDateFormat(DATE_FORMAT).create();
Expand All @@ -69,9 +78,20 @@ public class HueBridge {
* Connect with a bridge as a new user.
*
* @param ip ip address of bridge
* @param port port of bridge
* @param protocol protocol to connect to the bridge
*/
public HueBridge(String ip, ScheduledExecutorService scheduler) {
public HueBridge(String ip, int port, String protocol, ScheduledExecutorService scheduler) {
this.ip = ip;
String baseUrl;
try {
URI uri = new URI(protocol, null, ip, port, "/api", null, null);
baseUrl = uri.toString();
} catch (URISyntaxException e) {
logger.error("exception during constructing URI protocol={}, host={}, port={}", protocol, ip, port, e);
baseUrl = protocol + "://" + ip + ":" + port + "/api";
}
this.baseUrl = baseUrl;
this.scheduler = scheduler;
}

Expand All @@ -83,11 +103,13 @@ public HueBridge(String ip, ScheduledExecutorService scheduler) {
* you don't want to connect right now.
*
* @param ip ip address of bridge
* @param port port of bridge
* @param protocol protocol to connect to the bridge
* @param username username to authenticate with
*/
public HueBridge(String ip, String username, ScheduledExecutorService scheduler) throws IOException, ApiException {
this.ip = ip;
this.scheduler = scheduler;
public HueBridge(String ip, int port, String protocol, String username, ScheduledExecutorService scheduler)
throws IOException, ApiException {
this(ip, port, protocol, scheduler);
authenticate(username);
}

Expand Down Expand Up @@ -996,26 +1018,22 @@ public void handleErrors(Result result) throws IOException, ApiException {

// UTF-8 URL encode
private String enc(@Nullable String str) {
try {
if (str != null) {
return URLEncoder.encode(str, "utf-8");
} else {
return "";
if (str != null) {
try {
return URLEncoder.encode(str, StandardCharsets.UTF_8.name());
} catch (UnsupportedEncodingException e) {
throw new UnsupportedOperationException("UTF-8 not supported");
}
} catch (UnsupportedEncodingException e) {
// throw new EndOfTheWorldException()
throw new UnsupportedOperationException("UTF-8 not supported");
} else {
return "";
}
}

private String getRelativeURL(String path) {
String relativeUrl = "http://" + ip + "/api";
String relativeUrl = baseUrl;
if (username != null) {
relativeUrl += "/" + enc(username);
}
if (!path.isEmpty()) {
relativeUrl += "/" + path;
}
return relativeUrl;
return path.isEmpty() ? relativeUrl : relativeUrl + "/" + path;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
*/
package org.openhab.binding.hue.internal;

import java.io.UnsupportedEncodingException;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
Expand All @@ -33,11 +33,7 @@ private Util() {

// This is used to check what byte size strings have, because the bridge doesn't natively support UTF-8
public static int stringSize(String str) {
try {
return str.getBytes("utf-8").length;
} catch (UnsupportedEncodingException e) {
throw new UnsupportedOperationException("UTF-8 not supported");
}
return str.getBytes(StandardCharsets.UTF_8).length;
}

public static List<HueObject> idsToLights(List<String> ids) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,12 @@
*/
@NonNullByDefault
public class HueBridgeConfig {
public static final String HTTP = "http";
public static final String HTTPS = "https";

private @NonNullByDefault({}) String ipAddress;
private @Nullable Integer port;
private String protocol = HTTP;
private @Nullable String userName;
private int pollingInterval = 10;
private int sensorPollingInterval = 500;
Expand All @@ -36,6 +41,22 @@ public void setIpAddress(String ipAddress) {
this.ipAddress = ipAddress;
}

public int getPort() {
return (port != null) ? port.intValue() : HTTPS.equals(protocol) ? 443 : 80;
}

public void setPort(int port) {
this.port = port;
}

public String getProtocol() {
return protocol;
}

public void setProtocol(String protocol) {
this.protocol = protocol;
}

public @Nullable String getUserName() {
return userName;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,8 +52,10 @@ public Set<ThingTypeUID> getSupportedThingTypeUIDs() {
public @Nullable DiscoveryResult createResult(RemoteDevice device) {
ThingUID uid = getThingUID(device);
if (uid != null) {
Map<String, Object> properties = new HashMap<>(2);
Map<String, Object> properties = new HashMap<>();
properties.put(HOST, device.getDetails().getBaseURL().getHost());
properties.put(PORT, device.getDetails().getBaseURL().getPort());
properties.put(PROTOCOL, device.getDetails().getBaseURL().getProtocol());
properties.put(PROPERTY_SERIAL_NUMBER, device.getDetails().getSerialNumber());

DiscoveryResult result = DiscoveryResultBuilder.create(uid).withProperties(properties)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -394,12 +394,13 @@ public void initialize() {
logger.debug("Initializing hue bridge handler.");
hueBridgeConfig = getConfigAs(HueBridgeConfig.class);

if (hueBridgeConfig.getIpAddress() == null || hueBridgeConfig.getIpAddress().isEmpty()) {
String ip = hueBridgeConfig.getIpAddress();
if (ip == null || ip.isEmpty()) {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.OFFLINE.CONFIGURATION_ERROR,
"@text/offline.conf-error-no-ip-address");
} else {
if (hueBridge == null) {
hueBridge = new HueBridge(hueBridgeConfig.getIpAddress(), scheduler);
hueBridge = new HueBridge(ip, hueBridgeConfig.getPort(), hueBridgeConfig.getProtocol(), scheduler);
hueBridge.setTimeout(5000);
}
onUpdate();
Expand Down

0 comments on commit cfc0a3c

Please sign in to comment.