[lutron] Minor code and doc updates (#8795)

* [lutron] Minor code and doc updates
* [lutron] Address review comments

Signed-off-by: Bob Adair <bob.github@att.net>
This commit is contained in:
Bob A 2020-10-21 14:50:49 -04:00 committed by GitHub
parent 52b7c8e920
commit 800b500e01
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 104 additions and 53 deletions

View File

@ -1,18 +1,18 @@
# Lutron Binding # Lutron Binding
This binding integrates with [Lutron](http://www.lutron.com) lighting control and home automation systems. 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 * The original RadioRA system, referred to here as RadioRA Classic
* Legacy HomeWorks RS232 Processors * Legacy HomeWorks RS232 Processors
* Grafik Eye 3x/4x systems with GRX-PRG or GRX-CI-PRG control interfaces * Grafik Eye 3x/4x systems with GRX-PRG or GRX-CI-PRG control interfaces
Each is described in a separate section below. 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. 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. 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. 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 ## Discovery
Full discovery is supported for RadioRA 2 and HomeWorks QS systems. 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. Discovered repeaters/processors will be accessed using the default integration credentials.
These can be changed in the bridge thing configuration. 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. Caseta Smart Bridge hubs, Smart Bridge Pro 2 hubs, and RA2 Select main repeaters should be discovered automatically via mDNS.
Devices attached to them still need to be configured manually unless the experimental leapbridge is used. 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. 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 ## Binding Configuration
This binding does not require any special 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 ### 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. 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 | |Bridge Device | LIP | LEAP |
|------------------------|-----|------| |------------------------|-----|------|

View 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. 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. 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. 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 . 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 system, you can easily retrieve it using curl with a command like: 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 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. 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 youll need to give the binding access to. The lutron.keystore file that you end up with is the one youll need to give the binding access to.
The caseta.p12 file is just an intermediate file that you can delete later. The caseta.p12 file is just an intermediate file that you can delete later.
Finally youll then need to set the ipAddress, keystore, and keystorePassword parameters of the leapbridge thing. Finally youll 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. 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.

View File

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

View File

@ -12,7 +12,7 @@
*/ */
package org.openhab.binding.lutron.internal.config; 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}. * Configuration settings for an {@link org.openhab.binding.lutron.internal.handler.IPBridgeHandler}.

View File

@ -15,7 +15,6 @@ package org.openhab.binding.lutron.internal.grxprg;
import java.util.concurrent.ScheduledFuture; import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import org.apache.commons.lang.NullArgumentException;
import org.openhab.core.library.types.DecimalType; import org.openhab.core.library.types.DecimalType;
import org.openhab.core.library.types.IncreaseDecreaseType; import org.openhab.core.library.types.IncreaseDecreaseType;
import org.openhab.core.library.types.OnOffType; import org.openhab.core.library.types.OnOffType;
@ -332,12 +331,12 @@ public class GrafikEyeHandler extends BaseThingHandler {
private PrgProtocolHandler getProtocolHandler() { private PrgProtocolHandler getProtocolHandler() {
final Bridge bridge = getBridge(); final Bridge bridge = getBridge();
if (bridge == null || !(bridge.getHandler() instanceof PrgBridgeHandler)) { 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(); final PrgProtocolHandler handler = ((PrgBridgeHandler) bridge.getHandler()).getProtocolHandler();
if (handler == null) { 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; return handler;
} }

View File

@ -24,7 +24,6 @@ import java.util.concurrent.TimeUnit;
import java.util.regex.Matcher; import java.util.regex.Matcher;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import org.apache.commons.lang.NullArgumentException;
import org.openhab.core.library.types.DateTimeType; import org.openhab.core.library.types.DateTimeType;
import org.openhab.core.library.types.DecimalType; import org.openhab.core.library.types.DecimalType;
import org.openhab.core.library.types.OnOffType; import org.openhab.core.library.types.OnOffType;
@ -629,11 +628,11 @@ class PrgProtocolHandler {
* Sets the time on the PRG interface * Sets the time on the PRG interface
* *
* @param calendar a non-null calendar to set the time to * @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) { void setTime(Calendar calendar) {
if (calendar == null) { 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, 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)); calendar.get(Calendar.DAY_OF_WEEK));

View File

@ -15,8 +15,8 @@ package org.openhab.binding.lutron.internal.handler;
import static org.openhab.binding.lutron.internal.LutronBindingConstants.*; import static org.openhab.binding.lutron.internal.LutronBindingConstants.*;
import java.math.BigDecimal; 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.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable; import org.eclipse.jdt.annotation.Nullable;
import org.openhab.binding.lutron.internal.protocol.OutputCommand; import org.openhab.binding.lutron.internal.protocol.OutputCommand;
@ -181,7 +181,7 @@ public class CcoHandler extends LutronHandler {
@Override @Override
public void handleUpdate(LutronCommandType type, String... parameters) { 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 (outputType == CcoOutputType.MAINTAINED) {
if (type == LutronCommandType.OUTPUT && parameters.length > 1 if (type == LutronCommandType.OUTPUT && parameters.length > 1
@ -193,7 +193,7 @@ public class CcoHandler extends LutronHandler {
BigDecimal state = new BigDecimal(parameters[1]); BigDecimal state = new BigDecimal(parameters[1]);
updateState(CHANNEL_SWITCH, state.compareTo(BigDecimal.ZERO) == 0 ? OnOffType.OFF : OnOffType.ON); updateState(CHANNEL_SWITCH, state.compareTo(BigDecimal.ZERO) == 0 ? OnOffType.OFF : OnOffType.ON);
} catch (NumberFormatException e) { } 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); integrationId);
return; return;
} }

View File

@ -25,7 +25,7 @@ import java.util.regex.MatchResult;
import java.util.regex.Matcher; import java.util.regex.Matcher;
import java.util.regex.Pattern; 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.config.IPBridgeConfig;
import org.openhab.binding.lutron.internal.discovery.LutronDeviceDiscoveryService; import org.openhab.binding.lutron.internal.discovery.LutronDeviceDiscoveryService;
import org.openhab.binding.lutron.internal.net.TelnetSession; import org.openhab.binding.lutron.internal.net.TelnetSession;

View File

@ -281,8 +281,8 @@ public class LeapBridgeHandler extends LutronBridgeHandler implements LeapMessag
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, "Invalid port number"); updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, "Invalid port number");
return; return;
} catch (InterruptedIOException e) { } catch (InterruptedIOException e) {
Thread.currentThread().interrupt();
logger.debug("Interrupted while establishing connection"); logger.debug("Interrupted while establishing connection");
Thread.currentThread().interrupt();
return; return;
} catch (IOException e) { } catch (IOException e) {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
@ -337,9 +337,6 @@ public class LeapBridgeHandler extends LutronBridgeHandler implements LeapMessag
private synchronized void disconnect(boolean interruptAll) { private synchronized void disconnect(boolean interruptAll) {
logger.debug("Disconnecting"); logger.debug("Disconnecting");
Thread senderThread = this.senderThread;
Thread readerThread = this.readerThread;
ScheduledFuture<?> connectRetryJob = this.connectRetryJob; ScheduledFuture<?> connectRetryJob = this.connectRetryJob;
if (connectRetryJob != null) { if (connectRetryJob != null) {
connectRetryJob.cancel(true); connectRetryJob.cancel(true);
@ -351,9 +348,12 @@ public class LeapBridgeHandler extends LutronBridgeHandler implements LeapMessag
reconnectTaskCancel(interruptAll); // May be called from keepAliveReconnectJob thread reconnectTaskCancel(interruptAll); // May be called from keepAliveReconnectJob thread
Thread senderThread = this.senderThread;
if (senderThread != null && senderThread.isAlive()) { if (senderThread != null && senderThread.isAlive()) {
senderThread.interrupt(); senderThread.interrupt();
} }
Thread readerThread = this.readerThread;
if (readerThread != null && readerThread.isAlive()) { if (readerThread != null && readerThread.isAlive()) {
readerThread.interrupt(); readerThread.interrupt();
} }

View File

@ -102,7 +102,10 @@ public class DeviceCommand extends LutronCommandNew {
} else if (targetType == TargetType.VIRTUALKEYPAD) { } else if (targetType == TargetType.VIRTUALKEYPAD) {
if (action.equals(DeviceCommand.ACTION_PRESS)) { if (action.equals(DeviceCommand.ACTION_PRESS)) {
return new LeapCommand(Request.virtualButtonCommand(component, CommandType.PRESSANDRELEASE)); 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."); logger.debug("Ignoring device command with unsupported action.");
return null; return null;
} }

View File

@ -38,7 +38,11 @@ import com.google.gson.JsonParser;
import com.google.gson.JsonSyntaxException; 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 * @author Bob Adair - Initial contribution
*/ */

View File

@ -6,7 +6,7 @@
<bridge-type id="ipbridge"> <bridge-type id="ipbridge">
<label>Lutron IP Access Point</label> <label>Lutron IP Access Point</label>
<description>A Lutron controller using Lutron Integration Protocol (LIP) over TCP/IP</description> <description>Lutron controller using Lutron Integration Protocol (LIP) over TCP/IP</description>
<properties> <properties>
<property name="vendor">Lutron</property> <property name="vendor">Lutron</property>
</properties> </properties>
@ -59,7 +59,7 @@
<bridge-type id="leapbridge"> <bridge-type id="leapbridge">
<label>Lutron LEAP Access Point</label> <label>Lutron LEAP Access Point</label>
<description>A Lutron controller using LEAP protocol over TCP/IP</description> <description>Lutron controller using LEAP protocol over TCP/IP</description>
<channels> <channels>
<channel id="command" typeId="command-type"/> <channel id="command" typeId="command-type"/>
@ -132,8 +132,9 @@
<bridge-type-ref id="leapbridge"/> <bridge-type-ref id="leapbridge"/>
</supported-bridge-type-refs> </supported-bridge-type-refs>
<label>Maestro Dimmer</label> <label>Lutron Dimmer</label>
<description>Controls dimmable loads</description> <description>Controls dimmable loads</description>
<category>Lightbulb</category>
<channels> <channels>
<channel id="lightlevel" typeId="lightDimmer"/> <channel id="lightlevel" typeId="lightDimmer"/>
@ -202,8 +203,9 @@
<bridge-type-ref id="leapbridge"/> <bridge-type-ref id="leapbridge"/>
</supported-bridge-type-refs> </supported-bridge-type-refs>
<label>Sivoia QS Shade</label> <label>Lutron Shade</label>
<description>Controls roller shades</description> <description>Controls roller shades, drapes, and motor controllers</description>
<category>Blinds</category>
<channels> <channels>
<channel id="shadelevel" typeId="shadeControl"/> <channel id="shadelevel" typeId="shadeControl"/>
@ -258,8 +260,9 @@
<bridge-type-ref id="leapbridge"/> <bridge-type-ref id="leapbridge"/>
</supported-bridge-type-refs> </supported-bridge-type-refs>
<label>Maestro Switch</label> <label>Lutron Switch</label>
<description>On/off switch</description> <description>On/off switch</description>
<category>WallSwitch</category>
<channels> <channels>
<channel id="switchstatus" typeId="switchState"/> <channel id="switchstatus" typeId="switchState"/>
@ -368,6 +371,7 @@
<label>Radio Powr Savr Sensor</label> <label>Radio Powr Savr Sensor</label>
<description>Motion sensor to detect occupancy status</description> <description>Motion sensor to detect occupancy status</description>
<category>MotionDetector</category>
<channels> <channels>
<channel id="occupancystatus" typeId="occupiedState"/> <channel id="occupancystatus" typeId="occupiedState"/>
@ -411,6 +415,7 @@
<label>Occupancy Group</label> <label>Occupancy Group</label>
<description>Shows state of occupancy sensor group</description> <description>Shows state of occupancy sensor group</description>
<category>MotionDetector</category>
<channels> <channels>
<channel id="groupstate" typeId="groupState"/> <channel id="groupstate" typeId="groupState"/>
@ -642,7 +647,7 @@
<bridge-type-ref id="ipbridge"/> <bridge-type-ref id="ipbridge"/>
</supported-bridge-type-refs> </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> <description>Lutron GRAFIK Eye QS for RadioRA 2/HomeWorks QS</description>
<representation-property>integrationId</representation-property> <representation-property>integrationId</representation-property>
@ -717,7 +722,6 @@
</config-description> </config-description>
</thing-type> </thing-type>
<thing-type id="virtualkeypad"> <thing-type id="virtualkeypad">
<supported-bridge-type-refs> <supported-bridge-type-refs>
<bridge-type-ref id="ipbridge"/> <bridge-type-ref id="ipbridge"/>
@ -838,7 +842,7 @@
<bridge-type id="prgbridge"> <bridge-type id="prgbridge">
<label>Lutron GRX-PRG or GRX-CI-PRG Bridge</label> <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> <channels>
<channel id="buttonpress" typeId="buttonpress"/> <channel id="buttonpress" typeId="buttonpress"/>
@ -912,8 +916,8 @@
<bridge-type-ref id="prgbridge"/> <bridge-type-ref id="prgbridge"/>
</supported-bridge-type-refs> </supported-bridge-type-refs>
<label>Grafik Eye</label> <label>GRAFIK Eye</label>
<description>Controls a Grafik Eye</description> <description>Controls a GRAFIK Eye</description>
<channels> <channels>
<channel id="scene" typeId="scene"/> <channel id="scene" typeId="scene"/>
@ -1082,7 +1086,7 @@
<bridge-type id="hwserialbridge"> <bridge-type id="hwserialbridge">
<label>Lutron HomeWorks RS232 Bridge</label> <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> <config-description>
<parameter name="serialPort" type="text" required="true"> <parameter name="serialPort" type="text" required="true">
@ -1138,8 +1142,9 @@
<bridge-type-ref id="hwserialbridge"/> <bridge-type-ref id="hwserialbridge"/>
</supported-bridge-type-refs> </supported-bridge-type-refs>
<label>HomeWorks Dimmer</label> <label>Lutron Dimmer (Legacy HomeWorks)</label>
<description>Controls dimmable loads</description> <description>Controls dimmable loads for legacy HomeWorks systems</description>
<category>Lightbulb</category>
<channels> <channels>
<channel id="lightlevel" typeId="lightDimmer"/> <channel id="lightlevel" typeId="lightDimmer"/>
@ -1165,7 +1170,7 @@
<bridge-type id="ra-rs232"> <bridge-type id="ra-rs232">
<label>Lutron RadioRA RS232</label> <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> <config-description>
<parameter name="portName" type="text" required="true"> <parameter name="portName" type="text" required="true">
@ -1185,8 +1190,9 @@
<supported-bridge-type-refs> <supported-bridge-type-refs>
<bridge-type-ref id="ra-rs232"/> <bridge-type-ref id="ra-rs232"/>
</supported-bridge-type-refs> </supported-bridge-type-refs>
<label>RadioRA Dimmer</label> <label>Lutron Dimmer (Legacy RadioRA)</label>
<description>RadioRA Dimmer</description> <description>Controls dimmable loads for legacy RadioRA systems</description>
<category>Lightbulb</category>
<channels> <channels>
<channel id="lightlevel" typeId="lightDimmer"/> <channel id="lightlevel" typeId="lightDimmer"/>
@ -1212,8 +1218,9 @@
<supported-bridge-type-refs> <supported-bridge-type-refs>
<bridge-type-ref id="ra-rs232"/> <bridge-type-ref id="ra-rs232"/>
</supported-bridge-type-refs> </supported-bridge-type-refs>
<label>RadioRA Switch</label> <label>Lutron Switch (Legacy RadioRA)</label>
<description>RadioRA Switch</description> <description>On/off switch for Legacy RadioRA systems</description>
<category>WallSwitch</category>
<channels> <channels>
<channel id="switchstatus" typeId="switchState"/> <channel id="switchstatus" typeId="switchState"/>
@ -1231,8 +1238,8 @@
<supported-bridge-type-refs> <supported-bridge-type-refs>
<bridge-type-ref id="ra-rs232"/> <bridge-type-ref id="ra-rs232"/>
</supported-bridge-type-refs> </supported-bridge-type-refs>
<label>RadioRA Phantom Button</label> <label>Phantom Button (Legacy RadioRA)</label>
<description>RadioRA Phantom Button</description> <description>Phantom Button for Legacy RadioRA systems</description>
<channels> <channels>
<channel id="switchstatus" typeId="switchState"/> <channel id="switchstatus" typeId="switchState"/>