]> git.basschouten.com Git - openhab-addons.git/blob
bd3e2583b9fa027e332b103592673644a82507ea
[openhab-addons.git] /
1 /**
2  * Copyright (c) 2010-2023 Contributors to the openHAB project
3  *
4  * See the NOTICE file(s) distributed with this work for additional
5  * information.
6  *
7  * This program and the accompanying materials are made available under the
8  * terms of the Eclipse Public License 2.0 which is available at
9  * http://www.eclipse.org/legal/epl-2.0
10  *
11  * SPDX-License-Identifier: EPL-2.0
12  */
13 package org.openhab.binding.lutron.internal.discovery;
14
15 import static org.openhab.binding.lutron.internal.LutronBindingConstants.*;
16
17 import java.util.HashMap;
18 import java.util.List;
19 import java.util.Map;
20
21 import org.eclipse.jdt.annotation.NonNullByDefault;
22 import org.eclipse.jdt.annotation.Nullable;
23 import org.openhab.binding.lutron.internal.LutronHandlerFactory;
24 import org.openhab.binding.lutron.internal.handler.LeapBridgeHandler;
25 import org.openhab.binding.lutron.internal.protocol.leap.dto.Area;
26 import org.openhab.binding.lutron.internal.protocol.leap.dto.Device;
27 import org.openhab.binding.lutron.internal.protocol.leap.dto.OccupancyGroup;
28 import org.openhab.core.config.discovery.AbstractDiscoveryService;
29 import org.openhab.core.config.discovery.DiscoveryResult;
30 import org.openhab.core.config.discovery.DiscoveryResultBuilder;
31 import org.openhab.core.config.discovery.DiscoveryService;
32 import org.openhab.core.thing.ThingTypeUID;
33 import org.openhab.core.thing.ThingUID;
34 import org.openhab.core.thing.binding.ThingHandler;
35 import org.openhab.core.thing.binding.ThingHandlerService;
36 import org.slf4j.Logger;
37 import org.slf4j.LoggerFactory;
38
39 /**
40  * The {@link LeapDeviceDiscoveryService} discovers devices paired with Lutron bridges using the LEAP protocol.
41  *
42  * @author Bob Adair - Initial contribution
43  */
44 @NonNullByDefault
45 public class LeapDeviceDiscoveryService extends AbstractDiscoveryService
46         implements DiscoveryService, ThingHandlerService {
47
48     private static final int DISCOVERY_SERVICE_TIMEOUT = 0; // seconds
49
50     private final Logger logger = LoggerFactory.getLogger(LeapDeviceDiscoveryService.class);
51
52     /** Area number to name map **/
53     private @Nullable Map<Integer, String> areaMap;
54     private @Nullable List<OccupancyGroup> oGroupList;
55
56     private @NonNullByDefault({}) LeapBridgeHandler bridgeHandler;
57
58     public LeapDeviceDiscoveryService() {
59         super(LutronHandlerFactory.DISCOVERABLE_DEVICE_TYPES_UIDS, DISCOVERY_SERVICE_TIMEOUT);
60     }
61
62     @Override
63     public void setThingHandler(ThingHandler handler) {
64         if (handler instanceof LeapBridgeHandler leapBridgeHandler) {
65             bridgeHandler = leapBridgeHandler;
66             bridgeHandler.setDiscoveryService(this);
67         }
68     }
69
70     @Override
71     public @Nullable ThingHandler getThingHandler() {
72         return bridgeHandler;
73     }
74
75     @Override
76     protected void startScan() {
77         logger.debug("Active discovery scan started");
78         bridgeHandler.queryDiscoveryData();
79     }
80
81     public void processDeviceDefinitions(List<Device> deviceList) {
82         for (Device device : deviceList) {
83             // Integer zoneid = device.getZone();
84             Integer deviceId = device.getDevice();
85             String label = device.getFullyQualifiedName();
86             if (deviceId > 0) {
87                 logger.debug("Discovered device: {} type: {} id: {}", label, device.deviceType, deviceId);
88                 if (device.deviceType != null) {
89                     switch (device.deviceType) {
90                         case "SmartBridge":
91                         case "RA2SelectMainRepeater":
92                             notifyDiscovery(THING_TYPE_VIRTUALKEYPAD, deviceId, label, "model", "Caseta");
93                             break;
94                         case "RadioRa3Processor":
95                             notifyDiscovery(THING_TYPE_VIRTUALKEYPAD, deviceId, label, "model", "RadioRA 3");
96                             break;
97                         case "MaestroDimmer":
98                         case "SunnataDimmer":
99                         case "WallDimmer":
100                         case "PlugInDimmer":
101                             notifyDiscovery(THING_TYPE_DIMMER, deviceId, label);
102                             break;
103                         case "WallSwitch":
104                         case "PlugInSwitch":
105                             notifyDiscovery(THING_TYPE_SWITCH, deviceId, label);
106                             break;
107                         case "CasetaFanSpeedController":
108                         case "MaestroFanSpeedController":
109                             notifyDiscovery(THING_TYPE_FAN, deviceId, label);
110                             break;
111                         case "Pico2Button":
112                             notifyDiscovery(THING_TYPE_PICO, deviceId, label, "model", "2B");
113                             break;
114                         case "Pico2ButtonRaiseLower":
115                             notifyDiscovery(THING_TYPE_PICO, deviceId, label, "model", "2BRL");
116                             break;
117                         case "Pico3ButtonRaiseLower":
118                             notifyDiscovery(THING_TYPE_PICO, deviceId, label, "model", "3BRL");
119                             break;
120                         case "SerenaRollerShade":
121                         case "SerenaHoneycombShade":
122                         case "TriathlonRollerShade":
123                         case "TriathlonHoneycombShade":
124                         case "QsWirelessShade":
125                             notifyDiscovery(THING_TYPE_SHADE, deviceId, label);
126                             break;
127                         case "RPSOccupancySensor":
128                             // Don't discover sensors. Using occupancy groups instead.
129                             break;
130                         default:
131                             logger.info("Unrecognized device type: {}", device.deviceType);
132                             break;
133                     }
134                 }
135             }
136         }
137     }
138
139     private void processOccupancyGroups() {
140         Map<Integer, String> areaMap = this.areaMap;
141         List<OccupancyGroup> oGroupList = this.oGroupList;
142
143         if (areaMap != null && oGroupList != null) {
144             logger.trace("Processing occupancy groups");
145             for (OccupancyGroup oGroup : oGroupList) {
146                 logger.trace("Processing OccupancyGroup: {}", oGroup.href);
147                 int groupNum = oGroup.getOccupancyGroup();
148                 // Only process occupancy groups with associated occupancy sensors
149                 if (groupNum > 0 && oGroup.associatedSensors != null) {
150                     String areaName;
151                     if (oGroup.associatedAreas.length > 0) {
152                         // If multiple associated areas are listed, use only the first
153                         areaName = areaMap.get(oGroup.associatedAreas[0].getAreaNumber());
154                     } else {
155                         areaName = "Occupancy Group";
156                     }
157                     if (areaName != null) {
158                         logger.debug("Discovered occupancy group: {} areas: {} area name: {}", groupNum,
159                                 oGroup.associatedAreas.length, areaName);
160                         notifyDiscovery(THING_TYPE_OGROUP, groupNum, areaName);
161                     }
162                 }
163             }
164             this.areaMap = null;
165             this.oGroupList = null;
166         }
167     }
168
169     public void setOccupancyGroups(List<OccupancyGroup> oGroupList) {
170         logger.trace("Setting occupancy groups list");
171         this.oGroupList = oGroupList;
172
173         if (areaMap != null) {
174             processOccupancyGroups();
175         }
176     }
177
178     public void setAreas(List<Area> areaList) {
179         Map<Integer, String> areaMap = new HashMap<>();
180
181         logger.trace("Setting areas map");
182         for (Area area : areaList) {
183             int areaNum = area.getArea();
184             logger.trace("Inserting area into map - num: {} name: {}", areaNum, area.name);
185             if (areaNum > 0) {
186                 areaMap.put(areaNum, area.name);
187             } else {
188                 logger.debug("Ignoring area with unparsable href {}", area.href);
189             }
190         }
191         this.areaMap = areaMap;
192
193         if (oGroupList != null) {
194             processOccupancyGroups();
195         }
196     }
197
198     private void notifyDiscovery(ThingTypeUID thingTypeUID, @Nullable Integer integrationId, String label,
199             @Nullable String propName, @Nullable Object propValue) {
200         if (integrationId == null) {
201             logger.debug("Discovered {} with no integration ID", label);
202             return;
203         }
204         ThingUID bridgeUID = this.bridgeHandler.getThing().getUID();
205         ThingUID uid = new ThingUID(thingTypeUID, bridgeUID, integrationId.toString());
206
207         Map<String, Object> properties = new HashMap<>();
208
209         properties.put(INTEGRATION_ID, integrationId);
210         if (propName != null && propValue != null) {
211             properties.put(propName, propValue);
212         }
213
214         DiscoveryResult result = DiscoveryResultBuilder.create(uid).withBridge(bridgeUID).withLabel(label)
215                 .withProperties(properties).withRepresentationProperty(INTEGRATION_ID).build();
216         thingDiscovered(result);
217         logger.trace("Discovered {}", uid);
218     }
219
220     private void notifyDiscovery(ThingTypeUID thingTypeUID, Integer integrationId, String label) {
221         notifyDiscovery(thingTypeUID, integrationId, label, null, null);
222     }
223
224     @Override
225     public void deactivate() {
226         super.deactivate();
227     }
228 }