[lutron] initial submission for RA3 support (#15541)
* [lutron] initial submission for RA3 support * add parameter to getDevices(), remove getRA3Devices() --------- Signed-off-by: Peter J Wojciechowski <peterwoj@dwellersoul.com>
This commit is contained in:
committed by
GitHub
parent
57b265574d
commit
3c179d3fa7
@@ -91,6 +91,11 @@ public class LeapDeviceDiscoveryService extends AbstractDiscoveryService
|
||||
case "RA2SelectMainRepeater":
|
||||
notifyDiscovery(THING_TYPE_VIRTUALKEYPAD, deviceId, label, "model", "Caseta");
|
||||
break;
|
||||
case "RadioRa3Processor":
|
||||
notifyDiscovery(THING_TYPE_VIRTUALKEYPAD, deviceId, label, "model", "RadioRA 3");
|
||||
break;
|
||||
case "MaestroDimmer":
|
||||
case "SunnataDimmer":
|
||||
case "WallDimmer":
|
||||
case "PlugInDimmer":
|
||||
notifyDiscovery(THING_TYPE_DIMMER, deviceId, label);
|
||||
|
||||
@@ -30,6 +30,7 @@ import java.security.NoSuchAlgorithmException;
|
||||
import java.security.UnrecoverableKeyException;
|
||||
import java.security.cert.CertificateException;
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
@@ -66,6 +67,7 @@ import org.openhab.binding.lutron.internal.protocol.leap.dto.Area;
|
||||
import org.openhab.binding.lutron.internal.protocol.leap.dto.ButtonGroup;
|
||||
import org.openhab.binding.lutron.internal.protocol.leap.dto.Device;
|
||||
import org.openhab.binding.lutron.internal.protocol.leap.dto.OccupancyGroup;
|
||||
import org.openhab.binding.lutron.internal.protocol.leap.dto.Project;
|
||||
import org.openhab.binding.lutron.internal.protocol.leap.dto.ZoneStatus;
|
||||
import org.openhab.binding.lutron.internal.protocol.lip.LutronCommandType;
|
||||
import org.openhab.core.library.types.StringType;
|
||||
@@ -94,6 +96,7 @@ public class LeapBridgeHandler extends LutronBridgeHandler implements LeapMessag
|
||||
private static final long KEEPALIVE_TIMEOUT_SECONDS = 30;
|
||||
|
||||
private static final String STATUS_INITIALIZING = "Initializing";
|
||||
private static final String LUTRON_RADIORA_3_PROJECT = "Lutron RadioRA 3 Project";
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(LeapBridgeHandler.class);
|
||||
|
||||
@@ -101,6 +104,7 @@ public class LeapBridgeHandler extends LutronBridgeHandler implements LeapMessag
|
||||
private int reconnectInterval;
|
||||
private int heartbeatInterval;
|
||||
private int sendDelay;
|
||||
private boolean isRadioRA3 = false;
|
||||
|
||||
private @NonNullByDefault({}) SSLSocketFactory sslsocketfactory;
|
||||
private @Nullable SSLSocket sslsocket;
|
||||
@@ -305,9 +309,7 @@ public class LeapBridgeHandler extends LutronBridgeHandler implements LeapMessag
|
||||
senderThread.start();
|
||||
this.senderThread = senderThread;
|
||||
|
||||
sendCommand(new LeapCommand(Request.getButtonGroups()));
|
||||
queryDiscoveryData();
|
||||
sendCommand(new LeapCommand(Request.subscribeOccupancyGroupStatus()));
|
||||
sendCommand(new LeapCommand(Request.getProject()));
|
||||
|
||||
logger.debug("Starting keepalive job with interval {}", heartbeatInterval);
|
||||
keepAliveJob = scheduler.scheduleWithFixedDelay(this::sendKeepAlive, heartbeatInterval, heartbeatInterval,
|
||||
@@ -318,7 +320,11 @@ public class LeapBridgeHandler extends LutronBridgeHandler implements LeapMessag
|
||||
* Called by connect() and discovery service to request fresh discovery data
|
||||
*/
|
||||
public void queryDiscoveryData() {
|
||||
sendCommand(new LeapCommand(Request.getDevices()));
|
||||
if (!isRadioRA3) {
|
||||
sendCommand(new LeapCommand(Request.getDevices()));
|
||||
} else {
|
||||
sendCommand(new LeapCommand(Request.getDevices(false)));
|
||||
}
|
||||
sendCommand(new LeapCommand(Request.getAreas()));
|
||||
sendCommand(new LeapCommand(Request.getOccupancyGroups()));
|
||||
}
|
||||
@@ -591,7 +597,31 @@ public class LeapBridgeHandler extends LutronBridgeHandler implements LeapMessag
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleMultipleDeviceDefintion(List<Device> deviceList) {
|
||||
public void handleDeviceDefinition(Device device) {
|
||||
synchronized (zoneMapsLock) {
|
||||
int deviceId = device.getDevice();
|
||||
int zoneId = device.getZone();
|
||||
|
||||
if (zoneId > 0 && deviceId > 0) {
|
||||
zoneToDevice.put(zoneId, deviceId);
|
||||
deviceToZone.put(deviceId, zoneId);
|
||||
}
|
||||
|
||||
if (deviceId == 1 || device.isThisDevice) {
|
||||
setBridgeProperties(device);
|
||||
}
|
||||
}
|
||||
|
||||
checkInitialized();
|
||||
|
||||
LeapDeviceDiscoveryService discoveryService = this.discoveryService;
|
||||
if (discoveryService != null) {
|
||||
discoveryService.processDeviceDefinitions(Arrays.asList(device));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleMultipleDeviceDefinition(List<Device> deviceList) {
|
||||
synchronized (zoneMapsLock) {
|
||||
zoneToDevice.clear();
|
||||
deviceToZone.clear();
|
||||
@@ -603,7 +633,7 @@ public class LeapBridgeHandler extends LutronBridgeHandler implements LeapMessag
|
||||
zoneToDevice.put(zoneid, deviceid);
|
||||
deviceToZone.put(deviceid, zoneid);
|
||||
}
|
||||
if (deviceid == 1) { // ID 1 is the bridge
|
||||
if (deviceid == 1 || device.isThisDevice) { // ID 1 is the bridge
|
||||
setBridgeProperties(device);
|
||||
}
|
||||
}
|
||||
@@ -633,6 +663,26 @@ public class LeapBridgeHandler extends LutronBridgeHandler implements LeapMessag
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleProjectDefinition(Project project) {
|
||||
isRadioRA3 = LUTRON_RADIORA_3_PROJECT.equals(project.productType);
|
||||
|
||||
if (project.masterDeviceList.devices.length > 0 && project.masterDeviceList.devices[0].href != null) {
|
||||
sendCommand(new LeapCommand(Request.getDevices(true)));
|
||||
}
|
||||
|
||||
sendCommand(new LeapCommand(Request.getButtonGroups()));
|
||||
queryDiscoveryData();
|
||||
|
||||
if (!isRadioRA3) {
|
||||
logger.debug("Caseta Bridge Detected: {}", project.productType);
|
||||
} else {
|
||||
logger.debug("Detected a RadioRA 3 System: {}", project.productType);
|
||||
sendCommand(new LeapCommand(Request.subscribeZoneStatus()));
|
||||
}
|
||||
sendCommand(new LeapCommand(Request.subscribeOccupancyGroupStatus()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void validMessageReceived(String communiqueType) {
|
||||
reconnectTaskCancel(true); // Got a good message, so cancel reconnect task.
|
||||
@@ -642,7 +692,7 @@ public class LeapBridgeHandler extends LutronBridgeHandler implements LeapMessag
|
||||
* Set informational bridge properties from the Device entry for the hub/repeater
|
||||
*/
|
||||
private void setBridgeProperties(Device device) {
|
||||
if (device.getDevice() == 1 && device.repeaterProperties != null) {
|
||||
if ((device.getDevice() == 1 && device.repeaterProperties != null) || (device.isThisDevice)) {
|
||||
Map<String, String> properties = editProperties();
|
||||
if (device.name != null) {
|
||||
properties.put(PROPERTY_PRODTYP, device.name);
|
||||
|
||||
@@ -25,6 +25,7 @@ import org.openhab.binding.lutron.internal.protocol.leap.dto.ExceptionDetail;
|
||||
import org.openhab.binding.lutron.internal.protocol.leap.dto.Header;
|
||||
import org.openhab.binding.lutron.internal.protocol.leap.dto.OccupancyGroup;
|
||||
import org.openhab.binding.lutron.internal.protocol.leap.dto.OccupancyGroupStatus;
|
||||
import org.openhab.binding.lutron.internal.protocol.leap.dto.Project;
|
||||
import org.openhab.binding.lutron.internal.protocol.leap.dto.ZoneStatus;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
@@ -181,6 +182,12 @@ public class LeapMessageParser {
|
||||
case "OneZoneStatus":
|
||||
parseOneZoneStatus(body);
|
||||
break;
|
||||
case "OneProjectDefinition":
|
||||
parseOneProjectDefinition(body);
|
||||
break;
|
||||
case "OneDeviceDefinition":
|
||||
parseOneDeviceDefinition(body);
|
||||
break;
|
||||
case "MultipleAreaDefinition":
|
||||
parseMultipleAreaDefinition(body);
|
||||
break;
|
||||
@@ -198,6 +205,9 @@ public class LeapMessageParser {
|
||||
break;
|
||||
case "MultipleVirtualButtonDefinition":
|
||||
break;
|
||||
case "MultipleZoneStatus":
|
||||
parseMultipleZoneStatus(body);
|
||||
break;
|
||||
default:
|
||||
logger.debug("Unknown MessageBodyType received: {}", messageBodyType);
|
||||
break;
|
||||
@@ -297,13 +307,21 @@ public class LeapMessageParser {
|
||||
}
|
||||
}
|
||||
|
||||
private void parseMultipleZoneStatus(JsonObject messageBody) {
|
||||
List<ZoneStatus> statusList = parseBodyMultiple(messageBody, "ZoneStatuses", ZoneStatus.class);
|
||||
for (ZoneStatus status : statusList) {
|
||||
logger.debug("Setting zone {} to level: {}", status.href, status.level);
|
||||
callback.handleZoneUpdate(status);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses a MultipleDeviceDefinition message body and loads the zoneToDevice and deviceToZone maps. Also passes the
|
||||
* device data on to the discovery service and calls setBridgeProperties() with the hub's device entry.
|
||||
*/
|
||||
private void parseMultipleDeviceDefinition(JsonObject messageBody) {
|
||||
List<Device> deviceList = parseBodyMultiple(messageBody, "Devices", Device.class);
|
||||
callback.handleMultipleDeviceDefintion(deviceList);
|
||||
callback.handleMultipleDeviceDefinition(deviceList);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -313,4 +331,18 @@ public class LeapMessageParser {
|
||||
List<ButtonGroup> buttonGroupList = parseBodyMultiple(messageBody, "ButtonGroups", ButtonGroup.class);
|
||||
callback.handleMultipleButtonGroupDefinition(buttonGroupList);
|
||||
}
|
||||
|
||||
private void parseOneProjectDefinition(JsonObject messageBody) {
|
||||
Project project = parseBodySingle(messageBody, "Project", Project.class);
|
||||
if (project != null) {
|
||||
callback.handleProjectDefinition(project);
|
||||
}
|
||||
}
|
||||
|
||||
private void parseOneDeviceDefinition(JsonObject messageBody) {
|
||||
Device device = parseBodySingle(messageBody, "Device", Device.class);
|
||||
if (device != null) {
|
||||
callback.handleDeviceDefinition(device);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@ import org.openhab.binding.lutron.internal.protocol.leap.dto.Area;
|
||||
import org.openhab.binding.lutron.internal.protocol.leap.dto.ButtonGroup;
|
||||
import org.openhab.binding.lutron.internal.protocol.leap.dto.Device;
|
||||
import org.openhab.binding.lutron.internal.protocol.leap.dto.OccupancyGroup;
|
||||
import org.openhab.binding.lutron.internal.protocol.leap.dto.Project;
|
||||
import org.openhab.binding.lutron.internal.protocol.leap.dto.ZoneStatus;
|
||||
|
||||
/**
|
||||
@@ -29,6 +30,10 @@ import org.openhab.binding.lutron.internal.protocol.leap.dto.ZoneStatus;
|
||||
@NonNullByDefault
|
||||
public interface LeapMessageParserCallbacks {
|
||||
|
||||
void handleProjectDefinition(Project project);
|
||||
|
||||
void handleDeviceDefinition(Device device);
|
||||
|
||||
void validMessageReceived(String communiqueType);
|
||||
|
||||
void handleEmptyButtonGroupDefinition();
|
||||
@@ -39,7 +44,7 @@ public interface LeapMessageParserCallbacks {
|
||||
|
||||
void handleMultipleButtonGroupDefinition(List<ButtonGroup> buttonGroupList);
|
||||
|
||||
void handleMultipleDeviceDefintion(List<Device> deviceList);
|
||||
void handleMultipleDeviceDefinition(List<Device> deviceList);
|
||||
|
||||
void handleMultipleAreaDefinition(List<Area> areaList);
|
||||
|
||||
|
||||
@@ -108,7 +108,22 @@ public class Request {
|
||||
}
|
||||
|
||||
public static String getDevices() {
|
||||
return request(CommuniqueType.READREQUEST, "/device");
|
||||
return getDevices("");
|
||||
}
|
||||
|
||||
public static String getDevices(boolean thisDevice) {
|
||||
String url = String.format("where=IsThisDevice:%s", (thisDevice) ? "true" : "false");
|
||||
|
||||
return getDevices(url);
|
||||
}
|
||||
|
||||
public static String getDevices(String predicate) {
|
||||
String url = "/device";
|
||||
if (!predicate.isEmpty()) {
|
||||
url = String.format("%s?%s", url, predicate);
|
||||
}
|
||||
|
||||
return request(CommuniqueType.READREQUEST, url);
|
||||
}
|
||||
|
||||
public static String getVirtualButtons() {
|
||||
@@ -119,6 +134,10 @@ public class Request {
|
||||
return request(CommuniqueType.READREQUEST, BUTTON_GROUP_URL);
|
||||
}
|
||||
|
||||
public static String getProject() {
|
||||
return request(CommuniqueType.READREQUEST, "/project");
|
||||
}
|
||||
|
||||
public static String getAreas() {
|
||||
return request(CommuniqueType.READREQUEST, "/area");
|
||||
}
|
||||
@@ -138,4 +157,8 @@ public class Request {
|
||||
public static String subscribeOccupancyGroupStatus() {
|
||||
return request(CommuniqueType.SUBSCRIBEREQUEST, "/occupancygroup/status");
|
||||
}
|
||||
|
||||
public static String subscribeZoneStatus() {
|
||||
return request(CommuniqueType.SUBSCRIBEREQUEST, "/zone/status");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -69,11 +69,14 @@ public class Device extends AbstractMessageBody {
|
||||
@SerializedName("FirmwareImage")
|
||||
public FirmwareImage firmwareImage;
|
||||
|
||||
@SerializedName("IsThisDevice")
|
||||
public boolean isThisDevice;
|
||||
|
||||
public class FirmwareImage {
|
||||
@SerializedName("Firmware")
|
||||
public Firmware firmware;
|
||||
@SerializedName("Installed")
|
||||
public Installed installed;
|
||||
public ProjectTimestamp installed;
|
||||
}
|
||||
|
||||
public class Firmware {
|
||||
@@ -81,23 +84,6 @@ public class Device extends AbstractMessageBody {
|
||||
public String displayName;
|
||||
}
|
||||
|
||||
public class Installed {
|
||||
@SerializedName("Year")
|
||||
public int year;
|
||||
@SerializedName("Month")
|
||||
public int month;
|
||||
@SerializedName("Day")
|
||||
public int day;
|
||||
@SerializedName("Hour")
|
||||
public int hour;
|
||||
@SerializedName("Minute")
|
||||
public int minute;
|
||||
@SerializedName("Second")
|
||||
public int second;
|
||||
@SerializedName("Utc")
|
||||
public String utc;
|
||||
}
|
||||
|
||||
public class RepeaterProperties {
|
||||
@SerializedName("IsRepeater")
|
||||
public boolean isRepeater;
|
||||
|
||||
@@ -0,0 +1,62 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2023 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.protocol.leap.dto;
|
||||
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import org.openhab.binding.lutron.internal.protocol.leap.AbstractMessageBody;
|
||||
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
|
||||
/**
|
||||
* LEAP Project Object
|
||||
*
|
||||
* @author Peter Wojciechowski - Initial contribution
|
||||
*/
|
||||
public class Project extends AbstractMessageBody {
|
||||
@SerializedName("href")
|
||||
public String href;
|
||||
|
||||
@SerializedName("Name")
|
||||
public String name;
|
||||
|
||||
@SerializedName("ProductType")
|
||||
public String productType;
|
||||
|
||||
@SerializedName("MasterDeviceList")
|
||||
public MasterDeviceList masterDeviceList;
|
||||
|
||||
@SerializedName("Contacts")
|
||||
public Href[] contacts;
|
||||
|
||||
@SerializedName("TimeclockEventRules")
|
||||
public Href timeclockEventRules;
|
||||
|
||||
@SerializedName("ProjectModifiedTimestamp")
|
||||
public ProjectTimestamp projectModifiedTimestamp;
|
||||
|
||||
public class MasterDeviceList {
|
||||
public static final Pattern DEVICE_HREF_PATTERN = Pattern.compile("/device/([0-9]+)");
|
||||
|
||||
public int getDeviceIdFromHref(int deviceIndex) {
|
||||
if (devices.length == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return hrefNumber(DEVICE_HREF_PATTERN, devices[deviceIndex].href);
|
||||
}
|
||||
|
||||
@SerializedName("Devices")
|
||||
public Href[] devices;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2023 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.protocol.leap.dto;
|
||||
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
|
||||
/**
|
||||
* LEAP ProjectTimestamp Object
|
||||
*
|
||||
* @author Peter Wojciechowski - Initial contribution
|
||||
*/
|
||||
public class ProjectTimestamp {
|
||||
@SerializedName("Year")
|
||||
public int year;
|
||||
@SerializedName("Month")
|
||||
public int month;
|
||||
@SerializedName("Day")
|
||||
public int day;
|
||||
@SerializedName("Hour")
|
||||
public int hour;
|
||||
@SerializedName("Minute")
|
||||
public int minute;
|
||||
@SerializedName("Second")
|
||||
public int second;
|
||||
@SerializedName("Utc")
|
||||
public String utc;
|
||||
}
|
||||
Reference in New Issue
Block a user