[lutron] Add support for bridged RadioRA (classic) systems ()

Signed-off-by: Bob Adair <bob.github@att.net>
This commit is contained in:
Bob A 2021-03-31 16:44:58 -04:00 committed by GitHub
parent 1783017be4
commit 4b70da49db
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
25 changed files with 278 additions and 101 deletions

@ -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 Configuration Parameters
| 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 | 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

@ -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) {

@ -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) {

@ -12,12 +12,15 @@
*/
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;

@ -12,12 +12,15 @@
*/
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;

@ -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);

@ -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;
}
}

@ -12,32 +12,21 @@
*/
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;
}
}

@ -12,39 +12,30 @@
*/
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;
}
}

@ -12,21 +12,21 @@
*/
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;
}
}

@ -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())) {

@ -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

@ -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);
}
}
}
}

@ -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);
}

@ -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.");
}

@ -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;
}
}

@ -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

@ -12,6 +12,10 @@
*/
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;
}
}

@ -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 = ",";

@ -12,12 +12,15 @@
*/
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) {

@ -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 Dimmers 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;
}
}

@ -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;
}
}

@ -12,6 +12,10 @@
*/
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;
}
}

@ -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

@ -1203,6 +1203,11 @@
<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>
@ -1231,6 +1236,11 @@
<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>
@ -1250,6 +1260,11 @@
<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>