[lutron] Provides device location and names during discovery (#18484)
* [lutron] Provides device location and names during discovery Signed-off-by: Peter J Wojciechowski <peterwoj@dwellersoul.com>pull/18619/head
parent
72cdd823a3
commit
5e51365de5
|
@ -68,11 +68,24 @@ public class LeapDeviceDiscoveryService extends AbstractThingHandlerDiscoverySer
|
|||
thingHandler.queryDiscoveryData();
|
||||
}
|
||||
|
||||
public void processDeviceDefinitions(List<Device> deviceList) {
|
||||
public void processDeviceDefinitions(List<Device> deviceList, Map<Integer, String> zoneIdToName,
|
||||
Map<Integer, String> areaIdToName) {
|
||||
for (Device device : deviceList) {
|
||||
// Integer zoneid = device.getZone();
|
||||
Integer zoneId = device.getZone();
|
||||
Integer deviceId = device.getDevice();
|
||||
Integer areaId = device.getArea();
|
||||
|
||||
String label = device.getFullyQualifiedName();
|
||||
// RA3 doesn't provide a name for the above instead you
|
||||
// need to get the Area and Zone name to have it make sense
|
||||
if (label.isEmpty()) {
|
||||
String areaName = areaIdToName.getOrDefault(areaId, "");
|
||||
if (areaName.isEmpty()) {
|
||||
label = zoneIdToName.getOrDefault(zoneId, "");
|
||||
} else {
|
||||
label = String.format("%s - %s", areaName, zoneIdToName.getOrDefault(zoneId, ""));
|
||||
}
|
||||
}
|
||||
if (deviceId > 0) {
|
||||
logger.debug("Discovered device: {} type: {} id: {}", label, device.deviceType, deviceId);
|
||||
if (device.deviceType != null) {
|
||||
|
@ -117,6 +130,11 @@ public class LeapDeviceDiscoveryService extends AbstractThingHandlerDiscoverySer
|
|||
case "QsWirelessShade":
|
||||
notifyDiscovery(THING_TYPE_SHADE, deviceId, label);
|
||||
break;
|
||||
case "RPSWallMountedOccupancySensor":
|
||||
// TODO: Handle ra3 OccupancySensors, will need to get area
|
||||
// that the sensor is associated with to get at the sensor
|
||||
// status
|
||||
break;
|
||||
case "RPSOccupancySensor":
|
||||
// Don't discover sensors. Using occupancy groups instead.
|
||||
break;
|
||||
|
|
|
@ -72,6 +72,7 @@ import org.openhab.binding.lutron.internal.protocol.leap.dto.ButtonStatus;
|
|||
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.ZoneExpanded;
|
||||
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;
|
||||
|
@ -133,6 +134,11 @@ public class LeapBridgeHandler extends LutronBridgeHandler implements LeapMessag
|
|||
private final Map<Integer, Integer> deviceToZone = new HashMap<>();
|
||||
private final Object zoneMapsLock = new Object();
|
||||
|
||||
private final Object zoneIdToNameLock = new Object();
|
||||
private final Map<Integer, String> zoneIdToName = new HashMap<>();
|
||||
public final Object areaIdToNameLock = new Object();
|
||||
public final Map<Integer, String> areaIdToName = new HashMap<>();
|
||||
|
||||
private @Nullable Map<Integer, List<Integer>> deviceButtonMap;
|
||||
private Map<Integer, Integer> buttonToDevice = new HashMap<>();
|
||||
private final Object deviceButtonMapLock = new Object();
|
||||
|
@ -325,12 +331,14 @@ 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.getAreas()));
|
||||
|
||||
if (!isRadioRA3) {
|
||||
sendCommand(new LeapCommand(Request.getDevices()));
|
||||
} else {
|
||||
sendCommand(new LeapCommand(Request.getZoneStatuses()));
|
||||
sendCommand(new LeapCommand(Request.getDevices(false)));
|
||||
}
|
||||
sendCommand(new LeapCommand(Request.getAreas()));
|
||||
sendCommand(new LeapCommand(Request.getOccupancyGroups()));
|
||||
}
|
||||
|
||||
|
@ -628,7 +636,7 @@ public class LeapBridgeHandler extends LutronBridgeHandler implements LeapMessag
|
|||
|
||||
LeapDeviceDiscoveryService discoveryService = this.discoveryService;
|
||||
if (discoveryService != null) {
|
||||
discoveryService.processDeviceDefinitions(Arrays.asList(device));
|
||||
discoveryService.processDeviceDefinitions(Arrays.asList(device), zoneIdToName, areaIdToName);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -655,12 +663,36 @@ public class LeapBridgeHandler extends LutronBridgeHandler implements LeapMessag
|
|||
|
||||
LeapDeviceDiscoveryService discoveryService = this.discoveryService;
|
||||
if (discoveryService != null) {
|
||||
discoveryService.processDeviceDefinitions(deviceList);
|
||||
discoveryService.processDeviceDefinitions(deviceList, zoneIdToName, areaIdToName);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleMultipleZoneExpandedUpdate(List<ZoneExpanded> expandedZones) {
|
||||
synchronized (zoneIdToNameLock) {
|
||||
zoneIdToName.clear();
|
||||
for (ZoneExpanded zone : expandedZones) {
|
||||
int zoneId = zone.zone.getZone();
|
||||
if (zoneId > 0) {
|
||||
zoneIdToName.put(zoneId, zone.zone.name);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleMultipleAreaDefinition(List<Area> areaList) {
|
||||
synchronized (areaIdToNameLock) {
|
||||
areaIdToName.clear();
|
||||
for (Area area : areaList) {
|
||||
int areaId = area.getArea();
|
||||
if (areaId > 0) {
|
||||
logger.debug("area[{}] == {}", areaId, area.name);
|
||||
areaIdToName.put(areaId, area.name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
LeapDeviceDiscoveryService discoveryService = this.discoveryService;
|
||||
if (discoveryService != null) {
|
||||
discoveryService.setAreas(areaList);
|
||||
|
|
|
@ -27,6 +27,7 @@ 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.ZoneExpanded;
|
||||
import org.openhab.binding.lutron.internal.protocol.leap.dto.ZoneStatus;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
@ -213,6 +214,9 @@ public class LeapMessageParser {
|
|||
case "MultipleZoneStatus":
|
||||
parseMultipleZoneStatus(body);
|
||||
break;
|
||||
case "MultipleZoneExpandedStatus":
|
||||
parseMultipleZoneExpandedStatus(body);
|
||||
break;
|
||||
default:
|
||||
logger.debug("Unknown MessageBodyType received: {}", messageBodyType);
|
||||
break;
|
||||
|
@ -330,6 +334,12 @@ public class LeapMessageParser {
|
|||
}
|
||||
}
|
||||
|
||||
private void parseMultipleZoneExpandedStatus(JsonObject messageBody) {
|
||||
List<ZoneExpanded> zoneExpandedList = parseBodyMultiple(messageBody, "ZoneExpandedStatuses",
|
||||
ZoneExpanded.class);
|
||||
callback.handleMultipleZoneExpandedUpdate(zoneExpandedList);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
|
|
|
@ -21,6 +21,7 @@ import org.openhab.binding.lutron.internal.protocol.leap.dto.ButtonStatus;
|
|||
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.ZoneExpanded;
|
||||
import org.openhab.binding.lutron.internal.protocol.leap.dto.ZoneStatus;
|
||||
|
||||
/**
|
||||
|
@ -41,6 +42,8 @@ public interface LeapMessageParserCallbacks {
|
|||
|
||||
void handleZoneUpdate(ZoneStatus zoneStatus);
|
||||
|
||||
void handleMultipleZoneExpandedUpdate(List<ZoneExpanded> expandedZones);
|
||||
|
||||
void handleGroupUpdate(int groupNumber, String occupancyStatus);
|
||||
|
||||
void handleMultipleButtonGroupDefinition(List<ButtonGroup> buttonGroupList);
|
||||
|
|
|
@ -14,6 +14,9 @@ package org.openhab.binding.lutron.internal.protocol.leap;
|
|||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.binding.lutron.internal.protocol.FanSpeedType;
|
||||
import org.openhab.binding.lutron.internal.protocol.leap.dto.LeapRequest;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
|
||||
/**
|
||||
* Contains static methods for constructing LEAP messages
|
||||
|
@ -99,8 +102,13 @@ public class Request {
|
|||
}
|
||||
|
||||
public static String request(CommuniqueType cType, String url) {
|
||||
String request = "{\"CommuniqueType\": \"%s\",\"Header\": {\"Url\": \"%s\"}}";
|
||||
return String.format(request, cType.toString(), url);
|
||||
LeapRequest leapRequest = new LeapRequest();
|
||||
leapRequest.communiqueType = cType.toString();
|
||||
leapRequest.header = new LeapRequest.Header();
|
||||
leapRequest.header.url = url;
|
||||
|
||||
Gson gson = new Gson();
|
||||
return gson.toJson(leapRequest);
|
||||
}
|
||||
|
||||
public static String ping() {
|
||||
|
@ -150,6 +158,11 @@ public class Request {
|
|||
return request(CommuniqueType.READREQUEST, String.format("/zone/%d/status", zone));
|
||||
}
|
||||
|
||||
public static String getZoneStatuses() {
|
||||
return request(CommuniqueType.READREQUEST,
|
||||
"/zone/status/expanded?where=Zone.ControlType:\"Dimmed\"|\"Switched\"|\"CCO\"|\"Shade\"");
|
||||
}
|
||||
|
||||
public static String getOccupancyGroupStatus() {
|
||||
return request(CommuniqueType.READREQUEST, "/occupancygroup/status");
|
||||
}
|
||||
|
@ -165,4 +178,8 @@ public class Request {
|
|||
public static String subscribeZoneStatus() {
|
||||
return request(CommuniqueType.SUBSCRIBEREQUEST, "/zone/status");
|
||||
}
|
||||
|
||||
public static String subscribeAreaStatus() {
|
||||
return request(CommuniqueType.SUBSCRIBEREQUEST, "/area/status");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -26,6 +26,7 @@ import com.google.gson.annotations.SerializedName;
|
|||
public class Device extends AbstractMessageBody {
|
||||
public static final Pattern DEVICE_HREF_PATTERN = Pattern.compile("/device/([0-9]+)");
|
||||
private static final Pattern ZONE_HREF_PATTERN = Pattern.compile("/zone/([0-9]+)");
|
||||
private static final Pattern AREA_HREF_PATTERN = Pattern.compile("/area/([0-9]+)");
|
||||
|
||||
@SerializedName("href")
|
||||
public String href;
|
||||
|
@ -108,6 +109,14 @@ public class Device extends AbstractMessageBody {
|
|||
}
|
||||
}
|
||||
|
||||
public int getArea() {
|
||||
if (associatedArea != null && !associatedArea.href.isEmpty()) {
|
||||
return hrefNumber(AREA_HREF_PATTERN, associatedArea.href);
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
public String getFullyQualifiedName() {
|
||||
if (fullyQualifiedName != null && fullyQualifiedName.length > 0) {
|
||||
return String.join(" ", fullyQualifiedName);
|
||||
|
|
|
@ -0,0 +1,53 @@
|
|||
/*
|
||||
* Copyright (c) 2010-2025 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;
|
||||
|
||||
/**
|
||||
* LeapRequest object
|
||||
*
|
||||
* @author Peter J Wojciechowski - initial
|
||||
*/
|
||||
public class LeapRequest {
|
||||
@SerializedName("CommuniqueType")
|
||||
public String communiqueType = "";
|
||||
@SerializedName("Header")
|
||||
public Header header;
|
||||
@SerializedName("Body")
|
||||
public Body body;
|
||||
|
||||
public static class Body {
|
||||
@SerializedName("Command")
|
||||
public Command command;
|
||||
}
|
||||
|
||||
public static class Command {
|
||||
@SerializedName("CommandType")
|
||||
public String commandType;
|
||||
@SerializedName("Parameter")
|
||||
public CommandParameter commandParameter;
|
||||
|
||||
public static class CommandParameter {
|
||||
@SerializedName("Type")
|
||||
public String type;
|
||||
@SerializedName("Value")
|
||||
public String value;
|
||||
}
|
||||
}
|
||||
|
||||
public static class Header {
|
||||
@SerializedName("Url")
|
||||
public String url;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,61 @@
|
|||
/*
|
||||
* Copyright (c) 2010-2025 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 Zone Object
|
||||
*
|
||||
* @author Peter J Wojciechowski - Initial contribution
|
||||
*/
|
||||
|
||||
public class Zone extends AbstractMessageBody {
|
||||
public static final Pattern ZONE_HREF_PATTERN = Pattern.compile("/zone/([0-9]+)");
|
||||
|
||||
@SerializedName("href")
|
||||
public String href = "";
|
||||
@SerializedName("XID")
|
||||
public String xid = "";
|
||||
@SerializedName("Name")
|
||||
public String name = "";
|
||||
@SerializedName("AvailableControlTypes")
|
||||
public String[] controlTypes = {};
|
||||
@SerializedName("Category")
|
||||
public ZoneCategory zoneCategory = new ZoneCategory();
|
||||
@SerializedName("AssociatedArea")
|
||||
public Href associatedArea = new Href();
|
||||
@SerializedName("SortOrder")
|
||||
public int sortOrder;
|
||||
@SerializedName("ControlType")
|
||||
public String controlType = "";
|
||||
|
||||
public int getZone() {
|
||||
if (href != null) {
|
||||
return hrefNumber(ZONE_HREF_PATTERN, href);
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
public class ZoneCategory {
|
||||
@SerializedName("Type")
|
||||
public String type = "";
|
||||
@SerializedName("IsLight")
|
||||
public boolean isLight = false;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
/*
|
||||
* Copyright (c) 2010-2025 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 org.openhab.binding.lutron.internal.protocol.leap.AbstractMessageBody;
|
||||
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
|
||||
/**
|
||||
* ZoneExpanded object
|
||||
*
|
||||
* @author Peter J Wojciechowski - initial
|
||||
*/
|
||||
public class ZoneExpanded extends AbstractMessageBody {
|
||||
@SerializedName("href")
|
||||
public String href;
|
||||
@SerializedName("Level")
|
||||
public int level;
|
||||
@SerializedName("StatusAccuracy")
|
||||
public String statusAccuracy;
|
||||
@SerializedName("Zone")
|
||||
public Zone zone;
|
||||
}
|
Loading…
Reference in New Issue