From 179b2023293d280e9067ab40f3b241c09a23937e Mon Sep 17 00:00:00 2001 From: Christoph Weitkamp Date: Fri, 3 Nov 2017 15:20:07 +0100 Subject: [PATCH] [Tradfri] Added support for remote controller and motion sensor devices (#4373) * Added support for remote controller and motion sensor devices (read-only, battery level) * Restructuring and refactoring of classes * Moved some config classes to internal package Signed-off-by: Christoph Weitkamp --- .../core/thing/binding/BaseThingHandler.java | 4 +- .../META-INF/MANIFEST.MF | 2 +- .../pom.xml | 2 +- .../binding/tradfri/TradfriHandlerTest.java | 35 ++- .../TradfriDiscoveryParticipantOSGITest.java | 15 +- .../TradfriDiscoveryServiceTest.java | 122 ++++++-- .../ESH-INF/config/config.xml | 23 +- .../ESH-INF/i18n/tradfri_de.properties | 22 +- .../ESH-INF/thing/thing-types.xml | 62 ++-- .../README.md | 61 ++-- .../tradfri/TradfriBindingConstants.java | 18 +- .../handler/TradfriControllerHandler.java | 76 +++++ .../handler/TradfriGatewayHandler.java | 23 +- .../tradfri/handler/TradfriLightHandler.java | 292 +----------------- .../tradfri/handler/TradfriSensorHandler.java | 76 +++++ .../tradfri/handler/TradfriThingHandler.java | 124 ++++++++ .../tradfri/internal/TradfriCoapClient.java | 1 - .../internal/TradfriHandlerFactory.java | 13 +- .../config/TradfriDeviceConfig.java} | 8 +- .../config/TradfriGatewayConfig.java} | 10 +- .../TradfriDiscoveryParticipant.java | 21 +- .../discovery/TradfriDiscoveryService.java | 28 +- .../internal/model/TradfriControllerData.java | 29 ++ .../internal/model/TradfriDeviceData.java | 91 ++++++ .../internal/model/TradfriLightData.java | 133 ++++++++ .../internal/model/TradfriSensorData.java | 29 ++ .../model/TradfriWirelessDeviceData.java | 51 +++ 27 files changed, 964 insertions(+), 407 deletions(-) create mode 100644 extensions/binding/org.eclipse.smarthome.binding.tradfri/src/main/java/org/eclipse/smarthome/binding/tradfri/handler/TradfriControllerHandler.java create mode 100644 extensions/binding/org.eclipse.smarthome.binding.tradfri/src/main/java/org/eclipse/smarthome/binding/tradfri/handler/TradfriSensorHandler.java create mode 100644 extensions/binding/org.eclipse.smarthome.binding.tradfri/src/main/java/org/eclipse/smarthome/binding/tradfri/handler/TradfriThingHandler.java rename extensions/binding/org.eclipse.smarthome.binding.tradfri/src/main/java/org/eclipse/smarthome/binding/tradfri/{DeviceConfig.java => internal/config/TradfriDeviceConfig.java} (71%) rename extensions/binding/org.eclipse.smarthome.binding.tradfri/src/main/java/org/eclipse/smarthome/binding/tradfri/{GatewayConfig.java => internal/config/TradfriGatewayConfig.java} (66%) create mode 100644 extensions/binding/org.eclipse.smarthome.binding.tradfri/src/main/java/org/eclipse/smarthome/binding/tradfri/internal/model/TradfriControllerData.java create mode 100644 extensions/binding/org.eclipse.smarthome.binding.tradfri/src/main/java/org/eclipse/smarthome/binding/tradfri/internal/model/TradfriDeviceData.java create mode 100644 extensions/binding/org.eclipse.smarthome.binding.tradfri/src/main/java/org/eclipse/smarthome/binding/tradfri/internal/model/TradfriLightData.java create mode 100644 extensions/binding/org.eclipse.smarthome.binding.tradfri/src/main/java/org/eclipse/smarthome/binding/tradfri/internal/model/TradfriSensorData.java create mode 100644 extensions/binding/org.eclipse.smarthome.binding.tradfri/src/main/java/org/eclipse/smarthome/binding/tradfri/internal/model/TradfriWirelessDeviceData.java diff --git a/bundles/core/org.eclipse.smarthome.core.thing/src/main/java/org/eclipse/smarthome/core/thing/binding/BaseThingHandler.java b/bundles/core/org.eclipse.smarthome.core.thing/src/main/java/org/eclipse/smarthome/core/thing/binding/BaseThingHandler.java index 99c0809cec2..45f8e4e0c8f 100644 --- a/bundles/core/org.eclipse.smarthome.core.thing/src/main/java/org/eclipse/smarthome/core/thing/binding/BaseThingHandler.java +++ b/bundles/core/org.eclipse.smarthome.core.thing/src/main/java/org/eclipse/smarthome/core/thing/binding/BaseThingHandler.java @@ -142,8 +142,8 @@ public void handleConfigurationUpdate(Map configurationParameter // can be overridden by subclasses Configuration configuration = editConfiguration(); - for (Entry configurationParmeter : configurationParameters.entrySet()) { - configuration.put(configurationParmeter.getKey(), configurationParmeter.getValue()); + for (Entry configurationParameter : configurationParameters.entrySet()) { + configuration.put(configurationParameter.getKey(), configurationParameter.getValue()); } if (isInitialized()) { diff --git a/extensions/binding/org.eclipse.smarthome.binding.tradfri.test/META-INF/MANIFEST.MF b/extensions/binding/org.eclipse.smarthome.binding.tradfri.test/META-INF/MANIFEST.MF index 402e17a5754..c72838e0ce5 100644 --- a/extensions/binding/org.eclipse.smarthome.binding.tradfri.test/META-INF/MANIFEST.MF +++ b/extensions/binding/org.eclipse.smarthome.binding.tradfri.test/META-INF/MANIFEST.MF @@ -1,6 +1,6 @@ Manifest-Version: 1.0 Bundle-ManifestVersion: 2 -Bundle-Name: Tradfri Binding Tests +Bundle-Name: TRÃ…DFRI Binding Tests Bundle-RequiredExecutionEnvironment: JavaSE-1.8 Bundle-SymbolicName: org.eclipse.smarthome.binding.tradfri.test;singleto n:=true diff --git a/extensions/binding/org.eclipse.smarthome.binding.tradfri.test/pom.xml b/extensions/binding/org.eclipse.smarthome.binding.tradfri.test/pom.xml index 9e9ba2b4838..665bf86681a 100644 --- a/extensions/binding/org.eclipse.smarthome.binding.tradfri.test/pom.xml +++ b/extensions/binding/org.eclipse.smarthome.binding.tradfri.test/pom.xml @@ -14,7 +14,7 @@ 0.9.0-SNAPSHOT eclipse-test-plugin - Tradfri Binding Tests + TRÃ…DFRI Binding Tests org.eclipse.smarthome.binding.tradfri.test diff --git a/extensions/binding/org.eclipse.smarthome.binding.tradfri.test/src/test/java/org/eclipse/smarthome/binding/tradfri/TradfriHandlerTest.java b/extensions/binding/org.eclipse.smarthome.binding.tradfri.test/src/test/java/org/eclipse/smarthome/binding/tradfri/TradfriHandlerTest.java index be195b45e40..0946363b4da 100644 --- a/extensions/binding/org.eclipse.smarthome.binding.tradfri.test/src/test/java/org/eclipse/smarthome/binding/tradfri/TradfriHandlerTest.java +++ b/extensions/binding/org.eclipse.smarthome.binding.tradfri.test/src/test/java/org/eclipse/smarthome/binding/tradfri/TradfriHandlerTest.java @@ -7,6 +7,9 @@ */ package org.eclipse.smarthome.binding.tradfri; +import static org.eclipse.smarthome.binding.tradfri.TradfriBindingConstants.*; +import static org.eclipse.smarthome.binding.tradfri.internal.config.TradfriDeviceConfig.*; +import static org.eclipse.smarthome.binding.tradfri.internal.config.TradfriGatewayConfig.*; import static org.hamcrest.CoreMatchers.*; import static org.hamcrest.core.Is.is; import static org.junit.Assert.assertThat; @@ -46,14 +49,15 @@ public void setUp() { managedThingProvider = getService(ThingProvider.class, ManagedThingProvider.class); Map properties = new HashMap<>(); - properties.put(GatewayConfig.HOST, "1.2.3.4"); - properties.put(GatewayConfig.CODE, "abc"); - bridge = BridgeBuilder.create(TradfriBindingConstants.GATEWAY_TYPE_UID, "1").withLabel("My Gateway") + properties.put(CONFIG_HOST, "1.2.3.4"); + properties.put(CONFIG_CODE, "abc"); + bridge = BridgeBuilder.create(GATEWAY_TYPE_UID, "1").withLabel("My Gateway") .withConfiguration(new Configuration(properties)).build(); + properties = new HashMap<>(); - properties.put(DeviceConfig.ID, "65537"); - thing = ThingBuilder.create(TradfriBindingConstants.THING_TYPE_DIMMABLE_LIGHT, "1").withLabel("My Bulb") - .withBridge(bridge.getUID()).withConfiguration(new Configuration(properties)).build(); + properties.put(CONFIG_ID, "65537"); + thing = ThingBuilder.create(THING_TYPE_DIMMABLE_LIGHT, "1").withLabel("My Bulb").withBridge(bridge.getUID()) + .withConfiguration(new Configuration(properties)).build(); } @After @@ -68,6 +72,16 @@ public void creationOfTradfriGatewayHandler() { assertThat(bridge.getHandler(), is(nullValue())); managedThingProvider.add(bridge); waitForAssert(() -> assertThat(bridge.getHandler(), notNullValue())); + + configurationOfTradfriGatewayHandler(); + } + + private void configurationOfTradfriGatewayHandler() { + Configuration configuration = bridge.getConfiguration(); + assertThat(configuration, is(notNullValue())); + + assertThat(configuration.get(CONFIG_HOST), is("1.2.3.4")); + assertThat(configuration.get(CONFIG_CODE), is("abc")); } @Test @@ -76,5 +90,14 @@ public void creationOfTradfriLightHandler() { managedThingProvider.add(bridge); managedThingProvider.add(thing); waitForAssert(() -> assertThat(thing.getHandler(), notNullValue())); + + configurationOfTradfriLightHandler(); + } + + private void configurationOfTradfriLightHandler() { + Configuration configuration = thing.getConfiguration(); + assertThat(configuration, is(notNullValue())); + + assertThat(configuration.get(CONFIG_ID), is("65537")); } } diff --git a/extensions/binding/org.eclipse.smarthome.binding.tradfri.test/src/test/java/org/eclipse/smarthome/binding/tradfri/discovery/TradfriDiscoveryParticipantOSGITest.java b/extensions/binding/org.eclipse.smarthome.binding.tradfri.test/src/test/java/org/eclipse/smarthome/binding/tradfri/discovery/TradfriDiscoveryParticipantOSGITest.java index 442c2994fdc..f8f3788e680 100644 --- a/extensions/binding/org.eclipse.smarthome.binding.tradfri.test/src/test/java/org/eclipse/smarthome/binding/tradfri/discovery/TradfriDiscoveryParticipantOSGITest.java +++ b/extensions/binding/org.eclipse.smarthome.binding.tradfri.test/src/test/java/org/eclipse/smarthome/binding/tradfri/discovery/TradfriDiscoveryParticipantOSGITest.java @@ -7,6 +7,8 @@ */ package org.eclipse.smarthome.binding.tradfri.discovery; +import static org.eclipse.smarthome.binding.tradfri.TradfriBindingConstants.*; +import static org.eclipse.smarthome.binding.tradfri.internal.config.TradfriGatewayConfig.*; import static org.hamcrest.CoreMatchers.*; import static org.junit.Assert.*; import static org.mockito.Mockito.when; @@ -14,8 +16,6 @@ import javax.jmdns.ServiceInfo; -import org.eclipse.smarthome.binding.tradfri.GatewayConfig; -import org.eclipse.smarthome.binding.tradfri.TradfriBindingConstants; import org.eclipse.smarthome.binding.tradfri.internal.discovery.TradfriDiscoveryParticipant; import org.eclipse.smarthome.config.discovery.DiscoveryResult; import org.eclipse.smarthome.config.discovery.DiscoveryResultFlag; @@ -63,8 +63,7 @@ public void setUp() { @Test public void correctSupportedTypes() { assertThat(discoveryParticipant.getSupportedThingTypeUIDs().size(), is(1)); - assertThat(discoveryParticipant.getSupportedThingTypeUIDs().iterator().next(), - is(TradfriBindingConstants.GATEWAY_TYPE_UID)); + assertThat(discoveryParticipant.getSupportedThingTypeUIDs().iterator().next(), is(GATEWAY_TYPE_UID)); } @Test @@ -81,12 +80,12 @@ public void validDiscoveryResult() { assertThat(result.getProperties().get(Thing.PROPERTY_FIRMWARE_VERSION), is("1.1")); assertThat(result.getFlag(), is(DiscoveryResultFlag.NEW)); assertThat(result.getThingUID(), is(new ThingUID("tradfri:gateway:gw1234567890ab"))); - assertThat(result.getThingTypeUID(), is(TradfriBindingConstants.GATEWAY_TYPE_UID)); + assertThat(result.getThingTypeUID(), is(GATEWAY_TYPE_UID)); assertThat(result.getBridgeUID(), is(nullValue())); assertThat(result.getProperties().get(Thing.PROPERTY_VENDOR), is("IKEA of Sweden")); - assertThat(result.getProperties().get(GatewayConfig.HOST), is("192.168.0.5")); - assertThat(result.getProperties().get(GatewayConfig.PORT), is(1234)); - assertThat(result.getRepresentationProperty(), is(GatewayConfig.HOST)); + assertThat(result.getProperties().get(CONFIG_HOST), is("192.168.0.5")); + assertThat(result.getProperties().get(CONFIG_PORT), is(1234)); + assertThat(result.getRepresentationProperty(), is(CONFIG_HOST)); } @Test diff --git a/extensions/binding/org.eclipse.smarthome.binding.tradfri.test/src/test/java/org/eclipse/smarthome/binding/tradfri/discovery/TradfriDiscoveryServiceTest.java b/extensions/binding/org.eclipse.smarthome.binding.tradfri.test/src/test/java/org/eclipse/smarthome/binding/tradfri/discovery/TradfriDiscoveryServiceTest.java index 4e7315c1a50..b79f6c67691 100644 --- a/extensions/binding/org.eclipse.smarthome.binding.tradfri.test/src/test/java/org/eclipse/smarthome/binding/tradfri/discovery/TradfriDiscoveryServiceTest.java +++ b/extensions/binding/org.eclipse.smarthome.binding.tradfri.test/src/test/java/org/eclipse/smarthome/binding/tradfri/discovery/TradfriDiscoveryServiceTest.java @@ -7,6 +7,8 @@ */ package org.eclipse.smarthome.binding.tradfri.discovery; +import static org.eclipse.smarthome.binding.tradfri.TradfriBindingConstants.*; +import static org.eclipse.smarthome.binding.tradfri.internal.config.TradfriDeviceConfig.*; import static org.hamcrest.CoreMatchers.is; import static org.junit.Assert.*; import static org.mockito.Mockito.when; @@ -14,8 +16,6 @@ import java.util.Collection; -import org.eclipse.smarthome.binding.tradfri.DeviceConfig; -import org.eclipse.smarthome.binding.tradfri.TradfriBindingConstants; import org.eclipse.smarthome.binding.tradfri.handler.TradfriGatewayHandler; import org.eclipse.smarthome.binding.tradfri.internal.discovery.TradfriDiscoveryService; import org.eclipse.smarthome.config.discovery.DiscoveryListener; @@ -37,9 +37,12 @@ * Tests for {@link TradfriDiscoveryService}. * * @author Kai Kreuzer - Initial contribution + * @author Christoph Weitkamp - Added support for remote controller and motion sensor devices (read-only battery level) */ public class TradfriDiscoveryServiceTest { + private static final ThingUID GATEWAY_THING_UID = new ThingUID("tradfri:gateway:1"); + @Mock private TradfriGatewayHandler handler; @@ -51,8 +54,7 @@ public class TradfriDiscoveryServiceTest { @Before public void setUp() { initMocks(this); - when(handler.getThing()) - .thenReturn(BridgeBuilder.create(TradfriBindingConstants.GATEWAY_TYPE_UID, "1").build()); + when(handler.getThing()).thenReturn(BridgeBuilder.create(GATEWAY_TYPE_UID, "1").build()); discovery = new TradfriDiscoveryService(handler); listener = new DiscoveryListener() { @@ -81,15 +83,52 @@ public void cleanUp() { @Test public void correctSupportedTypes() { - assertThat(discovery.getSupportedThingTypes().size(), is(3)); - assertTrue(discovery.getSupportedThingTypes().contains(TradfriBindingConstants.THING_TYPE_DIMMABLE_LIGHT)); - assertTrue(discovery.getSupportedThingTypes().contains(TradfriBindingConstants.THING_TYPE_COLOR_TEMP_LIGHT)); - assertTrue(discovery.getSupportedThingTypes().contains(TradfriBindingConstants.THING_TYPE_COLOR_LIGHT)); + assertThat(discovery.getSupportedThingTypes().size(), is(6)); + assertTrue(discovery.getSupportedThingTypes().contains(THING_TYPE_DIMMABLE_LIGHT)); + assertTrue(discovery.getSupportedThingTypes().contains(THING_TYPE_COLOR_TEMP_LIGHT)); + assertTrue(discovery.getSupportedThingTypes().contains(THING_TYPE_COLOR_LIGHT)); + assertTrue(discovery.getSupportedThingTypes().contains(THING_TYPE_DIMMER)); + assertTrue(discovery.getSupportedThingTypes().contains(THING_TYPE_MOTION_SENSOR)); + assertTrue(discovery.getSupportedThingTypes().contains(THING_TYPE_REMOTE_CONTROL)); + } + + @Test + public void validDiscoveryResultWhiteLightW() { + String json = "{\"9001\":\"TRADFRI bulb E27 W opal 1000lm\",\"9002\":1492856270,\"9020\":1507194357,\"9003\":65537,\"3311\":[{\"5850\":1,\"5851\":254,\"9003\":0}],\"9054\":0,\"5750\":2,\"9019\":1,\"3\":{\"0\":\"IKEA of Sweden\",\"1\":\"TRADFRI bulb E27 W opal 1000lm\",\"2\":\"\",\"3\":\"1.2.214\",\"6\":1}}"; + JsonObject data = new JsonParser().parse(json).getAsJsonObject(); + + discovery.onUpdate("65537", data); + + assertNotNull(discoveryResult); + assertThat(discoveryResult.getFlag(), is(DiscoveryResultFlag.NEW)); + assertThat(discoveryResult.getThingUID(), is(new ThingUID("tradfri:0100:1:65537"))); + assertThat(discoveryResult.getThingTypeUID(), is(THING_TYPE_DIMMABLE_LIGHT)); + assertThat(discoveryResult.getBridgeUID(), is(GATEWAY_THING_UID)); + assertThat(discoveryResult.getProperties().get(CONFIG_ID), is(65537)); + assertThat(discoveryResult.getRepresentationProperty(), is(CONFIG_ID)); + } + + @Test + public void validDiscoveryResultWhiteLightWS() { + String json = "{\"9001\":\"TRADFRI bulb E27 WS opal 980lm\",\"9002\":1492955148,\"9020\":1507200447,\"9003\":65537,\"3311\":[{\"5710\":26909,\"5850\":1,\"5851\":203,\"5707\":0,\"5708\":0,\"5709\":30140,\"5711\":370,\"5706\":\"f1e0b5\",\"9003\":0}],\"9054\":0,\"5750\":2,\"9019\":1,\"3\":{\"0\":\"IKEA of Sweden\",\"1\":\"TRADFRI bulb E27 WS opal 980lm\",\"2\":\"\",\"3\":\"1.2.217\",\"6\":1}}"; + JsonObject data = new JsonParser().parse(json).getAsJsonObject(); + + discovery.onUpdate("65537", data); + + assertNotNull(discoveryResult); + assertThat(discoveryResult.getFlag(), is(DiscoveryResultFlag.NEW)); + assertThat(discoveryResult.getThingUID(), is(new ThingUID("tradfri:0220:1:65537"))); + assertThat(discoveryResult.getThingTypeUID(), is(THING_TYPE_COLOR_TEMP_LIGHT)); + assertThat(discoveryResult.getBridgeUID(), is(GATEWAY_THING_UID)); + assertThat(discoveryResult.getProperties().get(CONFIG_ID), is(65537)); + assertThat(discoveryResult.getRepresentationProperty(), is(CONFIG_ID)); } @Test - public void validDiscoveryResult() { - String json = "{\"9054\":0,\"9001\":\"LR\",\"5750\":2,\"9002\":1490983446,\"9020\":1491055861,\"9003\":65537,\"9019\":1,\"3\":{\"1\":\"TRADFRI bulb E27 WS opal 980lm\",\"0\":\"IKEA of Sweden\",\"2\":\"\",\"3\":\"1.1.1.1-5.7.2.0\",\"6\":1},\"3311\":[{\"5850\":1,\"5851\":254,\"5707\":0,\"5708\":0,\"5709\":33135,\"5710\":27211,\"9003\":0,\"5711\":0,\"5706\":\"efd275\"}]}"; + public void validDiscoveryResultWhiteLightWSWithIncompleteJson() { + // We do not always receive a COLOR = "5706" attribute, even the light supports it - but the gateway does not + // seem to have this information, if the bulb is unreachable. + String json = "{\"9001\":\"TRADFRI bulb E27 WS opal 980lm\",\"9002\":1492955148,\"9020\":1506968670,\"9003\":65537,\"3311\":[{\"9003\":0}],\"9054\":0,\"5750\":2,\"9019\":0,\"3\":{\"0\":\"IKEA of Sweden\",\"1\":\"TRADFRI bulb E27 WS opal 980lm\",\"2\":\"\",\"3\":\"1.2.217\",\"6\":1}}"; JsonObject data = new JsonParser().parse(json).getAsJsonObject(); discovery.onUpdate("65537", data); @@ -97,10 +136,10 @@ public void validDiscoveryResult() { assertNotNull(discoveryResult); assertThat(discoveryResult.getFlag(), is(DiscoveryResultFlag.NEW)); assertThat(discoveryResult.getThingUID(), is(new ThingUID("tradfri:0220:1:65537"))); - assertThat(discoveryResult.getThingTypeUID(), is(TradfriBindingConstants.THING_TYPE_COLOR_TEMP_LIGHT)); - assertThat(discoveryResult.getBridgeUID(), is(new ThingUID("tradfri:gateway:1"))); - assertThat(discoveryResult.getProperties().get(DeviceConfig.ID), is(65537)); - assertThat(discoveryResult.getRepresentationProperty(), is(DeviceConfig.ID)); + assertThat(discoveryResult.getThingTypeUID(), is(THING_TYPE_COLOR_TEMP_LIGHT)); + assertThat(discoveryResult.getBridgeUID(), is(GATEWAY_THING_UID)); + assertThat(discoveryResult.getProperties().get(CONFIG_ID), is(65537)); + assertThat(discoveryResult.getRepresentationProperty(), is(CONFIG_ID)); } @Test @@ -113,10 +152,57 @@ public void validDiscoveryResultColorLightCWS() { assertNotNull(discoveryResult); assertThat(discoveryResult.getFlag(), is(DiscoveryResultFlag.NEW)); assertThat(discoveryResult.getThingUID(), is(new ThingUID("tradfri:0210:1:65550"))); - assertThat(discoveryResult.getThingTypeUID(), is(TradfriBindingConstants.THING_TYPE_COLOR_LIGHT)); - assertThat(discoveryResult.getBridgeUID(), is(new ThingUID("tradfri:gateway:1"))); - assertThat(discoveryResult.getProperties().get(DeviceConfig.ID), is(65550)); - assertThat(discoveryResult.getRepresentationProperty(), is(DeviceConfig.ID)); + assertThat(discoveryResult.getThingTypeUID(), is(THING_TYPE_COLOR_LIGHT)); + assertThat(discoveryResult.getBridgeUID(), is(GATEWAY_THING_UID)); + assertThat(discoveryResult.getProperties().get(CONFIG_ID), is(65550)); + assertThat(discoveryResult.getRepresentationProperty(), is(CONFIG_ID)); } + @Test + public void validDiscoveryResultRemoteControl() { + String json = "{\"9001\":\"TRADFRI remote control\",\"9002\":1492843083,\"9020\":1506977986,\"9003\":65536,\"9054\":0,\"5750\":0,\"9019\":1,\"3\":{\"0\":\"IKEA of Sweden\",\"1\":\"TRADFRI remote control\",\"2\":\"\",\"3\":\"1.2.214\",\"6\":3,\"9\":47},\"15009\":[{\"9003\":0}]}"; + JsonObject data = new JsonParser().parse(json).getAsJsonObject(); + + discovery.onUpdate("65536", data); + + assertNotNull(discoveryResult); + assertThat(discoveryResult.getFlag(), is(DiscoveryResultFlag.NEW)); + assertThat(discoveryResult.getThingUID(), is(new ThingUID("tradfri:0830:1:65536"))); + assertThat(discoveryResult.getThingTypeUID(), is(THING_TYPE_REMOTE_CONTROL)); + assertThat(discoveryResult.getBridgeUID(), is(GATEWAY_THING_UID)); + assertThat(discoveryResult.getProperties().get(CONFIG_ID), is(65536)); + assertThat(discoveryResult.getRepresentationProperty(), is(CONFIG_ID)); + } + + @Test + public void validDiscoveryResultWirelessDimmer() { + String json = "{\"9001\":\"TRADFRI wireless dimmer\",\"9002\":1492843083,\"9020\":1506977986,\"9003\":65536,\"9054\":0,\"5750\":0,\"9019\":1,\"3\":{\"0\":\"IKEA of Sweden\",\"1\":\"TRADFRI wireless dimmer\",\"2\":\"\",\"3\":\"1.2.214\",\"6\":3,\"9\":47},\"15009\":[{\"9003\":0}]}"; + JsonObject data = new JsonParser().parse(json).getAsJsonObject(); + + discovery.onUpdate("65536", data); + + assertNotNull(discoveryResult); + assertThat(discoveryResult.getFlag(), is(DiscoveryResultFlag.NEW)); + assertThat(discoveryResult.getThingUID(), is(new ThingUID("tradfri:0820:1:65536"))); + assertThat(discoveryResult.getThingTypeUID(), is(THING_TYPE_DIMMER)); + assertThat(discoveryResult.getBridgeUID(), is(GATEWAY_THING_UID)); + assertThat(discoveryResult.getProperties().get(CONFIG_ID), is(65536)); + assertThat(discoveryResult.getRepresentationProperty(), is(CONFIG_ID)); + } + + @Test + public void validDiscoveryResultMotionSensor() { + String json = "{\"9001\":\"TRADFRI motion sensor\",\"9002\":1492955083,\"9020\":1507120083,\"9003\":65538,\"9054\":0,\"5750\":4,\"9019\":1,\"3\":{\"0\":\"IKEA of Sweden\",\"1\":\"TRADFRI motion sensor\",\"2\":\"\",\"3\":\"1.2.214\",\"6\":3,\"9\":60},\"3300\":[{\"9003\":0}]}"; + JsonObject data = new JsonParser().parse(json).getAsJsonObject(); + + discovery.onUpdate("65538", data); + + assertNotNull(discoveryResult); + assertThat(discoveryResult.getFlag(), is(DiscoveryResultFlag.NEW)); + assertThat(discoveryResult.getThingUID(), is(new ThingUID("tradfri:0107:1:65538"))); + assertThat(discoveryResult.getThingTypeUID(), is(THING_TYPE_MOTION_SENSOR)); + assertThat(discoveryResult.getBridgeUID(), is(GATEWAY_THING_UID)); + assertThat(discoveryResult.getProperties().get(CONFIG_ID), is(65538)); + assertThat(discoveryResult.getRepresentationProperty(), is(CONFIG_ID)); + } } diff --git a/extensions/binding/org.eclipse.smarthome.binding.tradfri/ESH-INF/config/config.xml b/extensions/binding/org.eclipse.smarthome.binding.tradfri/ESH-INF/config/config.xml index 1a5b6e3a9c6..6418c8230ec 100644 --- a/extensions/binding/org.eclipse.smarthome.binding.tradfri/ESH-INF/config/config.xml +++ b/extensions/binding/org.eclipse.smarthome.binding.tradfri/ESH-INF/config/config.xml @@ -1,8 +1,27 @@ - + + + network-address + + Hostname or IP address of the IKEA TRÃ…DFRI gateway + + + + Port for accessing the gateway + true + 5684 + + + password + + Security code printed on the label underneath the gateway. + + + diff --git a/extensions/binding/org.eclipse.smarthome.binding.tradfri/ESH-INF/i18n/tradfri_de.properties b/extensions/binding/org.eclipse.smarthome.binding.tradfri/ESH-INF/i18n/tradfri_de.properties index 1e9bc2e9044..8ca91643363 100644 --- a/extensions/binding/org.eclipse.smarthome.binding.tradfri/ESH-INF/i18n/tradfri_de.properties +++ b/extensions/binding/org.eclipse.smarthome.binding.tradfri/ESH-INF/i18n/tradfri_de.properties @@ -7,12 +7,12 @@ thing-type.tradfri.gateway.label = TR thing-type.tradfri.gateway.description = IKEA TRÅDFRI Gateway/zentrale Steuereinheit. # bridge type configuration -thing-type.config.tradfri.gateway.host.label = IP-Adresse -thing-type.config.tradfri.gateway.host.description = Lokale IP-Adresse oder Hostname des TRÅDFRI Gateway. -thing-type.config.tradfri.gateway.port.label = Port -thing-type.config.tradfri.gateway.port.description = Port des TRÅDFRI Gateway. -thing-type.config.tradfri.gateway.code.label = Security Code -thing-type.config.tradfri.gateway.code.description = Security Code zur Authentifizierung am TRÅDFRI Gateway. Befindet sich unterhalb des TRÅDFRI Gateway. +bridge-type.config.tradfri.gateway.host.label = IP-Adresse +bridge-type.config.tradfri.gateway.host.description = Lokale IP-Adresse oder Hostname des TRÅDFRI Gateway. +bridge-type.config.tradfri.gateway.port.label = Port +bridge-type.config.tradfri.gateway.port.description = Port des TRÅDFRI Gateway. +bridge-type.config.tradfri.gateway.code.label = Security Code +bridge-type.config.tradfri.gateway.code.description = Security Code zur Authentifizierung am TRÅDFRI Gateway. Befindet sich unterhalb des TRÅDFRI Gateway. # thing types thing-type.tradfri.0100.label = Dimmbare Lampe (weiß) @@ -21,10 +21,16 @@ thing-type.tradfri.0210.label = Farbspektrum Lampe thing-type.tradfri.0210.description = Dimmbare Lampe mit einstellbarer Farbe und Farbtemperatur. thing-type.tradfri.0220.label = Farbtemperatur Lampe (weiß) thing-type.tradfri.0220.description = Dimmbare Lampe mit einstellbarer Farbtemperatur. +thing-type.tradfri.0107.label = Funk-Bewegungsmelder +thing-type.tradfri.0107.description = Der Funk-Bewegungsmelder liefert Daten wie z.B. die Batterieladung. +thing-type.tradfri.0820.label = Kabelloser Dimmer +thing-type.tradfri.0820.description = Der Kabellose Dimmer liefert Daten wie z.B. die Batterieladung. +thing-type.tradfri.0830.label = Fernbedienung +thing-type.tradfri.0830.description = Die Fernbedienung liefert Daten wie z.B. die Batterieladung. # thing types config -thing-type.config.tradfri.device.id.label = ID der Lampe -thing-type.config.tradfri.device.id.description = ID zur Identifikation der Lampe. +thing-type.config.tradfri.device.id.label = ID des Gerätes +thing-type.config.tradfri.device.id.description = ID zur Identifikation des Gerätes. # channel types channel-type.tradfri.brightness.label = Helligkeit 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 11fa28d27cb..8dc6c92f162 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 @@ -7,24 +7,7 @@ IKEA TRÃ…DFRI IP Gateway - - - network-address - - Hostname or IP address of the IKEA TRÃ…DFRI gateway - - - - Port for accessing the gateway - true - 5684 - - - password - - Security code printed on the label underneath the gateway. - - + @@ -82,16 +65,53 @@ - + + + + + + + This represents the motion sensor capable of reporting the battery level. + + + + + + + id + + + + - + + This represents the wireless dimmer sensor capable of reporting the battery level. - + + + + + id + + + + + + + + + + + This represents the remote control capable of reporting the battery level. + + + + id diff --git a/extensions/binding/org.eclipse.smarthome.binding.tradfri/README.md b/extensions/binding/org.eclipse.smarthome.binding.tradfri/README.md index 958f3c8e62e..5e309d4693e 100644 --- a/extensions/binding/org.eclipse.smarthome.binding.tradfri/README.md +++ b/extensions/binding/org.eclipse.smarthome.binding.tradfri/README.md @@ -4,23 +4,35 @@ This binding integrates the IKEA TRÃ…DFRI gateway and devices connected to it (s ## Supported Things -Besides the gateway (thing type "gateway"), the binding currently supports dimmable warm white bulbs as well as white spectrum bulbs. - -The thing type ids are defined according to the lighting devices defined for ZigBee LightLink ([see page 24, table 2](https://www.nxp.com/documents/user_manual/JN-UG-3091.pdf). These are: - -| Device type | ZigBee Device ID | Thing type | -|--------------------------|------------------|------------| -| Dimmable Light | 0x0100 | 0100 | -| Colour Temperature Light | 0x0220 | 0220 | -| Extended Colour Light | 0x0210 | 0210 | +Beside the gateway (thing type "gateway"), the binding currently supports colored bulbs, dimmable warm white bulbs as well as white spectrum bulbs. +The binding also supports read-only data from remote controls and motion sensors (e.g. the battery status). +The TRÃ…DFRI controller and sensor devices currently cannot be observed right away. +We assume that they are communicating directly with the bulbs or lamps without routing their commands through the gateway. +This makes it nearly impossible to trigger events for pressed buttons. +We only can access some static data like the present status or battery level. + +The thing type ids are defined according to the lighting devices defined for ZigBee LightLink ([see page 24, table 2](https://www.nxp.com/documents/user_manual/JN-UG-3091.pdf). +These are: + +| Device type | ZigBee Device ID | Thing type | +|---------------------------------|------------------|------------| +| Dimmable Light | 0x0100 | 0100 | +| Colour Temperature Light | 0x0220 | 0220 | +| Extended Colour Light | 0x0210 | 0210 | +| Occupancy Sensor | 0x0107 | 0107 | +| Non-Colour Controller | 0x0820 | 0820 | +| Non-Colour Scene Controller | 0x0830 | 0830 | The following matrix lists the capabilities (channels) for each of the supported lighting device types: -| Thing type | Brightness | Color | Color Temperature | -|-------------|:----------:|:-----:|:-----------------:| -| 0100 | X | | | -| 0220 | X | | X | -| 0210 | | X | X | +| Thing type | Brightness | Color | Color Temperature | Battery Level | Battery Low | +|-------------|:----------:|:-----:|:-----------------:|:-------------:|:-----------:| +| 0100 | X | | | | | +| 0220 | X | | X | | | +| 0210 | | X | X | | | +| 0107 | | | | X | X | +| 0820 | | | | X | X | +| 0830 | | | | X | X | ## Thing Configuration @@ -36,13 +48,17 @@ The white spectrum bulbs additionally also support the `color_temperature` chann Full color bulbs support the `color_temperature` and `color` channels. Brightness can be changed with the `color` channel. +The remote control and the motion sensor supports the `battery_level` and `battery_low` channels for reading the battery status. + Refer to the matrix above. -| Channel Type ID | Item Type | Description | -|-------------------|-----------|---------------------------------------------| -| brightness | Dimmer | The brightness of the bulb in percent | -| color_temperature | Dimmer | color temperature from 0%=cold to 100%=warm | -| color | Color | full color | +| Channel Type ID | Item Type | Description | +|-------------------|-----------|--------------------------------------------------| +| brightness | Dimmer | The brightness of the bulb in percent | +| color_temperature | Dimmer | color temperature from 0% = cold to 100% = warm | +| color | Color | full color | +| battery_level | Number | battery level (in %) | +| battery_low | Switch | battery low warning (<=10% = ON, >10% = OFF) | ## Full Example @@ -53,6 +69,7 @@ Bridge tradfri:gateway:mygateway [ host="192.168.0.177", code="EHPW5rIJKyXFgjH3" 0100 myDimmableBulb [ id=65537 ] 0220 myColorTempBulb [ id=65538 ] 0210 myColorBulb [ id=65539 ] + 0830 myRemoteControl [ id=65545 ] } ``` @@ -62,7 +79,9 @@ demo.items: Dimmer Light1 { channel="tradfri:0100:mygateway:myDimmableBulb:brightness" } Dimmer Light2_Brightness { channel="tradfri:0220:mygateway:myColorTempBulb:brightness" } Dimmer Light2_ColorTemperature { channel="tradfri:0220:mygateway:myColorTempBulb:color_temperature" } -Color ColorLight { channel="tradfri:0210:mygateway:myColorBulb:color" } +Color ColorLight { channel="tradfri:0210:mygateway:myColorBulb:color" } +Number RemoteControlBatteryLevel { channel="tradfri:0830:mygateway:myRemoteControl:battery_level" } +Switch RemoteControlBatteryLow { channel="tradfri:0830:mygateway:myRemoteControl:battery_low" } ``` demo.sitemap: @@ -75,6 +94,8 @@ sitemap demo label="Main Menu" Slider item=Light2_Brightness label="Light2 Brightness [%.1f %%]" Slider item=Light2_ColorTemperature label="Light2 Color Temperature [%.1f %%]" Colorpicker item=ColorLight label="Color" + Number item=RemoteControlBatteryLevel label="Battery level [%d %%]" + Switch item=RemoteControlBatteryLow label="Battery low warning" } } ``` 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 f5471299e5d..14e28bbe6b8 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 @@ -19,6 +19,7 @@ * used across the whole binding. * * @author Kai Kreuzer - Initial contribution + * @author Christoph Weitkamp - Added support for remote controller and motion sensor devices (read-only battery level) */ public class TradfriBindingConstants { @@ -27,22 +28,27 @@ public class TradfriBindingConstants { // List of all Thing Type UIDs public static final ThingTypeUID GATEWAY_TYPE_UID = new ThingTypeUID(BINDING_ID, "gateway"); - 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_COLOR_LIGHT = new ThingTypeUID(BINDING_ID, "0210"); - public final static ThingTypeUID THING_TYPE_DIMMER = new ThingTypeUID(BINDING_ID, "0820"); + public static final ThingTypeUID THING_TYPE_DIMMABLE_LIGHT = new ThingTypeUID(BINDING_ID, "0100"); + public static final ThingTypeUID THING_TYPE_COLOR_TEMP_LIGHT = new ThingTypeUID(BINDING_ID, "0220"); + public static final ThingTypeUID THING_TYPE_COLOR_LIGHT = new ThingTypeUID(BINDING_ID, "0210"); + public static final ThingTypeUID THING_TYPE_DIMMER = new ThingTypeUID(BINDING_ID, "0820"); + public static final ThingTypeUID THING_TYPE_REMOTE_CONTROL = new ThingTypeUID(BINDING_ID, "0830"); + public static final ThingTypeUID THING_TYPE_MOTION_SENSOR = new ThingTypeUID(BINDING_ID, "0107"); public static final Set SUPPORTED_LIGHT_TYPES_UIDS = Collections .unmodifiableSet(Stream.of(THING_TYPE_DIMMABLE_LIGHT, THING_TYPE_COLOR_TEMP_LIGHT, THING_TYPE_COLOR_LIGHT) .collect(Collectors.toSet())); // Not yet used - included for future support - public static final Set SUPPORTED_CONTROLLER_TYPES_UIDS = Collections.singleton(THING_TYPE_DIMMER); + public static final Set SUPPORTED_CONTROLLER_TYPES_UIDS = Collections.unmodifiableSet(Stream + .of(THING_TYPE_DIMMER, THING_TYPE_REMOTE_CONTROL, THING_TYPE_MOTION_SENSOR).collect(Collectors.toSet())); // 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_COLOR = "color"; + public static final String CHANNEL_BATTERY_LEVEL = "battery_level"; + public static final String CHANNEL_BATTERY_LOW = "battery_low"; // IPSO Objects public static final String DEVICES = "15001"; @@ -149,8 +155,10 @@ public class TradfriBindingConstants { public static final int WAKE_UP_SMART_TASK = 3; public static final String TYPE_LIGHT = "2"; + public static final String TYPE_SENSOR = "4"; public static final String TYPE_SWITCH = "0"; public static final String DEVICE_VENDOR = "0"; public static final String DEVICE_MODEL = "1"; public static final String DEVICE_FIRMWARE = "3"; + public static final String DEVICE_BATTERY_LEVEL = "9"; } diff --git a/extensions/binding/org.eclipse.smarthome.binding.tradfri/src/main/java/org/eclipse/smarthome/binding/tradfri/handler/TradfriControllerHandler.java b/extensions/binding/org.eclipse.smarthome.binding.tradfri/src/main/java/org/eclipse/smarthome/binding/tradfri/handler/TradfriControllerHandler.java new file mode 100644 index 00000000000..f267a16710c --- /dev/null +++ b/extensions/binding/org.eclipse.smarthome.binding.tradfri/src/main/java/org/eclipse/smarthome/binding/tradfri/handler/TradfriControllerHandler.java @@ -0,0 +1,76 @@ +/** + * 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 org.eclipse.smarthome.binding.tradfri.internal.model.TradfriControllerData; +import org.eclipse.smarthome.core.library.types.DecimalType; +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.types.Command; +import org.eclipse.smarthome.core.types.RefreshType; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.gson.JsonElement; + +/** + * The {@link TradfriControllerHandler} is responsible for handling commands for individual controllers. + * + * @author Christoph Weitkamp - Initial contribution + */ +public class TradfriControllerHandler extends TradfriThingHandler { + + private final Logger logger = LoggerFactory.getLogger(TradfriControllerHandler.class); + + // keeps track of the current state for handling of increase/decrease + private TradfriControllerData state; + + public TradfriControllerHandler(Thing thing) { + super(thing); + } + + @Override + public void onUpdate(JsonElement data) { + if (active && !(data.isJsonNull())) { + state = new TradfriControllerData(data); + updateStatus(state.getReachabilityStatus() ? ThingStatus.ONLINE : ThingStatus.OFFLINE); + + DecimalType batteryLevel = state.getBatteryLevel(); + if (batteryLevel != null) { + updateState(CHANNEL_BATTERY_LEVEL, batteryLevel); + } + + OnOffType batteryLow = state.getBatteryLow(); + if (batteryLow != null) { + updateState(CHANNEL_BATTERY_LOW, batteryLow); + } + + updateDeviceProperties(state); + + logger.debug( + "Updating thing for controllerId {} to state {batteryLevel: {}, batteryLow: {}, firmwareVersion: {}, modelId: {}, vendor: {}}", + state.getDeviceId(), batteryLevel, batteryLow, state.getFirmwareVersion(), state.getModelId(), + state.getVendor()); + } + } + + @Override + public void handleCommand(ChannelUID channelUID, Command command) { + if (command instanceof RefreshType) { + logger.debug("Refreshing channel {}", channelUID); + coapClient.asyncGet(this); + return; + } + + logger.debug("The controller is a read-only device and cannot handle commands."); + } +} 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 944dd78df5d..38afcab5dc0 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,16 +7,16 @@ */ package org.eclipse.smarthome.binding.tradfri.handler; -import static org.eclipse.smarthome.binding.tradfri.TradfriBindingConstants.DEVICES; -import static org.eclipse.smarthome.binding.tradfri.TradfriBindingConstants.GATEWAY; -import static org.eclipse.smarthome.binding.tradfri.TradfriBindingConstants.GATEWAY_DETAILS; -import static org.eclipse.smarthome.binding.tradfri.TradfriBindingConstants.VERSION; +import static org.eclipse.smarthome.binding.tradfri.TradfriBindingConstants.*; +import static org.eclipse.smarthome.binding.tradfri.internal.config.TradfriGatewayConfig.*; import java.io.IOException; import java.net.InetSocketAddress; import java.net.URI; import java.net.URISyntaxException; +import java.util.Map; import java.util.Set; +import java.util.Map.Entry; import java.util.concurrent.CopyOnWriteArraySet; import java.util.concurrent.ScheduledFuture; import java.util.concurrent.TimeUnit; @@ -26,11 +26,12 @@ import org.eclipse.californium.scandium.DTLSConnector; import org.eclipse.californium.scandium.config.DtlsConnectorConfig; import org.eclipse.californium.scandium.dtls.pskstore.StaticPskStore; -import org.eclipse.smarthome.binding.tradfri.GatewayConfig; import org.eclipse.smarthome.binding.tradfri.internal.CoapCallback; import org.eclipse.smarthome.binding.tradfri.internal.DeviceUpdateListener; import org.eclipse.smarthome.binding.tradfri.internal.TradfriCoapClient; import org.eclipse.smarthome.binding.tradfri.internal.TradfriCoapHandler; +import org.eclipse.smarthome.binding.tradfri.internal.config.TradfriGatewayConfig; +import org.eclipse.smarthome.config.core.Configuration; import org.eclipse.smarthome.core.thing.Bridge; import org.eclipse.smarthome.core.thing.ChannelUID; import org.eclipse.smarthome.core.thing.Thing; @@ -45,6 +46,7 @@ import com.google.gson.JsonElement; import com.google.gson.JsonObject; import com.google.gson.JsonParser; +import com.google.gson.JsonPrimitive; import com.google.gson.JsonSyntaxException; /** @@ -78,7 +80,7 @@ public void handleCommand(ChannelUID channelUID, Command command) { @Override public void initialize() { - GatewayConfig configuration = getConfigAs(GatewayConfig.class); + TradfriGatewayConfig configuration = getConfigAs(TradfriGatewayConfig.class); if (configuration.host == null || configuration.host.isEmpty()) { updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, "Host must be specified in the configuration!"); @@ -91,7 +93,8 @@ public void initialize() { } this.gatewayURI = "coaps://" + configuration.host + ":" + configuration.port + "/" + DEVICES; - this.gatewayInfoURI = "coaps://" + configuration.host + ":" + configuration.port + "/" + GATEWAY + "/" + GATEWAY_DETAILS; + this.gatewayInfoURI = "coaps://" + configuration.host + ":" + configuration.port + "/" + GATEWAY + "/" + + GATEWAY_DETAILS; try { URI uri = new URI(gatewayURI); deviceClient = new TradfriCoapClient(uri); @@ -137,7 +140,7 @@ public void dispose() { */ public void startScan() { if (endPoint != null) { - updateGatewayInfo(); + requestGatewayInfo(); deviceClient.get(new TradfriCoapHandler(this)); } } @@ -176,8 +179,8 @@ public void onUpdate(JsonElement data) { } } } - - private synchronized void updateGatewayInfo() { + + private synchronized void requestGatewayInfo() { // we are reusing our coap client and merely temporarily set a gateway info to call deviceClient.setURI(this.gatewayInfoURI); deviceClient.asyncGet().thenAccept(data -> { 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 79c90517572..bf04535d8fd 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 @@ -9,14 +9,7 @@ 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.binding.tradfri.internal.TradfriColor; +import org.eclipse.smarthome.binding.tradfri.internal.model.TradfriLightData; import org.eclipse.smarthome.core.library.types.HSBType; import org.eclipse.smarthome.core.library.types.IncreaseDecreaseType; import org.eclipse.smarthome.core.library.types.OnOffType; @@ -24,28 +17,21 @@ 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.ThingStatusInfo; -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.JsonArray; import com.google.gson.JsonElement; -import com.google.gson.JsonObject; -import com.google.gson.JsonPrimitive; -import com.google.gson.JsonSyntaxException; /** - * The {@link TradfriLightHandler} is responsible for handling commands for - * individual lights. + * The {@link TradfriLightHandler} is responsible for handling commands for individual lights. * * @author Kai Kreuzer - Initial contribution * @author Holger Reichert - Support for color bulbs + * @author Christoph Weitkamp - Restructuring and refactoring of the binding */ -public class TradfriLightHandler extends BaseThingHandler implements CoapCallback { +public class TradfriLightHandler extends TradfriThingHandler { private final Logger logger = LoggerFactory.getLogger(TradfriLightHandler.class); @@ -53,66 +39,16 @@ public class TradfriLightHandler extends BaseThingHandler implements CoapCallbac private static final int STEP = 10; // keeps track of the current state for handling of increase/decrease - private LightData 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; + private TradfriLightData state; public TradfriLightHandler(Thing thing) { super(thing); } - @Override - public synchronized void initialize() { - this.id = getConfigAs(DeviceConfig.class).id; - TradfriGatewayHandler handler = (TradfriGatewayHandler) getBridge().getHandler(); - String uriString = handler.getGatewayURI() + "/" + id; - try { - URI uri = new URI(uriString); - coapClient = new TradfriCoapClient(uri); - coapClient.setEndpoint(handler.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 LightData(data); + state = new TradfriLightData(data); updateStatus(state.getReachabilityStatus() ? ThingStatus.ONLINE : ThingStatus.OFFLINE); if (!state.getOnOffState()) { @@ -126,7 +62,7 @@ public void onUpdate(JsonElement data) { } PercentType dimmer = state.getBrightness(); - if (dimmer != null && !lightHasColorSupport()) { // color lighs do not have brightness channel + if (dimmer != null && !lightHasColorSupport()) { // color lights do not have brightness channel updateState(CHANNEL_BRIGHTNESS, dimmer); } @@ -143,67 +79,35 @@ public void onUpdate(JsonElement data) { } } - String devicefirmware = state.getFirmwareVersion(); - if (devicefirmware != null) { - getThing().setProperty(Thing.PROPERTY_FIRMWARE_VERSION, devicefirmware); - } - - String modelId = state.getModelId(); - if (modelId != null) { - getThing().setProperty(Thing.PROPERTY_MODEL_ID, modelId); - } - - String vendor = state.getVendor(); - if (vendor != null) { - getThing().setProperty(Thing.PROPERTY_VENDOR, vendor); - } + updateDeviceProperties(state); logger.debug( - "Updating thing for lightId {} to state {dimmer: {}, colorTemp: {}, color: {}, devicefirmware: {}, modelId: {}, vendor: {}}", - state.getLightId(), dimmer, colorTemp, color, devicefirmware, modelId, vendor); + "Updating thing for lightId {} to state {dimmer: {}, colorTemp: {}, color: {}, firmwareVersion: {}, modelId: {}, vendor: {}}", + state.getDeviceId(), dimmer, colorTemp, color, state.getFirmwareVersion(), state.getModelId(), + state.getVendor()); } } - @Override - public void bridgeStatusChanged(ThingStatusInfo bridgeStatusInfo) { - super.bridgeStatusChanged(bridgeStatusInfo); - - if (bridgeStatusInfo.getStatus() == ThingStatus.ONLINE) { - scheduler.schedule(() -> { - coapClient.startObserve(this); - }, 0, TimeUnit.SECONDS); - } - } - - private void set(String payload, Integer delay) { - logger.debug("Sending payload: {}", payload); - coapClient.asyncPut(payload, this, delay, scheduler); - } - - private void set(String payload) { - set(payload, null); - } - private void setBrightness(PercentType percent) { - LightData data = new LightData(); + TradfriLightData data = new TradfriLightData(); data.setBrightness(percent).setTransitionTime(DEFAULT_DIMMER_TRANSITION_TIME); set(data.getJsonString()); } private void setState(OnOffType onOff) { - LightData data = new LightData(); + TradfriLightData data = new TradfriLightData(); data.setOnOffState(onOff == OnOffType.ON); set(data.getJsonString()); } private void setColorTemperature(PercentType percent) { - LightData data = new LightData(); + TradfriLightData data = new TradfriLightData(); data.setColorTemperature(percent).setTransitionTime(DEFAULT_DIMMER_TRANSITION_TIME); set(data.getJsonString()); } private void setColor(HSBType hsb) { - LightData data = new LightData(); + TradfriLightData data = new TradfriLightData(); data.setColor(hsb).setTransitionTime(DEFAULT_DIMMER_TRANSITION_TIME); set(data.getJsonString(), 1000); } @@ -305,170 +209,4 @@ private void handleColorCommand(Command command) { private boolean lightHasColorSupport() { return thing.getThingTypeUID().getId().equals(THING_TYPE_COLOR_LIGHT.getId()); } - - /** - * This class is a Java wrapper for the raw JSON data about the light state. - */ - private static class LightData { - - private final Logger logger = LoggerFactory.getLogger(LightData.class); - - JsonObject root; - JsonArray array; - JsonObject attributes; - JsonObject generalInfo; - - public LightData() { - root = new JsonObject(); - array = new JsonArray(); - attributes = new JsonObject(); - array.add(attributes); - root.add(LIGHT, array); - - generalInfo = new JsonObject(); - root.add(DEVICE, generalInfo); - } - - public LightData(JsonElement json) { - try { - root = json.getAsJsonObject(); - array = root.getAsJsonArray(LIGHT); - attributes = array.get(0).getAsJsonObject(); - generalInfo = root.getAsJsonObject(DEVICE); - } catch (JsonSyntaxException e) { - logger.error("JSON error: {}", e.getMessage(), e); - } - } - - public LightData setBrightness(PercentType brightness) { - attributes.add(DIMMER, new JsonPrimitive(Math.round(brightness.floatValue() / 100.0f * 254))); - return this; - } - - public PercentType getBrightness() { - PercentType result = null; - - JsonElement dimmer = attributes.get(DIMMER); - if (dimmer != null) { - result = TradfriColor.xyBrightnessToPercentType(dimmer.getAsInt()); - } - - return result; - } - - public boolean getReachabilityStatus() { - if (root.get(REACHABILITY_STATE) != null) { - return root.get(REACHABILITY_STATE).getAsInt() == 1; - } else { - return false; - } - } - - public LightData setTransitionTime(int seconds) { - attributes.add(TRANSITION_TIME, new JsonPrimitive(seconds)); - return this; - } - - @SuppressWarnings("unused") - public int getTransitionTime() { - JsonElement transitionTime = attributes.get(TRANSITION_TIME); - if (transitionTime != null) { - return transitionTime.getAsInt(); - } else { - return 0; - } - } - - public LightData setColorTemperature(PercentType c) { - TradfriColor color = TradfriColor.fromColorTemperature(c); - int x = color.xyX; - int y = color.xyY; - logger.debug("New color temperature: {},{} ({} %)", x, y, c.intValue()); - attributes.add(COLOR_X, new JsonPrimitive(x)); - attributes.add(COLOR_Y, new JsonPrimitive(y)); - return this; - } - - PercentType getColorTemperature() { - JsonElement colorX = attributes.get(COLOR_X); - JsonElement colorY = attributes.get(COLOR_Y); - if (colorX != null && colorY != null) { - return TradfriColor.calculateColorTemperature(colorX.getAsInt(), colorY.getAsInt()); - } else { - return null; - } - } - - public LightData setColor(HSBType hsb) { - // construct new HSBType with full brightness and extract XY color values from it - HSBType hsbFullBright = new HSBType(hsb.getHue(), hsb.getSaturation(), PercentType.HUNDRED); - TradfriColor color = TradfriColor.fromHSBType(hsbFullBright); - attributes.add(COLOR_X, new JsonPrimitive(color.xyX)); - attributes.add(COLOR_Y, new JsonPrimitive(color.xyY)); - return this; - } - - public HSBType getColor() { - // XY color coordinates plus brightness is needed for color calculation - JsonElement colorX = attributes.get(COLOR_X); - JsonElement colorY = attributes.get(COLOR_Y); - JsonElement dimmer = attributes.get(DIMMER); - if (colorX != null && colorY != null && dimmer != null) { - int x = colorX.getAsInt(); - int y = colorY.getAsInt(); - int brightness = dimmer.getAsInt(); - // extract HSBType from converted xy/brightness - TradfriColor color = TradfriColor.fromCie(x, y, brightness); - return color.hsbType; - } - return null; - } - - LightData setOnOffState(boolean on) { - attributes.add(ONOFF, new JsonPrimitive(on ? 1 : 0)); - return this; - } - - boolean getOnOffState() { - JsonElement onOff = attributes.get(ONOFF); - if (onOff != null) { - return attributes.get(ONOFF).getAsInt() == 1; - } else { - return false; - } - } - - Integer getLightId() { - return root.get(INSTANCE_ID).getAsInt(); - } - - String getFirmwareVersion() { - if (generalInfo.get(DEVICE_FIRMWARE) != null) { - return generalInfo.get(DEVICE_FIRMWARE).getAsString(); - } else { - return null; - } - } - - String getModelId() { - if (generalInfo.get(DEVICE_MODEL) != null) { - return generalInfo.get(DEVICE_MODEL).getAsString(); - } else { - return null; - } - } - - String getVendor() { - if (generalInfo.get(DEVICE_VENDOR) != null) { - return generalInfo.get(DEVICE_VENDOR).getAsString(); - } else { - return null; - } - } - - String getJsonString() { - return root.toString(); - } - } - } diff --git a/extensions/binding/org.eclipse.smarthome.binding.tradfri/src/main/java/org/eclipse/smarthome/binding/tradfri/handler/TradfriSensorHandler.java b/extensions/binding/org.eclipse.smarthome.binding.tradfri/src/main/java/org/eclipse/smarthome/binding/tradfri/handler/TradfriSensorHandler.java new file mode 100644 index 00000000000..a2ccf146c07 --- /dev/null +++ b/extensions/binding/org.eclipse.smarthome.binding.tradfri/src/main/java/org/eclipse/smarthome/binding/tradfri/handler/TradfriSensorHandler.java @@ -0,0 +1,76 @@ +/** + * 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 org.eclipse.smarthome.binding.tradfri.internal.model.TradfriSensorData; +import org.eclipse.smarthome.core.library.types.DecimalType; +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.types.Command; +import org.eclipse.smarthome.core.types.RefreshType; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.gson.JsonElement; + +/** + * The {@link TradfriSensorHandler} is responsible for handling commands for individual sensors. + * + * @author Christoph Weitkamp - Initial contribution + */ +public class TradfriSensorHandler extends TradfriThingHandler { + + private final Logger logger = LoggerFactory.getLogger(TradfriSensorHandler.class); + + // keeps track of the current state for handling of increase/decrease + private TradfriSensorData state; + + public TradfriSensorHandler(Thing thing) { + super(thing); + } + + @Override + public void onUpdate(JsonElement data) { + if (active && !(data.isJsonNull())) { + state = new TradfriSensorData(data); + updateStatus(state.getReachabilityStatus() ? ThingStatus.ONLINE : ThingStatus.OFFLINE); + + DecimalType batteryLevel = state.getBatteryLevel(); + if (batteryLevel != null) { + updateState(CHANNEL_BATTERY_LEVEL, batteryLevel); + } + + OnOffType batteryLow = state.getBatteryLow(); + if (batteryLow != null) { + updateState(CHANNEL_BATTERY_LOW, batteryLow); + } + + updateDeviceProperties(state); + + logger.debug( + "Updating thing for sensorId {} to state {batteryLevel: {}, batteryLow: {}, firmwareVersion: {}, modelId: {}, vendor: {}}", + state.getDeviceId(), batteryLevel, batteryLow, state.getFirmwareVersion(), state.getModelId(), + state.getVendor()); + } + } + + @Override + public void handleCommand(ChannelUID channelUID, Command command) { + if (command instanceof RefreshType) { + logger.debug("Refreshing channel {}", channelUID); + coapClient.asyncGet(this); + return; + } + + logger.debug("The sensor is a read-only device and cannot handle commands."); + } +} diff --git a/extensions/binding/org.eclipse.smarthome.binding.tradfri/src/main/java/org/eclipse/smarthome/binding/tradfri/handler/TradfriThingHandler.java b/extensions/binding/org.eclipse.smarthome.binding.tradfri/src/main/java/org/eclipse/smarthome/binding/tradfri/handler/TradfriThingHandler.java new file mode 100644 index 00000000000..d4d83385a0b --- /dev/null +++ b/extensions/binding/org.eclipse.smarthome.binding.tradfri/src/main/java/org/eclipse/smarthome/binding/tradfri/handler/TradfriThingHandler.java @@ -0,0 +1,124 @@ +/** + * 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.core.thing.Thing.*; + +import java.net.URI; +import java.net.URISyntaxException; +import java.util.concurrent.TimeUnit; + +import org.eclipse.smarthome.binding.tradfri.internal.CoapCallback; +import org.eclipse.smarthome.binding.tradfri.internal.TradfriCoapClient; +import org.eclipse.smarthome.binding.tradfri.internal.config.TradfriDeviceConfig; +import org.eclipse.smarthome.binding.tradfri.internal.model.TradfriDeviceData; +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.ThingStatusInfo; +import org.eclipse.smarthome.core.thing.binding.BaseThingHandler; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * The {@link TradfriThingHandler} is the abstract base class for individual device handlers. + * + * @author Kai Kreuzer - Initial contribution + * @author Christoph Weitkamp - Restructuring and refactoring of the binding + */ +public abstract class TradfriThingHandler extends BaseThingHandler implements CoapCallback { + + private final Logger logger = LoggerFactory.getLogger(TradfriThingHandler.class); + + // the unique instance id of the device + protected Integer id; + + // used to check whether we have already been disposed when receiving data asynchronously + protected volatile boolean active; + + protected TradfriCoapClient coapClient; + + public TradfriThingHandler(Thing thing) { + super(thing); + } + + @Override + public synchronized void initialize() { + this.id = getConfigAs(TradfriDeviceConfig.class).id; + TradfriGatewayHandler handler = (TradfriGatewayHandler) getBridge().getHandler(); + String uriString = handler.getGatewayURI() + "/" + id; + try { + URI uri = new URI(uriString); + coapClient = new TradfriCoapClient(uri); + coapClient.setEndpoint(handler.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 bridgeStatusChanged(ThingStatusInfo bridgeStatusInfo) { + super.bridgeStatusChanged(bridgeStatusInfo); + + if (bridgeStatusInfo.getStatus() == ThingStatus.ONLINE) { + scheduler.submit(() -> coapClient.startObserve(this)); + } + } + + protected void set(String payload, Integer delay) { + logger.debug("Sending payload: {}", payload); + coapClient.asyncPut(payload, this, delay, scheduler); + } + + protected void set(String payload) { + set(payload, null); + } + + protected void updateDeviceProperties(TradfriDeviceData state) { + String firmwareVersion = state.getFirmwareVersion(); + if (firmwareVersion != null) { + getThing().setProperty(PROPERTY_FIRMWARE_VERSION, firmwareVersion); + } + + String modelId = state.getModelId(); + if (modelId != null) { + getThing().setProperty(PROPERTY_MODEL_ID, modelId); + } + + String vendor = state.getVendor(); + if (vendor != null) { + getThing().setProperty(PROPERTY_VENDOR, vendor); + } + } +} diff --git a/extensions/binding/org.eclipse.smarthome.binding.tradfri/src/main/java/org/eclipse/smarthome/binding/tradfri/internal/TradfriCoapClient.java b/extensions/binding/org.eclipse.smarthome.binding.tradfri/src/main/java/org/eclipse/smarthome/binding/tradfri/internal/TradfriCoapClient.java index c211f7dd553..dce8442db47 100644 --- a/extensions/binding/org.eclipse.smarthome.binding.tradfri/src/main/java/org/eclipse/smarthome/binding/tradfri/internal/TradfriCoapClient.java +++ b/extensions/binding/org.eclipse.smarthome.binding.tradfri/src/main/java/org/eclipse/smarthome/binding/tradfri/internal/TradfriCoapClient.java @@ -116,7 +116,6 @@ public void asyncPut(String payload, CoapCallback callback, Integer delay, Sched * @param scheduler scheduler to be used for sending commands */ public void asyncPut(PayloadCallbackPair payloadCallbackPair, ScheduledExecutorService scheduler) { - synchronized (this.commandsQueue) { if (this.commandsQueue.isEmpty()) { this.commandsQueue.offer(payloadCallbackPair); 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 35695a5f2d2..81bcee6c7af 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,8 +16,10 @@ import java.util.stream.Collectors; import java.util.stream.Stream; +import org.eclipse.smarthome.binding.tradfri.handler.TradfriControllerHandler; import org.eclipse.smarthome.binding.tradfri.handler.TradfriGatewayHandler; import org.eclipse.smarthome.binding.tradfri.handler.TradfriLightHandler; +import org.eclipse.smarthome.binding.tradfri.handler.TradfriSensorHandler; import org.eclipse.smarthome.binding.tradfri.internal.discovery.TradfriDiscoveryService; import org.eclipse.smarthome.config.discovery.DiscoveryService; import org.eclipse.smarthome.core.thing.Bridge; @@ -32,11 +34,14 @@ * The {@link TradfriHandlerFactory} is responsible for creating things and thing handlers. * * @author Kai Kreuzer - Initial contribution + * @author Christoph Weitkamp - Added support for remote controller and motion sensor devices (read-only battery level) */ public class TradfriHandlerFactory extends BaseThingHandlerFactory { private static final Set SUPPORTED_THING_TYPES_UIDS = Stream - .concat(Stream.of(GATEWAY_TYPE_UID), SUPPORTED_LIGHT_TYPES_UIDS.stream()).collect(Collectors.toSet()); + .concat(Stream.of(GATEWAY_TYPE_UID), + Stream.concat(SUPPORTED_LIGHT_TYPES_UIDS.stream(), SUPPORTED_CONTROLLER_TYPES_UIDS.stream())) + .collect(Collectors.toSet()); private Map> discoveryServiceRegs = new HashMap<>(); @@ -49,10 +54,14 @@ public boolean supportsThingType(ThingTypeUID thingTypeUID) { protected ThingHandler createHandler(Thing thing) { ThingTypeUID thingTypeUID = thing.getThingTypeUID(); - if (thingTypeUID.equals(GATEWAY_TYPE_UID)) { + if (GATEWAY_TYPE_UID.equals(thingTypeUID)) { TradfriGatewayHandler handler = new TradfriGatewayHandler((Bridge) thing); registerDiscoveryService(handler); return handler; + } else if (THING_TYPE_DIMMER.equals(thingTypeUID) || THING_TYPE_REMOTE_CONTROL.equals(thingTypeUID)) { + return new TradfriControllerHandler(thing); + } else if (THING_TYPE_MOTION_SENSOR.equals(thingTypeUID)) { + return new TradfriSensorHandler(thing); } else if (SUPPORTED_LIGHT_TYPES_UIDS.contains(thingTypeUID)) { return new TradfriLightHandler(thing); } diff --git a/extensions/binding/org.eclipse.smarthome.binding.tradfri/src/main/java/org/eclipse/smarthome/binding/tradfri/DeviceConfig.java b/extensions/binding/org.eclipse.smarthome.binding.tradfri/src/main/java/org/eclipse/smarthome/binding/tradfri/internal/config/TradfriDeviceConfig.java similarity index 71% rename from extensions/binding/org.eclipse.smarthome.binding.tradfri/src/main/java/org/eclipse/smarthome/binding/tradfri/DeviceConfig.java rename to extensions/binding/org.eclipse.smarthome.binding.tradfri/src/main/java/org/eclipse/smarthome/binding/tradfri/internal/config/TradfriDeviceConfig.java index 53c5e9adb08..1571efda149 100644 --- a/extensions/binding/org.eclipse.smarthome.binding.tradfri/src/main/java/org/eclipse/smarthome/binding/tradfri/DeviceConfig.java +++ b/extensions/binding/org.eclipse.smarthome.binding.tradfri/src/main/java/org/eclipse/smarthome/binding/tradfri/internal/config/TradfriDeviceConfig.java @@ -5,17 +5,17 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.smarthome.binding.tradfri; +package org.eclipse.smarthome.binding.tradfri.internal.config; /** - * The {@link DeviceConfig} holds the + * The {@link TradfriDeviceConfig} holds the * configuration information needed to access single bulbs on the gateway. * * @author Kai Kreuzer - Initial contribution */ -public class DeviceConfig { +public class TradfriDeviceConfig { - public static final String ID = "id"; + public static final String CONFIG_ID = "id"; public Integer id; } diff --git a/extensions/binding/org.eclipse.smarthome.binding.tradfri/src/main/java/org/eclipse/smarthome/binding/tradfri/GatewayConfig.java b/extensions/binding/org.eclipse.smarthome.binding.tradfri/src/main/java/org/eclipse/smarthome/binding/tradfri/internal/config/TradfriGatewayConfig.java similarity index 66% rename from extensions/binding/org.eclipse.smarthome.binding.tradfri/src/main/java/org/eclipse/smarthome/binding/tradfri/GatewayConfig.java rename to extensions/binding/org.eclipse.smarthome.binding.tradfri/src/main/java/org/eclipse/smarthome/binding/tradfri/internal/config/TradfriGatewayConfig.java index 81217996f6b..34c60a19283 100644 --- a/extensions/binding/org.eclipse.smarthome.binding.tradfri/src/main/java/org/eclipse/smarthome/binding/tradfri/GatewayConfig.java +++ b/extensions/binding/org.eclipse.smarthome.binding.tradfri/src/main/java/org/eclipse/smarthome/binding/tradfri/internal/config/TradfriGatewayConfig.java @@ -5,18 +5,18 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.smarthome.binding.tradfri; +package org.eclipse.smarthome.binding.tradfri.internal.config; /** * Configuration class for the gateway. * * @author Kai Kreuzer - Initial contribution */ -public class GatewayConfig { +public class TradfriGatewayConfig { - public static final String HOST = "host"; - public static final String PORT = "port"; - public static final String CODE = "code"; + public static final String CONFIG_HOST = "host"; + public static final String CONFIG_PORT = "port"; + public static final String CONFIG_CODE = "code"; public String host; public int port = 5684; // default port diff --git a/extensions/binding/org.eclipse.smarthome.binding.tradfri/src/main/java/org/eclipse/smarthome/binding/tradfri/internal/discovery/TradfriDiscoveryParticipant.java b/extensions/binding/org.eclipse.smarthome.binding.tradfri/src/main/java/org/eclipse/smarthome/binding/tradfri/internal/discovery/TradfriDiscoveryParticipant.java index 7323b34b9b2..f7876216ce2 100644 --- a/extensions/binding/org.eclipse.smarthome.binding.tradfri/src/main/java/org/eclipse/smarthome/binding/tradfri/internal/discovery/TradfriDiscoveryParticipant.java +++ b/extensions/binding/org.eclipse.smarthome.binding.tradfri/src/main/java/org/eclipse/smarthome/binding/tradfri/internal/discovery/TradfriDiscoveryParticipant.java @@ -7,6 +7,10 @@ */ package org.eclipse.smarthome.binding.tradfri.internal.discovery; +import static org.eclipse.smarthome.binding.tradfri.TradfriBindingConstants.*; +import static org.eclipse.smarthome.binding.tradfri.internal.config.TradfriGatewayConfig.*; +import static org.eclipse.smarthome.core.thing.Thing.*; + import java.util.Collections; import java.util.HashMap; import java.util.Map; @@ -14,11 +18,8 @@ import javax.jmdns.ServiceInfo; -import org.eclipse.smarthome.binding.tradfri.GatewayConfig; -import org.eclipse.smarthome.binding.tradfri.TradfriBindingConstants; import org.eclipse.smarthome.config.discovery.DiscoveryResult; import org.eclipse.smarthome.config.discovery.DiscoveryResultBuilder; -import org.eclipse.smarthome.core.thing.Thing; import org.eclipse.smarthome.core.thing.ThingTypeUID; import org.eclipse.smarthome.core.thing.ThingUID; import org.eclipse.smarthome.io.transport.mdns.discovery.MDNSDiscoveryParticipant; @@ -38,7 +39,7 @@ public class TradfriDiscoveryParticipant implements MDNSDiscoveryParticipant { @Override public Set getSupportedThingTypeUIDs() { - return Collections.singleton(TradfriBindingConstants.GATEWAY_TYPE_UID); + return Collections.singleton(GATEWAY_TYPE_UID); } @Override @@ -52,7 +53,7 @@ public ThingUID getThingUID(ServiceInfo service) { String name = service.getName(); if ((service.getType() != null) && service.getType().equals(getServiceType()) && (name.matches("gw:([a-f0-9]{2}[-]?){6}"))) { - return new ThingUID(TradfriBindingConstants.GATEWAY_TYPE_UID, name.replaceAll("[^A-Za-z0-9_]", "")); + return new ThingUID(GATEWAY_TYPE_UID, name.replaceAll("[^A-Za-z0-9_]", "")); } } return null; @@ -69,15 +70,15 @@ public DiscoveryResult createResult(ServiceInfo service) { if (thingUID != null) { logger.debug("Discovered Tradfri gateway: {}", service); Map properties = new HashMap<>(4); - properties.put(Thing.PROPERTY_VENDOR, "IKEA of Sweden"); - properties.put(GatewayConfig.HOST, ip); - properties.put(GatewayConfig.PORT, service.getPort()); + properties.put(PROPERTY_VENDOR, "IKEA of Sweden"); + properties.put(CONFIG_HOST, ip); + properties.put(CONFIG_PORT, service.getPort()); String fwVersion = service.getPropertyString("version"); if (fwVersion != null) { - properties.put(Thing.PROPERTY_FIRMWARE_VERSION, fwVersion); + properties.put(PROPERTY_FIRMWARE_VERSION, fwVersion); } return DiscoveryResultBuilder.create(thingUID).withProperties(properties).withLabel("TRÃ…DFRI Gateway") - .withRepresentationProperty(GatewayConfig.HOST).build(); + .withRepresentationProperty(CONFIG_HOST).build(); } } 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 2202d4b890e..8613736ae83 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 @@ -8,18 +8,20 @@ package org.eclipse.smarthome.binding.tradfri.internal.discovery; import static org.eclipse.smarthome.binding.tradfri.TradfriBindingConstants.*; +import static org.eclipse.smarthome.core.thing.Thing.*; import java.util.Arrays; import java.util.Date; import java.util.HashMap; import java.util.Map; +import java.util.stream.Collectors; +import java.util.stream.Stream; import org.eclipse.smarthome.binding.tradfri.handler.TradfriGatewayHandler; import org.eclipse.smarthome.binding.tradfri.internal.DeviceUpdateListener; import org.eclipse.smarthome.config.discovery.AbstractDiscoveryService; import org.eclipse.smarthome.config.discovery.DiscoveryResult; import org.eclipse.smarthome.config.discovery.DiscoveryResultBuilder; -import org.eclipse.smarthome.core.thing.Thing; import org.eclipse.smarthome.core.thing.ThingTypeUID; import org.eclipse.smarthome.core.thing.ThingUID; import org.slf4j.Logger; @@ -32,6 +34,7 @@ * This class identifies devices that are available on the gateway and adds discovery results for them. * * @author Kai Kreuzer - Initial contribution + * @author Christoph Weitkamp - Added support for remote controller and motion sensor devices (read-only battery level) * @author Andre Fuechsel - fixed the results removal */ public class TradfriDiscoveryService extends AbstractDiscoveryService implements DeviceUpdateListener { @@ -40,6 +43,8 @@ public class TradfriDiscoveryService extends AbstractDiscoveryService implements private final TradfriGatewayHandler handler; + private static final String REMOTE_CONTROLLER_MODEL = "TRADFRI remote control"; + private static final String[] COLOR_TEMP_MODELS = new String[] { "TRADFRI bulb E27 WS opal 980lm", "TRADFRI bulb E27 WS clear 950lm", "TRADFRI bulb GU10 WS 400lm", "TRADFRI bulb E14 WS opal 400lm", "FLOALT panel WS 30x30", "FLOALT panel WS 60x60", "FLOALT panel WS 30x90" }; @@ -47,7 +52,8 @@ public class TradfriDiscoveryService extends AbstractDiscoveryService implements private static final String COLOR_MODELS_IDENTIFIER = "CWS"; public TradfriDiscoveryService(TradfriGatewayHandler bridgeHandler) { - super(SUPPORTED_LIGHT_TYPES_UIDS, 10, true); + super(Stream.concat(SUPPORTED_LIGHT_TYPES_UIDS.stream(), SUPPORTED_CONTROLLER_TYPES_UIDS.stream()) + .collect(Collectors.toSet()), 10, true); this.handler = bridgeHandler; } @@ -83,7 +89,7 @@ public void onUpdate(String instanceId, JsonObject data) { String model = deviceInfo.get(DEVICE_MODEL).getAsString(); ThingUID thingId = null; - if (type.equals(TYPE_LIGHT) && data.has(LIGHT)) { + if (TYPE_LIGHT.equals(type) && data.has(LIGHT)) { JsonObject state = data.get(LIGHT).getAsJsonArray().get(0).getAsJsonObject(); // Color temperature light: @@ -105,6 +111,16 @@ public void onUpdate(String instanceId, JsonObject data) { thingType = THING_TYPE_DIMMABLE_LIGHT; } thingId = new ThingUID(thingType, bridge, Integer.toString(id)); + } else if (TYPE_SWITCH.equals(type) && data.has(SWITCH)) { + // Remote control and wireless dimmer + // As protocol does not distinguishes between remote control and wireless dimmer, + // we check for the whole model name + ThingTypeUID thingType = (model != null && REMOTE_CONTROLLER_MODEL.equals(model)) + ? THING_TYPE_REMOTE_CONTROL : THING_TYPE_DIMMER; + thingId = new ThingUID(thingType, bridge, Integer.toString(id)); + } else if (TYPE_SENSOR.equals(type) && data.has(SENSOR)) { + // Motion sensor + thingId = new ThingUID(THING_TYPE_MOTION_SENSOR, bridge, Integer.toString(id)); } if (thingId == null) { @@ -116,13 +132,13 @@ public void onUpdate(String instanceId, JsonObject data) { Map properties = new HashMap<>(1); properties.put("id", id); - properties.put(Thing.PROPERTY_MODEL_ID, model); + properties.put(PROPERTY_MODEL_ID, model); if (deviceInfo.get(DEVICE_VENDOR) != null) { - properties.put(Thing.PROPERTY_VENDOR, deviceInfo.get(DEVICE_VENDOR).getAsString()); + properties.put(PROPERTY_VENDOR, deviceInfo.get(DEVICE_VENDOR).getAsString()); } if (deviceInfo.get(DEVICE_FIRMWARE) != null) { - properties.put(Thing.PROPERTY_FIRMWARE_VERSION, deviceInfo.get(DEVICE_FIRMWARE).getAsString()); + properties.put(PROPERTY_FIRMWARE_VERSION, deviceInfo.get(DEVICE_FIRMWARE).getAsString()); } logger.debug("Adding device {} to inbox", thingId); diff --git a/extensions/binding/org.eclipse.smarthome.binding.tradfri/src/main/java/org/eclipse/smarthome/binding/tradfri/internal/model/TradfriControllerData.java b/extensions/binding/org.eclipse.smarthome.binding.tradfri/src/main/java/org/eclipse/smarthome/binding/tradfri/internal/model/TradfriControllerData.java new file mode 100644 index 00000000000..76d013d5ea6 --- /dev/null +++ b/extensions/binding/org.eclipse.smarthome.binding.tradfri/src/main/java/org/eclipse/smarthome/binding/tradfri/internal/model/TradfriControllerData.java @@ -0,0 +1,29 @@ +/** + * 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.internal.model; + +import static org.eclipse.smarthome.binding.tradfri.TradfriBindingConstants.*; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.gson.JsonElement; + +/** + * The {@link TradfriControllerData} class is a Java wrapper for the raw JSON data about the controller state. + * + * @author Christoph Weitkamp - Initial contribution + */ +public class TradfriControllerData extends TradfriWirelessDeviceData { + + private final Logger logger = LoggerFactory.getLogger(TradfriControllerData.class); + + public TradfriControllerData(JsonElement json) { + super(SWITCH, json); + } +} diff --git a/extensions/binding/org.eclipse.smarthome.binding.tradfri/src/main/java/org/eclipse/smarthome/binding/tradfri/internal/model/TradfriDeviceData.java b/extensions/binding/org.eclipse.smarthome.binding.tradfri/src/main/java/org/eclipse/smarthome/binding/tradfri/internal/model/TradfriDeviceData.java new file mode 100644 index 00000000000..dcf60c157b9 --- /dev/null +++ b/extensions/binding/org.eclipse.smarthome.binding.tradfri/src/main/java/org/eclipse/smarthome/binding/tradfri/internal/model/TradfriDeviceData.java @@ -0,0 +1,91 @@ +/** + * 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.internal.model; + +import static org.eclipse.smarthome.binding.tradfri.TradfriBindingConstants.*; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonSyntaxException; + +/** + * The {@link TradfriDeviceData} class is a Java wrapper for the raw JSON data about the device state. + * + * @author Kai Kreuzer - Initial contribution + * @author Christoph Weitkamp - Restructuring and refactoring of the binding + */ +public abstract class TradfriDeviceData { + + private final Logger logger = LoggerFactory.getLogger(TradfriDeviceData.class); + + protected JsonObject root; + protected JsonArray array; + protected JsonObject attributes; + protected JsonObject generalInfo; + + public TradfriDeviceData(String attributesNodeName) { + root = new JsonObject(); + array = new JsonArray(); + attributes = new JsonObject(); + array.add(attributes); + root.add(attributesNodeName, array); + generalInfo = new JsonObject(); + root.add(DEVICE, generalInfo); + } + + public TradfriDeviceData(String attributesNodeName, JsonElement json) { + try { + root = json.getAsJsonObject(); + array = root.getAsJsonArray(attributesNodeName); + attributes = array.get(0).getAsJsonObject(); + generalInfo = root.getAsJsonObject(DEVICE); + } catch (JsonSyntaxException e) { + logger.error("JSON error: {}", e.getMessage(), e); + } + } + + public Integer getDeviceId() { + return root.get(INSTANCE_ID).getAsInt(); + } + + public boolean getReachabilityStatus() { + if (root.get(REACHABILITY_STATE) != null) { + return root.get(REACHABILITY_STATE).getAsInt() == 1; + } else { + return false; + } + } + + public String getFirmwareVersion() { + if (generalInfo.get(DEVICE_FIRMWARE) != null) { + return generalInfo.get(DEVICE_FIRMWARE).getAsString(); + } else { + return null; + } + } + + public String getModelId() { + if (generalInfo.get(DEVICE_MODEL) != null) { + return generalInfo.get(DEVICE_MODEL).getAsString(); + } else { + return null; + } + } + + public String getVendor() { + if (generalInfo.get(DEVICE_VENDOR) != null) { + return generalInfo.get(DEVICE_VENDOR).getAsString(); + } else { + return null; + } + } +} diff --git a/extensions/binding/org.eclipse.smarthome.binding.tradfri/src/main/java/org/eclipse/smarthome/binding/tradfri/internal/model/TradfriLightData.java b/extensions/binding/org.eclipse.smarthome.binding.tradfri/src/main/java/org/eclipse/smarthome/binding/tradfri/internal/model/TradfriLightData.java new file mode 100644 index 00000000000..843a1125da0 --- /dev/null +++ b/extensions/binding/org.eclipse.smarthome.binding.tradfri/src/main/java/org/eclipse/smarthome/binding/tradfri/internal/model/TradfriLightData.java @@ -0,0 +1,133 @@ +/** + * 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.internal.model; + +import static org.eclipse.smarthome.binding.tradfri.TradfriBindingConstants.*; + +import org.eclipse.smarthome.binding.tradfri.internal.TradfriColor; +import org.eclipse.smarthome.core.library.types.HSBType; +import org.eclipse.smarthome.core.library.types.PercentType; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.gson.JsonElement; +import com.google.gson.JsonPrimitive; + +/** + * The {@link TradfriLightData} class is a Java wrapper for the raw JSON data about the light state. + * + * @author Kai Kreuzer - Initial contribution + * @author Holger Reichert - Support for color bulbs + * @author Christoph Weitkamp - Restructuring and refactoring of the binding + */ +public class TradfriLightData extends TradfriDeviceData { + + private final Logger logger = LoggerFactory.getLogger(TradfriLightData.class); + + public TradfriLightData() { + super(LIGHT); + } + + public TradfriLightData(JsonElement json) { + super(LIGHT, json); + } + + public TradfriLightData setBrightness(PercentType brightness) { + attributes.add(DIMMER, new JsonPrimitive(Math.round(brightness.floatValue() / 100.0f * 254))); + return this; + } + + public PercentType getBrightness() { + PercentType result = null; + + JsonElement dimmer = attributes.get(DIMMER); + if (dimmer != null) { + result = TradfriColor.xyBrightnessToPercentType(dimmer.getAsInt()); + } + + return result; + } + + public TradfriLightData setTransitionTime(int seconds) { + attributes.add(TRANSITION_TIME, new JsonPrimitive(seconds)); + return this; + } + + @SuppressWarnings("unused") + public int getTransitionTime() { + JsonElement transitionTime = attributes.get(TRANSITION_TIME); + if (transitionTime != null) { + return transitionTime.getAsInt(); + } else { + return 0; + } + } + + public TradfriLightData setColorTemperature(PercentType c) { + TradfriColor color = TradfriColor.fromColorTemperature(c); + int x = color.xyX; + int y = color.xyY; + logger.debug("New color temperature: {},{} ({} %)", x, y, c.intValue()); + attributes.add(COLOR_X, new JsonPrimitive(x)); + attributes.add(COLOR_Y, new JsonPrimitive(y)); + return this; + } + + public PercentType getColorTemperature() { + JsonElement colorX = attributes.get(COLOR_X); + JsonElement colorY = attributes.get(COLOR_Y); + if (colorX != null && colorY != null) { + return TradfriColor.calculateColorTemperature(colorX.getAsInt(), colorY.getAsInt()); + } else { + return null; + } + } + + public TradfriLightData setColor(HSBType hsb) { + // construct new HSBType with full brightness and extract XY color values from it + HSBType hsbFullBright = new HSBType(hsb.getHue(), hsb.getSaturation(), PercentType.HUNDRED); + TradfriColor color = TradfriColor.fromHSBType(hsbFullBright); + attributes.add(COLOR_X, new JsonPrimitive(color.xyX)); + attributes.add(COLOR_Y, new JsonPrimitive(color.xyY)); + return this; + } + + public HSBType getColor() { + // XY color coordinates plus brightness is needed for color calculation + JsonElement colorX = attributes.get(COLOR_X); + JsonElement colorY = attributes.get(COLOR_Y); + JsonElement dimmer = attributes.get(DIMMER); + if (colorX != null && colorY != null && dimmer != null) { + int x = colorX.getAsInt(); + int y = colorY.getAsInt(); + int brightness = dimmer.getAsInt(); + // extract HSBType from converted xy/brightness + TradfriColor color = TradfriColor.fromCie(x, y, brightness); + return color.hsbType; + } + return null; + } + + public TradfriLightData setOnOffState(boolean on) { + attributes.add(ONOFF, new JsonPrimitive(on ? 1 : 0)); + return this; + } + + public boolean getOnOffState() { + JsonElement onOff = attributes.get(ONOFF); + if (onOff != null) { + return attributes.get(ONOFF).getAsInt() == 1; + } else { + return false; + } + } + + public String getJsonString() { + return root.toString(); + } +} diff --git a/extensions/binding/org.eclipse.smarthome.binding.tradfri/src/main/java/org/eclipse/smarthome/binding/tradfri/internal/model/TradfriSensorData.java b/extensions/binding/org.eclipse.smarthome.binding.tradfri/src/main/java/org/eclipse/smarthome/binding/tradfri/internal/model/TradfriSensorData.java new file mode 100644 index 00000000000..45757d7f713 --- /dev/null +++ b/extensions/binding/org.eclipse.smarthome.binding.tradfri/src/main/java/org/eclipse/smarthome/binding/tradfri/internal/model/TradfriSensorData.java @@ -0,0 +1,29 @@ +/** + * 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.internal.model; + +import static org.eclipse.smarthome.binding.tradfri.TradfriBindingConstants.*; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.gson.JsonElement; + +/** + * The {@link TradfriSensorData} class is a Java wrapper for the raw JSON data about the sensor state. + * + * @author Christoph Weitkamp - Initial contribution + */ +public class TradfriSensorData extends TradfriWirelessDeviceData { + + private final Logger logger = LoggerFactory.getLogger(TradfriSensorData.class); + + public TradfriSensorData(JsonElement json) { + super(SENSOR, json); + } +} diff --git a/extensions/binding/org.eclipse.smarthome.binding.tradfri/src/main/java/org/eclipse/smarthome/binding/tradfri/internal/model/TradfriWirelessDeviceData.java b/extensions/binding/org.eclipse.smarthome.binding.tradfri/src/main/java/org/eclipse/smarthome/binding/tradfri/internal/model/TradfriWirelessDeviceData.java new file mode 100644 index 00000000000..b77d995f572 --- /dev/null +++ b/extensions/binding/org.eclipse.smarthome.binding.tradfri/src/main/java/org/eclipse/smarthome/binding/tradfri/internal/model/TradfriWirelessDeviceData.java @@ -0,0 +1,51 @@ +/** + * 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.internal.model; + +import static org.eclipse.smarthome.binding.tradfri.TradfriBindingConstants.*; + +import org.eclipse.smarthome.core.library.types.DecimalType; +import org.eclipse.smarthome.core.library.types.OnOffType; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.gson.JsonElement; + +/** + * The {@link TradfriWirelessDeviceData} class is a Java wrapper for the raw JSON data about wireless device state. + * + * @author Christoph Weitkamp - Initial contribution + */ +public abstract class TradfriWirelessDeviceData extends TradfriDeviceData { + + private final Logger logger = LoggerFactory.getLogger(TradfriWirelessDeviceData.class); + + public TradfriWirelessDeviceData(String attributesNodeName) { + super(attributesNodeName); + } + + public TradfriWirelessDeviceData(String attributesNodeName, JsonElement json) { + super(attributesNodeName, json); + } + + public DecimalType getBatteryLevel() { + if (generalInfo.get(DEVICE_BATTERY_LEVEL) != null) { + return new DecimalType(generalInfo.get(DEVICE_BATTERY_LEVEL).getAsInt()); + } else { + return null; + } + } + + public OnOffType getBatteryLow() { + if (generalInfo.get(DEVICE_BATTERY_LEVEL) != null) { + return generalInfo.get(DEVICE_BATTERY_LEVEL).getAsInt() <= 10 ? OnOffType.ON : OnOffType.OFF; + } else { + return null; + } + } +}