From 0c153b3ab067233e5ff0b84b16e14ac0da411c2b Mon Sep 17 00:00:00 2001 From: David Graeff Date: Fri, 11 Jan 2019 11:58:13 +0100 Subject: [PATCH] PercentageChannel: Return value between min and max. Homie: Remove handling completely. Readme: Add retain and isCommand and some more mqtt1 details. Rollershutter: Fix Signed-off-by: David Graeff --- .../generic/HomieImplementationTests.java | 5 +- .../handler/HomieThingHandlerTests.java | 35 +------- .../ESH-INF/config/dimmer-channel-config.xml | 87 +++++++++++++++++++ .../ESH-INF/thing/channels.xml | 2 +- .../README.md | 45 +++++++++- .../internal/convention/homie300/Device.java | 48 +--------- .../convention/homie300/DeviceCallback.java | 14 --- .../homie300/DeviceStatsAttributes.java | 31 ------- .../internal/handler/HomieThingHandler.java | 36 +------- .../internal/values/PercentageValue.java | 33 ++++++- .../internal/values/RollershutterValue.java | 4 +- .../generic/internal/values/ValueFactory.java | 2 +- 12 files changed, 171 insertions(+), 171 deletions(-) create mode 100644 extensions/binding/org.eclipse.smarthome.binding.mqtt.generic/ESH-INF/config/dimmer-channel-config.xml delete mode 100644 extensions/binding/org.eclipse.smarthome.binding.mqtt.generic/src/main/java/org/eclipse/smarthome/binding/mqtt/generic/internal/convention/homie300/DeviceStatsAttributes.java diff --git a/extensions/binding/org.eclipse.smarthome.binding.mqtt.generic.test/src/test/java/org/eclipse/smarthome/binding/mqtt/generic/HomieImplementationTests.java b/extensions/binding/org.eclipse.smarthome.binding.mqtt.generic.test/src/test/java/org/eclipse/smarthome/binding/mqtt/generic/HomieImplementationTests.java index 97dd615f7a1..954c163923f 100644 --- a/extensions/binding/org.eclipse.smarthome.binding.mqtt.generic.test/src/test/java/org/eclipse/smarthome/binding/mqtt/generic/HomieImplementationTests.java +++ b/extensions/binding/org.eclipse.smarthome.binding.mqtt.generic.test/src/test/java/org/eclipse/smarthome/binding/mqtt/generic/HomieImplementationTests.java @@ -35,7 +35,6 @@ import org.eclipse.smarthome.binding.mqtt.generic.internal.convention.homie300.DeviceAttributes; import org.eclipse.smarthome.binding.mqtt.generic.internal.convention.homie300.DeviceAttributes.ReadyState; import org.eclipse.smarthome.binding.mqtt.generic.internal.convention.homie300.DeviceCallback; -import org.eclipse.smarthome.binding.mqtt.generic.internal.convention.homie300.DeviceStatsAttributes; import org.eclipse.smarthome.binding.mqtt.generic.internal.convention.homie300.Node; import org.eclipse.smarthome.binding.mqtt.generic.internal.convention.homie300.NodeAttributes; import org.eclipse.smarthome.binding.mqtt.generic.internal.convention.homie300.Property; @@ -248,8 +247,8 @@ public void parseHomieTree() throws InterruptedException, ExecutionException, Ti // Create a Homie Device object. Because spied Nodes are required for call verification, // the full Device constructor need to be used and a ChildMap object need to be created manually. ChildMap nodeMap = new ChildMap<>(); - Device device = spy(new Device(ThingChannelConstants.testHomieThing, callback, new DeviceAttributes(), - new DeviceStatsAttributes(), nodeMap, Device.createDeviceStatisticsListener(handler))); + Device device = spy( + new Device(ThingChannelConstants.testHomieThing, callback, new DeviceAttributes(), nodeMap)); // Intercept creating a node in initialize()->start() and inject a spy'ed node. doAnswer(this::createSpyNode).when(device).createNode(any()); diff --git a/extensions/binding/org.eclipse.smarthome.binding.mqtt.generic.test/src/test/java/org/eclipse/smarthome/binding/mqtt/generic/internal/handler/HomieThingHandlerTests.java b/extensions/binding/org.eclipse.smarthome.binding.mqtt.generic.test/src/test/java/org/eclipse/smarthome/binding/mqtt/generic/internal/handler/HomieThingHandlerTests.java index 475cbe21bec..3920e9080bb 100644 --- a/extensions/binding/org.eclipse.smarthome.binding.mqtt.generic.test/src/test/java/org/eclipse/smarthome/binding/mqtt/generic/internal/handler/HomieThingHandlerTests.java +++ b/extensions/binding/org.eclipse.smarthome.binding.mqtt.generic.test/src/test/java/org/eclipse/smarthome/binding/mqtt/generic/internal/handler/HomieThingHandlerTests.java @@ -34,7 +34,6 @@ import org.eclipse.smarthome.binding.mqtt.generic.internal.convention.homie300.Device; import org.eclipse.smarthome.binding.mqtt.generic.internal.convention.homie300.DeviceAttributes; import org.eclipse.smarthome.binding.mqtt.generic.internal.convention.homie300.DeviceAttributes.ReadyState; -import org.eclipse.smarthome.binding.mqtt.generic.internal.convention.homie300.DeviceStatsAttributes; import org.eclipse.smarthome.binding.mqtt.generic.internal.convention.homie300.Node; import org.eclipse.smarthome.binding.mqtt.generic.internal.convention.homie300.NodeAttributes; import org.eclipse.smarthome.binding.mqtt.generic.internal.convention.homie300.Property; @@ -132,8 +131,7 @@ public void setUp() { thingHandler = spy(handler); thingHandler.setCallback(callback); final Device device = new Device(thing.getUID(), thingHandler, spy(new DeviceAttributes()), - spy(new DeviceStatsAttributes()), new ChildMap<>(), - Device.createDeviceStatisticsListener(thingHandler)); + spy(new ChildMap<>())); thingHandler.setInternalObjects(spy(device), spy(new DelayedBatchProcessing(500, thingHandler, scheduler))); @@ -366,35 +364,4 @@ public void propertiesChanged() throws InterruptedException, ExecutionException assertThat(properties.get(MqttBindingConstants.HOMIE_PROPERTY_VERSION), is("3.0")); assertThat(properties.size(), is(1)); } - - @Test - public void heartBeatInterval() - throws InterruptedException, ExecutionException, NoSuchFieldException, SecurityException { - thingHandler.device.initialize("homie", "device", new ArrayList()); - thingHandler.connection = connection; - - // Inject spy'ed subscriber object - doAnswer(this::createSubscriberAnswer).when(thingHandler.device.stats).createSubscriber(any(), any(), any(), - anyBoolean()); - doAnswer(this::createSubscriberAnswer).when(thingHandler.device.attributes).createSubscriber(any(), any(), - any(), anyBoolean()); - - thingHandler.device.attributes.state = ReadyState.ready; - thingHandler.device.attributes.name = "device"; - thingHandler.device.attributes.homie = "3.0"; - thingHandler.device.attributes.nodes = new String[] {}; - - thingHandler.initialize(); - - assertThat(thingHandler.device.isInitialized(), is(true)); - - verify(thingHandler.device).attributesReceived(any(), any(), anyInt()); - verify(thingHandler.device.stats).subscribeAndReceive(any(), any(), anyString(), any(), anyInt()); - - // Emulate a received value for the "interval" topic - thingHandler.device.stats.fieldChanged(DeviceStatsAttributes.class.getDeclaredField("interval"), 60); - - verify(thingHandler).heartbeatIntervalChanged(anyInt()); - verify(callback).thingUpdated(any()); - } } diff --git a/extensions/binding/org.eclipse.smarthome.binding.mqtt.generic/ESH-INF/config/dimmer-channel-config.xml b/extensions/binding/org.eclipse.smarthome.binding.mqtt.generic/ESH-INF/config/dimmer-channel-config.xml new file mode 100644 index 00000000000..06e402c9a13 --- /dev/null +++ b/extensions/binding/org.eclipse.smarthome.binding.mqtt.generic/ESH-INF/config/dimmer-channel-config.xml @@ -0,0 +1,87 @@ + + + + + + + These configuration parameters allow you to alter a value before it is published to MQTT or before a received value is assigned to an item. + true + + + + + An MQTT topic that this thing will subscribe to, to receive the state. This can be left empty, the channel will be state-less command-only channel. + + + + An MQTT topic that this thing will send a command to. If not set, this will be a read-only switch. + + + + + true + + + + + true + + + + + true + %s + + + + The value will be published to the command topic as retained message. A retained value stays on the broker and can even be seen by MQTT clients that are subscribing at a later point in time. + false + true + + + + + This configuration represents the minimum of the allowed range. For a percentage channel that equals zero percent. + + + + This configuration represents the maximum of the allowed range. For a percentage channel that equals one-hundred percent. + + + + A number/dimmer channel can receive Increase/Decrease commands and computes the target number by adding or subtracting this delta value. + 1.0 + true + + + + A number (like 1, 10) or a string (like "enabled") that is additionally recognised as on/open state. You can use this parameter for a second keyword, next to ON (OPEN respectively on a Contact). + 1 + + + + A number (like 0, -10) or a string (like "disabled") that is additionally recognised as off/closed state. You can use this parameter for a second keyword, next to OFF (CLOSED respectively on a Contact). + 0 + + + diff --git a/extensions/binding/org.eclipse.smarthome.binding.mqtt.generic/ESH-INF/thing/channels.xml b/extensions/binding/org.eclipse.smarthome.binding.mqtt.generic/ESH-INF/thing/channels.xml index 165c3912ac6..70feef66bc6 100644 --- a/extensions/binding/org.eclipse.smarthome.binding.mqtt.generic/ESH-INF/thing/channels.xml +++ b/extensions/binding/org.eclipse.smarthome.binding.mqtt.generic/ESH-INF/thing/channels.xml @@ -41,7 +41,7 @@ Dimmer - + diff --git a/extensions/binding/org.eclipse.smarthome.binding.mqtt.generic/README.md b/extensions/binding/org.eclipse.smarthome.binding.mqtt.generic/README.md index c892a896e54..4ff672194ac 100644 --- a/extensions/binding/org.eclipse.smarthome.binding.mqtt.generic/README.md +++ b/extensions/binding/org.eclipse.smarthome.binding.mqtt.generic/README.md @@ -70,6 +70,8 @@ All things require a configured broker. * __transformationPatternOut__: An optional transformation pattern like [JSONPath](http://goessner.net/articles/JsonPath/index.html#e2) that is applied before publishing a value to MQTT. * __commandTopic__: The MQTT topic that commands are send to. This can be empty, the thing channel will be read-only then. Transformations are not applied for sending data. * __formatBeforePublish__: Format a value before it is published to the MQTT broker. The default is to just pass the channel/item state. If you want to apply a prefix, say "MYCOLOR,", you would use "MYCOLOR,%s". If you want to adjust the precision of a number to for example 4 digits, you would use "%.4f". +* __postCommand__: If the received MQTT value should not only update the state of linked items, but command them, enable this option. You usually need this enabled if your item is also linked to another channel, say a KNX actor, and you want a received MQTT payload to command that KNX actor. +* __retained__: The value will be published to the command topic as retained message. A retained value stays on the broker and can even be seen by MQTT clients that are subscribing at a later point in time. ### Channel Type "string" @@ -226,6 +228,13 @@ Here are a few examples: - For an output of *23.05.1995* use "%1$**td**.%1$**tm**.%1$**tY**". - For an output of *23:15* use "%1$**tH**:%1$**tM**". +## Troubleshooting + +* If you get the error "No MQTT client": Please update your installation. +* If you use the Mosquitto broker: Please be aware that there is a relatively low setting + for retained messages. At some point messages will just not being delivered + anymore: Change the setting + ## Examples Have a look at the following textual examples. @@ -311,10 +320,14 @@ end The conversion is straight forward, but need to be done for each item. You do not need to convert everything in one go. MQTT1 and MQTT2 can coexist. +> For mqtt1 make sure you have enabled the Legacy 1.x repository and installed "mqtt1". + +### 1 Command / 1 State topic + Assume you have this item: ```xtend -Switch ExampleItem "Heatpump Power" { mqtt=">[mosquitto:heatpump/set:command:*:DEFAULT)],<[mosquitto:heatpump:state:JSONPATH($.power)]" } +Switch ExampleItem "Heatpump Power" { mqtt=">[mosquitto:heatpump/set:command:*:DEFAULT)],<[mosquitto:heatpump/state:JSONPATH($.power)]" } ``` This converts to an entry in your *.things file with a **Broker Thing** and a **Generic MQTT Thing** that uses the bridge: @@ -336,3 +349,33 @@ Your items change to: ```xtend Switch ExampleItem "Heatpump Power" { channel="mqtt:myUnsecureBroker:topic:mything:heatpumpChannel" } ``` + + +### 1 Command / 2 State topics + +If you receive updates from two different topics, you need to create multiple channels now, 1 for each MQTT receive topic. + +```xtend +Switch ExampleItem "Heatpump Power" { mqtt=">[mosquitto:heatpump/set:command:*:DEFAULT)],<[mosquitto:heatpump/state1:state:*:DEFAULT",<[mosquitto:heatpump/state2:state:*:DEFAULT" } +``` + +This converts to: + +```xtend +Bridge mqtt:broker:myUnsecureBroker [ host="192.168.0.42", secure=false ] +{ + Thing mqtt:topic:mything { + Channels: + Type switch : heatpumpChannel "Heatpump Power" [ stateTopic="heatpump/state1", commandTopic="heatpump/set" ] + Type switch : heatpumpChannel2 "Heatpump Power" [ stateTopic="heatpump/state2" ] + } +} +``` + +Link both channels to one item. That item will publish to "heatpump/set" on a change and +receive values from "heatpump/state1" and "heatpump/state2". + +```xtend +Switch ExampleItem "Heatpump Power" { channel="mqtt:myUnsecureBroker:topic:mything:heatpumpChannel", + channel="mqtt:myUnsecureBroker:topic:mything:heatpumpChannel2" } +``` diff --git a/extensions/binding/org.eclipse.smarthome.binding.mqtt.generic/src/main/java/org/eclipse/smarthome/binding/mqtt/generic/internal/convention/homie300/Device.java b/extensions/binding/org.eclipse.smarthome.binding.mqtt.generic/src/main/java/org/eclipse/smarthome/binding/mqtt/generic/internal/convention/homie300/Device.java index 0d460ccc48d..3e107a52d55 100644 --- a/extensions/binding/org.eclipse.smarthome.binding.mqtt.generic/src/main/java/org/eclipse/smarthome/binding/mqtt/generic/internal/convention/homie300/Device.java +++ b/extensions/binding/org.eclipse.smarthome.binding.mqtt.generic/src/main/java/org/eclipse/smarthome/binding/mqtt/generic/internal/convention/homie300/Device.java @@ -20,7 +20,6 @@ import org.eclipse.jdt.annotation.Nullable; import org.eclipse.smarthome.binding.mqtt.generic.internal.handler.HomieThingHandler; import org.eclipse.smarthome.binding.mqtt.generic.internal.mapping.AbstractMqttAttributeClass; -import org.eclipse.smarthome.binding.mqtt.generic.internal.mapping.AbstractMqttAttributeClass.AttributeChanged; import org.eclipse.smarthome.binding.mqtt.generic.internal.tools.ChildMap; import org.eclipse.smarthome.core.thing.Channel; import org.eclipse.smarthome.core.thing.ChannelUID; @@ -50,7 +49,6 @@ public class Device implements AbstractMqttAttributeClass.AttributeChanged { private final Logger logger = LoggerFactory.getLogger(Device.class); // The device attributes, statistics and nodes of this device public final DeviceAttributes attributes; - public final DeviceStatsAttributes stats; public final ChildMap nodes; // The corresponding ThingUID and callback of this device object @@ -61,7 +59,6 @@ public class Device implements AbstractMqttAttributeClass.AttributeChanged { private String topic = ""; public String deviceID = ""; private boolean initialized = false; - private final AttributeChanged deviceStatisticsListener; /** * Creates a Homie Device structure. It consists of device attributes, device statistics and nodes. @@ -69,16 +66,12 @@ public class Device implements AbstractMqttAttributeClass.AttributeChanged { * @param thingUID The thing UID * @param callback A callback, used to notify about new/removed nodes/properties and more. * @param attributes The device attributes object - * @param stats The device statistics object */ - public Device(ThingUID thingUID, DeviceCallback callback, DeviceAttributes attributes, - DeviceStatsAttributes stats) { + public Device(ThingUID thingUID, DeviceCallback callback, DeviceAttributes attributes) { this.thingUID = thingUID; this.callback = callback; this.attributes = attributes; - this.stats = stats; this.nodes = new ChildMap<>(); - this.deviceStatisticsListener = createDeviceStatisticsListener(callback); } /** @@ -87,40 +80,13 @@ public Device(ThingUID thingUID, DeviceCallback callback, DeviceAttributes attri * @param thingUID The thing UID * @param callback A callback, used to notify about new/removed nodes/properties and more. * @param attributes The device attributes object - * @param stats The device statistics object * @param nodes The nodes map - * @param deviceStatisticsListener The AttributeChanged listener for the device statistics. Create the default one - * with {@link #createDeviceStatisticsListener(DeviceCallback)}. */ - public Device(ThingUID thingUID, DeviceCallback callback, DeviceAttributes attributes, DeviceStatsAttributes stats, - ChildMap nodes, AttributeChanged deviceStatisticsListener) { + public Device(ThingUID thingUID, DeviceCallback callback, DeviceAttributes attributes, ChildMap nodes) { this.thingUID = thingUID; this.callback = callback; this.attributes = attributes; - this.stats = stats; this.nodes = nodes; - this.deviceStatisticsListener = deviceStatisticsListener; - } - - /** - * Create the default listener for the device statistic attributes object. - * - *

- * To be used for the - * {@link #Device(ThingUID, DeviceCallback, DeviceAttributes, DeviceStatsAttributes, ChildMap, AttributeChanged)} - * constructor. - *

- * - * @param callback A device callback - * @return The listener - */ - public static AttributeChanged createDeviceStatisticsListener(DeviceCallback callback) { - return (String name, Object value, MqttBrokerConnection connection, ScheduledExecutorService scheduler, - boolean allMandatoryFieldsReceived) -> { - if ("interval".equals(name)) { - callback.heartbeatIntervalChanged((int) value); - } - }; } /** @@ -154,14 +120,6 @@ public static AttributeChanged createDeviceStatisticsListener(DeviceCallback cal public CompletableFuture<@Nullable Void> attributesReceived(MqttBrokerConnection connection, ScheduledExecutorService scheduler, int timeout) { callback.readyStateChanged(attributes.state); - // Subscribe to statistics attributes - stats.subscribeAndReceive(connection, scheduler, topic + "/$stats", deviceStatisticsListener, timeout) - .exceptionally(e -> { - logger.warn("Did not receive all required device statistics attributes!"); - // Default heartbeat interval assumed - callback.heartbeatIntervalChanged(stats.interval); - return null; - }); return applyNodes(connection, scheduler, timeout); } @@ -207,7 +165,7 @@ public static AttributeChanged createDeviceStatisticsListener(DeviceCallback cal * Unsubscribe from everything. */ public CompletableFuture<@Nullable Void> stop() { - return attributes.unsubscribe().thenCompose(b -> stats.unsubscribe()).thenCompose( + return attributes.unsubscribe().thenCompose( b -> CompletableFuture.allOf(nodes.stream().map(n -> n.stop()).toArray(CompletableFuture[]::new))); } diff --git a/extensions/binding/org.eclipse.smarthome.binding.mqtt.generic/src/main/java/org/eclipse/smarthome/binding/mqtt/generic/internal/convention/homie300/DeviceCallback.java b/extensions/binding/org.eclipse.smarthome.binding.mqtt.generic/src/main/java/org/eclipse/smarthome/binding/mqtt/generic/internal/convention/homie300/DeviceCallback.java index 5a584d5bb68..6011037bc4f 100644 --- a/extensions/binding/org.eclipse.smarthome.binding.mqtt.generic/src/main/java/org/eclipse/smarthome/binding/mqtt/generic/internal/convention/homie300/DeviceCallback.java +++ b/extensions/binding/org.eclipse.smarthome.binding.mqtt.generic/src/main/java/org/eclipse/smarthome/binding/mqtt/generic/internal/convention/homie300/DeviceCallback.java @@ -24,13 +24,6 @@ */ @NonNullByDefault public interface DeviceCallback extends ChannelStateUpdateListener { - /** - * Called whenever the heartbeat interval changes. - * - * @param intervalInSec Interval in seconds. - */ - void heartbeatIntervalChanged(int intervalInSec); - /** * Called whenever the device state changed * @@ -38,13 +31,6 @@ public interface DeviceCallback extends ChannelStateUpdateListener { */ void readyStateChanged(ReadyState state); - /** - * Called whenever the statistics properties changed - * - * @param stats The new statistics - */ - void statisticAttributesChanged(DeviceStatsAttributes stats); - /** * Called, whenever a Homie node was existing before, but is not anymore. * diff --git a/extensions/binding/org.eclipse.smarthome.binding.mqtt.generic/src/main/java/org/eclipse/smarthome/binding/mqtt/generic/internal/convention/homie300/DeviceStatsAttributes.java b/extensions/binding/org.eclipse.smarthome.binding.mqtt.generic/src/main/java/org/eclipse/smarthome/binding/mqtt/generic/internal/convention/homie300/DeviceStatsAttributes.java deleted file mode 100644 index 9e90ed0b7ea..00000000000 --- a/extensions/binding/org.eclipse.smarthome.binding.mqtt.generic/src/main/java/org/eclipse/smarthome/binding/mqtt/generic/internal/convention/homie300/DeviceStatsAttributes.java +++ /dev/null @@ -1,31 +0,0 @@ -/** - * Copyright (c) 2014,2019 Contributors to the Eclipse Foundation - * - * See the NOTICE file(s) distributed with this work for additional - * information regarding copyright ownership. - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License 2.0 which is available at - * http://www.eclipse.org/legal/epl-2.0 - * - * SPDX-License-Identifier: EPL-2.0 - */ -package org.eclipse.smarthome.binding.mqtt.generic.internal.convention.homie300; - -import org.eclipse.jdt.annotation.NonNullByDefault; -import org.eclipse.smarthome.binding.mqtt.generic.internal.mapping.AbstractMqttAttributeClass; - -/** - * Homie 3.x Device statistic attributes - * - * @author David Graeff - Initial contribution - */ -@NonNullByDefault -public class DeviceStatsAttributes extends AbstractMqttAttributeClass { - public int interval = 0; // In seconds - - @Override - public Object getFieldsOf() { - return this; - } -} diff --git a/extensions/binding/org.eclipse.smarthome.binding.mqtt.generic/src/main/java/org/eclipse/smarthome/binding/mqtt/generic/internal/handler/HomieThingHandler.java b/extensions/binding/org.eclipse.smarthome.binding.mqtt.generic/src/main/java/org/eclipse/smarthome/binding/mqtt/generic/internal/handler/HomieThingHandler.java index ad46cc6979a..56550bae764 100644 --- a/extensions/binding/org.eclipse.smarthome.binding.mqtt.generic/src/main/java/org/eclipse/smarthome/binding/mqtt/generic/internal/handler/HomieThingHandler.java +++ b/extensions/binding/org.eclipse.smarthome.binding.mqtt.generic/src/main/java/org/eclipse/smarthome/binding/mqtt/generic/internal/handler/HomieThingHandler.java @@ -13,11 +13,8 @@ package org.eclipse.smarthome.binding.mqtt.generic.internal.handler; import java.util.List; -import java.util.Map; -import java.util.TreeMap; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ScheduledFuture; -import java.util.concurrent.TimeUnit; import java.util.function.Consumer; import java.util.stream.Collectors; @@ -28,7 +25,6 @@ import org.eclipse.smarthome.binding.mqtt.generic.internal.convention.homie300.DeviceAttributes; import org.eclipse.smarthome.binding.mqtt.generic.internal.convention.homie300.DeviceAttributes.ReadyState; import org.eclipse.smarthome.binding.mqtt.generic.internal.convention.homie300.DeviceCallback; -import org.eclipse.smarthome.binding.mqtt.generic.internal.convention.homie300.DeviceStatsAttributes; import org.eclipse.smarthome.binding.mqtt.generic.internal.convention.homie300.HandlerConfiguration; import org.eclipse.smarthome.binding.mqtt.generic.internal.convention.homie300.Node; import org.eclipse.smarthome.binding.mqtt.generic.internal.convention.homie300.Property; @@ -80,7 +76,7 @@ public HomieThingHandler(Thing thing, MqttChannelTypeProvider channelTypeProvide this.subscribeTimeout = subscribeTimeout; this.attributeReceiveTimeout = attributeReceiveTimeout; this.delayedProcessing = new DelayedBatchProcessing(subscribeTimeout, this, scheduler); - this.device = new Device(this.thing.getUID(), this, new DeviceAttributes(), new DeviceStatsAttributes()); + this.device = new Device(this.thing.getUID(), this, new DeviceAttributes()); } /** @@ -160,13 +156,6 @@ public void readyStateChanged(ReadyState state) { } } - @Override - public void statisticAttributesChanged(DeviceStatsAttributes stats) { - Map properties = new TreeMap<>(); - properties.put("interval", String.valueOf(stats.interval)); - updateProperties(properties); - } - @Override public void nodeRemoved(Node node) { channelTypeProvider.removeChannelGroupType(node.channelGroupTypeUID); @@ -213,27 +202,4 @@ public void accept(@Nullable List t) { }); } } - - protected void heartbeatFailed() { - readyStateChanged(ReadyState.lost); - } - - @Override - public void heartbeatIntervalChanged(int intervalInSec) { - // Cancel existing timeout - final ScheduledFuture scheduledFuture = this.heartBeatTimer; - if (scheduledFuture != null) { - scheduledFuture.cancel(false); - this.heartBeatTimer = null; - } - // Schedule new one - if (intervalInSec > 0) { - this.heartBeatTimer = scheduler.schedule(this::heartbeatFailed, intervalInSec, TimeUnit.SECONDS); - } - updateProperty(MqttBindingConstants.HOMIE_PROPERTY_HEARTBEAT_INTERVAL, String.valueOf(device.stats.interval)); - // if heart beat missed last time -> set online again - if (thing.getStatus() == ThingStatus.OFFLINE) { - readyStateChanged(device.attributes.state); - } - } } diff --git a/extensions/binding/org.eclipse.smarthome.binding.mqtt.generic/src/main/java/org/eclipse/smarthome/binding/mqtt/generic/internal/values/PercentageValue.java b/extensions/binding/org.eclipse.smarthome.binding.mqtt.generic/src/main/java/org/eclipse/smarthome/binding/mqtt/generic/internal/values/PercentageValue.java index 6c678579a7d..30f2f555d32 100644 --- a/extensions/binding/org.eclipse.smarthome.binding.mqtt.generic/src/main/java/org/eclipse/smarthome/binding/mqtt/generic/internal/values/PercentageValue.java +++ b/extensions/binding/org.eclipse.smarthome.binding.mqtt.generic/src/main/java/org/eclipse/smarthome/binding/mqtt/generic/internal/values/PercentageValue.java @@ -23,6 +23,7 @@ import org.eclipse.smarthome.core.library.types.DecimalType; import org.eclipse.smarthome.core.library.types.IncreaseDecreaseType; import org.eclipse.smarthome.core.library.types.PercentType; +import org.eclipse.smarthome.core.library.types.StringType; import org.eclipse.smarthome.core.library.types.UpDownType; import org.eclipse.smarthome.core.types.Command; import org.eclipse.smarthome.core.types.StateDescription; @@ -46,10 +47,16 @@ public class PercentageValue extends Value { private final double min; private final double max; private final double step; + private final @Nullable String onValue; + private final @Nullable String offValue; - public PercentageValue(@Nullable BigDecimal min, @Nullable BigDecimal max, @Nullable BigDecimal step) { - super(CoreItemFactory.DIMMER, Stream.of(DecimalType.class, IncreaseDecreaseType.class, UpDownType.class) - .collect(Collectors.toList())); + public PercentageValue(@Nullable BigDecimal min, @Nullable BigDecimal max, @Nullable BigDecimal step, + @Nullable String onValue, @Nullable String offValue) { + super(CoreItemFactory.DIMMER, + Stream.of(DecimalType.class, IncreaseDecreaseType.class, UpDownType.class, StringType.class) + .collect(Collectors.toList())); + this.onValue = onValue; + this.offValue = offValue; this.min = min == null ? 0.0 : min.doubleValue(); this.max = max == null ? 100.0 : max.doubleValue(); if (this.min >= this.max) { @@ -83,11 +90,31 @@ public void update(Command command) throws IllegalArgumentException { final double v = oldvalue.doubleValue() - step; state = new PercentType(new BigDecimal(v >= min ? v : min)); } + } else if (command instanceof StringType) { + if (onValue != null && command.toString().equals(onValue)) { + state = new PercentType(new BigDecimal(max)); + } else if (offValue != null && command.toString().equals(offValue)) { + state = new PercentType(new BigDecimal(min)); + } else { + throw new IllegalStateException("Unknown String!"); + } } else { state = PercentType.valueOf(command.toString()); } } + @Override + public String getMQTTpublishValue() { + if (state == UnDefType.UNDEF) { + return ""; + } + // Formular: value*max/100+min + // Calculation need to happen with big decimals to either return a straight integer or a decimal depending on + // the value. + return ((PercentType) state).toBigDecimal().multiply(BigDecimal.valueOf(max)).divide(BigDecimal.valueOf(100)) + .add(BigDecimal.valueOf(min)).toString(); + } + @Override public StateDescription createStateDescription(String unit, boolean readOnly) { return new StateDescription(new BigDecimal(min), new BigDecimal(max), new BigDecimal(step), diff --git a/extensions/binding/org.eclipse.smarthome.binding.mqtt.generic/src/main/java/org/eclipse/smarthome/binding/mqtt/generic/internal/values/RollershutterValue.java b/extensions/binding/org.eclipse.smarthome.binding.mqtt.generic/src/main/java/org/eclipse/smarthome/binding/mqtt/generic/internal/values/RollershutterValue.java index b30a5032715..5f2e691e974 100644 --- a/extensions/binding/org.eclipse.smarthome.binding.mqtt.generic/src/main/java/org/eclipse/smarthome/binding/mqtt/generic/internal/values/RollershutterValue.java +++ b/extensions/binding/org.eclipse.smarthome.binding.mqtt.generic/src/main/java/org/eclipse/smarthome/binding/mqtt/generic/internal/values/RollershutterValue.java @@ -54,9 +54,7 @@ public RollershutterValue(@Nullable String upString, @Nullable String downString @Override public void update(Command command) throws IllegalArgumentException { - if (command instanceof UpDownType) { - throw new IllegalStateException("Cannot call update() with UpDownType"); - } else if (command instanceof StopMoveType) { + if (command instanceof StopMoveType) { throw new IllegalStateException("Cannot call update() with StopMoveType"); } else if (command instanceof PercentType) { state = (PercentType) command; diff --git a/extensions/binding/org.eclipse.smarthome.binding.mqtt.generic/src/main/java/org/eclipse/smarthome/binding/mqtt/generic/internal/values/ValueFactory.java b/extensions/binding/org.eclipse.smarthome.binding.mqtt.generic/src/main/java/org/eclipse/smarthome/binding/mqtt/generic/internal/values/ValueFactory.java index 32bc8566ac5..26437cf43a7 100644 --- a/extensions/binding/org.eclipse.smarthome.binding.mqtt.generic/src/main/java/org/eclipse/smarthome/binding/mqtt/generic/internal/values/ValueFactory.java +++ b/extensions/binding/org.eclipse.smarthome.binding.mqtt.generic/src/main/java/org/eclipse/smarthome/binding/mqtt/generic/internal/values/ValueFactory.java @@ -50,7 +50,7 @@ public static Value createValueState(ChannelConfig config, String channelTypeID) value = new NumberValue(config.min, config.max, config.step); break; case MqttBindingConstants.DIMMER: - value = new PercentageValue(config.min, config.max, config.step); + value = new PercentageValue(config.min, config.max, config.step, config.on, config.off); break; case MqttBindingConstants.COLOR_RGB: value = new ColorValue(true, config.on, config.off, config.onBrightness);