diff --git a/addons/binding/org.openhab.binding.hue.test/src/test/java/org/openhab/binding/hue/internal/handler/HueBridgeHandlerOSGiTest.java b/addons/binding/org.openhab.binding.hue.test/src/test/java/org/openhab/binding/hue/internal/handler/HueBridgeHandlerOSGiTest.java index e01e102c8b828..290d5b06a9599 100644 --- a/addons/binding/org.openhab.binding.hue.test/src/test/java/org/openhab/binding/hue/internal/handler/HueBridgeHandlerOSGiTest.java +++ b/addons/binding/org.openhab.binding.hue.test/src/test/java/org/openhab/binding/hue/internal/handler/HueBridgeHandlerOSGiTest.java @@ -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; @@ -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; /** @@ -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"; @@ -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; @@ -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 { }; @@ -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(); @@ -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(); @@ -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(); diff --git a/addons/binding/org.openhab.binding.hue/ESH-INF/i18n/hue_de.properties b/addons/binding/org.openhab.binding.hue/ESH-INF/i18n/hue_de.properties index 2c9aa1c1ed3eb..22f95d1288831 100644 --- a/addons/binding/org.openhab.binding.hue/ESH-INF/i18n/hue_de.properties +++ b/addons/binding/org.openhab.binding.hue/ESH-INF/i18n/hue_de.properties @@ -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 diff --git a/addons/binding/org.openhab.binding.hue/ESH-INF/thing/bridge.xml b/addons/binding/org.openhab.binding.hue/ESH-INF/thing/bridge.xml index 616c9520ed269..75b09d943ce0b 100644 --- a/addons/binding/org.openhab.binding.hue/ESH-INF/thing/bridge.xml +++ b/addons/binding/org.openhab.binding.hue/ESH-INF/thing/bridge.xml @@ -20,6 +20,10 @@ Network address of the Hue bridge. true + + + Port of the Hue bridge. + password diff --git a/addons/binding/org.openhab.binding.hue/README.md b/addons/binding/org.openhab.binding.hue/README.md index f1b0193d183ee..eb16abeeecb1d 100644 --- a/addons/binding/org.openhab.binding.hue/README.md +++ b/addons/binding/org.openhab.binding.hue/README.md @@ -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"). | diff --git a/addons/binding/org.openhab.binding.hue/src/main/java/org/openhab/binding/hue/internal/HueBindingConstants.java b/addons/binding/org.openhab.binding.hue/src/main/java/org/openhab/binding/hue/internal/HueBindingConstants.java index 91da0cee02427..96a19aa37827a 100644 --- a/addons/binding/org.openhab.binding.hue/src/main/java/org/openhab/binding/hue/internal/HueBindingConstants.java +++ b/addons/binding/org.openhab.binding.hue/src/main/java/org/openhab/binding/hue/internal/HueBindingConstants.java @@ -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 diff --git a/addons/binding/org.openhab.binding.hue/src/main/java/org/openhab/binding/hue/internal/HueBridge.java b/addons/binding/org.openhab.binding.hue/src/main/java/org/openhab/binding/hue/internal/HueBridge.java index d20e11a1df289..e77622cae4916 100644 --- a/addons/binding/org.openhab.binding.hue/src/main/java/org/openhab/binding/hue/internal/HueBridge.java +++ b/addons/binding/org.openhab.binding.hue/src/main/java/org/openhab/binding/hue/internal/HueBridge.java @@ -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; @@ -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; @@ -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(); @@ -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; } @@ -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); } @@ -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; } } diff --git a/addons/binding/org.openhab.binding.hue/src/main/java/org/openhab/binding/hue/internal/Util.java b/addons/binding/org.openhab.binding.hue/src/main/java/org/openhab/binding/hue/internal/Util.java index eb8b65f7290d5..93f1c63d54139 100644 --- a/addons/binding/org.openhab.binding.hue/src/main/java/org/openhab/binding/hue/internal/Util.java +++ b/addons/binding/org.openhab.binding.hue/src/main/java/org/openhab/binding/hue/internal/Util.java @@ -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; @@ -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 idsToLights(List ids) { diff --git a/addons/binding/org.openhab.binding.hue/src/main/java/org/openhab/binding/hue/internal/config/HueBridgeConfig.java b/addons/binding/org.openhab.binding.hue/src/main/java/org/openhab/binding/hue/internal/config/HueBridgeConfig.java index 0d5eb75c5cf3d..dc5c0c2c62904 100644 --- a/addons/binding/org.openhab.binding.hue/src/main/java/org/openhab/binding/hue/internal/config/HueBridgeConfig.java +++ b/addons/binding/org.openhab.binding.hue/src/main/java/org/openhab/binding/hue/internal/config/HueBridgeConfig.java @@ -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; @@ -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; } diff --git a/addons/binding/org.openhab.binding.hue/src/main/java/org/openhab/binding/hue/internal/discovery/HueBridgeDiscoveryParticipant.java b/addons/binding/org.openhab.binding.hue/src/main/java/org/openhab/binding/hue/internal/discovery/HueBridgeDiscoveryParticipant.java index 6b4f670aa38b1..38003dd35db1c 100644 --- a/addons/binding/org.openhab.binding.hue/src/main/java/org/openhab/binding/hue/internal/discovery/HueBridgeDiscoveryParticipant.java +++ b/addons/binding/org.openhab.binding.hue/src/main/java/org/openhab/binding/hue/internal/discovery/HueBridgeDiscoveryParticipant.java @@ -52,8 +52,10 @@ public Set getSupportedThingTypeUIDs() { public @Nullable DiscoveryResult createResult(RemoteDevice device) { ThingUID uid = getThingUID(device); if (uid != null) { - Map properties = new HashMap<>(2); + Map 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) diff --git a/addons/binding/org.openhab.binding.hue/src/main/java/org/openhab/binding/hue/internal/handler/HueBridgeHandler.java b/addons/binding/org.openhab.binding.hue/src/main/java/org/openhab/binding/hue/internal/handler/HueBridgeHandler.java index d2e36f1ad0f96..83f58f11f7d9a 100644 --- a/addons/binding/org.openhab.binding.hue/src/main/java/org/openhab/binding/hue/internal/handler/HueBridgeHandler.java +++ b/addons/binding/org.openhab.binding.hue/src/main/java/org/openhab/binding/hue/internal/handler/HueBridgeHandler.java @@ -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();