From 594aea43c1e9aca2dea48e6e01f4203144f9bdcd Mon Sep 17 00:00:00 2001 From: Mario Smit Date: Tue, 4 Jul 2017 21:47:36 +0200 Subject: [PATCH 1/2] Changes to the Tradfri Binding to discover and use Groups (and additional Remotes added to empty ones) --- .../ESH-INF/thing/thing-types.xml | 28 ++- .../tradfri/TradfriBindingConstants.java | 3 + .../handler/TradfriGatewayHandler.java | 182 ++++++++++------- .../tradfri/handler/TradfriGroupHandler.java | 191 ++++++++++++++++++ .../tradfri/handler/TradfriLightHandler.java | 4 +- .../internal/TradfriHandlerFactory.java | 9 +- .../discovery/TradfriDiscoveryService.java | 50 +++-- 7 files changed, 366 insertions(+), 101 deletions(-) create mode 100644 extensions/binding/org.eclipse.smarthome.binding.tradfri/src/main/java/org/eclipse/smarthome/binding/tradfri/handler/TradfriGroupHandler.java diff --git a/extensions/binding/org.eclipse.smarthome.binding.tradfri/ESH-INF/thing/thing-types.xml b/extensions/binding/org.eclipse.smarthome.binding.tradfri/ESH-INF/thing/thing-types.xml index f6448ac6cc9..6215f915e0c 100644 --- a/extensions/binding/org.eclipse.smarthome.binding.tradfri/ESH-INF/thing/thing-types.xml +++ b/extensions/binding/org.eclipse.smarthome.binding.tradfri/ESH-INF/thing/thing-types.xml @@ -69,6 +69,26 @@ + + + + + + + A group of Tradfri lamps + + + + + + + + + The identifier of the group on the gateway + + + + @@ -109,5 +129,11 @@ Allows to control the color temperature of light. ColorLight - + + + Switch + + Allows to switch on or off all lamps in a group. + + diff --git a/extensions/binding/org.eclipse.smarthome.binding.tradfri/src/main/java/org/eclipse/smarthome/binding/tradfri/TradfriBindingConstants.java b/extensions/binding/org.eclipse.smarthome.binding.tradfri/src/main/java/org/eclipse/smarthome/binding/tradfri/TradfriBindingConstants.java index 63815deda64..9d948fea743 100644 --- a/extensions/binding/org.eclipse.smarthome.binding.tradfri/src/main/java/org/eclipse/smarthome/binding/tradfri/TradfriBindingConstants.java +++ b/extensions/binding/org.eclipse.smarthome.binding.tradfri/src/main/java/org/eclipse/smarthome/binding/tradfri/TradfriBindingConstants.java @@ -29,6 +29,8 @@ public class TradfriBindingConstants { public final static ThingTypeUID THING_TYPE_DIMMABLE_LIGHT = new ThingTypeUID(BINDING_ID, "0100"); public final static ThingTypeUID THING_TYPE_COLOR_TEMP_LIGHT = new ThingTypeUID(BINDING_ID, "0220"); public final static ThingTypeUID THING_TYPE_DIMMER = new ThingTypeUID(BINDING_ID, "0820"); + // Grouped lights (and maybe in the future other devices) + public final static ThingTypeUID THING_TYPE_GROUP = new ThingTypeUID(BINDING_ID, "group"); public static final Set SUPPORTED_LIGHT_TYPES_UIDS = ImmutableSet.of(THING_TYPE_DIMMABLE_LIGHT, THING_TYPE_COLOR_TEMP_LIGHT); @@ -39,6 +41,7 @@ public class TradfriBindingConstants { // List of all Channel IDs public static final String CHANNEL_BRIGHTNESS = "brightness"; public static final String CHANNEL_COLOR_TEMPERATURE = "color_temperature"; + public static final String CHANNEL_GROUP_STATE = "group_state"; // IPSO Objects public static final String DEVICES = "15001"; diff --git a/extensions/binding/org.eclipse.smarthome.binding.tradfri/src/main/java/org/eclipse/smarthome/binding/tradfri/handler/TradfriGatewayHandler.java b/extensions/binding/org.eclipse.smarthome.binding.tradfri/src/main/java/org/eclipse/smarthome/binding/tradfri/handler/TradfriGatewayHandler.java index a7f2aca47e6..9df9f1b284b 100644 --- a/extensions/binding/org.eclipse.smarthome.binding.tradfri/src/main/java/org/eclipse/smarthome/binding/tradfri/handler/TradfriGatewayHandler.java +++ b/extensions/binding/org.eclipse.smarthome.binding.tradfri/src/main/java/org/eclipse/smarthome/binding/tradfri/handler/TradfriGatewayHandler.java @@ -7,7 +7,7 @@ */ package org.eclipse.smarthome.binding.tradfri.handler; -import static org.eclipse.smarthome.binding.tradfri.TradfriBindingConstants.DEVICES; +import static org.eclipse.smarthome.binding.tradfri.TradfriBindingConstants.*; import java.io.IOException; import java.net.InetSocketAddress; @@ -48,13 +48,13 @@ * sent to one of the channels. * * @author Kai Kreuzer - Initial contribution + * @author Mario Smit - Group Handler added */ -public class TradfriGatewayHandler extends BaseBridgeHandler implements CoapCallback { +public class TradfriGatewayHandler extends BaseBridgeHandler { private final Logger logger = LoggerFactory.getLogger(TradfriGatewayHandler.class); - private TradfriCoapClient deviceClient; - private String gatewayURI; + public MyCoapCallback devices, groups; private DTLSConnector dtlsConnector; private CoapEndpoint endPoint; @@ -85,27 +85,44 @@ public void initialize() { return; } - this.gatewayURI = "coaps://" + configuration.host + ":" + configuration.port + "/" + DEVICES; + DtlsConnectorConfig.Builder builder = new DtlsConnectorConfig.Builder(new InetSocketAddress(0)); + builder.setPskStore(new StaticPskStore("", configuration.code.getBytes())); + dtlsConnector = new DTLSConnector(builder.build()); + endPoint = new CoapEndpoint(dtlsConnector, NetworkConfig.getStandard()); + + // setup DEVICES scanner + devices = new MyCoapCallback(); + devices.gatewayURI = "coaps://" + configuration.host + ":" + configuration.port + "/" + DEVICES; try { - URI uri = new URI(gatewayURI); - deviceClient = new TradfriCoapClient(uri); + URI uri = new URI(devices.gatewayURI); + devices.client = new TradfriCoapClient(uri); } catch (URISyntaxException e) { - logger.debug("Illegal gateway URI `{}`: {}", gatewayURI, e.getMessage()); + logger.debug("Illegal gateway URI `{}`: {}", devices.gatewayURI, e.getMessage()); updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, e.getMessage()); return; } + devices.client.setEndpoint(endPoint); + + // setup GROUPS scanner + groups = new MyCoapCallback(); + groups.gatewayURI = "coaps://" + configuration.host + ":" + configuration.port + "/" + GROUPS; + try { + URI uri = new URI(groups.gatewayURI); + groups.client = new TradfriCoapClient(uri); + } catch (URISyntaxException e) { + logger.debug("Illegal gateway URI `{}`: {}", groups.gatewayURI, e.getMessage()); + updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, e.getMessage()); + return; + } + groups.client.setEndpoint(endPoint); - DtlsConnectorConfig.Builder builder = new DtlsConnectorConfig.Builder(new InetSocketAddress(0)); - builder.setPskStore(new StaticPskStore("", configuration.code.getBytes())); - dtlsConnector = new DTLSConnector(builder.build()); - endPoint = new CoapEndpoint(dtlsConnector, NetworkConfig.getStandard()); - deviceClient.setEndpoint(endPoint); updateStatus(ThingStatus.UNKNOWN); // schedule a new scan every minute scanJob = scheduler.scheduleWithFixedDelay(() -> { - startScan(); - }, 0, 1, TimeUnit.MINUTES); + devices.startScan(); + groups.startScan(); + }, 0, 60, TimeUnit.SECONDS); } @Override @@ -114,9 +131,13 @@ public void dispose() { scanJob.cancel(true); scanJob = null; } - if (deviceClient != null) { - deviceClient.shutdown(); - deviceClient = null; + if (devices.client != null) { + devices.client.shutdown(); + devices.client = null; + } + if (groups.client != null) { + groups.client.shutdown(); + groups.client = null; } if (endPoint != null) { endPoint.destroy(); @@ -125,74 +146,83 @@ public void dispose() { super.dispose(); } - /** - * Does a request to the gateway to list all available devices/services. - * The response is received and processed by the method {@link onUpdate(JsonElement data)}. - */ - public void startScan() { - if (endPoint != null) { - deviceClient.get(new TradfriCoapHandler(this)); + public class MyCoapCallback implements CoapCallback { + private TradfriCoapClient client; + private String gatewayURI; + + MyCoapCallback() { + } - } - /** - * Returns the root URI of the gateway. - * - * @return root URI of the gateway with coaps scheme - */ - public String getGatewayURI() { - return gatewayURI; - } + /** + * Does a request to the gateway to list all available devices/services. + * The response is received and processed by the method {@link onUpdate(JsonElement data)}. + */ + public void startScan() { + if (endPoint != null) { + client.get(new TradfriCoapHandler(this)); + } + } - /** - * Returns the coap endpoint that can be used within coap clients. - * - * @return the coap endpoint - */ - public CoapEndpoint getEndpoint() { - return endPoint; - } + /** + * Returns the root URI of the gateway. + * + * @return root URI of the gateway with coaps scheme + */ + public String getGatewayURI() { + return gatewayURI; + } - @Override - public void onUpdate(JsonElement data) { - logger.trace("Response: {}", data); + /** + * Returns the coap endpoint that can be used within coap clients. + * + * @return the coap endpoint + */ + public CoapEndpoint getEndpoint() { + return endPoint; + } - if (endPoint != null) { - try { - JsonArray array = data.getAsJsonArray(); - for (int i = 0; i < array.size(); i++) { - requestDeviceDetails(array.get(i).getAsString()); + @Override + public void onUpdate(JsonElement data) { + logger.debug("Gateway response: {}", data); + + if (endPoint != null) { + try { + JsonArray array = data.getAsJsonArray(); + for (int i = 0; i < array.size(); i++) { + requestDeviceDetails(array.get(i).getAsString()); + } + } catch (JsonSyntaxException e) { + logger.debug("JSON error: {}", e.getMessage()); + setStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR); } - } catch (JsonSyntaxException e) { - logger.debug("JSON error: {}", e.getMessage()); - setStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR); } } - } - private void requestDeviceDetails(String instanceId) { - // we are reusing our coap client and merely temporarily set a sub-URI to call - deviceClient.setURI(gatewayURI + "/" + instanceId); - deviceClient.asyncGet().thenAccept(data -> { - logger.debug("Response: {}", data); - JsonObject json = new JsonParser().parse(data).getAsJsonObject(); - deviceUpdateListeners.forEach(listener -> listener.onUpdate(instanceId, json)); - }); - // restore root URI - deviceClient.setURI(gatewayURI); - } + private void requestDeviceDetails(String instanceId) { + // we are reusing our coap client and merely temporarily set a sub-URI to call + client.setURI(gatewayURI + "/" + instanceId); + client.asyncGet().thenAccept(data -> { + logger.debug("Response: {}", data); + JsonObject json = new JsonParser().parse(data).getAsJsonObject(); + deviceUpdateListeners.forEach(listener -> listener.onUpdate(instanceId, json)); + }); + // restore root URI + client.setURI(gatewayURI); + } - @Override - public void setStatus(ThingStatus status, ThingStatusDetail statusDetail) { - // are we still connected at all? - if (endPoint != null) { - updateStatus(status, statusDetail); - if (dtlsConnector != null && status == ThingStatus.OFFLINE) { - try { - dtlsConnector.stop(); - dtlsConnector.start(); - } catch (IOException e) { - logger.debug("Error restarting the DTLS connector: {}", e.getMessage()); + @Override + public void setStatus(ThingStatus status, ThingStatusDetail statusDetail) { + // are we still connected at all? + if (endPoint != null) { + updateStatus(status, statusDetail); + if (dtlsConnector != null && status == ThingStatus.OFFLINE) { + try { + dtlsConnector.stop(); + dtlsConnector.start(); + } catch (IOException e) { + logger.debug("Error restarting the DTLS connector: {}", e.getMessage()); + } } } } diff --git a/extensions/binding/org.eclipse.smarthome.binding.tradfri/src/main/java/org/eclipse/smarthome/binding/tradfri/handler/TradfriGroupHandler.java b/extensions/binding/org.eclipse.smarthome.binding.tradfri/src/main/java/org/eclipse/smarthome/binding/tradfri/handler/TradfriGroupHandler.java new file mode 100644 index 00000000000..378932a0cca --- /dev/null +++ b/extensions/binding/org.eclipse.smarthome.binding.tradfri/src/main/java/org/eclipse/smarthome/binding/tradfri/handler/TradfriGroupHandler.java @@ -0,0 +1,191 @@ +/** + * Copyright (c) 2014-2017 by the respective copyright holders. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + */ +package org.eclipse.smarthome.binding.tradfri.handler; + +import static org.eclipse.smarthome.binding.tradfri.TradfriBindingConstants.*; + +import java.net.URI; +import java.net.URISyntaxException; +import java.util.concurrent.TimeUnit; + +import org.eclipse.smarthome.binding.tradfri.DeviceConfig; +import org.eclipse.smarthome.binding.tradfri.internal.CoapCallback; +import org.eclipse.smarthome.binding.tradfri.internal.TradfriCoapClient; +import org.eclipse.smarthome.core.library.types.OnOffType; +import org.eclipse.smarthome.core.thing.ChannelUID; +import org.eclipse.smarthome.core.thing.Thing; +import org.eclipse.smarthome.core.thing.ThingStatus; +import org.eclipse.smarthome.core.thing.ThingStatusDetail; +import org.eclipse.smarthome.core.thing.binding.BaseThingHandler; +import org.eclipse.smarthome.core.types.Command; +import org.eclipse.smarthome.core.types.RefreshType; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonSyntaxException; + +/** + * The {@link TradfriGroupHandler} is responsible for handling commands for + * individual lights. + * + * @author Kai Kreuzer - Initial contribution + * @author Mario Smit - Group Handler added + */ +public class TradfriGroupHandler extends BaseThingHandler implements CoapCallback { + + private final Logger logger = LoggerFactory.getLogger(TradfriGroupHandler.class); + + // keeps track of the current state for handling of increase/decrease + private GroupData state; + + // the unique instance id of the light + private Integer id; + + // used to check whether we have already been disposed when receiving data asynchronously + private volatile boolean active; + + private TradfriCoapClient coapClient; + + public TradfriGroupHandler(Thing thing) { + super(thing); + } + + @Override + public synchronized void initialize() { + this.id = getConfigAs(DeviceConfig.class).id; + TradfriGatewayHandler handler = (TradfriGatewayHandler) getBridge().getHandler(); + String uriString = handler.groups.getGatewayURI() + "/" + id; + try { + URI uri = new URI(uriString); + coapClient = new TradfriCoapClient(uri); + coapClient.setEndpoint(handler.groups.getEndpoint()); + } catch (URISyntaxException e) { + logger.debug("Illegal device URI `{}`: {}", uriString, e.getMessage()); + updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, e.getMessage()); + return; + } + updateStatus(ThingStatus.UNKNOWN); + active = true; + + scheduler.schedule(() -> { + coapClient.startObserve(this); + }, 3, TimeUnit.SECONDS); + } + + @Override + public synchronized void dispose() { + active = false; + if (coapClient != null) { + coapClient.shutdown(); + } + super.dispose(); + } + + @Override + public void setStatus(ThingStatus status, ThingStatusDetail statusDetail) { + if (active && getBridge().getStatus() != ThingStatus.OFFLINE && status != ThingStatus.ONLINE) { + updateStatus(status, statusDetail); + // we are offline and lost our observe relation - let's try to establish the connection in 10 seconds again + scheduler.schedule(() -> { + coapClient.startObserve(this); + }, 10, TimeUnit.SECONDS); + } + } + + @Override + public void onUpdate(JsonElement data) { + if (active && !(data.isJsonNull())) { + state = new GroupData(data); + updateStatus(ThingStatus.ONLINE); + + if (state.getOnOffState()) { + updateState(CHANNEL_GROUP_STATE, OnOffType.ON); + } else { + updateState(CHANNEL_GROUP_STATE, OnOffType.OFF); + } + } + } + + private void set(String payload) { + logger.debug("Sending payload: {}", payload); + coapClient.asyncPut(payload, this); + } + + private void setState(OnOffType onOff) { + GroupData data = new GroupData(); + data.setOnOffState(onOff == OnOffType.ON); + set(data.getJsonString()); + } + + @Override + public void handleCommand(ChannelUID channelUID, Command command) { + if (command instanceof RefreshType) { + logger.debug("Refreshing channel {}", channelUID); + coapClient.asyncGet(this); + return; + } + + switch (channelUID.getId()) { + case CHANNEL_GROUP_STATE: + handleGroupStateCommand(command); + break; + + default: + logger.error("Unknown channel UID {}", channelUID); + } + } + + private void handleGroupStateCommand(Command command) { + if (command instanceof OnOffType) { + setState(((OnOffType) command)); + } else { + logger.debug("Cannot handle command {} for channel {}", command, CHANNEL_GROUP_STATE); + } + } + + /** + * This class is a Java wrapper for the raw JSON data about the group state. + */ + private static class GroupData { + + private final Logger logger = LoggerFactory.getLogger(GroupData.class); + + JsonObject root; + boolean ison; + + public GroupData() { + root = new JsonObject(); + } + + public GroupData(JsonElement json) { + try { + root = json.getAsJsonObject(); + ison = (root.get(ONOFF).getAsInt() == 1) ? true : false; + } catch (JsonSyntaxException e) { + logger.error("JSON error: {}", e.getMessage(), e); + } + } + + GroupData setOnOffState(boolean on) { + ison = on; + root.addProperty(ONOFF, ison ? 1 : 0); + return this; + } + + boolean getOnOffState() { + return ison; + } + + String getJsonString() { + return root.toString(); + } + } + +} diff --git a/extensions/binding/org.eclipse.smarthome.binding.tradfri/src/main/java/org/eclipse/smarthome/binding/tradfri/handler/TradfriLightHandler.java b/extensions/binding/org.eclipse.smarthome.binding.tradfri/src/main/java/org/eclipse/smarthome/binding/tradfri/handler/TradfriLightHandler.java index f8633f0348a..6c937ed7dcc 100644 --- a/extensions/binding/org.eclipse.smarthome.binding.tradfri/src/main/java/org/eclipse/smarthome/binding/tradfri/handler/TradfriLightHandler.java +++ b/extensions/binding/org.eclipse.smarthome.binding.tradfri/src/main/java/org/eclipse/smarthome/binding/tradfri/handler/TradfriLightHandler.java @@ -67,11 +67,11 @@ public TradfriLightHandler(Thing thing) { public synchronized void initialize() { this.id = getConfigAs(DeviceConfig.class).id; TradfriGatewayHandler handler = (TradfriGatewayHandler) getBridge().getHandler(); - String uriString = handler.getGatewayURI() + "/" + id; + String uriString = handler.devices.getGatewayURI() + "/" + id; try { URI uri = new URI(uriString); coapClient = new TradfriCoapClient(uri); - coapClient.setEndpoint(handler.getEndpoint()); + coapClient.setEndpoint(handler.devices.getEndpoint()); } catch (URISyntaxException e) { logger.debug("Illegal device URI `{}`: {}", uriString, e.getMessage()); updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, e.getMessage()); diff --git a/extensions/binding/org.eclipse.smarthome.binding.tradfri/src/main/java/org/eclipse/smarthome/binding/tradfri/internal/TradfriHandlerFactory.java b/extensions/binding/org.eclipse.smarthome.binding.tradfri/src/main/java/org/eclipse/smarthome/binding/tradfri/internal/TradfriHandlerFactory.java index 347c783a734..65dcb1f995e 100644 --- a/extensions/binding/org.eclipse.smarthome.binding.tradfri/src/main/java/org/eclipse/smarthome/binding/tradfri/internal/TradfriHandlerFactory.java +++ b/extensions/binding/org.eclipse.smarthome.binding.tradfri/src/main/java/org/eclipse/smarthome/binding/tradfri/internal/TradfriHandlerFactory.java @@ -16,6 +16,7 @@ import java.util.Set; import org.eclipse.smarthome.binding.tradfri.handler.TradfriGatewayHandler; +import org.eclipse.smarthome.binding.tradfri.handler.TradfriGroupHandler; import org.eclipse.smarthome.binding.tradfri.handler.TradfriLightHandler; import org.eclipse.smarthome.binding.tradfri.internal.discovery.TradfriDiscoveryService; import org.eclipse.smarthome.config.discovery.DiscoveryService; @@ -36,8 +37,9 @@ */ public class TradfriHandlerFactory extends BaseThingHandlerFactory { - private static final Set SUPPORTED_THING_TYPES_UIDS = Sets - .union(Collections.singleton(GATEWAY_TYPE_UID), SUPPORTED_LIGHT_TYPES_UIDS); + private static final Set SUPPORTED_THING_TYPES_UIDS = Sets.union( + Collections.singleton(GATEWAY_TYPE_UID), + Sets.union(SUPPORTED_LIGHT_TYPES_UIDS, Collections.singleton(THING_TYPE_GROUP))); private Map> discoveryServiceRegs = new HashMap<>(); @@ -56,6 +58,9 @@ protected ThingHandler createHandler(Thing thing) { return handler; } else if (SUPPORTED_LIGHT_TYPES_UIDS.contains(thingTypeUID)) { return new TradfriLightHandler(thing); + } else if (thingTypeUID.equals(THING_TYPE_GROUP)) { + // TODO: Construct Group Handler + return new TradfriGroupHandler(thing); } return null; } diff --git a/extensions/binding/org.eclipse.smarthome.binding.tradfri/src/main/java/org/eclipse/smarthome/binding/tradfri/internal/discovery/TradfriDiscoveryService.java b/extensions/binding/org.eclipse.smarthome.binding.tradfri/src/main/java/org/eclipse/smarthome/binding/tradfri/internal/discovery/TradfriDiscoveryService.java index 8ae55ca4faa..af21b1da194 100644 --- a/extensions/binding/org.eclipse.smarthome.binding.tradfri/src/main/java/org/eclipse/smarthome/binding/tradfri/internal/discovery/TradfriDiscoveryService.java +++ b/extensions/binding/org.eclipse.smarthome.binding.tradfri/src/main/java/org/eclipse/smarthome/binding/tradfri/internal/discovery/TradfriDiscoveryService.java @@ -10,10 +10,10 @@ import static org.eclipse.smarthome.binding.tradfri.TradfriBindingConstants.*; import java.util.Arrays; +import java.util.Collections; import java.util.HashMap; import java.util.Map; -import org.eclipse.smarthome.binding.tradfri.TradfriBindingConstants; import org.eclipse.smarthome.binding.tradfri.handler.TradfriGatewayHandler; import org.eclipse.smarthome.binding.tradfri.internal.DeviceUpdateListener; import org.eclipse.smarthome.config.discovery.AbstractDiscoveryService; @@ -23,6 +23,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import com.google.common.collect.Sets; import com.google.gson.JsonObject; import com.google.gson.JsonSyntaxException; @@ -30,6 +31,7 @@ * This class identifies devices that are available on the gateway and adds discovery results for them. * * @author Kai Kreuzer - Initial contribution + * @author Mario Smit - Group Handler added */ public class TradfriDiscoveryService extends AbstractDiscoveryService implements DeviceUpdateListener { @@ -37,17 +39,18 @@ public class TradfriDiscoveryService extends AbstractDiscoveryService implements private TradfriGatewayHandler handler; - private String[] COLOR_TEMP_MODELS = new String[] { "TRADFRI bulb E27 WS opal 980lm", - "TRADFRI bulb GU10 WS 400lm" }; + private String[] COLOR_TEMP_MODELS = new String[] { "TRADFRI bulb E27 WS opal 980lm", "TRADFRI bulb GU10 WS 400lm", + "TRADFRI bulb E14 WS opal 400lm" }; public TradfriDiscoveryService(TradfriGatewayHandler bridgeHandler) { - super(TradfriBindingConstants.SUPPORTED_LIGHT_TYPES_UIDS, 10, true); + super(Sets.union(SUPPORTED_LIGHT_TYPES_UIDS, Collections.singleton(THING_TYPE_GROUP)), 10, true); this.handler = bridgeHandler; } @Override protected void startScan() { - handler.startScan(); + handler.devices.startScan(); + handler.groups.startScan(); } public void activate() { @@ -65,23 +68,30 @@ public void onUpdate(String instanceId, JsonObject data) { try { if (data.has(INSTANCE_ID)) { int id = data.get(INSTANCE_ID).getAsInt(); - String type = data.get(TYPE).getAsString(); - JsonObject deviceInfo = data.get(DEVICE).getAsJsonObject(); - String model = deviceInfo.get(DEVICE_MODEL).getAsString(); ThingUID thingId = null; - - if (type.equals(TYPE_LIGHT) && data.has(LIGHT)) { - JsonObject state = data.get(LIGHT).getAsJsonArray().get(0).getAsJsonObject(); - - // Color temperature light - // We do not always receive a COLOR attribute, even the light supports it - but the gateway does not - // seem to have this information, if the bulb is unreachable. We therefore also check against - // concrete model names. - if (state.has(COLOR) || (model != null && Arrays.asList(COLOR_TEMP_MODELS).contains(model))) { - thingId = new ThingUID(THING_TYPE_COLOR_TEMP_LIGHT, bridge, Integer.toString(id)); - } else { - thingId = new ThingUID(THING_TYPE_DIMMABLE_LIGHT, bridge, Integer.toString(id)); + JsonObject deviceInfo = new JsonObject(); + if (data.has(TYPE)) { + String type = data.get(TYPE).getAsString(); + deviceInfo = data.get(DEVICE).getAsJsonObject(); + String model = deviceInfo.get(DEVICE_MODEL).getAsString(); + + if (type.equals(TYPE_LIGHT) && data.has(LIGHT)) { + JsonObject state = data.get(LIGHT).getAsJsonArray().get(0).getAsJsonObject(); + + // Color temperature light + // We do not always receive a COLOR attribute, even the light supports it - but the gateway does + // not + // seem to have this information, if the bulb is unreachable. We therefore also check against + // concrete model names. + if (state.has(COLOR) || (model != null && Arrays.asList(COLOR_TEMP_MODELS).contains(model))) { + thingId = new ThingUID(THING_TYPE_COLOR_TEMP_LIGHT, bridge, Integer.toString(id)); + } else { + thingId = new ThingUID(THING_TYPE_DIMMABLE_LIGHT, bridge, Integer.toString(id)); + } } + } else if (data.has(HS_ACCESSORY_LINK)) { + // GROUP info + thingId = new ThingUID(THING_TYPE_GROUP, bridge, Integer.toString(id)); } if (thingId == null) { From de202b4ac871371a821234e477e8bd22ae1edb9a Mon Sep 17 00:00:00 2001 From: Date: Sun, 9 Jul 2017 11:18:36 +0200 Subject: [PATCH 2/2] Couple of changes requested by sjka under id: #3799 Signed-off-by: mario.smit.nl@gmail.com --- .../handler/TradfriGatewayHandler.java | 63 +++++++++---------- .../internal/TradfriHandlerFactory.java | 1 - 2 files changed, 31 insertions(+), 33 deletions(-) diff --git a/extensions/binding/org.eclipse.smarthome.binding.tradfri/src/main/java/org/eclipse/smarthome/binding/tradfri/handler/TradfriGatewayHandler.java b/extensions/binding/org.eclipse.smarthome.binding.tradfri/src/main/java/org/eclipse/smarthome/binding/tradfri/handler/TradfriGatewayHandler.java index 9df9f1b284b..0cfb5cbfa61 100644 --- a/extensions/binding/org.eclipse.smarthome.binding.tradfri/src/main/java/org/eclipse/smarthome/binding/tradfri/handler/TradfriGatewayHandler.java +++ b/extensions/binding/org.eclipse.smarthome.binding.tradfri/src/main/java/org/eclipse/smarthome/binding/tradfri/handler/TradfriGatewayHandler.java @@ -54,7 +54,7 @@ public class TradfriGatewayHandler extends BaseBridgeHandler { private final Logger logger = LoggerFactory.getLogger(TradfriGatewayHandler.class); - public MyCoapCallback devices, groups; + public TradfriCoapCallback devices, groups; private DTLSConnector dtlsConnector; private CoapEndpoint endPoint; @@ -91,51 +91,54 @@ public void initialize() { endPoint = new CoapEndpoint(dtlsConnector, NetworkConfig.getStandard()); // setup DEVICES scanner - devices = new MyCoapCallback(); - devices.gatewayURI = "coaps://" + configuration.host + ":" + configuration.port + "/" + DEVICES; - try { - URI uri = new URI(devices.gatewayURI); - devices.client = new TradfriCoapClient(uri); - } catch (URISyntaxException e) { - logger.debug("Illegal gateway URI `{}`: {}", devices.gatewayURI, e.getMessage()); - updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, e.getMessage()); - return; + devices = setupScanner("coaps://" + configuration.host + ":" + configuration.port + "/" + DEVICES); + if (devices == null) { + logger.debug("Unable to scan for Tradfri DEVICES"); } - devices.client.setEndpoint(endPoint); - - // setup GROUPS scanner - groups = new MyCoapCallback(); - groups.gatewayURI = "coaps://" + configuration.host + ":" + configuration.port + "/" + GROUPS; - try { - URI uri = new URI(groups.gatewayURI); - groups.client = new TradfriCoapClient(uri); - } catch (URISyntaxException e) { - logger.debug("Illegal gateway URI `{}`: {}", groups.gatewayURI, e.getMessage()); - updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, e.getMessage()); - return; + groups = setupScanner("coaps://" + configuration.host + ":" + configuration.port + "/" + GROUPS); + if (groups == null) { + logger.debug("Unable to scan for Tradfri GROUPS"); } - groups.client.setEndpoint(endPoint); updateStatus(ThingStatus.UNKNOWN); // schedule a new scan every minute scanJob = scheduler.scheduleWithFixedDelay(() -> { - devices.startScan(); - groups.startScan(); + if (devices != null) { + devices.startScan(); + } + if (groups != null) { + groups.startScan(); + } }, 0, 60, TimeUnit.SECONDS); } + TradfriCoapCallback setupScanner(String url) { + TradfriCoapCallback scanner = new TradfriCoapCallback(); + scanner.gatewayURI = url; + try { + URI uri = new URI(scanner.gatewayURI); + scanner.client = new TradfriCoapClient(uri); + } catch (URISyntaxException e) { + logger.debug("Illegal gateway URI `{}`: {}", scanner.gatewayURI, e.getMessage()); + updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, e.getMessage()); + return null; + } + scanner.client.setEndpoint(endPoint); + return scanner; + } + @Override public void dispose() { if (scanJob != null) { scanJob.cancel(true); scanJob = null; } - if (devices.client != null) { + if (devices != null && devices.client != null) { devices.client.shutdown(); devices.client = null; } - if (groups.client != null) { + if (groups != null && groups.client != null) { groups.client.shutdown(); groups.client = null; } @@ -146,14 +149,10 @@ public void dispose() { super.dispose(); } - public class MyCoapCallback implements CoapCallback { + public class TradfriCoapCallback implements CoapCallback { private TradfriCoapClient client; private String gatewayURI; - MyCoapCallback() { - - } - /** * Does a request to the gateway to list all available devices/services. * The response is received and processed by the method {@link onUpdate(JsonElement data)}. diff --git a/extensions/binding/org.eclipse.smarthome.binding.tradfri/src/main/java/org/eclipse/smarthome/binding/tradfri/internal/TradfriHandlerFactory.java b/extensions/binding/org.eclipse.smarthome.binding.tradfri/src/main/java/org/eclipse/smarthome/binding/tradfri/internal/TradfriHandlerFactory.java index 65dcb1f995e..1e39e028d2f 100644 --- a/extensions/binding/org.eclipse.smarthome.binding.tradfri/src/main/java/org/eclipse/smarthome/binding/tradfri/internal/TradfriHandlerFactory.java +++ b/extensions/binding/org.eclipse.smarthome.binding.tradfri/src/main/java/org/eclipse/smarthome/binding/tradfri/internal/TradfriHandlerFactory.java @@ -59,7 +59,6 @@ protected ThingHandler createHandler(Thing thing) { } else if (SUPPORTED_LIGHT_TYPES_UIDS.contains(thingTypeUID)) { return new TradfriLightHandler(thing); } else if (thingTypeUID.equals(THING_TYPE_GROUP)) { - // TODO: Construct Group Handler return new TradfriGroupHandler(thing); } return null;