]> git.basschouten.com Git - openhab-addons.git/commitdiff
[lutron] Add support for bridged RadioRA (classic) systems (#10302)
authorBob A <bobadair@users.noreply.github.com>
Wed, 31 Mar 2021 20:44:58 +0000 (16:44 -0400)
committerGitHub <noreply@github.com>
Wed, 31 Mar 2021 20:44:58 +0000 (22:44 +0200)
Signed-off-by: Bob Adair <bob.github@att.net>
25 files changed:
bundles/org.openhab.binding.lutron/README.md
bundles/org.openhab.binding.lutron/src/main/java/org/openhab/binding/lutron/internal/radiora/RS232Connection.java
bundles/org.openhab.binding.lutron/src/main/java/org/openhab/binding/lutron/internal/radiora/RS232MessageParser.java
bundles/org.openhab.binding.lutron/src/main/java/org/openhab/binding/lutron/internal/radiora/RadioRAConnection.java
bundles/org.openhab.binding.lutron/src/main/java/org/openhab/binding/lutron/internal/radiora/RadioRAConnectionException.java
bundles/org.openhab.binding.lutron/src/main/java/org/openhab/binding/lutron/internal/radiora/RadioRAFeedbackListener.java
bundles/org.openhab.binding.lutron/src/main/java/org/openhab/binding/lutron/internal/radiora/config/DimmerConfig.java
bundles/org.openhab.binding.lutron/src/main/java/org/openhab/binding/lutron/internal/radiora/config/PhantomButtonConfig.java
bundles/org.openhab.binding.lutron/src/main/java/org/openhab/binding/lutron/internal/radiora/config/RS232Config.java
bundles/org.openhab.binding.lutron/src/main/java/org/openhab/binding/lutron/internal/radiora/config/SwitchConfig.java
bundles/org.openhab.binding.lutron/src/main/java/org/openhab/binding/lutron/internal/radiora/handler/DimmerHandler.java
bundles/org.openhab.binding.lutron/src/main/java/org/openhab/binding/lutron/internal/radiora/handler/LutronHandler.java
bundles/org.openhab.binding.lutron/src/main/java/org/openhab/binding/lutron/internal/radiora/handler/PhantomButtonHandler.java
bundles/org.openhab.binding.lutron/src/main/java/org/openhab/binding/lutron/internal/radiora/handler/RS232Handler.java
bundles/org.openhab.binding.lutron/src/main/java/org/openhab/binding/lutron/internal/radiora/handler/SwitchHandler.java
bundles/org.openhab.binding.lutron/src/main/java/org/openhab/binding/lutron/internal/radiora/protocol/ButtonPressCommand.java
bundles/org.openhab.binding.lutron/src/main/java/org/openhab/binding/lutron/internal/radiora/protocol/LEDMapFeedback.java
bundles/org.openhab.binding.lutron/src/main/java/org/openhab/binding/lutron/internal/radiora/protocol/LocalZoneChangeFeedback.java
bundles/org.openhab.binding.lutron/src/main/java/org/openhab/binding/lutron/internal/radiora/protocol/RadioRACommand.java
bundles/org.openhab.binding.lutron/src/main/java/org/openhab/binding/lutron/internal/radiora/protocol/RadioRAFeedback.java
bundles/org.openhab.binding.lutron/src/main/java/org/openhab/binding/lutron/internal/radiora/protocol/SetDimmerLevelCommand.java
bundles/org.openhab.binding.lutron/src/main/java/org/openhab/binding/lutron/internal/radiora/protocol/SetSwitchLevelCommand.java
bundles/org.openhab.binding.lutron/src/main/java/org/openhab/binding/lutron/internal/radiora/protocol/ZoneMapFeedback.java
bundles/org.openhab.binding.lutron/src/main/java/org/openhab/binding/lutron/internal/radiora/protocol/ZoneMapInquiryCommand.java
bundles/org.openhab.binding.lutron/src/main/resources/OH-INF/thing/thing-types.xml

index 149f6b8b5669d58f28a2807ff3e5688ed0e581b7..a0dd8232158b676d08f51f3a0a1d54d6d93a5ff2 100644 (file)
@@ -794,7 +794,12 @@ end
 This binding integrates with the legacy Lutron RadioRA (Classic) lighting system.
 
 This binding depends on RS232 communication.
-It has only been tested using the Chronos time module but the RS232 module should work as well.
+It has only been tested using the Chronos System Bridge and Timeclock (RA-SBT-CHR) module, but Lutron's RA-RS232 or RB-RS232 module should work as well.
+
+Support has been added for bridged RadioRA systems.
+A system is considered “bridged” when a Chronos System Bridge and Timeclock is used to integrate two RadioRA Systems in a single residence.
+In a bridged system, the `system` parameter of each configured ra-dimmer, ra-switch, or ra-phantomButton thing should be set to indicate which RadioRA system it is a part of (i.e. 1 or 2).
+In a non-bridged system, these parameters should be left at their default of 0.
 
 ## Supported Things
 
@@ -808,17 +813,20 @@ This binding currently supports the following thing types:
 | ra-phantomButton | Thing   | Phantom Button to control multiple controls (Scenes) |
 
 
-## Thing Configurations
-
-| Thing            | Config       | Description                                                           |
-|------------------|--------------|-----------------------------------------------------------------------|
-| ra-rs232         | portName     | The serial port to use to communicate with Chronos or RS232 module    |
-|                  | baud         | (Optional) Baud Rate (defaults to 9600)                               |
-| ra-dimmer        | zoneNumber   | Assigned Zone Number within the Lutron RadioRA system                 |
-|                  | fadeOutSec   | (Optional) Time in seconds dimmer should take when lowering the level |
-|                  | fadeInSec    | (Optional) Time in seconds dimmer should take when lowering the level |
-| ra-switch        | zoneNumber   | Assigned Zone Number within the Lutron RadioRA system                 |
-| ra-phantomButton | buttonNumber | Phantom Button Number within the Lutron RadioRA system                |
+## Thing Configuration Parameters
+
+| Thing            | Parameter    | Description                                                            |
+|------------------|--------------|------------------------------------------------------------------------|
+| ra-rs232         | portName     | The serial port to use to communicate with Chronos or RS232 module     |
+|                  | baud         | (Optional) Baud Rate (defaults to 9600)                                |
+| ra-dimmer        | zoneNumber   | Assigned Zone Number within the Lutron RadioRA system                  |
+|                  | system       | (Optional) System number (1 or 2) in a bridged system. Default=0 (n/a) |
+|                  | fadeOutSec   | (Optional) Time in seconds dimmer should take when lowering the level  |
+|                  | fadeInSec    | (Optional) Time in seconds dimmer should take when lowering the level  |
+| ra-switch        | zoneNumber   | Assigned Zone Number within the Lutron RadioRA system                  |
+|                  | system       | (Optional) System number (1 or 2) in a bridged system. Default=0 (n/a) |
+| ra-phantomButton | buttonNumber | Phantom Button Number within the Lutron RadioRA system                 |
+|                  | system       | (Optional) System number (1 or 2) in a bridged system. Default=0 (n/a) |
 
 ## Channels
 
index 2335ef0f99895c6d0a4bf077e3b11da727c21836..f917aa0127254c79bc530152a5294ca4cabdf821 100644 (file)
@@ -15,8 +15,11 @@ package org.openhab.binding.lutron.internal.radiora;
 import java.io.BufferedReader;
 import java.io.IOException;
 import java.io.InputStreamReader;
+import java.io.OutputStream;
 import java.util.TooManyListenersException;
 
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.eclipse.jdt.annotation.Nullable;
 import org.openhab.binding.lutron.internal.radiora.protocol.RadioRAFeedback;
 import org.openhab.core.io.transport.serial.PortInUseException;
 import org.openhab.core.io.transport.serial.SerialPort;
@@ -34,16 +37,17 @@ import org.slf4j.LoggerFactory;
  * @author Jeff Lauterbach - Initial Contribution
  *
  */
+@NonNullByDefault
 public class RS232Connection implements RadioRAConnection, SerialPortEventListener {
 
     private final Logger logger = LoggerFactory.getLogger(RS232Connection.class);
 
     protected SerialPortManager serialPortManager;
-    protected SerialPort serialPort;
+    protected @Nullable SerialPort serialPort;
 
-    protected BufferedReader inputReader;
+    protected @Nullable BufferedReader inputReader;
 
-    protected RadioRAFeedbackListener listener;
+    protected @Nullable RadioRAFeedbackListener listener;
     protected RS232MessageParser parser = new RS232MessageParser();
 
     public RS232Connection(SerialPortManager serialPortManager) {
@@ -59,7 +63,8 @@ public class RS232Connection implements RadioRAConnection, SerialPortEventListen
         }
 
         try {
-            serialPort = portIdentifier.open("openhab", 5000);
+            SerialPort serialPort = portIdentifier.open("openhab", 5000);
+            this.serialPort = serialPort;
             serialPort.notifyOnDataAvailable(true);
             serialPort.setSerialPortParams(baud, SerialPort.DATABITS_8, SerialPort.STOPBITS_1, SerialPort.PARITY_NONE);
             serialPort.addEventListener(this);
@@ -78,8 +83,19 @@ public class RS232Connection implements RadioRAConnection, SerialPortEventListen
     @Override
     public void write(String command) {
         logger.debug("Writing to serial port: {}", command.toString());
+        SerialPort serialPort = this.serialPort;
+
         try {
-            serialPort.getOutputStream().write(command.getBytes());
+            if (serialPort != null) {
+                OutputStream outputStream = serialPort.getOutputStream();
+                if (outputStream != null) {
+                    outputStream.write(command.getBytes());
+                } else {
+                    logger.debug("Cannot write to serial port. outputStream is null.");
+                }
+            } else {
+                logger.debug("Cannot write to serial port. serialPort is null.");
+            }
         } catch (IOException e) {
             logger.debug("An error occurred writing to serial port", e);
         }
@@ -87,15 +103,19 @@ public class RS232Connection implements RadioRAConnection, SerialPortEventListen
 
     @Override
     public void disconnect() {
-        serialPort.close();
+        SerialPort serialPort = this.serialPort;
+        if (serialPort != null) {
+            serialPort.close();
+        }
     }
 
     @Override
     public void serialEvent(SerialPortEvent ev) {
         switch (ev.getEventType()) {
             case SerialPortEvent.DATA_AVAILABLE:
+                BufferedReader inputReader = this.inputReader;
                 try {
-                    if (!inputReader.ready()) {
+                    if (inputReader == null || !inputReader.ready()) {
                         logger.debug("Serial Data Available but input reader not ready");
                         return;
                     }
@@ -106,7 +126,12 @@ public class RS232Connection implements RadioRAConnection, SerialPortEventListen
 
                     if (feedback != null) {
                         logger.debug("Msg Parsed as {}", feedback.getClass().getName());
-                        listener.handleRadioRAFeedback(feedback);
+                        RadioRAFeedbackListener listener = this.listener;
+                        if (listener != null) {
+                            listener.handleRadioRAFeedback(feedback);
+                        } else {
+                            logger.debug("Cannot handle feedback message. Listener is null.");
+                        }
                     }
                     logger.debug("Finished handling feedback");
                 } catch (IOException e) {
index 4ee5082f7da1e09929997d7b08e50ff2ad27f15c..6052f748d251b306d8b3bf60bed983b29b626bdf 100644 (file)
@@ -12,6 +12,8 @@
  */
 package org.openhab.binding.lutron.internal.radiora;
 
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.eclipse.jdt.annotation.Nullable;
 import org.openhab.binding.lutron.internal.radiora.protocol.LEDMapFeedback;
 import org.openhab.binding.lutron.internal.radiora.protocol.LocalZoneChangeFeedback;
 import org.openhab.binding.lutron.internal.radiora.protocol.RadioRAFeedback;
@@ -25,11 +27,12 @@ import org.slf4j.LoggerFactory;
  * @author Jeff Lauterbach - Initial Contribution
  *
  */
+@NonNullByDefault
 public class RS232MessageParser {
 
-    private Logger logger = LoggerFactory.getLogger(RS232MessageParser.class);
+    private final Logger logger = LoggerFactory.getLogger(RS232MessageParser.class);
 
-    public RadioRAFeedback parse(String msg) {
+    public @Nullable RadioRAFeedback parse(String msg) {
         String prefix = parsePrefix(msg);
 
         switch (prefix) {
index 1b4cb218355929fefd020ac6c429a3f1381db0e8..e03b6287d9f2b85107294b1970ab8b38018dc3b9 100644 (file)
  */
 package org.openhab.binding.lutron.internal.radiora;
 
+import org.eclipse.jdt.annotation.NonNullByDefault;
+
 /**
  * Interface to the RadioRA Classic system
  *
  * @author Jeff Lauterbach - Initial Contribution
  *
  */
+@NonNullByDefault
 public interface RadioRAConnection {
 
     public void open(String portName, int baud) throws RadioRAConnectionException;
index 198f3bf0d751e5253d775be059c6219db18fee94..df9f7106deb99dad36f7bc0c991633cc702b02c1 100644 (file)
  */
 package org.openhab.binding.lutron.internal.radiora;
 
+import org.eclipse.jdt.annotation.NonNullByDefault;
+
 /**
  * Thrown when an attempt to open a RadioRA Connection fails.
  *
  * @author Jeff Lauterbach - Initial Contribution
  *
  */
+@NonNullByDefault
 public class RadioRAConnectionException extends Exception {
 
     private static final long serialVersionUID = 1L;
index 9b884f45d987cda71e4379c6556081e45a3fd0c5..4e6050e6cb0d1152bea354c4ae9e2f016b1d1770 100644 (file)
@@ -12,6 +12,7 @@
  */
 package org.openhab.binding.lutron.internal.radiora;
 
+import org.eclipse.jdt.annotation.NonNullByDefault;
 import org.openhab.binding.lutron.internal.radiora.protocol.RadioRAFeedback;
 
 /**
@@ -20,6 +21,7 @@ import org.openhab.binding.lutron.internal.radiora.protocol.RadioRAFeedback;
  * @author Jeff Lauterbach - Initial Contribution
  *
  */
+@NonNullByDefault
 public interface RadioRAFeedbackListener {
 
     void handleRadioRAFeedback(RadioRAFeedback feedback);
index b6344794e6fb6257c29dd1259faecb727c891c6c..08a32a39db1a62b2631d081f4a5a7e967aac2dfe 100644 (file)
@@ -21,31 +21,20 @@ import java.math.BigDecimal;
  *
  */
 public class DimmerConfig {
-    private int zoneNumber;
-    private BigDecimal fadeOutSec;
-    private BigDecimal fadeInSec;
+    public int zoneNumber;
+    public int system = 0;
+    public BigDecimal fadeOutSec;
+    public BigDecimal fadeInSec;
 
     public int getZoneNumber() {
         return zoneNumber;
     }
 
-    public void setZoneNumber(int zoneNumber) {
-        this.zoneNumber = zoneNumber;
-    }
-
     public BigDecimal getFadeOutSec() {
         return fadeOutSec;
     }
 
-    public void setFadeOutSec(BigDecimal fadeOutSec) {
-        this.fadeOutSec = fadeOutSec;
-    }
-
     public BigDecimal getFadeInSec() {
         return fadeInSec;
     }
-
-    public void setFadeInSec(BigDecimal fadeInSec) {
-        this.fadeInSec = fadeInSec;
-    }
 }
index 8637c4427486598b178692895a975cd8bf85acda..2c68be75f3a3fe676c76911f1640ac318200dc61 100644 (file)
  */
 package org.openhab.binding.lutron.internal.radiora.config;
 
-import java.math.BigDecimal;
+import org.eclipse.jdt.annotation.NonNullByDefault;
 
 /**
  * Configuration class for PhantomButton thing type.
- * 
+ *
  * @author Jeff Lauterbach - Initial Contribution
  *
  */
+@NonNullByDefault
 public class PhantomButtonConfig {
 
-    private int buttonNumber;
-    private BigDecimal fadeSec;
+    public int buttonNumber;
+    public int system = 0;
 
     public int getButtonNumber() {
         return buttonNumber;
     }
-
-    public void setButtonNumber(int buttonNumber) {
-        this.buttonNumber = buttonNumber;
-    }
-
-    public BigDecimal getFadeSec() {
-        return fadeSec;
-    }
-
-    public void setFadeSec(BigDecimal fadeSec) {
-        this.fadeSec = fadeSec;
-    }
 }
index 1b236846ddd12f172ab6e4f91c39799fc17fdc7a..07ab05787546ca61418ef1b020f3540980153d24 100644 (file)
  */
 package org.openhab.binding.lutron.internal.radiora.config;
 
+import org.eclipse.jdt.annotation.NonNullByDefault;
+
 /**
  * Configuration class for RS232 thing type.
  *
  * @author Jeff Lauterbach - Initial Contribution
  *
  */
+@NonNullByDefault
 public class RS232Config {
 
-    private String portName;
-    private int baud = 9600;
-    private int zoneMapQueryInterval = 60;
+    public String portName = "";
+    public int baud = 9600;
+    public int zoneMapQueryInterval = 60;
 
     public String getPortName() {
         return portName;
     }
 
-    public void setPortName(String portName) {
-        this.portName = portName;
-    }
-
     public int getBaud() {
         return baud;
     }
 
-    public void setBaud(int baud) {
-        this.baud = baud;
-    }
-
     public int getZoneMapQueryInterval() {
         return zoneMapQueryInterval;
     }
-
-    public void setZoneMapQueryInterval(int zoneMapQueryInterval) {
-        this.zoneMapQueryInterval = zoneMapQueryInterval;
-    }
 }
index ec7a5bec492b2f9c253108c0814d27a5e147beec..064a000de5a707c8f20f4d2dd73398a4e32c1679 100644 (file)
  */
 package org.openhab.binding.lutron.internal.radiora.config;
 
+import org.eclipse.jdt.annotation.NonNullByDefault;
+
 /**
  * Configuration class for Switch thing type.
- * 
+ *
  * @author Jeff Lauterbach - Initial Contribution
  *
  */
+@NonNullByDefault
 public class SwitchConfig {
 
-    private int zoneNumber;
+    public int zoneNumber;
+    public int system = 0;
 
     public int getZoneNumber() {
         return zoneNumber;
     }
-
-    public void setZoneNumber(int zoneNumber) {
-        this.zoneNumber = zoneNumber;
-    }
 }
index 997c871eb7b629d0dca086d050f82fbc850120cb..051ab6254a905eb5cc5b565df7d69f246882c127 100644 (file)
@@ -15,6 +15,7 @@ package org.openhab.binding.lutron.internal.radiora.handler;
 import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.concurrent.atomic.AtomicInteger;
 
+import org.eclipse.jdt.annotation.NonNullByDefault;
 import org.openhab.binding.lutron.internal.LutronBindingConstants;
 import org.openhab.binding.lutron.internal.radiora.config.DimmerConfig;
 import org.openhab.binding.lutron.internal.radiora.protocol.LocalZoneChangeFeedback;
@@ -34,6 +35,7 @@ import org.openhab.core.types.Command;
  * @author Jeff Lauterbach - Initial Contribution
  *
  */
+@NonNullByDefault
 public class DimmerHandler extends LutronHandler {
 
     /**
@@ -41,24 +43,33 @@ public class DimmerHandler extends LutronHandler {
      * to external dimmer changes since RadioRA protocol does not send dimmer
      * levels in their messages.
      */
+    private @NonNullByDefault({}) DimmerConfig config;
     private AtomicInteger lastKnownIntensity = new AtomicInteger(100);
-
     private AtomicBoolean switchEnabled = new AtomicBoolean(false);
 
     public DimmerHandler(Thing thing) {
         super(thing);
     }
 
+    @Override
+    public void initialize() {
+        config = getConfigAs(DimmerConfig.class);
+        super.initialize();
+    }
+
     @Override
     public void handleCommand(ChannelUID channelUID, Command command) {
-        DimmerConfig config = getConfigAs(DimmerConfig.class);
+        RS232Handler bridgeHandler = getRS232Handler();
+        if (bridgeHandler == null) {
+            return;
+        }
 
         if (LutronBindingConstants.CHANNEL_LIGHTLEVEL.equals(channelUID.getId())) {
             if (command instanceof PercentType) {
                 int intensity = ((PercentType) command).intValue();
 
-                SetDimmerLevelCommand cmd = new SetDimmerLevelCommand(config.getZoneNumber(), intensity);
-                getRS232Handler().sendCommand(cmd);
+                SetDimmerLevelCommand cmd = new SetDimmerLevelCommand(config.getZoneNumber(), intensity, config.system);
+                bridgeHandler.sendCommand(cmd);
 
                 updateInternalState(intensity);
             }
@@ -66,11 +77,10 @@ public class DimmerHandler extends LutronHandler {
             if (command instanceof OnOffType) {
                 OnOffType onOffCmd = (OnOffType) command;
 
-                SetSwitchLevelCommand cmd = new SetSwitchLevelCommand(config.getZoneNumber(), onOffCmd);
-                getRS232Handler().sendCommand(cmd);
+                SetSwitchLevelCommand cmd = new SetSwitchLevelCommand(config.getZoneNumber(), onOffCmd, config.system);
+                bridgeHandler.sendCommand(cmd);
 
                 updateInternalState(onOffCmd);
-
             }
         }
     }
@@ -85,7 +95,10 @@ public class DimmerHandler extends LutronHandler {
     }
 
     private void handleZoneMapFeedback(ZoneMapFeedback feedback) {
-        char value = feedback.getZoneValue(getConfigAs(DimmerConfig.class).getZoneNumber());
+        if (!systemsMatch(feedback.getSystem(), config.system)) {
+            return;
+        }
+        char value = feedback.getZoneValue(config.getZoneNumber());
         if (value == '1') {
             turnDimmerOnToLastKnownIntensity();
         } else if (value == '0') {
@@ -94,7 +107,7 @@ public class DimmerHandler extends LutronHandler {
     }
 
     private void handleLocalZoneChangeFeedback(LocalZoneChangeFeedback feedback) {
-        if (feedback.getZoneNumber() == getConfigAs(DimmerConfig.class).getZoneNumber()) {
+        if (systemsMatch(feedback.getSystem(), config.system) && feedback.getZoneNumber() == config.getZoneNumber()) {
             if (LocalZoneChangeFeedback.State.ON.equals(feedback.getState())) {
                 turnDimmerOnToLastKnownIntensity();
             } else if (LocalZoneChangeFeedback.State.OFF.equals(feedback.getState())) {
index b49366a5a740544272b6f84f6466d15cb9f02546..b0e9cd80ffb854cceb158605293f2ec403b25f6f 100644 (file)
@@ -12,6 +12,8 @@
  */
 package org.openhab.binding.lutron.internal.radiora.handler;
 
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.eclipse.jdt.annotation.Nullable;
 import org.openhab.binding.lutron.internal.radiora.protocol.RadioRAFeedback;
 import org.openhab.core.thing.Bridge;
 import org.openhab.core.thing.Thing;
@@ -26,13 +28,14 @@ import org.openhab.core.thing.binding.ThingHandler;
  * @author Jeff Lauterbach - Initial Contribution
  *
  */
+@NonNullByDefault
 public abstract class LutronHandler extends BaseThingHandler {
 
     public LutronHandler(Thing thing) {
         super(thing);
     }
 
-    public RS232Handler getRS232Handler() {
+    public @Nullable RS232Handler getRS232Handler() {
         Bridge bridge = getBridge();
         if (bridge == null) {
             updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.BRIDGE_UNINITIALIZED, "Unable to get bridge");
@@ -47,6 +50,13 @@ public abstract class LutronHandler extends BaseThingHandler {
         }
     }
 
+    /**
+     * Returns true if system numbers match, meaning that either both are 2 or both are 1 or 0 (n/a).
+     */
+    public static boolean systemsMatch(int a, int b) {
+        return ((a == 2 && b == 2) || ((a == 0 || a == 1) && (b == 0 || b == 1)));
+    }
+
     public abstract void handleFeedback(RadioRAFeedback feedback);
 
     @Override
index 22199d8c5517bcaacf09ddc7198a8b3dcee6de73..6b17f9193c56f5942015da5a0dd474e3a6c1e1eb 100644 (file)
@@ -12,6 +12,7 @@
  */
 package org.openhab.binding.lutron.internal.radiora.handler;
 
+import org.eclipse.jdt.annotation.NonNullByDefault;
 import org.openhab.binding.lutron.internal.LutronBindingConstants;
 import org.openhab.binding.lutron.internal.radiora.config.PhantomButtonConfig;
 import org.openhab.binding.lutron.internal.radiora.protocol.ButtonPressCommand;
@@ -28,20 +29,31 @@ import org.openhab.core.types.Command;
  * @author Jeff Lauterbach - Initial Contribution
  *
  */
+@NonNullByDefault
 public class PhantomButtonHandler extends LutronHandler {
 
+    private @NonNullByDefault({}) PhantomButtonConfig config;
+
     public PhantomButtonHandler(Thing thing) {
         super(thing);
     }
 
+    @Override
+    public void initialize() {
+        config = getConfigAs(PhantomButtonConfig.class);
+        super.initialize();
+    }
+
     @Override
     public void handleCommand(ChannelUID channelUID, Command command) {
+        RS232Handler bridgeHandler = getRS232Handler();
         if (channelUID.getId().equals(LutronBindingConstants.CHANNEL_SWITCH)) {
             if (command instanceof OnOffType) {
-                ButtonPressCommand cmd = new ButtonPressCommand(
-                        getConfigAs(PhantomButtonConfig.class).getButtonNumber(),
-                        ButtonPressCommand.ButtonState.valueOf(command.toString()));
-                getRS232Handler().sendCommand(cmd);
+                ButtonPressCommand cmd = new ButtonPressCommand(config.getButtonNumber(),
+                        ButtonPressCommand.ButtonState.valueOf(command.toString()), config.system);
+                if (bridgeHandler != null) {
+                    bridgeHandler.sendCommand(cmd);
+                }
             }
         }
     }
index 086b5a687bc91fc2a06b9c8d89e151bf99c1f1c4..66cd7b502082d62780624de9f79f2a1f3b5d6a5f 100644 (file)
@@ -15,6 +15,8 @@ package org.openhab.binding.lutron.internal.radiora.handler;
 import java.util.concurrent.ScheduledFuture;
 import java.util.concurrent.TimeUnit;
 
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.eclipse.jdt.annotation.Nullable;
 import org.openhab.binding.lutron.internal.radiora.RS232Connection;
 import org.openhab.binding.lutron.internal.radiora.RadioRAConnection;
 import org.openhab.binding.lutron.internal.radiora.RadioRAConnectionException;
@@ -41,13 +43,14 @@ import org.slf4j.LoggerFactory;
  *
  * @author Jeff Lauterbach - Initial contribution
  */
+@NonNullByDefault
 public class RS232Handler extends BaseBridgeHandler implements RadioRAFeedbackListener {
 
-    private Logger logger = LoggerFactory.getLogger(RS232Handler.class);
+    private final Logger logger = LoggerFactory.getLogger(RS232Handler.class);
 
     private RadioRAConnection connection;
 
-    private ScheduledFuture<?> zoneMapScheduledTask;
+    private @Nullable ScheduledFuture<?> zoneMapScheduledTask;
 
     public RS232Handler(Bridge bridge, SerialPortManager serialPortManager) {
         super(bridge);
@@ -58,6 +61,7 @@ public class RS232Handler extends BaseBridgeHandler implements RadioRAFeedbackLi
 
     @Override
     public void dispose() {
+        ScheduledFuture<?> zoneMapScheduledTask = this.zoneMapScheduledTask;
         if (zoneMapScheduledTask != null) {
             zoneMapScheduledTask.cancel(true);
         }
index 1232b2ae30980b9d5948ee05a79221800c0ebaec..aa3e27eab0ec1d950682248d8e955820bfd62110 100644 (file)
@@ -12,6 +12,7 @@
  */
 package org.openhab.binding.lutron.internal.radiora.handler;
 
+import org.eclipse.jdt.annotation.NonNullByDefault;
 import org.openhab.binding.lutron.internal.LutronBindingConstants;
 import org.openhab.binding.lutron.internal.radiora.config.SwitchConfig;
 import org.openhab.binding.lutron.internal.radiora.protocol.LocalZoneChangeFeedback;
@@ -31,22 +32,33 @@ import org.slf4j.LoggerFactory;
  * @author Jeff Lauterbach - Initial Contribution
  *
  */
+@NonNullByDefault
 public class SwitchHandler extends LutronHandler {
 
-    private Logger logger = LoggerFactory.getLogger(SwitchHandler.class);
+    private final Logger logger = LoggerFactory.getLogger(SwitchHandler.class);
+    private @NonNullByDefault({}) SwitchConfig config;
 
     public SwitchHandler(Thing thing) {
         super(thing);
     }
 
+    @Override
+    public void initialize() {
+        config = getConfigAs(SwitchConfig.class);
+        super.initialize();
+    }
+
     @Override
     public void handleCommand(ChannelUID channelUID, Command command) {
+        RS232Handler bridgeHandler = getRS232Handler();
         if (LutronBindingConstants.CHANNEL_SWITCH.equals(channelUID.getId())) {
             if (command instanceof OnOffType) {
-                SetSwitchLevelCommand cmd = new SetSwitchLevelCommand(getConfigAs(SwitchConfig.class).getZoneNumber(),
-                        (OnOffType) command);
+                SetSwitchLevelCommand cmd = new SetSwitchLevelCommand(config.getZoneNumber(), (OnOffType) command,
+                        config.system);
 
-                getRS232Handler().sendCommand(cmd);
+                if (bridgeHandler != null) {
+                    bridgeHandler.sendCommand(cmd);
+                }
             }
         }
     }
@@ -61,7 +73,10 @@ public class SwitchHandler extends LutronHandler {
     }
 
     private void handleZoneMapFeedback(ZoneMapFeedback feedback) {
-        char value = feedback.getZoneValue(getConfigAs(SwitchConfig.class).getZoneNumber());
+        if (!systemsMatch(feedback.getSystem(), config.system)) {
+            return;
+        }
+        char value = feedback.getZoneValue(config.getZoneNumber());
 
         if (value == '1') {
             updateState(LutronBindingConstants.CHANNEL_SWITCH, OnOffType.ON);
@@ -71,7 +86,7 @@ public class SwitchHandler extends LutronHandler {
     }
 
     private void handleLocalZoneChangeFeedback(LocalZoneChangeFeedback feedback) {
-        if (feedback.getZoneNumber() == getConfigAs(SwitchConfig.class).getZoneNumber()) {
+        if (systemsMatch(feedback.getSystem(), config.system) && feedback.getZoneNumber() == config.getZoneNumber()) {
             if (LocalZoneChangeFeedback.State.CHG.equals(feedback.getState())) {
                 logger.debug("Not Implemented Yet - CHG state received from Local Zone Change Feedback.");
             }
index 5d07fd63932c77730147c1454cb378603d09c3d7..8f5a31fc69461e3b26e70a1a351bd3c227317f0e 100644 (file)
@@ -15,6 +15,9 @@ package org.openhab.binding.lutron.internal.radiora.protocol;
 import java.util.ArrayList;
 import java.util.List;
 
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.eclipse.jdt.annotation.Nullable;
+
 /**
  * Button Press (BP) Command.
  * Trigger a Phantom Button Press on the RadioRA Serial Device.
@@ -22,6 +25,7 @@ import java.util.List;
  * @author Jeff Lauterbach - Initial Contribution
  *
  */
+@NonNullByDefault
 public class ButtonPressCommand extends RadioRACommand {
 
     public enum ButtonState {
@@ -32,11 +36,13 @@ public class ButtonPressCommand extends RadioRACommand {
 
     private int buttonNumber; // 1 to 15, 16 ALL ON, 17 ALL OFF
     private ButtonState state; // ON/OFF/TOG
-    private Integer fadeSec; // 0 to 240 (optional)
+    private @Nullable Integer fadeSec; // 0 to 240 (optional)
+    private int system; // 1 or 2, or 0 for none
 
-    public ButtonPressCommand(int buttonNumber, ButtonState state) {
+    public ButtonPressCommand(int buttonNumber, ButtonState state, int system) {
         this.buttonNumber = buttonNumber;
         this.state = state;
+        this.system = system;
     }
 
     public void setFadeSeconds(int seconds) {
@@ -58,6 +64,10 @@ public class ButtonPressCommand extends RadioRACommand {
             args.add(String.valueOf(fadeSec));
         }
 
+        if (system == 1 || system == 2) {
+            args.add("S" + String.valueOf(system));
+        }
+
         return args;
     }
 }
index f25a01367b3cf067c2a9eddcdc222680cd3c5695..7c6ca738f9e915fd7e096687e233965f5f8d8bea 100644 (file)
@@ -12,6 +12,8 @@
  */
 package org.openhab.binding.lutron.internal.radiora.protocol;
 
+import org.eclipse.jdt.annotation.NonNullByDefault;
+
 /**
  * Feedback (LMP) that gives the state of all phantom LEDs
  * <p>
@@ -34,6 +36,7 @@ package org.openhab.binding.lutron.internal.radiora.protocol;
  * @author Jeff Lauterbach - Initial Contribution
  *
  */
+@NonNullByDefault
 public class LEDMapFeedback extends RadioRAFeedback {
 
     private String bitmap; // 15 bit String of (0,1). 1 is ON, 0 is OFF
index 96fff4fc67db488b4bccdb04efefa0a97cd177ff..5cd9391f28a14a493d07a516418cc6a547edb9ae 100644 (file)
  */
 package org.openhab.binding.lutron.internal.radiora.protocol;
 
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
 /**
  * Feedback for when a device was changed locally (not through Master Control)
  * <p>
@@ -37,13 +41,22 @@ package org.openhab.binding.lutron.internal.radiora.protocol;
  * LZC,04,ON
  * </pre>
  *
+ * In a bridged system, a system parameter S1 or S2 will be appended.
+ *
+ * <pre>
+ * LZC,04,ON,S2
+ * </pre>
+ *
  * @author Jeff Lauterbach - Initial Contribution
  *
  */
+@NonNullByDefault
 public class LocalZoneChangeFeedback extends RadioRAFeedback {
+    private final Logger logger = LoggerFactory.getLogger(LocalZoneChangeFeedback.class);
 
     private int zoneNumber; // 1 to 32
     private State state; // ON, OFF, CHG
+    private int system; // 1 or 2, or 0 for none
 
     public enum State {
         ON,
@@ -56,6 +69,18 @@ public class LocalZoneChangeFeedback extends RadioRAFeedback {
 
         zoneNumber = Integer.parseInt(params[1].trim());
         state = State.valueOf(params[2].trim().toUpperCase());
+
+        system = 0;
+        if (params.length > 3) {
+            String sysParam = params[3].trim().toUpperCase();
+            if ("S1".equals(sysParam)) {
+                system = 1;
+            } else if ("S2".equals(sysParam)) {
+                system = 2;
+            } else {
+                logger.debug("Invalid 3rd parameter {} in LZC message. Should be S1 or S2.", sysParam);
+            }
+        }
     }
 
     public State getState() {
@@ -65,4 +90,8 @@ public class LocalZoneChangeFeedback extends RadioRAFeedback {
     public int getZoneNumber() {
         return zoneNumber;
     }
+
+    public int getSystem() {
+        return system;
+    }
 }
index 180f48f223df17b2039ed0259d5bda2370646510..ba103e665dd7b2dd93b0f0e17120d530d343e26c 100644 (file)
@@ -14,12 +14,15 @@ package org.openhab.binding.lutron.internal.radiora.protocol;
 
 import java.util.List;
 
+import org.eclipse.jdt.annotation.NonNullByDefault;
+
 /**
  * Abstract base class for commands.
  *
  * @author Jeff Lauterbach - Initial Contribution
  *
  */
+@NonNullByDefault
 public abstract class RadioRACommand {
 
     protected static final String FIELD_SEPARATOR = ",";
index 366eddec09a94348f1de316d078c04134434a5bc..5ee20a6d6a146116c7d2358c4e3d2771fde54c6d 100644 (file)
  */
 package org.openhab.binding.lutron.internal.radiora.protocol;
 
+import org.eclipse.jdt.annotation.NonNullByDefault;
+
 /**
  * Base class for Feedback from RadioRA
  *
  * @author Jeff Lauterbach - Initial Contribution
  *
  */
+@NonNullByDefault
 public class RadioRAFeedback {
 
     public String[] parse(String msg, int numParams) {
index ae17a3781bf44bec36a9ac4d932982f25a57ce14..16f4762e8e1f60fd6b07bc492407a3694ddbb144 100644 (file)
@@ -15,6 +15,9 @@ package org.openhab.binding.lutron.internal.radiora.protocol;
 import java.util.ArrayList;
 import java.util.List;
 
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.eclipse.jdt.annotation.Nullable;
+
 /**
  * Set Dimmer Level (SDL)
  * Set an individual Dimmer’s light level.
@@ -22,15 +25,18 @@ import java.util.List;
  * @author Jeff Lauterbach - Initial Contribution
  *
  */
+@NonNullByDefault
 public class SetDimmerLevelCommand extends RadioRACommand {
 
     private int zoneNumber; // 1 to 32
     private int dimmerLevel; // 0 to 100
-    private Integer fadeSec; // 0 to 240 (optional)
+    private @Nullable Integer fadeSec; // 0 to 240 (optional)
+    private int system; // 1 or 2, or 0 for none
 
-    public SetDimmerLevelCommand(int zoneNumber, int dimmerLevel) {
+    public SetDimmerLevelCommand(int zoneNumber, int dimmerLevel, int system) {
         this.zoneNumber = zoneNumber;
         this.dimmerLevel = dimmerLevel;
+        this.system = system;
     }
 
     public void setFadeSeconds(int seconds) {
@@ -52,6 +58,10 @@ public class SetDimmerLevelCommand extends RadioRACommand {
             args.add(String.valueOf(fadeSec));
         }
 
+        if (system == 1 || system == 2) {
+            args.add("S" + String.valueOf(system));
+        }
+
         return args;
     }
 }
index 06694a51e14efc893ca41a1876c5e9be9b75b19e..d762c9b680d727dd1599b013d1c1180b26c087ee 100644 (file)
@@ -15,6 +15,8 @@ package org.openhab.binding.lutron.internal.radiora.protocol;
 import java.util.ArrayList;
 import java.util.List;
 
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.eclipse.jdt.annotation.Nullable;
 import org.openhab.core.library.types.OnOffType;
 
 /**
@@ -24,15 +26,18 @@ import org.openhab.core.library.types.OnOffType;
  * @author Jeff Lauterbach - Initial Contribution
  *
  */
+@NonNullByDefault
 public class SetSwitchLevelCommand extends RadioRACommand {
 
     private int zoneNumber; // 1 to 32
     private OnOffType state; // ON/OFF
-    private Integer delaySec; // 0 to 240 (optional)
+    private @Nullable Integer delaySec; // 0 to 240 (optional)
+    private int system; // 1 or 2, or 0 for none
 
-    public SetSwitchLevelCommand(int zoneNumber, OnOffType state) {
+    public SetSwitchLevelCommand(int zoneNumber, OnOffType state, int system) {
         this.zoneNumber = zoneNumber;
         this.state = state;
+        this.system = system;
     }
 
     public void setDelaySeconds(int seconds) {
@@ -54,6 +59,10 @@ public class SetSwitchLevelCommand extends RadioRACommand {
             args.add(String.valueOf(delaySec));
         }
 
+        if (system == 1 || system == 2) {
+            args.add("S" + String.valueOf(system));
+        }
+
         return args;
     }
 }
index 68fae75c010295f5ee62b5fcb6bf8f63cf3b1026..6f046287f099c88333b80ee56f42717edb6e573d 100644 (file)
  */
 package org.openhab.binding.lutron.internal.radiora.protocol;
 
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
 /**
  * Feedback that gives the state of all zones
  * <p>
@@ -26,22 +30,39 @@ package org.openhab.binding.lutron.internal.radiora.protocol;
  * <b>Example:</b>
  * <p>
  * Zones 2 and 9 are ON, all others are OFF, and Zones 31 and 32 are unassigned.
+ * In a bridged system, a system parameter S1 or S2 will be appended.
  *
  * <pre>
  * ZMP,010000001000000000000000000000XX
+ * ZMP,00100000010000000000000000000000,S2
  * </pre>
  *
  * @author Jeff Lauterbach - Initial Contribution
  *
  */
+@NonNullByDefault
 public class ZoneMapFeedback extends RadioRAFeedback {
+    private final Logger logger = LoggerFactory.getLogger(ZoneMapFeedback.class);
 
     private String zoneStates; // 32 bit String of (0,1,X)
+    private int system; // 1 or 2, or 0 for none
 
     public ZoneMapFeedback(String msg) {
         String[] params = parse(msg, 1);
 
         zoneStates = params[1];
+
+        system = 0;
+        if (params.length > 2) {
+            String sysParam = params[2].trim().toUpperCase();
+            if ("S1".equals(sysParam)) {
+                system = 1;
+            } else if ("S2".equals(sysParam)) {
+                system = 2;
+            } else {
+                logger.debug("Invalid 2nd parameter {} in ZMP message. Should be S1 or S2.", sysParam);
+            }
+        }
     }
 
     public String getZoneStates() {
@@ -55,4 +76,8 @@ public class ZoneMapFeedback extends RadioRAFeedback {
 
         return zoneStates.charAt(zone - 1);
     }
+
+    public int getSystem() {
+        return system;
+    }
 }
index caf411b7442292d95c07e060786b52b41ef28d86..11e6cba15b1ba56bd2a88beceb0faa352ed7e7b6 100644 (file)
@@ -15,12 +15,15 @@ package org.openhab.binding.lutron.internal.radiora.protocol;
 import java.util.Collections;
 import java.util.List;
 
+import org.eclipse.jdt.annotation.NonNullByDefault;
+
 /**
  * Requests an updated ZoneMap.
  *
  * @author Jeff Lauterbach - Initial Contribution
  *
  */
+@NonNullByDefault
 public class ZoneMapInquiryCommand extends RadioRACommand {
 
     @Override
index d9e9459ac6e8cb4c8a79926b8f51ee0164d599d5..b3b40832e227cf810c83754019f81be433eb8982 100644 (file)
                                <label>Zone Number</label>
                                <description>Assigned Zone Number within the Lutron RadioRA system.</description>
                        </parameter>
+                       <parameter name="system" type="integer" min="0" max="2" required="false">
+                               <label>System Number</label>
+                               <description>System number (bridged systems only). Set to 1 or 2. 0 = NA (default).</description>
+                               <default>0</default>
+                       </parameter>
                        <parameter name="fadeOutSec" type="integer" required="false">
                                <label>Fade Out (sec)</label>
                                <description>Time in seconds dimmer should take when lowering the level</description>
                                <label>Zone Number</label>
                                <description>Assigned Zone Number within the Lutron RadioRA system.</description>
                        </parameter>
+                       <parameter name="system" type="integer" min="0" max="2" required="false">
+                               <label>System Number</label>
+                               <description>System number (bridged systems only). Set to 1 or 2. 0 = NA (default).</description>
+                               <default>0</default>
+                       </parameter>
                </config-description>
        </thing-type>
 
                                <label>Phantom Button Number</label>
                                <description>Phantom Button Number within the Lutron RadioRA system.</description>
                        </parameter>
+                       <parameter name="system" type="integer" min="0" max="2" required="false">
+                               <label>System Number</label>
+                               <description>System number (bridged systems only). Set to 1 or 2. 0 = NA (default).</description>
+                               <default>0</default>
+                       </parameter>
                </config-description>
        </thing-type>