]> git.basschouten.com Git - openhab-addons.git/commitdiff
[lutron] Minor code and doc updates (#8795)
authorBob A <bobadair@users.noreply.github.com>
Wed, 21 Oct 2020 18:50:49 +0000 (14:50 -0400)
committerGitHub <noreply@github.com>
Wed, 21 Oct 2020 18:50:49 +0000 (11:50 -0700)
* [lutron] Minor code and doc updates
* [lutron] Address review comments

Signed-off-by: Bob Adair <bob.github@att.net>
12 files changed:
bundles/org.openhab.binding.lutron/README.md
bundles/org.openhab.binding.lutron/doc/leapnotes.md
bundles/org.openhab.binding.lutron/src/main/java/org/openhab/binding/lutron/internal/StringUtils.java [new file with mode: 0644]
bundles/org.openhab.binding.lutron/src/main/java/org/openhab/binding/lutron/internal/config/IPBridgeConfig.java
bundles/org.openhab.binding.lutron/src/main/java/org/openhab/binding/lutron/internal/grxprg/GrafikEyeHandler.java
bundles/org.openhab.binding.lutron/src/main/java/org/openhab/binding/lutron/internal/grxprg/PrgProtocolHandler.java
bundles/org.openhab.binding.lutron/src/main/java/org/openhab/binding/lutron/internal/handler/CcoHandler.java
bundles/org.openhab.binding.lutron/src/main/java/org/openhab/binding/lutron/internal/handler/IPBridgeHandler.java
bundles/org.openhab.binding.lutron/src/main/java/org/openhab/binding/lutron/internal/handler/LeapBridgeHandler.java
bundles/org.openhab.binding.lutron/src/main/java/org/openhab/binding/lutron/internal/protocol/DeviceCommand.java
bundles/org.openhab.binding.lutron/src/main/java/org/openhab/binding/lutron/internal/protocol/leap/LeapMessageParser.java
bundles/org.openhab.binding.lutron/src/main/resources/OH-INF/thing/thing-types.xml

index f7d459b3f1c1c25ecabb815dd382ee7fff5100b5..149f6b8b5669d58f28a2807ff3e5688ed0e581b7 100644 (file)
@@ -1,18 +1,18 @@
 # Lutron Binding
 
 This binding integrates with [Lutron](http://www.lutron.com) lighting control and home automation systems.
-It contains separate binding support for four different types of Lutron systems:
+It contains support for four different types of Lutron systems via different bridge things:
 
-* RadioRA 2, HomeWorks QS, and other systems that can be controlled by Lutron Integration Protocol (LIP) or LEAP, such as RA2 Select, and Caseta
+* RadioRA 2, HomeWorks QS, Caseta, RA2 Select, and other current systems that can be controlled via Lutron Integration Protocol (LIP) or LEAP
 * The original RadioRA system, referred to here as RadioRA Classic
 * Legacy HomeWorks RS232 Processors
 * Grafik Eye 3x/4x systems with GRX-PRG or GRX-CI-PRG control interfaces
 
 Each is described in a separate section below.
 
-# Lutron RadioRA 2/HomeWorks QS/Caseta Binding
+# Lutron RadioRA 2/HomeWorks QS/RA2 Select/Caseta Binding
 
-**Note:** While the Lutron Integration Protocol used by this binding should largely be compatible with other current Lutron systems, this binding has only been fully tested with RadioRA 2, HomeWorks QS, and Caseta with Smart Bridge Pro.
+**Note:** While the Lutron Integration Protocol used by ipbridge in this binding should largely be compatible with other current Lutron systems, it has only been fully tested with RadioRA 2, HomeWorks QS, and Caseta with Smart Bridge Pro.
 Homeworks QS support is still a work in progress, since not all features/devices are supported yet.
 RA2 Select systems work with the binding, but full support for all devices still needs to be confirmed.
 Caseta Smart Bridge (non-Pro model) support and support for Caseta occupancy sensors is available only through the experimental leapbridge thing.
@@ -49,16 +49,20 @@ This binding currently supports the following thing types:
 ## Discovery
 
 Full discovery is supported for RadioRA 2 and HomeWorks QS systems.
-Both the main repeaters/processors themselves and the devices connected to them can be automatically discovered.
+Both the main repeaters/processors themselves and the devices connected to them will be automatically discovered.
 Discovered repeaters/processors will be accessed using the default integration credentials.
 These can be changed in the bridge thing configuration.
-Discovered keypad devices should now have their model parameters automatically set to the correct value.
+Discovered keypad devices should have their model parameters automatically set to the correct value.
 
-Caseta Smart Bridge hubs, Smart Bridge Pro 2 hubs, and RA2 Select main repeaters should now be discovered automatically via mDNS.
-Devices attached to them still need to be configured manually unless the experimental leapbridge is used.
+Caseta Smart Bridge hubs, Smart Bridge Pro 2 hubs, and RA2 Select main repeaters should be discovered automatically via mDNS.
+Devices attached to them need to be configured manually when using ipbridge.
+The experimental leapbridge supports full automated discovery of these systems, but authentication information must be manually entered.
 
 Other supported Lutron systems must be configured manually.
 
+**Note:** Discovery selects ipbridge for HomeWorks QS, RadioRA 2, RA2 Select, and Caseta Smart Bridge Pro.
+It select leapbridge for Caseta Smart Bridge, since only LEAP protocol is supported by this system.
+
 ## Binding Configuration
 
 This binding does not require any special configuration.
@@ -71,9 +75,9 @@ If a thing will not come online, but instead has the status "UNKNOWN: Awaiting i
 
 ### Bridges
 
-Two different bridges are now supported by the binding, ipbridge and leapbridge.
+Two different bridges are now supported by the binding for current Lutron systems, ipbridge and leapbridge.
 The LIP protocol is supported by ipbridge while the LEAP protocol is supported by leapbridge.
-Current Lutron systems support one or both protocols as shown below.
+Current systems support one or both protocols as shown below.
 
 |Bridge Device           | LIP | LEAP |
 |------------------------|-----|------|
index c19b68fbf8fa505d005919a0145913a931cbf5ab..c962cf87059b98197cba165ff01007ccda2e94b1 100644 (file)
@@ -3,8 +3,8 @@
 Unlike LIP, which was designed to use a simple serial or telnet connection and authenticates using a username/password, LEAP uses a SSL connection and authenticates using certificates.
 This necessarily makes configuration more complicated.
 There are several open source utilities available for generating the certificate files necessary to access your Caseta or RA2 Select hub.
-One good choice is the get_lutron_cert.py script included with the pylutron library which is available on Github at https://github.com/gurumitts/pylutron-caseta .
-On a unix system, you can easily retrieve it using curl with a command like:
+One good choice is the get_lutron_cert.py script included with the popular pylutron library which is available on Github at https://github.com/gurumitts/pylutron-caseta .
+On a unix-like system, you can easily retrieve it using curl with a command like:
 
 ```
 curl https://raw.githubusercontent.com/gurumitts/pylutron-caseta/dev/get_lutron_cert.py >get_lutron_cert.py
@@ -30,11 +30,10 @@ keytool -importcert -file caseta-bridge.crt -keystore lutron.keystore -alias cas
 ```
 
 Respond to the password prompt(s) with a password, and then use that password in the -srcstorepass parameter of the keytool command and in the keystorePassword parameter for leapbridge.
-In the example above, the pkcs12 store password was set to “secret”, but hopefully you can think of a better one.
+In the example above, the pkcs12 store password was set to “secret”, but hopefully you can think of a better one!
 The lutron.keystore file that you end up with is the one you’ll need to give the binding access to.
 The caseta.p12 file is just an intermediate file that you can delete later.
 
 Finally you’ll then need to set the ipAddress, keystore, and keystorePassword parameters of the leapbridge thing.
 The ipAddress will be set for you if you used discovery to detect a Caseta Smart Bridge.
-
-
+This should also work with DHCP, although setting a static IP address for your bridge is still recommended.
diff --git a/bundles/org.openhab.binding.lutron/src/main/java/org/openhab/binding/lutron/internal/StringUtils.java b/bundles/org.openhab.binding.lutron/src/main/java/org/openhab/binding/lutron/internal/StringUtils.java
new file mode 100644 (file)
index 0000000..988ab17
--- /dev/null
@@ -0,0 +1,36 @@
+/**
+ * Copyright (c) 2010-2020 Contributors to the openHAB project
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information.
+ *
+ * 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.openhab.binding.lutron.internal;
+
+import java.util.Objects;
+
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.eclipse.jdt.annotation.Nullable;
+
+/**
+ * Supply some string utility methods formerly provided by org.apache.commons.lang.StringUtils.
+ *
+ * @author Bob Adair - Initial contribution
+ *
+ */
+@NonNullByDefault
+public class StringUtils {
+
+    public static boolean equals(@Nullable String s1, @Nullable String s2) {
+        return Objects.equals(s1, s2);
+    }
+
+    public static boolean isEmpty(@Nullable String s1) {
+        return (s1 == null || s1.isEmpty());
+    }
+}
index 998b8a6e25970ad98ddc82fdea1aa6ab0a60cb38..93529088f554e42091788eedd910bdce0dd595aa 100644 (file)
@@ -12,7 +12,7 @@
  */
 package org.openhab.binding.lutron.internal.config;
 
-import org.apache.commons.lang.StringUtils;
+import org.openhab.binding.lutron.internal.StringUtils;
 
 /**
  * Configuration settings for an {@link org.openhab.binding.lutron.internal.handler.IPBridgeHandler}.
index 9c718542de1f13c400f28f7b2ed665fd6ae8ac42..b98786a25ea26c0f2e61dbaa5956c788038ace38 100644 (file)
@@ -15,7 +15,6 @@ package org.openhab.binding.lutron.internal.grxprg;
 import java.util.concurrent.ScheduledFuture;
 import java.util.concurrent.TimeUnit;
 
-import org.apache.commons.lang.NullArgumentException;
 import org.openhab.core.library.types.DecimalType;
 import org.openhab.core.library.types.IncreaseDecreaseType;
 import org.openhab.core.library.types.OnOffType;
@@ -332,12 +331,12 @@ public class GrafikEyeHandler extends BaseThingHandler {
     private PrgProtocolHandler getProtocolHandler() {
         final Bridge bridge = getBridge();
         if (bridge == null || !(bridge.getHandler() instanceof PrgBridgeHandler)) {
-            throw new NullArgumentException("Cannot have a Grafix Eye thing outside of the PRG bridge");
+            throw new IllegalArgumentException("Cannot have a Grafix Eye thing outside of the PRG bridge");
         }
 
         final PrgProtocolHandler handler = ((PrgBridgeHandler) bridge.getHandler()).getProtocolHandler();
         if (handler == null) {
-            throw new NullArgumentException("No protocol handler set in the PrgBridgeHandler!");
+            throw new IllegalArgumentException("No protocol handler set in the PrgBridgeHandler!");
         }
         return handler;
     }
index 9fc2c5c08e832fafe6de49d11422f2a4326a95ca..edd9bc84f6dd92a4c9ea0bb0d5cc70111bba9458 100644 (file)
@@ -24,7 +24,6 @@ import java.util.concurrent.TimeUnit;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
-import org.apache.commons.lang.NullArgumentException;
 import org.openhab.core.library.types.DateTimeType;
 import org.openhab.core.library.types.DecimalType;
 import org.openhab.core.library.types.OnOffType;
@@ -629,11 +628,11 @@ class PrgProtocolHandler {
      * Sets the time on the PRG interface
      *
      * @param calendar a non-null calendar to set the time to
-     * @throws NullArgumentException if calendar is null
+     * @throws IllegalArgumentException if calendar is null
      */
     void setTime(Calendar calendar) {
         if (calendar == null) {
-            throw new NullArgumentException("calendar cannot be null");
+            throw new IllegalArgumentException("calendar cannot be null");
         }
         final String cmd = String.format("%1 %2$tk %2$tM %2$tm %2$te %2ty %3", CMD_SETTIME, calendar,
                 calendar.get(Calendar.DAY_OF_WEEK));
index 91bb9558dd0aa5f88c08338149f80887d90a7b95..72b87aee5889e5bd15e70ba062ea669854d11c17 100644 (file)
@@ -15,8 +15,8 @@ package org.openhab.binding.lutron.internal.handler;
 import static org.openhab.binding.lutron.internal.LutronBindingConstants.*;
 
 import java.math.BigDecimal;
+import java.util.Arrays;
 
-import org.apache.commons.lang.StringUtils;
 import org.eclipse.jdt.annotation.NonNullByDefault;
 import org.eclipse.jdt.annotation.Nullable;
 import org.openhab.binding.lutron.internal.protocol.OutputCommand;
@@ -181,7 +181,7 @@ public class CcoHandler extends LutronHandler {
 
     @Override
     public void handleUpdate(LutronCommandType type, String... parameters) {
-        logger.debug("Update received for CCO: {} {}", type, StringUtils.join(parameters, ","));
+        logger.debug("Update received for CCO: {} {}", type, Arrays.asList(parameters));
 
         if (outputType == CcoOutputType.MAINTAINED) {
             if (type == LutronCommandType.OUTPUT && parameters.length > 1
@@ -193,7 +193,7 @@ public class CcoHandler extends LutronHandler {
                     BigDecimal state = new BigDecimal(parameters[1]);
                     updateState(CHANNEL_SWITCH, state.compareTo(BigDecimal.ZERO) == 0 ? OnOffType.OFF : OnOffType.ON);
                 } catch (NumberFormatException e) {
-                    logger.warn("Unable to parse update {} {} from CCO {}", type, StringUtils.join(parameters, ","),
+                    logger.warn("Unable to parse update {} {} from CCO {}", type, Arrays.asList(parameters),
                             integrationId);
                     return;
                 }
index 6fcd071f860da00107ed50680d6f9395d2cc1f67..b7a351ed5d71c760b4e00df79b245fd593cff24e 100644 (file)
@@ -25,7 +25,7 @@ import java.util.regex.MatchResult;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
-import org.apache.commons.lang.StringUtils;
+import org.openhab.binding.lutron.internal.StringUtils;
 import org.openhab.binding.lutron.internal.config.IPBridgeConfig;
 import org.openhab.binding.lutron.internal.discovery.LutronDeviceDiscoveryService;
 import org.openhab.binding.lutron.internal.net.TelnetSession;
index f4f3215d565105168898262b639fd07676c83423..c2a29dd35457db0ecc3943c4bcb435985fbf8023 100644 (file)
@@ -281,8 +281,8 @@ public class LeapBridgeHandler extends LutronBridgeHandler implements LeapMessag
             updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, "Invalid port number");
             return;
         } catch (InterruptedIOException e) {
-            Thread.currentThread().interrupt();
             logger.debug("Interrupted while establishing connection");
+            Thread.currentThread().interrupt();
             return;
         } catch (IOException e) {
             updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
@@ -337,9 +337,6 @@ public class LeapBridgeHandler extends LutronBridgeHandler implements LeapMessag
     private synchronized void disconnect(boolean interruptAll) {
         logger.debug("Disconnecting");
 
-        Thread senderThread = this.senderThread;
-        Thread readerThread = this.readerThread;
-
         ScheduledFuture<?> connectRetryJob = this.connectRetryJob;
         if (connectRetryJob != null) {
             connectRetryJob.cancel(true);
@@ -351,9 +348,12 @@ public class LeapBridgeHandler extends LutronBridgeHandler implements LeapMessag
 
         reconnectTaskCancel(interruptAll); // May be called from keepAliveReconnectJob thread
 
+        Thread senderThread = this.senderThread;
         if (senderThread != null && senderThread.isAlive()) {
             senderThread.interrupt();
         }
+
+        Thread readerThread = this.readerThread;
         if (readerThread != null && readerThread.isAlive()) {
             readerThread.interrupt();
         }
index a4befa5db764d802b9c3ce0ea2b2bc226e12346e..9862d1f8a29c8b6653f8ec4c20a0d8d662cf2051 100644 (file)
@@ -102,7 +102,10 @@ public class DeviceCommand extends LutronCommandNew {
         } else if (targetType == TargetType.VIRTUALKEYPAD) {
             if (action.equals(DeviceCommand.ACTION_PRESS)) {
                 return new LeapCommand(Request.virtualButtonCommand(component, CommandType.PRESSANDRELEASE));
-            } else if (!action.equals(DeviceCommand.ACTION_RELEASE)) {
+            } else if (action.equals(DeviceCommand.ACTION_RELEASE)) {
+                logger.trace("Ignoring release command for virtual keypad button.");
+                return null;
+            } else {
                 logger.debug("Ignoring device command with unsupported action.");
                 return null;
             }
index 99720d93c5f0db43fc4e194e7420383672b00f8a..a8d96050a1cf8dbcbebd2664b6a05acf63d74d29 100644 (file)
@@ -38,7 +38,11 @@ import com.google.gson.JsonParser;
 import com.google.gson.JsonSyntaxException;
 
 /**
- * Class responsible for parsing incoming LEAP messages
+ * Class responsible for parsing incoming LEAP messages. Calls back to an object implementing the
+ * LeapMessageParserCallbacks interface.
+ *
+ * Thanks to the authors of the pylutron-caseta Python API (github.com/gurumitts/pylutron-caseta), which I used as a
+ * reference when first researching the LEAP protocol.
  *
  * @author Bob Adair - Initial contribution
  */
index c72a808b86ab760efb3d2e07840da1c39dbdde51..d9e9459ac6e8cb4c8a79926b8f51ee0164d599d5 100644 (file)
@@ -6,7 +6,7 @@
 
        <bridge-type id="ipbridge">
                <label>Lutron IP Access Point</label>
-               <description>Lutron controller using Lutron Integration Protocol (LIP) over TCP/IP</description>
+               <description>Lutron controller using Lutron Integration Protocol (LIP) over TCP/IP</description>
                <properties>
                        <property name="vendor">Lutron</property>
                </properties>
@@ -59,7 +59,7 @@
 
        <bridge-type id="leapbridge">
                <label>Lutron LEAP Access Point</label>
-               <description>Lutron controller using LEAP protocol over TCP/IP</description>
+               <description>Lutron controller using LEAP protocol over TCP/IP</description>
 
                <channels>
                        <channel id="command" typeId="command-type"/>
                        <bridge-type-ref id="leapbridge"/>
                </supported-bridge-type-refs>
 
-               <label>Maestro Dimmer</label>
+               <label>Lutron Dimmer</label>
                <description>Controls dimmable loads</description>
+               <category>Lightbulb</category>
 
                <channels>
                        <channel id="lightlevel" typeId="lightDimmer"/>
                        <bridge-type-ref id="leapbridge"/>
                </supported-bridge-type-refs>
 
-               <label>Sivoia QS Shade</label>
-               <description>Controls roller shades</description>
+               <label>Lutron Shade</label>
+               <description>Controls roller shades, drapes, and motor controllers</description>
+               <category>Blinds</category>
 
                <channels>
                        <channel id="shadelevel" typeId="shadeControl"/>
                        <bridge-type-ref id="leapbridge"/>
                </supported-bridge-type-refs>
 
-               <label>Maestro Switch</label>
+               <label>Lutron Switch</label>
                <description>On/off switch</description>
+               <category>WallSwitch</category>
 
                <channels>
                        <channel id="switchstatus" typeId="switchState"/>
 
                <label>Radio Powr Savr Sensor</label>
                <description>Motion sensor to detect occupancy status</description>
+               <category>MotionDetector</category>
 
                <channels>
                        <channel id="occupancystatus" typeId="occupiedState"/>
 
                <label>Occupancy Group</label>
                <description>Shows state of occupancy sensor group</description>
+               <category>MotionDetector</category>
 
                <channels>
                        <channel id="groupstate" typeId="groupState"/>
                        <bridge-type-ref id="ipbridge"/>
                </supported-bridge-type-refs>
 
-               <label>GRAFIK Eye QS</label>
+               <label>GRAFIK Eye QS Keypad</label>
                <description>Lutron GRAFIK Eye QS for RadioRA 2/HomeWorks QS</description>
 
                <representation-property>integrationId</representation-property>
                </config-description>
        </thing-type>
 
-
        <thing-type id="virtualkeypad">
                <supported-bridge-type-refs>
                        <bridge-type-ref id="ipbridge"/>
 
        <bridge-type id="prgbridge">
                <label>Lutron GRX-PRG or GRX-CI-PRG Bridge</label>
-               <description>Ethernet access point to Lutron Grafik Eye 3x/4x Systems</description>
+               <description>Ethernet access point to Lutron GRAFIK Eye 3x/4x Systems</description>
 
                <channels>
                        <channel id="buttonpress" typeId="buttonpress"/>
                        <bridge-type-ref id="prgbridge"/>
                </supported-bridge-type-refs>
 
-               <label>Grafik Eye</label>
-               <description>Controls a Grafik Eye</description>
+               <label>GRAFIK Eye</label>
+               <description>Controls a GRAFIK Eye</description>
 
                <channels>
                        <channel id="scene" typeId="scene"/>
 
        <bridge-type id="hwserialbridge">
                <label>Lutron HomeWorks RS232 Bridge</label>
-               <description>RS232 access point to Lutron HomeWorks lighting control system</description>
+               <description>RS232 access point to Legacy Lutron HomeWorks lighting control system</description>
 
                <config-description>
                        <parameter name="serialPort" type="text" required="true">
                        <bridge-type-ref id="hwserialbridge"/>
                </supported-bridge-type-refs>
 
-               <label>HomeWorks Dimmer</label>
-               <description>Controls dimmable loads</description>
+               <label>Lutron Dimmer (Legacy HomeWorks)</label>
+               <description>Controls dimmable loads for legacy HomeWorks systems</description>
+               <category>Lightbulb</category>
 
                <channels>
                        <channel id="lightlevel" typeId="lightDimmer"/>
 
        <bridge-type id="ra-rs232">
                <label>Lutron RadioRA RS232</label>
-               <description>RS-232 access to Lutron RadioRA</description>
+               <description>RS-232 access to legacy Lutron RadioRA systems</description>
 
                <config-description>
                        <parameter name="portName" type="text" required="true">
                <supported-bridge-type-refs>
                        <bridge-type-ref id="ra-rs232"/>
                </supported-bridge-type-refs>
-               <label>RadioRA Dimmer</label>
-               <description>RadioRA Dimmer</description>
+               <label>Lutron Dimmer (Legacy RadioRA)</label>
+               <description>Controls dimmable loads for legacy RadioRA systems</description>
+               <category>Lightbulb</category>
 
                <channels>
                        <channel id="lightlevel" typeId="lightDimmer"/>
                <supported-bridge-type-refs>
                        <bridge-type-ref id="ra-rs232"/>
                </supported-bridge-type-refs>
-               <label>RadioRA Switch</label>
-               <description>RadioRA Switch</description>
+               <label>Lutron Switch (Legacy RadioRA)</label>
+               <description>On/off switch for Legacy RadioRA systems</description>
+               <category>WallSwitch</category>
 
                <channels>
                        <channel id="switchstatus" typeId="switchState"/>
                <supported-bridge-type-refs>
                        <bridge-type-ref id="ra-rs232"/>
                </supported-bridge-type-refs>
-               <label>RadioRA Phantom Button</label>
-               <description>RadioRA Phantom Button</description>
+               <label>Phantom Button (Legacy RadioRA)</label>
+               <description>Phantom Button for Legacy RadioRA systems</description>
 
                <channels>
                        <channel id="switchstatus" typeId="switchState"/>