]> git.basschouten.com Git - openhab-addons.git/blob
0cd34f2e290ee4f2315ec3d5295e305da8cfb52e
[openhab-addons.git] /
1 /**
2  * Copyright (c) 2010-2024 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.haywardomnilogic.internal.discovery;
14
15 import static org.openhab.binding.haywardomnilogic.internal.HaywardBindingConstants.THING_TYPES_UIDS;
16
17 import java.util.ArrayList;
18 import java.util.Collections;
19 import java.util.HashMap;
20 import java.util.List;
21 import java.util.Map;
22 import java.util.function.BiConsumer;
23
24 import org.eclipse.jdt.annotation.NonNullByDefault;
25 import org.eclipse.jdt.annotation.Nullable;
26 import org.openhab.binding.haywardomnilogic.internal.HaywardBindingConstants;
27 import org.openhab.binding.haywardomnilogic.internal.HaywardException;
28 import org.openhab.binding.haywardomnilogic.internal.HaywardTypeToRequest;
29 import org.openhab.binding.haywardomnilogic.internal.handler.HaywardBridgeHandler;
30 import org.openhab.core.config.discovery.AbstractThingHandlerDiscoveryService;
31 import org.openhab.core.config.discovery.DiscoveryResult;
32 import org.openhab.core.config.discovery.DiscoveryResultBuilder;
33 import org.openhab.core.thing.ThingTypeUID;
34 import org.openhab.core.thing.ThingUID;
35 import org.osgi.service.component.annotations.Component;
36 import org.osgi.service.component.annotations.ServiceScope;
37 import org.slf4j.Logger;
38 import org.slf4j.LoggerFactory;
39
40 /**
41  * Sets up the discovery results and details
42  *
43  * @author Matt Myers - Initial contribution
44  */
45 @Component(scope = ServiceScope.PROTOTYPE, service = HaywardDiscoveryService.class)
46 @NonNullByDefault
47 public class HaywardDiscoveryService extends AbstractThingHandlerDiscoveryService<HaywardBridgeHandler> {
48     private final Logger logger = LoggerFactory.getLogger(HaywardDiscoveryService.class);
49
50     public HaywardDiscoveryService() {
51         super(HaywardBridgeHandler.class, THING_TYPES_UIDS, 0, false);
52     }
53
54     @Override
55     protected void startScan() {
56         try {
57             String xmlResults = thingHandler.getMspConfig();
58             mspConfigDiscovery(xmlResults);
59         } catch (HaywardException e) {
60             logger.warn("Exception during discovery scan: {}", e.getMessage());
61         } catch (InterruptedException e) {
62             return;
63         }
64     }
65
66     public synchronized void mspConfigDiscovery(String xmlResponse) {
67         List<String> systemIDs = new ArrayList<>();
68         List<String> names = new ArrayList<>();
69         Map<String, Object> backyardProperties = new HashMap<>();
70         Map<String, Object> bowProperties = new HashMap<>();
71
72         // Find Backyard
73         names = thingHandler.evaluateXPath("//Backyard/Name/text()", xmlResponse);
74
75         for (int i = 0; i < names.size(); i++) {
76             backyardProperties.put(HaywardBindingConstants.PROPERTY_TYPE, HaywardTypeToRequest.BACKYARD);
77             backyardProperties.put(HaywardBindingConstants.PROPERTY_SYSTEM_ID, thingHandler.account.mspSystemID);
78
79             onDeviceDiscovered(HaywardBindingConstants.THING_TYPE_BACKYARD, names.get(i), backyardProperties);
80         }
81
82         // Find Bodies of Water
83         systemIDs = thingHandler.evaluateXPath("//Body-of-water/System-Id/text()", xmlResponse);
84         names = thingHandler.evaluateXPath("//Body-of-water/Name/text()", xmlResponse);
85
86         final List<String> bowProperty1 = thingHandler.evaluateXPath("//Body-of-water/Type/text()", xmlResponse);
87         final List<String> bowProperty2 = thingHandler.evaluateXPath("//Body-of-water/Shared-Type/text()", xmlResponse);
88         final List<String> bowProperty3 = thingHandler.evaluateXPath("//Body-of-water/Shared-Priority/text()",
89                 xmlResponse);
90         final List<String> bowProperty4 = thingHandler
91                 .evaluateXPath("//Body-of-water/Shared-Equipment-System-ID/text()", xmlResponse);
92         final List<String> bowProperty5 = thingHandler.evaluateXPath("//Body-of-water/Supports-Spillover/text()",
93                 xmlResponse);
94         final List<String> bowProperty6 = thingHandler.evaluateXPath("//Body-of-water/Size-In-Gallons/text()",
95                 xmlResponse);
96
97         for (int i = 0; i < systemIDs.size(); i++) {
98             bowProperties.put(HaywardBindingConstants.PROPERTY_TYPE, HaywardTypeToRequest.BOW);
99             bowProperties.put(HaywardBindingConstants.PROPERTY_SYSTEM_ID, systemIDs.get(i));
100             bowProperties.put(HaywardBindingConstants.PROPERTY_BOW_TYPE, bowProperty1.get(i));
101             bowProperties.put(HaywardBindingConstants.PROPERTY_BOW_SHAREDTYPE, bowProperty2.get(i));
102             bowProperties.put(HaywardBindingConstants.PROPERTY_BOW_SHAREDPRIORITY, bowProperty3.get(i));
103             bowProperties.put(HaywardBindingConstants.PROPERTY_BOW_SHAREDEQUIPID, bowProperty4.get(i));
104             bowProperties.put(HaywardBindingConstants.PROPERTY_BOW_SUPPORTSSPILLOVER, bowProperty5.get(i));
105             bowProperties.put(HaywardBindingConstants.PROPERTY_BOW_SIZEINGALLONS, bowProperty6.get(i));
106
107             onDeviceDiscovered(HaywardBindingConstants.THING_TYPE_BOW, names.get(i), bowProperties);
108         }
109
110         // Find Chlorinators
111         final List<String> chlorinatorProperty1 = thingHandler
112                 .evaluateXPath("//Body-of-water/Chlorinator/Shared-Type/text()", xmlResponse);
113         final List<String> chlorinatorProperty2 = thingHandler.evaluateXPath("//Body-of-water/Chlorinator/Mode/text()",
114                 xmlResponse);
115         final List<String> chlorinatorProperty3 = thingHandler
116                 .evaluateXPath("//Body-of-water/Chlorinator/Cell-Type/text()", xmlResponse);
117         final List<String> chlorinatorProperty4 = thingHandler
118                 .evaluateXPath("//Body-of-water/Chlorinator/Dispenser-Type/text()", xmlResponse);
119
120         discoverDevices(thingHandler, xmlResponse, "Chlorinator", HaywardTypeToRequest.CHLORINATOR,
121                 HaywardBindingConstants.THING_TYPE_CHLORINATOR, (props, i) -> {
122                     props.put(HaywardBindingConstants.PROPERTY_CHLORINATOR_SHAREDTYPE, chlorinatorProperty1.get(i));
123                     props.put(HaywardBindingConstants.PROPERTY_CHLORINATOR_MODE, chlorinatorProperty2.get(i));
124                     props.put(HaywardBindingConstants.PROPERTY_CHLORINATOR_CELLTYPE, chlorinatorProperty3.get(i));
125                     props.put(HaywardBindingConstants.PROPERTY_CHLORINATOR_DISPENSERTYPE, chlorinatorProperty4.get(i));
126                 });
127
128         // Find ColorLogic Lights
129         final List<String> colorLogicProperty1 = thingHandler.evaluateXPath("//Backyard//ColorLogic-Light/Type/text()",
130                 xmlResponse);
131
132         discoverDevices(thingHandler, xmlResponse, "ColorLogic-Light", HaywardTypeToRequest.COLORLOGIC,
133                 HaywardBindingConstants.THING_TYPE_COLORLOGIC, (props, i) -> {
134                     props.put(HaywardBindingConstants.PROPERTY_COLORLOGIC_TYPE, colorLogicProperty1.get(i));
135                 });
136
137         // Find Filters
138         final List<String> filterProperty1 = thingHandler.evaluateXPath("//Body-of-water/Filter/Shared-Type/text()",
139                 xmlResponse);
140         final List<String> filterProperty2 = thingHandler.evaluateXPath("//Body-of-water/Filter/Filter-Type/text()",
141                 xmlResponse);
142         final List<String> filterProperty3 = thingHandler.evaluateXPath("//Body-of-water/Filter/Priming-Enabled/text()",
143                 xmlResponse);
144         final List<String> filterProperty4 = thingHandler.evaluateXPath("//Body-of-water/Filter/Min-Pump-Speed/text()",
145                 xmlResponse);
146         final List<String> filterProperty5 = thingHandler.evaluateXPath("//Body-of-water/Filter/Max-Pump-Speed/text()",
147                 xmlResponse);
148         final List<String> filterProperty6 = thingHandler.evaluateXPath("//Body-of-water/Filter/Min-Pump-RPM/text()",
149                 xmlResponse);
150         final List<String> filterProperty7 = thingHandler.evaluateXPath("//Body-of-water/Filter/Max-Pump-RPM/text()",
151                 xmlResponse);
152         final List<String> filterProperty8 = thingHandler
153                 .evaluateXPath("//Body-of-water/Filter/Vsp-Low-Pump-Speed/text()", xmlResponse);
154         final List<String> filterProperty9 = thingHandler
155                 .evaluateXPath("//Body-of-water/Filter/Vsp-Medium-Pump-Speed/text()", xmlResponse);
156         final List<String> filterProperty10 = thingHandler
157                 .evaluateXPath("//Body-of-water/Filter/Vsp-High-Pump-Speed/text()", xmlResponse);
158         final List<String> filterProperty11 = thingHandler
159                 .evaluateXPath("//Body-of-water/Filter/Vsp-Custom-Pump-Speed/text()", xmlResponse);
160         final List<String> filterProperty12 = thingHandler
161                 .evaluateXPath("//Body-of-water/Filter/Freeze-Protect-Override-Interval/text()", xmlResponse);
162
163         discoverDevices(thingHandler, xmlResponse, "Filter", HaywardTypeToRequest.FILTER,
164                 HaywardBindingConstants.THING_TYPE_FILTER, (props, i) -> {
165                     props.put(HaywardBindingConstants.PROPERTY_FILTER_SHAREDTYPE, filterProperty1.get(i));
166                     props.put(HaywardBindingConstants.PROPERTY_FILTER_FILTERTYPE, filterProperty2.get(i));
167                     props.put(HaywardBindingConstants.PROPERTY_FILTER_PRIMINGENABLED, filterProperty3.get(i));
168                     props.put(HaywardBindingConstants.PROPERTY_FILTER_MINSPEED, filterProperty4.get(i));
169                     props.put(HaywardBindingConstants.PROPERTY_FILTER_MAXSPEED, filterProperty5.get(i));
170                     props.put(HaywardBindingConstants.PROPERTY_FILTER_MINRPM, filterProperty6.get(i));
171                     props.put(HaywardBindingConstants.PROPERTY_FILTER_MAXRPM, filterProperty7.get(i));
172                     props.put(HaywardBindingConstants.PROPERTY_FILTER_LOWSPEED, filterProperty8.get(i));
173                     props.put(HaywardBindingConstants.PROPERTY_FILTER_MEDSPEED, filterProperty9.get(i));
174                     props.put(HaywardBindingConstants.PROPERTY_FILTER_HIGHSPEED, filterProperty10.get(i));
175                     props.put(HaywardBindingConstants.PROPERTY_FILTER_CUSTOMSPEED, filterProperty11.get(i));
176                     props.put(HaywardBindingConstants.PROPERTY_FILTER_FREEZEPROTECTOVERRIDEINTERVAL,
177                             filterProperty12.get(i));
178                 });
179
180         // Find Heaters
181         final List<String> heaterProperty1 = thingHandler
182                 .evaluateXPath("//Body-of-water/Heater/Operation/Heater-Equipment/Type/text()", xmlResponse);
183         final List<String> heaterProperty2 = thingHandler
184                 .evaluateXPath("//Body-of-water/Heater/Operation/Heater-Equipment/Heater-Type/text()", xmlResponse);
185         final List<String> heaterProperty3 = thingHandler.evaluateXPath(
186                 "//Body-of-water/Heater/Operation/Heater-Equipment/Shared-Equipment-System-ID/text()", xmlResponse);
187
188         discoverDevices(thingHandler, xmlResponse, "Heater-Equipment", HaywardTypeToRequest.HEATER,
189                 HaywardBindingConstants.THING_TYPE_HEATER, (props, i) -> {
190                     props.put(HaywardBindingConstants.PROPERTY_HEATER_TYPE, heaterProperty1.get(i));
191                     props.put(HaywardBindingConstants.PROPERTY_HEATER_HEATERTYPE, heaterProperty2.get(i));
192                     props.put(HaywardBindingConstants.PROPERTY_HEATER_SHAREDEQUIPID, heaterProperty3.get(i));
193                 });
194
195         // Find Pumps
196         final List<String> pumpProperty1 = thingHandler.evaluateXPath("//Body-of-water/Pump/Type/text()", xmlResponse);
197         final List<String> pumpProperty2 = thingHandler.evaluateXPath("//Body-of-water/Pump/Function/text()",
198                 xmlResponse);
199         final List<String> pumpProperty3 = thingHandler.evaluateXPath("//Body-of-water/Pump/Priming-Enabled/text()",
200                 xmlResponse);
201         final List<String> pumpProperty4 = thingHandler.evaluateXPath("//Body-of-water/Pump/Min-Pump-Speed/text()",
202                 xmlResponse);
203         final List<String> pumpProperty5 = thingHandler.evaluateXPath("//Body-of-water/Pump/Max-Pump-Speed/text()",
204                 xmlResponse);
205         final List<String> pumpProperty6 = thingHandler.evaluateXPath("//Body-of-water/Pump/Min-Pump-RPM/text()",
206                 xmlResponse);
207         final List<String> pumpProperty7 = thingHandler.evaluateXPath("//Body-of-water/Pump/Max-Pump-RPM/text()",
208                 xmlResponse);
209         final List<String> pumpProperty8 = thingHandler.evaluateXPath("//Body-of-water/Pump/Vsp-Low-Pump-Speed/text()",
210                 xmlResponse);
211         final List<String> pumpProperty9 = thingHandler
212                 .evaluateXPath("//Body-of-water/Pump/Vsp-Medium-Pump-Speed/text()", xmlResponse);
213         final List<String> pumpProperty10 = thingHandler
214                 .evaluateXPath("//Body-of-water/Pump/Vsp-High-Pump-Speed/text()", xmlResponse);
215         final List<String> pumpProperty11 = thingHandler
216                 .evaluateXPath("//Body-of-water/Pump/Vsp-Custom-Pump-Speed/text()", xmlResponse);
217
218         discoverDevices(thingHandler, xmlResponse, "Pump", HaywardTypeToRequest.PUMP,
219                 HaywardBindingConstants.THING_TYPE_PUMP, (props, i) -> {
220                     props.put(HaywardBindingConstants.PROPERTY_PUMP_TYPE, pumpProperty1.get(i));
221                     props.put(HaywardBindingConstants.PROPERTY_PUMP_FUNCTION, pumpProperty2.get(i));
222                     props.put(HaywardBindingConstants.PROPERTY_PUMP_PRIMINGENABLED, pumpProperty3.get(i));
223                     props.put(HaywardBindingConstants.PROPERTY_PUMP_MINSPEED, pumpProperty4.get(i));
224                     props.put(HaywardBindingConstants.PROPERTY_PUMP_MAXSPEED, pumpProperty5.get(i));
225                     props.put(HaywardBindingConstants.PROPERTY_PUMP_MINRPM, pumpProperty6.get(i));
226                     props.put(HaywardBindingConstants.PROPERTY_PUMP_MAXRPM, pumpProperty7.get(i));
227                     props.put(HaywardBindingConstants.PROPERTY_PUMP_LOWSPEED, pumpProperty8.get(i));
228                     props.put(HaywardBindingConstants.PROPERTY_PUMP_MEDSPEED, pumpProperty9.get(i));
229                     props.put(HaywardBindingConstants.PROPERTY_PUMP_HIGHSPEED, pumpProperty10.get(i));
230                     props.put(HaywardBindingConstants.PROPERTY_PUMP_CUSTOMSPEED, pumpProperty11.get(i));
231                 });
232
233         // Find Relays
234         final List<String> relayProperty1 = thingHandler.evaluateXPath("//Backyard//Relay/Type/text()", xmlResponse);
235         final List<String> relayProperty2 = thingHandler.evaluateXPath("//Backyard//Relay/Function/text()",
236                 xmlResponse);
237
238         discoverDevices(thingHandler, xmlResponse, "Relay", HaywardTypeToRequest.RELAY,
239                 HaywardBindingConstants.THING_TYPE_RELAY, (props, i) -> {
240                     props.put(HaywardBindingConstants.PROPERTY_RELAY_TYPE, relayProperty1.get(i));
241                     props.put(HaywardBindingConstants.PROPERTY_RELAY_FUNCTION, relayProperty2.get(i));
242                 });
243
244         // Find Virtual Heaters
245         final List<String> virtualHeaterProperty1 = thingHandler
246                 .evaluateXPath("//Body-of-water/Heater/Shared-Type/text()", xmlResponse);
247         final List<String> virtualHeaterProperty2 = thingHandler
248                 .evaluateXPath("//Body-of-water/Heater/Min-Settable-Water-Temp/text()", xmlResponse);
249         final List<String> virtualHeaterProperty3 = thingHandler
250                 .evaluateXPath("//Body-of-water/Heater/Max-Settable-Water-Temp/text()", xmlResponse);
251         final List<String> virtualHeaterProperty4 = thingHandler
252                 .evaluateXPath("//Body-of-water/Heater/Max-Water-Temp/text()", xmlResponse);
253
254         discoverDevices(thingHandler, xmlResponse, "Heater", HaywardTypeToRequest.VIRTUALHEATER,
255                 HaywardBindingConstants.THING_TYPE_VIRTUALHEATER, (props, i) -> {
256                     props.put(HaywardBindingConstants.PROPERTY_VIRTUALHEATER_SHAREDTYPE, virtualHeaterProperty1.get(i));
257                     props.put(HaywardBindingConstants.PROPERTY_VIRTUALHEATER_MINSETTABLEWATERTEMP,
258                             virtualHeaterProperty2.get(i));
259                     props.put(HaywardBindingConstants.PROPERTY_VIRTUALHEATER_MAXSETTABLEWATERTEMP,
260                             virtualHeaterProperty3.get(i));
261                     props.put(HaywardBindingConstants.PROPERTY_VIRTUALHEATER_MAXWATERTEMP,
262                             virtualHeaterProperty4.get(i));
263                 });
264     }
265
266     private void discoverDevices(HaywardBridgeHandler bridgehandler, String xmlResponse, String xmlSearchTerm,
267             HaywardTypeToRequest type, ThingTypeUID thingType,
268             @Nullable BiConsumer<Map<String, Object>, Integer> additionalPropertyConsumer) {
269         List<String> systemIDs = bridgehandler.evaluateXPath("//Backyard//" + xmlSearchTerm + "/System-Id/text()",
270                 xmlResponse);
271         List<String> names;
272
273         // Set Virtual Heater Name
274         if (HaywardBindingConstants.THING_TYPE_VIRTUALHEATER.equals(thingType)) {
275             names = new ArrayList<>(systemIDs);
276             Collections.fill(names, "Heater");
277         } else {
278             names = bridgehandler.evaluateXPath("//Backyard//" + xmlSearchTerm + "/Name/text()", xmlResponse);
279         }
280
281         for (int i = 0; i < systemIDs.size(); i++) {
282             // get Body of Water for each item
283             List<String> bowID = bridgehandler.evaluateXPath(
284                     "//*[System-Id=" + systemIDs.get(i) + "]/ancestor::Body-of-water/System-Id/text()", xmlResponse);
285             List<String> bowName = bridgehandler.evaluateXPath(
286                     "//*[System-Id=" + systemIDs.get(i) + "]/ancestor::Body-of-water/Name/text()", xmlResponse);
287
288             Map<String, Object> properties = new HashMap<>();
289             properties.put(HaywardBindingConstants.PROPERTY_TYPE, type);
290             properties.put(HaywardBindingConstants.PROPERTY_SYSTEM_ID, systemIDs.get(i));
291
292             if (!bowID.isEmpty()) {
293                 properties.put(HaywardBindingConstants.PROPERTY_BOWID, bowID.get(0));
294             } else {
295                 // Set BOWID = 0 for backyard items
296                 properties.put(HaywardBindingConstants.PROPERTY_BOWID, "0");
297             }
298
299             if (!bowName.isEmpty()) {
300                 properties.put(HaywardBindingConstants.PROPERTY_BOWNAME, bowName.get(0));
301             } else {
302                 // Set BOWNAME = Backyard for backyard items
303                 properties.put(HaywardBindingConstants.PROPERTY_BOWNAME, "Backyard");
304             }
305
306             if (additionalPropertyConsumer != null) {
307                 additionalPropertyConsumer.accept(properties, i);
308             }
309
310             onDeviceDiscovered(thingType, names.get(i), properties);
311         }
312     }
313
314     public void onDeviceDiscovered(ThingTypeUID thingType, String label, Map<String, Object> properties) {
315         HaywardBridgeHandler bridgehandler = thingHandler;
316         String systemID = (String) properties.get(HaywardBindingConstants.PROPERTY_SYSTEM_ID);
317         if (bridgehandler != null) {
318             if (systemID != null) {
319                 ThingUID thingUID = new ThingUID(thingType, bridgehandler.getThing().getUID(), systemID);
320                 DiscoveryResult result = DiscoveryResultBuilder.create(thingUID)
321                         .withBridge(bridgehandler.getThing().getUID())
322                         .withRepresentationProperty(HaywardBindingConstants.PROPERTY_SYSTEM_ID)
323                         .withLabel("Hayward " + label).withProperties(properties).build();
324                 thingDiscovered(result);
325             }
326         }
327     }
328 }