2 * Copyright (c) 2010-2021 Contributors to the openHAB project
4 * See the NOTICE file(s) distributed with this work for additional
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
11 * SPDX-License-Identifier: EPL-2.0
13 package org.openhab.binding.haywardomnilogic.internal.discovery;
15 import static org.openhab.binding.haywardomnilogic.internal.HaywardBindingConstants.THING_TYPES_UIDS;
17 import java.util.ArrayList;
18 import java.util.Collections;
19 import java.util.HashMap;
20 import java.util.List;
22 import java.util.function.BiConsumer;
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.AbstractDiscoveryService;
31 import org.openhab.core.config.discovery.DiscoveryResult;
32 import org.openhab.core.config.discovery.DiscoveryResultBuilder;
33 import org.openhab.core.config.discovery.DiscoveryService;
34 import org.openhab.core.thing.ThingTypeUID;
35 import org.openhab.core.thing.ThingUID;
36 import org.openhab.core.thing.binding.ThingHandler;
37 import org.openhab.core.thing.binding.ThingHandlerService;
38 import org.slf4j.Logger;
39 import org.slf4j.LoggerFactory;
42 * Sets up the discovery results and details
44 * @author Matt Myers - Initial contribution
48 public class HaywardDiscoveryService extends AbstractDiscoveryService implements DiscoveryService, ThingHandlerService {
49 private final Logger logger = LoggerFactory.getLogger(HaywardDiscoveryService.class);
50 private @Nullable HaywardBridgeHandler discoveryBridgehandler;
52 public HaywardDiscoveryService() {
53 super(THING_TYPES_UIDS, 0, false);
57 public void activate() {
62 public void deactivate() {
67 protected void startScan() {
68 HaywardBridgeHandler bridgehandler = discoveryBridgehandler;
70 if (bridgehandler != null) {
71 String xmlResults = bridgehandler.getMspConfig();
72 mspConfigDiscovery(xmlResults);
74 } catch (HaywardException e) {
75 logger.warn("Exception during discovery scan: {}", e.getMessage());
76 } catch (InterruptedException e) {
81 public synchronized void mspConfigDiscovery(String xmlResponse) {
82 List<String> systemIDs = new ArrayList<>();
83 List<String> names = new ArrayList<>();
84 Map<String, Object> backyardProperties = new HashMap<>();
85 Map<String, Object> bowProperties = new HashMap<>();
86 HaywardBridgeHandler bridgehandler = discoveryBridgehandler;
88 if (bridgehandler == null) {
93 names = bridgehandler.evaluateXPath("//Backyard/Name/text()", xmlResponse);
95 for (int i = 0; i < names.size(); i++) {
96 backyardProperties.put(HaywardBindingConstants.PROPERTY_TYPE, HaywardTypeToRequest.BACKYARD);
97 backyardProperties.put(HaywardBindingConstants.PROPERTY_SYSTEM_ID, bridgehandler.account.mspSystemID);
99 onDeviceDiscovered(HaywardBindingConstants.THING_TYPE_BACKYARD, names.get(i), backyardProperties);
102 // Find Bodies of Water
103 systemIDs = bridgehandler.evaluateXPath("//Body-of-water/System-Id/text()", xmlResponse);
104 names = bridgehandler.evaluateXPath("//Body-of-water/Name/text()", xmlResponse);
106 for (int i = 0; i < systemIDs.size(); i++) {
107 bowProperties.put(HaywardBindingConstants.PROPERTY_TYPE, HaywardTypeToRequest.BOW);
108 bowProperties.put(HaywardBindingConstants.PROPERTY_SYSTEM_ID, systemIDs.get(i));
110 onDeviceDiscovered(HaywardBindingConstants.THING_TYPE_BOW, names.get(i), bowProperties);
114 discoverDevices(bridgehandler, xmlResponse, "Chlorinator", HaywardTypeToRequest.CHLORINATOR,
115 HaywardBindingConstants.THING_TYPE_CHLORINATOR, null);
117 // Find ColorLogic Lights
118 discoverDevices(bridgehandler, xmlResponse, "ColorLogic-Light", HaywardTypeToRequest.COLORLOGIC,
119 HaywardBindingConstants.THING_TYPE_COLORLOGIC, null);
122 final List<String> filterProperty1 = bridgehandler.evaluateXPath("//Filter/Min-Pump-Speed/text()", xmlResponse);
123 final List<String> filterProperty2 = bridgehandler.evaluateXPath("//Filter/Max-Pump-Speed/text()", xmlResponse);
124 final List<String> filterProperty3 = bridgehandler.evaluateXPath("//Filter/Min-Pump-RPM/text()", xmlResponse);
125 final List<String> filterProperty4 = bridgehandler.evaluateXPath("//Filter/Max-Pump-RPM/text()", xmlResponse);
127 discoverDevices(bridgehandler, xmlResponse, "Filter", HaywardTypeToRequest.FILTER,
128 HaywardBindingConstants.THING_TYPE_FILTER, (props, i) -> {
129 props.put(HaywardBindingConstants.PROPERTY_FILTER_MINPUMPSPEED, filterProperty1.get(i));
130 props.put(HaywardBindingConstants.PROPERTY_FILTER_MAXPUMPSPEED, filterProperty2.get(i));
131 props.put(HaywardBindingConstants.PROPERTY_FILTER_MINPUMPRPM, filterProperty3.get(i));
132 props.put(HaywardBindingConstants.PROPERTY_FILTER_MAXPUMPRPM, filterProperty4.get(i));
136 discoverDevices(bridgehandler, xmlResponse, "Heater-Equipment", HaywardTypeToRequest.HEATER,
137 HaywardBindingConstants.THING_TYPE_HEATER, null);
140 final List<String> pumpProperty1 = bridgehandler.evaluateXPath("//Pump/Min-Pump-Speed/text()", xmlResponse);
141 final List<String> pumpProperty2 = bridgehandler.evaluateXPath("//Pump/Max-Pump-Speed/text()", xmlResponse);
142 final List<String> pumpProperty3 = bridgehandler.evaluateXPath("//Pump/Min-Pump-RPM/text()", xmlResponse);
143 final List<String> pumpProperty4 = bridgehandler.evaluateXPath("//Pump/Max-Pump-RPM/text()", xmlResponse);
145 discoverDevices(bridgehandler, xmlResponse, "Pump", HaywardTypeToRequest.PUMP,
146 HaywardBindingConstants.THING_TYPE_FILTER, (props, i) -> {
147 props.put(HaywardBindingConstants.PROPERTY_FILTER_MINPUMPSPEED, pumpProperty1.get(i));
148 props.put(HaywardBindingConstants.PROPERTY_FILTER_MAXPUMPSPEED, pumpProperty2.get(i));
149 props.put(HaywardBindingConstants.PROPERTY_FILTER_MINPUMPRPM, pumpProperty3.get(i));
150 props.put(HaywardBindingConstants.PROPERTY_FILTER_MAXPUMPRPM, pumpProperty4.get(i));
154 discoverDevices(bridgehandler, xmlResponse, "Relay", HaywardTypeToRequest.RELAY,
155 HaywardBindingConstants.THING_TYPE_RELAY, null);
157 // Find Virtual Heaters
158 discoverDevices(bridgehandler, xmlResponse, "Heater", HaywardTypeToRequest.VIRTUALHEATER,
159 HaywardBindingConstants.THING_TYPE_VIRTUALHEATER, null);
162 discoverDevices(bridgehandler, xmlResponse, "Sensor", HaywardTypeToRequest.SENSOR,
163 HaywardBindingConstants.THING_TYPE_SENSOR, null);
166 private void discoverDevices(HaywardBridgeHandler bridgehandler, String xmlResponse, String xmlSearchTerm,
167 HaywardTypeToRequest type, ThingTypeUID thingType,
168 @Nullable BiConsumer<Map<String, Object>, Integer> additionalPropertyConsumer) {
169 List<String> systemIDs = bridgehandler.evaluateXPath("//" + xmlSearchTerm + "/System-Id/text()", xmlResponse);
172 // Set Virtual Heater Name
173 if (HaywardBindingConstants.THING_TYPE_VIRTUALHEATER.equals(thingType)) {
174 names = new ArrayList<>(systemIDs);
175 Collections.fill(names, "Heater");
177 names = bridgehandler.evaluateXPath("//" + xmlSearchTerm + "/Name/text()", xmlResponse);
180 for (int i = 0; i < systemIDs.size(); i++) {
181 // get Body of Water for each item
182 List<String> bowID = bridgehandler.evaluateXPath(
183 "//*[System-Id=" + systemIDs.get(i) + "]/ancestor::Body-of-water/System-Id/text()", xmlResponse);
184 List<String> bowName = bridgehandler.evaluateXPath(
185 "//*[System-Id=" + systemIDs.get(i) + "]/ancestor::Body-of-water/Name/text()", xmlResponse);
187 // skip system sensors with no BOW
188 if (bowID.isEmpty()) {
192 Map<String, Object> properties = new HashMap<>();
193 properties.put(HaywardBindingConstants.PROPERTY_TYPE, type);
194 properties.put(HaywardBindingConstants.PROPERTY_SYSTEM_ID, systemIDs.get(i));
195 properties.put(HaywardBindingConstants.PROPERTY_BOWID, bowID.get(0));
196 properties.put(HaywardBindingConstants.PROPERTY_BOWNAME, bowName.get(0));
197 if (additionalPropertyConsumer != null) {
198 additionalPropertyConsumer.accept(properties, i);
200 onDeviceDiscovered(thingType, names.get(i), properties);
204 public void onDeviceDiscovered(ThingTypeUID thingType, String label, Map<String, Object> properties) {
205 HaywardBridgeHandler bridgehandler = discoveryBridgehandler;
206 String systemID = (String) properties.get(HaywardBindingConstants.PROPERTY_SYSTEM_ID);
207 if (bridgehandler != null) {
208 if (systemID != null) {
209 ThingUID thingUID = new ThingUID(thingType, bridgehandler.getThing().getUID(), systemID);
210 DiscoveryResult result = DiscoveryResultBuilder.create(thingUID)
211 .withBridge(bridgehandler.getThing().getUID())
212 .withRepresentationProperty(HaywardBindingConstants.PROPERTY_SYSTEM_ID)
213 .withLabel("Hayward " + label).withProperties(properties).build();
214 thingDiscovered(result);
220 public void setThingHandler(@Nullable ThingHandler handler) {
221 if (handler instanceof HaywardBridgeHandler) {
222 this.discoveryBridgehandler = (HaywardBridgeHandler) handler;
227 public @Nullable ThingHandler getThingHandler() {
228 return discoveryBridgehandler;