[haywardomnilogic] Replacement for Hayward Omnilogic Pool Automation Binding (#8685)

* Initial Contribution

Signed-off-by: Matt Myers <mmyers75@icloud.com>
This commit is contained in:
Matt
2021-01-22 17:32:52 -05:00
committed by GitHub
parent 37bc57f856
commit ab290c5464
37 changed files with 3150 additions and 0 deletions

View File

@@ -0,0 +1,35 @@
/**
* Copyright (c) 2010-2021 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.haywardomnilogic.internal;
import org.eclipse.jdt.annotation.NonNullByDefault;
/**
* The {@link HaywardAccount} class contains fields mapping thing configuration parameters.
*
* @author Matt Myers - Initial contribution
*/
@NonNullByDefault
public class HaywardAccount {
public String token = "";
public String mspSystemID = "";
public String userID = "";
public String backyardName = "";
public String address = "";
public String firstName = "";
public String lastName = "";
public String roleType = "";
public String units = "";
public String vspSpeedFormat = "";
}

View File

@@ -0,0 +1,134 @@
/**
* Copyright (c) 2010-2021 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.haywardomnilogic.internal;
import java.util.Set;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.core.thing.ThingTypeUID;
/**
* The {@link HaywardBindingConstants} class defines common constants, which are
* used across the whole binding.
*
* @author Matt Myers - Initial contribution
*/
@NonNullByDefault
public class HaywardBindingConstants {
private static final String BINDING_ID = "haywardomnilogic";
// List of all Thing Type UIDs
public static final ThingTypeUID THING_TYPE_BACKYARD = new ThingTypeUID(BINDING_ID, "backyard");
public static final ThingTypeUID THING_TYPE_BOW = new ThingTypeUID(BINDING_ID, "bow");
public static final ThingTypeUID THING_TYPE_BRIDGE = new ThingTypeUID(BINDING_ID, "bridge");
public static final ThingTypeUID THING_TYPE_CHLORINATOR = new ThingTypeUID(BINDING_ID, "chlorinator");
public static final ThingTypeUID THING_TYPE_COLORLOGIC = new ThingTypeUID(BINDING_ID, "colorlogic");
public static final ThingTypeUID THING_TYPE_FILTER = new ThingTypeUID(BINDING_ID, "filter");
public static final ThingTypeUID THING_TYPE_HEATER = new ThingTypeUID(BINDING_ID, "heater");
public static final ThingTypeUID THING_TYPE_PUMP = new ThingTypeUID(BINDING_ID, "pump");
public static final ThingTypeUID THING_TYPE_RELAY = new ThingTypeUID(BINDING_ID, "relay");
public static final ThingTypeUID THING_TYPE_SENSOR = new ThingTypeUID(BINDING_ID, "sensor");
public static final ThingTypeUID THING_TYPE_VIRTUALHEATER = new ThingTypeUID(BINDING_ID, "virtualHeater");
public static final Set<ThingTypeUID> BRIDGE_THING_TYPES_UIDS = Set.of(THING_TYPE_BRIDGE);
public static final Set<ThingTypeUID> THING_TYPES_UIDS = Set.of(HaywardBindingConstants.THING_TYPE_BACKYARD,
HaywardBindingConstants.THING_TYPE_BOW, HaywardBindingConstants.THING_TYPE_BRIDGE,
HaywardBindingConstants.THING_TYPE_CHLORINATOR, HaywardBindingConstants.THING_TYPE_COLORLOGIC,
HaywardBindingConstants.THING_TYPE_FILTER, HaywardBindingConstants.THING_TYPE_HEATER,
HaywardBindingConstants.THING_TYPE_PUMP, HaywardBindingConstants.THING_TYPE_RELAY,
HaywardBindingConstants.THING_TYPE_SENSOR, HaywardBindingConstants.THING_TYPE_VIRTUALHEATER);
// List of all Channel ids (bridge)
// No Channels
// List of all Channel ids (backyard)
public static final String CHANNEL_BACKYARD_AIRTEMP = "backyardAirTemp";
public static final String CHANNEL_BACKYARD_STATUS = "backyardStatus";
public static final String CHANNEL_BACKYARD_STATE = "backyardState";
// List of all Channel ids (bow)
public static final String CHANNEL_BOW_WATERTEMP = "bowWaterTemp";
public static final String CHANNEL_BOW_FLOW = "bowFlow";
// List of all Channel ids (chlorinator)
public static final String CHANNEL_CHLORINATOR_ENABLE = "chlorEnable";
public static final String CHANNEL_CHLORINATOR_OPERATINGMODE = "chlorOperatingMode";
public static final String CHANNEL_CHLORINATOR_TIMEDPERCENT = "chlorTimedPercent";
public static final String CHANNEL_CHLORINATOR_SCMODE = "chlorScMode";
public static final String CHANNEL_CHLORINATOR_ERROR = "chlorError";
public static final String CHANNEL_CHLORINATOR_ALERT = "chlorAlert";
public static final String CHANNEL_CHLORINATOR_AVGSALTLEVEL = "chlorAvgSaltLevel";
public static final String CHANNEL_CHLORINATOR_INSTANTSALTLEVEL = "chlorInstantSaltLevel";
public static final String CHANNEL_CHLORINATOR_STATUS = "chlorStatus";
// List of all Channel ids (colorlogic)
public static final String CHANNEL_COLORLOGIC_ENABLE = "colorLogicLightEnable";
public static final String CHANNEL_COLORLOGIC_LIGHTSTATE = "colorLogicLightState";
public static final String CHANNEL_COLORLOGIC_CURRENTSHOW = "colorLogicLightCurrentShow";
// List of all Channel ids (filter)
public static final String CHANNEL_FILTER_ENABLE = "filterEnable";
public static final String CHANNEL_FILTER_VALVEPOSITION = "filterValvePosition";
public static final String CHANNEL_FILTER_SPEED = "filterSpeed";
public static final String CHANNEL_FILTER_STATE = "filterState";
public static final String CHANNEL_FILTER_LASTSPEED = "filterLastSpeed";
public static final String PROPERTY_FILTER_MINPUMPSPEED = "Min Pump Percent";
public static final String PROPERTY_FILTER_MAXPUMPSPEED = "Max Pump Percent";
public static final String PROPERTY_FILTER_MINPUMPRPM = "Min Pump RPM";
public static final String PROPERTY_FILTER_MAXPUMPRPM = "Max Pump RPM";
// List of all Channel ids (heater)
public static final String CHANNEL_HEATER_STATE = "heaterState";
public static final String CHANNEL_HEATER_TEMP = "heaterTemp";
public static final String CHANNEL_HEATER_ENABLE = "heaterEnable";
// List of all Channel ids (pump)
public static final String CHANNEL_PUMP_ENABLE = "pumpEnable";
public static final String CHANNEL_PUMP_SPEED = "pumpSpeed";
public static final String PROPERTY_PUMP_MINPUMPSPEED = "Min Pump Speed";
public static final String PROPERTY_PUMP_MAXPUMPSPEED = "Min Pump Speed";
public static final String PROPERTY_PUMP_MINPUMPRPM = "Min Pump RPM";
public static final String PROPERTY_PUMP_MAXPUMPRPM = "Max Pump RPM";
// List of all Channel ids (relay)
public static final String CHANNEL_RELAY_STATE = "relayState";
// List of all Channel ids (sensor)
public static final String CHANNEL_SENSOR_DATA = "sensorData";
// List of all Channel ids (virtualHeater)
public static final String CHANNEL_VIRTUALHEATER_CURRENTSETPOINT = "virtualHeaterCurrentSetpoint";
public static final String CHANNEL_VIRTUALHEATER_ENABLE = "virtualHeaterEnable";
// The properties associated with all things
public static final String PROPERTY_SYSTEM_ID = "Property system ID";
public static final String PROPERTY_TYPE = "propertyType";
public static final String PROPERTY_BOWNAME = "BOW Name";
public static final String PROPERTY_BOWID = "BOW ID";
// Hayward Command html
public static final String COMMAND_PARAMETERS = "<?xml version=\"1.0\" encoding=\"utf-8\"?><Request>";
public static final String COMMAND_SCHEDULE = "<Parameter name=\"IsCountDownTimer\" dataType=\"bool\">false</Parameter>"
+ "<Parameter name=\"StartTimeHours\" dataType=\"int\">0</Parameter>"
+ "<Parameter name=\"StartTimeMinutes\" dataType=\"int\">0</Parameter>"
+ "<Parameter name=\"EndTimeHours\" dataType=\"int\">0</Parameter>"
+ "<Parameter name=\"EndTimeMinutes\" dataType=\"int\">0</Parameter>"
+ "<Parameter name=\"DaysActive\" dataType=\"int\">0</Parameter>"
+ "<Parameter name=\"Recurring\" dataType=\"bool\">false</Parameter>";
}

View File

@@ -0,0 +1,40 @@
/**
* Copyright (c) 2010-2021 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.haywardomnilogic.internal;
import org.eclipse.jdt.annotation.NonNullByDefault;
/**
* The {@link HaywardException} is thrown during the getMspConfig, mspConfigDiscovery, getTelemetry,
* evaluateXPath and httpXmlResponse methods
*
* @author Matt Myers - Initial contribution
*/
@NonNullByDefault
public class HaywardException extends Exception {
/**
* The {@link HaywardException} is thrown by getMspConfig() and mspConfigDiscovery()
*
*/
private static final long serialVersionUID = 1L;
/**
* Constructor.
*
* @param message Hayward error message
*/
public HaywardException(String message) {
super(message);
}
}

View File

@@ -0,0 +1,110 @@
/**
* Copyright (c) 2010-2021 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.haywardomnilogic.internal;
import static org.openhab.binding.haywardomnilogic.internal.HaywardBindingConstants.*;
import java.util.Collections;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.eclipse.jetty.client.HttpClient;
import org.openhab.binding.haywardomnilogic.internal.handler.HaywardBackyardHandler;
import org.openhab.binding.haywardomnilogic.internal.handler.HaywardBowHandler;
import org.openhab.binding.haywardomnilogic.internal.handler.HaywardBridgeHandler;
import org.openhab.binding.haywardomnilogic.internal.handler.HaywardChlorinatorHandler;
import org.openhab.binding.haywardomnilogic.internal.handler.HaywardColorLogicHandler;
import org.openhab.binding.haywardomnilogic.internal.handler.HaywardFilterHandler;
import org.openhab.binding.haywardomnilogic.internal.handler.HaywardHeaterHandler;
import org.openhab.binding.haywardomnilogic.internal.handler.HaywardRelayHandler;
import org.openhab.binding.haywardomnilogic.internal.handler.HaywardSensorHandler;
import org.openhab.binding.haywardomnilogic.internal.handler.HaywardVirtualHeaterHandler;
import org.openhab.core.io.net.http.HttpClientFactory;
import org.openhab.core.thing.Bridge;
import org.openhab.core.thing.Thing;
import org.openhab.core.thing.ThingTypeUID;
import org.openhab.core.thing.binding.BaseThingHandlerFactory;
import org.openhab.core.thing.binding.ThingHandler;
import org.openhab.core.thing.binding.ThingHandlerFactory;
import org.osgi.service.component.annotations.Activate;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Reference;
/**
* The {@link HaywardHandlerFactory} is responsible for creating things and thing
* handlers.
*
* @author Matt Myers - Initial contribution
*/
@Component(service = ThingHandlerFactory.class, configurationPid = "binding.haywardomnilogic")
@NonNullByDefault
public class HaywardHandlerFactory extends BaseThingHandlerFactory {
private static final Set<ThingTypeUID> SUPPORTED_THING_TYPES_UIDS = Collections.unmodifiableSet(
Stream.concat(BRIDGE_THING_TYPES_UIDS.stream(), THING_TYPES_UIDS.stream()).collect(Collectors.toSet()));
private final HttpClient httpClient;
@Override
public boolean supportsThingType(ThingTypeUID thingTypeUID) {
return SUPPORTED_THING_TYPES_UIDS.contains(thingTypeUID);
}
@Activate
public HaywardHandlerFactory(@Reference HttpClientFactory httpClientFactory) {
this.httpClient = httpClientFactory.getCommonHttpClient();
}
/**
* Creates the specific handler for this thing.
*/
@Override
protected @Nullable ThingHandler createHandler(Thing thing) {
ThingTypeUID thingTypeUID = thing.getThingTypeUID();
if (thingTypeUID.equals(HaywardBindingConstants.THING_TYPE_BRIDGE)) {
return new HaywardBridgeHandler((Bridge) thing, httpClient);
}
if (thingTypeUID.equals(HaywardBindingConstants.THING_TYPE_BACKYARD)) {
return new HaywardBackyardHandler(thing);
}
if (thingTypeUID.equals(HaywardBindingConstants.THING_TYPE_BOW)) {
return new HaywardBowHandler(thing);
}
if (thingTypeUID.equals(HaywardBindingConstants.THING_TYPE_CHLORINATOR)) {
return new HaywardChlorinatorHandler(thing);
}
if (thingTypeUID.equals(HaywardBindingConstants.THING_TYPE_COLORLOGIC)) {
return new HaywardColorLogicHandler(thing);
}
if (thingTypeUID.equals(HaywardBindingConstants.THING_TYPE_FILTER)) {
return new HaywardFilterHandler(thing);
}
if (thingTypeUID.equals(HaywardBindingConstants.THING_TYPE_HEATER)) {
return new HaywardHeaterHandler(thing);
}
if (thingTypeUID.equals(HaywardBindingConstants.THING_TYPE_RELAY)) {
return new HaywardRelayHandler(thing);
}
if (thingTypeUID.equals(HaywardBindingConstants.THING_TYPE_SENSOR)) {
return new HaywardSensorHandler(thing);
}
if (thingTypeUID.equals(HaywardBindingConstants.THING_TYPE_VIRTUALHEATER)) {
return new HaywardVirtualHeaterHandler(thing);
}
return null;
}
}

View File

@@ -0,0 +1,121 @@
/**
* Copyright (c) 2010-2021 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.haywardomnilogic.internal;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.binding.haywardomnilogic.internal.handler.HaywardBridgeHandler;
import org.openhab.core.library.types.DecimalType;
import org.openhab.core.library.types.OnOffType;
import org.openhab.core.library.types.QuantityType;
import org.openhab.core.library.types.StringType;
import org.openhab.core.library.unit.ImperialUnits;
import org.openhab.core.library.unit.SIUnits;
import org.openhab.core.library.unit.Units;
import org.openhab.core.thing.Bridge;
import org.openhab.core.thing.Channel;
import org.openhab.core.thing.ChannelUID;
import org.openhab.core.thing.Thing;
import org.openhab.core.thing.ThingStatus;
import org.openhab.core.thing.binding.BaseThingHandler;
import org.openhab.core.types.Command;
import org.openhab.core.types.State;
/**
* The {@link HaywarThingHandler} is a subclass of the BaseThingHandler and a Super
* Class to each Hayward Thing Handler
*
* @author Matt Myers - Initial contribution
*/
@NonNullByDefault
public abstract class HaywardThingHandler extends BaseThingHandler {
public HaywardThingHandler(Thing thing) {
super(thing);
}
@Override
public void initialize() {
updateStatus(ThingStatus.ONLINE);
}
@Override
public void handleCommand(ChannelUID channelUID, Command command) {
}
public abstract void getTelemetry(String xmlResponse) throws HaywardException;
public State toState(String type, String channelID, String value) throws NumberFormatException {
switch (type) {
case "Number":
return new DecimalType(value);
case "Switch":
case "system.power":
return Integer.parseInt(value) > 0 ? OnOffType.ON : OnOffType.OFF;
case "Number:Dimensionless":
switch (channelID) {
case "chlorTimedPercent":
case "filterSpeed":
case "pumpSpeed":
case "filterLastSpeed":
return new QuantityType<>(Integer.parseInt(value), Units.PERCENT);
case "chlorAvgSaltLevel":
case "chlorInstantSaltLevel":
return new QuantityType<>(Integer.parseInt(value), Units.PARTS_PER_MILLION);
}
return StringType.valueOf(value);
case "Number:Temperature":
Bridge bridge = getBridge();
if (bridge != null) {
HaywardBridgeHandler bridgehandler = (HaywardBridgeHandler) bridge.getHandler();
if (bridgehandler != null) {
if (bridgehandler.account.units.equals("Standard")) {
return new QuantityType<>(Integer.parseInt(value), ImperialUnits.FAHRENHEIT);
} else {
return new QuantityType<>(Integer.parseInt(value), SIUnits.CELSIUS);
}
}
}
// default to imperial if no bridge
return new QuantityType<>(Integer.parseInt(value), ImperialUnits.FAHRENHEIT);
default:
return StringType.valueOf(value);
}
}
public String cmdToString(Command command) {
if (command == OnOffType.OFF) {
return "0";
} else if (command == OnOffType.ON) {
return "1";
} else if (command instanceof DecimalType) {
return ((DecimalType) command).toString();
} else if (command instanceof QuantityType) {
return ((QuantityType<?>) command).format("%1.0f");
} else {
return command.toString();
}
}
public void updateData(String channelID, String data) {
Channel chan = getThing().getChannel(channelID);
if (chan != null) {
String acceptedItemType = chan.getAcceptedItemType();
if (acceptedItemType != null) {
State state = toState(acceptedItemType, channelID, data);
updateState(chan.getUID(), state);
}
}
}
}

View File

@@ -0,0 +1,27 @@
/**
* Copyright (c) 2010-2021 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.haywardomnilogic.internal;
import org.eclipse.jdt.annotation.NonNullByDefault;
/**
* The {@link HaywardThingProperties} class contains fields mapping thing configuration parameters.
*
* @author Matt Myers - Initial contribution
*/
@NonNullByDefault
public class HaywardThingProperties {
public String systemID = "";
public String poolID = "";
}

View File

@@ -0,0 +1,35 @@
/**
* Copyright (c) 2010-2021 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.haywardomnilogic.internal;
import org.eclipse.jdt.annotation.NonNullByDefault;
/**
* The type to request.
*
* @author Matt Myers - Initial contribution
*/
@NonNullByDefault
public enum HaywardTypeToRequest {
BACKYARD,
BOW,
CHLORINATOR,
COLORLOGIC,
CSAD,
FILTER,
HEATER,
PUMP,
RELAY,
SENSOR,
VIRTUALHEATER
}

View File

@@ -0,0 +1,30 @@
/**
* Copyright (c) 2010-2021 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.haywardomnilogic.internal.config;
import org.eclipse.jdt.annotation.NonNullByDefault;
/**
* The {@link HaywardConfig} class contains fields mapping thing configuration parameters.
*
* @author Matt Myers - Initial contribution
*/
@NonNullByDefault
public class HaywardConfig {
public String endpointUrl = "";
public String username = "";
public String password = "";
public int alarmPollTime = 60;
public int telemetryPollTime = 10;
}

View File

@@ -0,0 +1,230 @@
/**
* Copyright (c) 2010-2021 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.haywardomnilogic.internal.discovery;
import static org.openhab.binding.haywardomnilogic.internal.HaywardBindingConstants.THING_TYPES_UIDS;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.BiConsumer;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.binding.haywardomnilogic.internal.HaywardBindingConstants;
import org.openhab.binding.haywardomnilogic.internal.HaywardException;
import org.openhab.binding.haywardomnilogic.internal.HaywardTypeToRequest;
import org.openhab.binding.haywardomnilogic.internal.handler.HaywardBridgeHandler;
import org.openhab.core.config.discovery.AbstractDiscoveryService;
import org.openhab.core.config.discovery.DiscoveryResult;
import org.openhab.core.config.discovery.DiscoveryResultBuilder;
import org.openhab.core.config.discovery.DiscoveryService;
import org.openhab.core.thing.ThingTypeUID;
import org.openhab.core.thing.ThingUID;
import org.openhab.core.thing.binding.ThingHandler;
import org.openhab.core.thing.binding.ThingHandlerService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Sets up the discovery results and details
*
* @author Matt Myers - Initial contribution
*/
@NonNullByDefault
public class HaywardDiscoveryService extends AbstractDiscoveryService implements DiscoveryService, ThingHandlerService {
private final Logger logger = LoggerFactory.getLogger(HaywardDiscoveryService.class);
private @Nullable HaywardBridgeHandler discoveryBridgehandler;
public HaywardDiscoveryService() {
super(THING_TYPES_UIDS, 0, false);
}
@Override
public void activate() {
super.activate(null);
}
@Override
public void deactivate() {
super.deactivate();
}
@Override
protected void startScan() {
HaywardBridgeHandler bridgehandler = discoveryBridgehandler;
try {
if (bridgehandler != null) {
String xmlResults = bridgehandler.getMspConfig();
mspConfigDiscovery(xmlResults);
}
} catch (HaywardException e) {
logger.warn("Exception during discovery scan: {}", e.getMessage());
} catch (InterruptedException e) {
return;
}
}
public synchronized void mspConfigDiscovery(String xmlResponse) {
List<String> systemIDs = new ArrayList<>();
List<String> names = new ArrayList<>();
Map<String, Object> backyardProperties = new HashMap<>();
Map<String, Object> bowProperties = new HashMap<>();
HaywardBridgeHandler bridgehandler = discoveryBridgehandler;
if (bridgehandler == null) {
return;
}
// Find Backyard
names = bridgehandler.evaluateXPath("//Backyard/Name/text()", xmlResponse);
for (int i = 0; i < names.size(); i++) {
backyardProperties.put(HaywardBindingConstants.PROPERTY_TYPE, HaywardTypeToRequest.BACKYARD);
backyardProperties.put(HaywardBindingConstants.PROPERTY_SYSTEM_ID, bridgehandler.account.mspSystemID);
onDeviceDiscovered(HaywardBindingConstants.THING_TYPE_BACKYARD, names.get(i), backyardProperties);
}
// Find Bodies of Water
systemIDs = bridgehandler.evaluateXPath("//Body-of-water/System-Id/text()", xmlResponse);
names = bridgehandler.evaluateXPath("//Body-of-water/Name/text()", xmlResponse);
for (int i = 0; i < systemIDs.size(); i++) {
bowProperties.put(HaywardBindingConstants.PROPERTY_TYPE, HaywardTypeToRequest.BOW);
bowProperties.put(HaywardBindingConstants.PROPERTY_SYSTEM_ID, systemIDs.get(i));
onDeviceDiscovered(HaywardBindingConstants.THING_TYPE_BOW, names.get(i), bowProperties);
}
// Find Chlorinators
discoverDevices(bridgehandler, xmlResponse, "Chlorinator", HaywardTypeToRequest.CHLORINATOR,
HaywardBindingConstants.THING_TYPE_CHLORINATOR, null);
// Find ColorLogic Lights
discoverDevices(bridgehandler, xmlResponse, "ColorLogic-Light", HaywardTypeToRequest.COLORLOGIC,
HaywardBindingConstants.THING_TYPE_COLORLOGIC, null);
// Find Filters
final List<String> filterProperty1 = bridgehandler.evaluateXPath("//Filter/Min-Pump-Speed/text()", xmlResponse);
final List<String> filterProperty2 = bridgehandler.evaluateXPath("//Filter/Max-Pump-Speed/text()", xmlResponse);
final List<String> filterProperty3 = bridgehandler.evaluateXPath("//Filter/Min-Pump-RPM/text()", xmlResponse);
final List<String> filterProperty4 = bridgehandler.evaluateXPath("//Filter/Max-Pump-RPM/text()", xmlResponse);
discoverDevices(bridgehandler, xmlResponse, "Filter", HaywardTypeToRequest.FILTER,
HaywardBindingConstants.THING_TYPE_FILTER, (props, i) -> {
props.put(HaywardBindingConstants.PROPERTY_FILTER_MINPUMPSPEED, filterProperty1.get(i));
props.put(HaywardBindingConstants.PROPERTY_FILTER_MAXPUMPSPEED, filterProperty2.get(i));
props.put(HaywardBindingConstants.PROPERTY_FILTER_MINPUMPRPM, filterProperty3.get(i));
props.put(HaywardBindingConstants.PROPERTY_FILTER_MAXPUMPRPM, filterProperty4.get(i));
});
// Find Heaters
discoverDevices(bridgehandler, xmlResponse, "Heater-Equipment", HaywardTypeToRequest.HEATER,
HaywardBindingConstants.THING_TYPE_HEATER, null);
// Find Pumps
final List<String> pumpProperty1 = bridgehandler.evaluateXPath("//Pump/Min-Pump-Speed/text()", xmlResponse);
final List<String> pumpProperty2 = bridgehandler.evaluateXPath("//Pump/Max-Pump-Speed/text()", xmlResponse);
final List<String> pumpProperty3 = bridgehandler.evaluateXPath("//Pump/Min-Pump-RPM/text()", xmlResponse);
final List<String> pumpProperty4 = bridgehandler.evaluateXPath("//Pump/Max-Pump-RPM/text()", xmlResponse);
discoverDevices(bridgehandler, xmlResponse, "Pump", HaywardTypeToRequest.PUMP,
HaywardBindingConstants.THING_TYPE_FILTER, (props, i) -> {
props.put(HaywardBindingConstants.PROPERTY_FILTER_MINPUMPSPEED, pumpProperty1.get(i));
props.put(HaywardBindingConstants.PROPERTY_FILTER_MAXPUMPSPEED, pumpProperty2.get(i));
props.put(HaywardBindingConstants.PROPERTY_FILTER_MINPUMPRPM, pumpProperty3.get(i));
props.put(HaywardBindingConstants.PROPERTY_FILTER_MAXPUMPRPM, pumpProperty4.get(i));
});
// Find Relays
discoverDevices(bridgehandler, xmlResponse, "Relay", HaywardTypeToRequest.RELAY,
HaywardBindingConstants.THING_TYPE_RELAY, null);
// Find Virtual Heaters
discoverDevices(bridgehandler, xmlResponse, "Heater", HaywardTypeToRequest.VIRTUALHEATER,
HaywardBindingConstants.THING_TYPE_VIRTUALHEATER, null);
// Find Sensors
discoverDevices(bridgehandler, xmlResponse, "Sensor", HaywardTypeToRequest.SENSOR,
HaywardBindingConstants.THING_TYPE_SENSOR, null);
}
private void discoverDevices(HaywardBridgeHandler bridgehandler, String xmlResponse, String xmlSearchTerm,
HaywardTypeToRequest type, ThingTypeUID thingType,
@Nullable BiConsumer<Map<String, Object>, Integer> additionalPropertyConsumer) {
List<String> systemIDs = bridgehandler.evaluateXPath("//" + xmlSearchTerm + "/System-Id/text()", xmlResponse);
List<String> names;
// Set Virtual Heater Name
if (thingType == HaywardBindingConstants.THING_TYPE_VIRTUALHEATER) {
names = new ArrayList<>(systemIDs);
Collections.fill(names, "Heater");
} else {
names = bridgehandler.evaluateXPath("//" + xmlSearchTerm + "/Name/text()", xmlResponse);
}
for (int i = 0; i < systemIDs.size(); i++) {
// get Body of Water for each item
List<String> bowID = bridgehandler.evaluateXPath(
"//*[System-Id=" + systemIDs.get(i) + "]/ancestor::Body-of-water/System-Id/text()", xmlResponse);
List<String> bowName = bridgehandler.evaluateXPath(
"//*[System-Id=" + systemIDs.get(i) + "]/ancestor::Body-of-water/Name/text()", xmlResponse);
// skip system sensors with no BOW
if (bowID.isEmpty()) {
continue;
}
Map<String, Object> properties = new HashMap<>();
properties.put(HaywardBindingConstants.PROPERTY_TYPE, type);
properties.put(HaywardBindingConstants.PROPERTY_SYSTEM_ID, systemIDs.get(i));
properties.put(HaywardBindingConstants.PROPERTY_BOWID, bowID.get(0));
properties.put(HaywardBindingConstants.PROPERTY_BOWNAME, bowName.get(0));
if (additionalPropertyConsumer != null) {
additionalPropertyConsumer.accept(properties, i);
}
onDeviceDiscovered(thingType, names.get(i), properties);
}
}
public void onDeviceDiscovered(ThingTypeUID thingType, String label, Map<String, Object> properties) {
HaywardBridgeHandler bridgehandler = discoveryBridgehandler;
String systemID = (String) properties.get(HaywardBindingConstants.PROPERTY_SYSTEM_ID);
if (bridgehandler != null) {
if (systemID != null) {
ThingUID thingUID = new ThingUID(thingType, bridgehandler.getThing().getUID(), systemID);
DiscoveryResult result = DiscoveryResultBuilder.create(thingUID)
.withBridge(bridgehandler.getThing().getUID())
.withRepresentationProperty(HaywardBindingConstants.PROPERTY_SYSTEM_ID)
.withLabel("Hayward " + label).withProperties(properties).build();
thingDiscovered(result);
}
}
}
@Override
public void setThingHandler(@Nullable ThingHandler handler) {
if (handler instanceof HaywardBridgeHandler) {
this.discoveryBridgehandler = (HaywardBridgeHandler) handler;
}
}
@Override
public @Nullable ThingHandler getThingHandler() {
return discoveryBridgehandler;
}
}

View File

@@ -0,0 +1,135 @@
/**
* Copyright (c) 2010-2021 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.haywardomnilogic.internal.handler;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.binding.haywardomnilogic.internal.HaywardBindingConstants;
import org.openhab.binding.haywardomnilogic.internal.HaywardException;
import org.openhab.binding.haywardomnilogic.internal.HaywardThingHandler;
import org.openhab.core.thing.Bridge;
import org.openhab.core.thing.Thing;
import org.openhab.core.thing.ThingStatus;
import org.openhab.core.thing.ThingStatusDetail;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* The Backyard Handler
*
* @author Matt Myers - Initial contribution
*/
@NonNullByDefault
public class HaywardBackyardHandler extends HaywardThingHandler {
private final Logger logger = LoggerFactory.getLogger(HaywardBackyardHandler.class);
public HaywardBackyardHandler(Thing thing) {
super(thing);
}
@Override
public void getTelemetry(String xmlResponse) throws HaywardException {
List<String> data = new ArrayList<>();
List<String> systemIDs = new ArrayList<>();
Bridge bridge = getBridge();
if (bridge != null) {
HaywardBridgeHandler bridgehandler = (HaywardBridgeHandler) bridge.getHandler();
if (bridgehandler != null) {
systemIDs = bridgehandler.evaluateXPath("//Backyard/@systemId", xmlResponse);
String thingSystemID = getThing().getUID().getId();
for (int i = 0; i < systemIDs.size(); i++) {
if (systemIDs.get(i).equals(thingSystemID)) {
// Air temp
data = bridgehandler.evaluateXPath("//Backyard/@airTemp", xmlResponse);
updateData(HaywardBindingConstants.CHANNEL_BACKYARD_AIRTEMP, data.get(0));
// Status
data = bridgehandler.evaluateXPath("//Backyard/@status", xmlResponse);
updateData(HaywardBindingConstants.CHANNEL_BACKYARD_STATUS, data.get(0));
// State
data = bridgehandler.evaluateXPath("//Backyard/@state", xmlResponse);
updateData(HaywardBindingConstants.CHANNEL_BACKYARD_STATE, data.get(0));
}
}
this.updateStatus(ThingStatus.ONLINE);
} else {
this.updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.BRIDGE_UNINITIALIZED);
}
}
}
public boolean getAlarmList(String systemID) throws HaywardException {
List<String> bowID = new ArrayList<>();
List<String> parameter1 = new ArrayList<>();
List<String> message = new ArrayList<>();
String alarmStr;
Bridge bridge = getBridge();
if (bridge != null) {
HaywardBridgeHandler bridgehandler = (HaywardBridgeHandler) bridge.getHandler();
if (bridgehandler != null) {
// *****Request Alarm List from Hayward server
String urlParameters = "<?xml version=\"1.0\" encoding=\"utf-8\"?><Request><Name>GetAlarmList</Name><Parameters>"
+ "<Parameter name=\"Token\" dataType=\"String\">" + bridgehandler.account.token
+ "</Parameter>" + "<Parameter name=\"MspSystemID\" dataType=\"int\">"
+ bridgehandler.account.mspSystemID + "</Parameter>"
+ "<Parameter name=\"CultureInfoName\" dataType=\"String\">en-us</Parameter></Parameters></Request>";
try {
String xmlResponse = bridgehandler.httpXmlResponse(urlParameters);
if (xmlResponse.isEmpty()) {
logger.debug("Hayward getAlarmList XML response was empty");
return false;
}
String status = bridgehandler
.evaluateXPath("/Response/Parameters//Parameter[@name='Status']/text()", xmlResponse)
.get(0);
if (!(status.equals("0"))) {
logger.trace("Hayward getAlarm XML response: {}", xmlResponse);
return false;
}
bowID = bridgehandler.evaluateXPath("//Property[@name='BowID']/text()", xmlResponse);
parameter1 = bridgehandler.evaluateXPath("//Property[@name='Parameter1']/text()", xmlResponse);
message = bridgehandler.evaluateXPath("//Property[@name='Message']/text()", xmlResponse);
for (int i = 0; i < 5; i++) {
if (i < bowID.size()) {
alarmStr = parameter1.get(i) + ": " + message.get(i);
} else {
alarmStr = "";
}
updateData("backyardAlarm" + String.format("%01d", i + 1), alarmStr);
}
this.updateStatus(ThingStatus.ONLINE);
return true;
} catch (InterruptedException e) {
return false;
}
} else {
this.updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.BRIDGE_UNINITIALIZED);
return false;
}
} else {
this.updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.BRIDGE_UNINITIALIZED);
return false;
}
}
}

View File

@@ -0,0 +1,68 @@
/**
* Copyright (c) 2010-2021 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.haywardomnilogic.internal.handler;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.binding.haywardomnilogic.internal.HaywardBindingConstants;
import org.openhab.binding.haywardomnilogic.internal.HaywardException;
import org.openhab.binding.haywardomnilogic.internal.HaywardThingHandler;
import org.openhab.core.thing.Bridge;
import org.openhab.core.thing.Thing;
import org.openhab.core.thing.ThingStatus;
import org.openhab.core.thing.ThingStatusDetail;
/**
* The Body of Water Handler
*
* @author Matt Myers - Initial contribution
*/
@NonNullByDefault
public class HaywardBowHandler extends HaywardThingHandler {
public HaywardBowHandler(Thing thing) {
super(thing);
}
@Override
public void getTelemetry(String xmlResponse) throws HaywardException {
List<String> systemIDs = new ArrayList<>();
List<String> data = new ArrayList<>();
Bridge bridge = getBridge();
if (bridge != null) {
HaywardBridgeHandler bridgehandler = (HaywardBridgeHandler) bridge.getHandler();
if (bridgehandler != null) {
systemIDs = bridgehandler.evaluateXPath("//BodyOfWater/@systemId", xmlResponse);
String thingSystemID = getThing().getUID().getId();
for (int i = 0; i < systemIDs.size(); i++) {
if (systemIDs.get(i).equals(thingSystemID)) {
// Flow
data = bridgehandler.evaluateXPath("//BodyOfWater/@flow", xmlResponse);
updateData(HaywardBindingConstants.CHANNEL_BOW_FLOW, data.get(i));
// Water Temp
data = bridgehandler.evaluateXPath("//BodyOfWater/@waterTemp", xmlResponse);
updateData(HaywardBindingConstants.CHANNEL_BOW_WATERTEMP, data.get(i));
}
}
this.updateStatus(ThingStatus.ONLINE);
} else {
this.updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.BRIDGE_UNINITIALIZED);
}
}
}
}

View File

@@ -0,0 +1,475 @@
/**
* Copyright (c) 2010-2021 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.haywardomnilogic.internal.handler;
import java.io.StringReader;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.eclipse.jetty.client.HttpClient;
import org.eclipse.jetty.client.api.ContentResponse;
import org.eclipse.jetty.client.api.Request;
import org.eclipse.jetty.client.util.StringContentProvider;
import org.eclipse.jetty.http.HttpHeader;
import org.eclipse.jetty.http.HttpMethod;
import org.eclipse.jetty.http.HttpVersion;
import org.openhab.binding.haywardomnilogic.internal.HaywardAccount;
import org.openhab.binding.haywardomnilogic.internal.HaywardBindingConstants;
import org.openhab.binding.haywardomnilogic.internal.HaywardException;
import org.openhab.binding.haywardomnilogic.internal.HaywardThingHandler;
import org.openhab.binding.haywardomnilogic.internal.HaywardTypeToRequest;
import org.openhab.binding.haywardomnilogic.internal.config.HaywardConfig;
import org.openhab.binding.haywardomnilogic.internal.discovery.HaywardDiscoveryService;
import org.openhab.core.library.types.OnOffType;
import org.openhab.core.thing.Bridge;
import org.openhab.core.thing.ChannelUID;
import org.openhab.core.thing.Thing;
import org.openhab.core.thing.ThingStatus;
import org.openhab.core.thing.ThingStatusDetail;
import org.openhab.core.thing.binding.BaseBridgeHandler;
import org.openhab.core.thing.binding.ThingHandlerService;
import org.openhab.core.types.Command;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;
/**
* The {@link HaywardBridgeHandler} is responsible for handling commands, which are
* sent to one of the channels.
*
* @author Matt Myers - Initial contribution
*/
@NonNullByDefault
public class HaywardBridgeHandler extends BaseBridgeHandler {
private final Logger logger = LoggerFactory.getLogger(HaywardBridgeHandler.class);
private final HttpClient httpClient;
private @Nullable ScheduledFuture<?> initializeFuture;
private @Nullable ScheduledFuture<?> pollTelemetryFuture;
private @Nullable ScheduledFuture<?> pollAlarmsFuture;
private int commFailureCount;
public HaywardConfig config = getConfig().as(HaywardConfig.class);
public HaywardAccount account = getConfig().as(HaywardAccount.class);
@Override
public Collection<Class<? extends ThingHandlerService>> getServices() {
return Collections.singleton(HaywardDiscoveryService.class);
}
public HaywardBridgeHandler(Bridge bridge, HttpClient httpClient) {
super(bridge);
this.httpClient = httpClient;
}
@Override
public void handleCommand(ChannelUID channelUID, Command command) {
}
@Override
public void dispose() {
clearPolling(initializeFuture);
clearPolling(pollTelemetryFuture);
clearPolling(pollAlarmsFuture);
logger.trace("Hayward polling cancelled");
super.dispose();
}
@Override
public void initialize() {
updateStatus(ThingStatus.UNKNOWN);
initializeFuture = scheduler.schedule(this::scheduledInitialize, 1, TimeUnit.SECONDS);
return;
}
public void scheduledInitialize() {
config = getConfigAs(HaywardConfig.class);
try {
clearPolling(pollTelemetryFuture);
clearPolling(pollAlarmsFuture);
if (!(login())) {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
"Unable to Login to Hayward's server");
clearPolling(pollTelemetryFuture);
clearPolling(pollAlarmsFuture);
commFailureCount = 50;
initPolling(60);
return;
}
if (!(getSiteList())) {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
"Unable to getMSP from Hayward's server");
clearPolling(pollTelemetryFuture);
clearPolling(pollAlarmsFuture);
commFailureCount = 50;
initPolling(60);
return;
}
if (!(mspConfigUnits())) {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
"Unable to getMSPConfigUnits from Hayward's server");
clearPolling(pollTelemetryFuture);
clearPolling(pollAlarmsFuture);
commFailureCount = 50;
initPolling(60);
return;
}
updateStatus(ThingStatus.ONLINE);
logger.debug("Succesfully opened connection to Hayward's server: {} Username:{}", config.endpointUrl,
config.username);
initPolling(0);
logger.trace("Hayward Telemetry polling scheduled");
if (config.alarmPollTime > 0) {
initAlarmPolling(1);
}
} catch (HaywardException e) {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.HANDLER_INITIALIZING_ERROR,
"scheduledInitialize exception: " + e.getMessage());
clearPolling(pollTelemetryFuture);
clearPolling(pollAlarmsFuture);
commFailureCount = 50;
initPolling(60);
return;
} catch (InterruptedException e) {
return;
}
}
public synchronized boolean login() throws HaywardException, InterruptedException {
String xmlResponse;
String status;
// *****Login to Hayward server
String urlParameters = "<?xml version=\"1.0\" encoding=\"utf-8\"?><Request>" + "<Name>Login</Name><Parameters>"
+ "<Parameter name=\"UserName\" dataType=\"String\">" + config.username + "</Parameter>"
+ "<Parameter name=\"Password\" dataType=\"String\">" + config.password + "</Parameter>"
+ "</Parameters></Request>";
xmlResponse = httpXmlResponse(urlParameters);
if (xmlResponse.isEmpty()) {
return false;
}
status = evaluateXPath("/Response/Parameters//Parameter[@name='Status']/text()", xmlResponse).get(0);
if (!(status.equals("0"))) {
logger.debug("Hayward Connection thing: Login XML response: {}", xmlResponse);
return false;
}
account.token = evaluateXPath("/Response/Parameters//Parameter[@name='Token']/text()", xmlResponse).get(0);
account.userID = evaluateXPath("/Response/Parameters//Parameter[@name='UserID']/text()", xmlResponse).get(0);
return true;
}
public synchronized boolean getApiDef() throws HaywardException, InterruptedException {
String xmlResponse;
// *****getConfig from Hayward server
String urlParameters = "<?xml version=\"1.0\" encoding=\"utf-8\"?><Request><Name>GetAPIDef</Name><Parameters>"
+ "<Parameter name=\"Token\" dataType=\"String\">" + account.token + "</Parameter>"
+ "<Parameter name=\"MspSystemID\" dataType=\"int\">" + account.mspSystemID + "</Parameter>;"
+ "<Parameter name=\"Version\" dataType=\"string\">0.4</Parameter >\r\n"
+ "<Parameter name=\"Language\" dataType=\"string\">en</Parameter >\r\n" + "</Parameters></Request>";
xmlResponse = httpXmlResponse(urlParameters);
if (xmlResponse.isEmpty()) {
logger.debug("Hayward Connection thing: Login XML response was null");
return false;
}
return true;
}
public synchronized boolean getSiteList() throws HaywardException, InterruptedException {
String xmlResponse;
String status;
// *****Get MSP
String urlParameters = "<?xml version=\"1.0\" encoding=\"utf-8\"?><Request><Name>GetSiteList</Name><Parameters>"
+ "<Parameter name=\"Token\" dataType=\"String\">" + account.token
+ "</Parameter><Parameter name=\"UserID\" dataType=\"String\">" + account.userID
+ "</Parameter></Parameters></Request>";
xmlResponse = httpXmlResponse(urlParameters);
if (xmlResponse.isEmpty()) {
logger.debug("Hayward Connection thing: getSiteList XML response was null");
return false;
}
status = evaluateXPath("/Response/Parameters//Parameter[@name='Status']/text()", xmlResponse).get(0);
if (!(status.equals("0"))) {
logger.debug("Hayward Connection thing: getSiteList XML response: {}", xmlResponse);
return false;
}
account.mspSystemID = evaluateXPath("/Response/Parameters/Parameter/Item//Property[@name='MspSystemID']/text()",
xmlResponse).get(0);
account.backyardName = evaluateXPath(
"/Response/Parameters/Parameter/Item//Property[@name='BackyardName']/text()", xmlResponse).get(0);
account.address = evaluateXPath("/Response/Parameters/Parameter/Item//Property[@name='Address']/text()",
xmlResponse).get(0);
return true;
}
public synchronized String getMspConfig() throws HaywardException, InterruptedException {
// *****getMspConfig from Hayward server
String urlParameters = "<?xml version=\"1.0\" encoding=\"utf-8\"?><Request><Name>GetMspConfigFile</Name><Parameters>"
+ "<Parameter name=\"Token\" dataType=\"String\">" + account.token + "</Parameter>"
+ "<Parameter name=\"MspSystemID\" dataType=\"int\">" + account.mspSystemID
+ "</Parameter><Parameter name=\"Version\" dataType=\"string\">0</Parameter>\r\n"
+ "</Parameters></Request>";
String xmlResponse = httpXmlResponse(urlParameters);
// Debug: Inject xml file for testing
// String path =
// "C:/Users/Controls/openhab-2-5-x/git/openhab-addons/bundles/org.openhab.binding.haywardomnilogic/getConfig.xml";
// xmlResponse = new String(Files.readAllBytes(Paths.get(path)));
if (xmlResponse.isEmpty()) {
logger.debug("Hayward Connection thing: requestConfig XML response was null");
return "Fail";
}
if (evaluateXPath("//Backyard/Name/text()", xmlResponse).isEmpty()) {
logger.debug("Hayward Connection thing: requestConfiguration XML response: {}", xmlResponse);
return "Fail";
}
return xmlResponse;
}
public synchronized boolean mspConfigUnits() throws HaywardException, InterruptedException {
List<String> property1 = new ArrayList<>();
List<String> property2 = new ArrayList<>();
String xmlResponse = getMspConfig();
// Get Units (Standard, Metric)
property1 = evaluateXPath("//System/Units/text()", xmlResponse);
account.units = property1.get(0);
// Get Variable Speed Pump Units (percent, RPM)
property2 = evaluateXPath("//System/Msp-Vsp-Speed-Format/text()", xmlResponse);
account.vspSpeedFormat = property2.get(0);
return true;
}
public synchronized boolean getTelemetryData() throws HaywardException, InterruptedException {
// *****getTelemetry from Hayward server
String urlParameters = "<?xml version=\"1.0\" encoding=\"utf-8\"?><Request><Name>GetTelemetryData</Name><Parameters>"
+ "<Parameter name=\"Token\" dataType=\"String\">" + account.token + "</Parameter>"
+ "<Parameter name=\"MspSystemID\" dataType=\"int\">" + account.mspSystemID
+ "</Parameter></Parameters></Request>";
String xmlResponse = httpXmlResponse(urlParameters);
if (xmlResponse.isEmpty()) {
logger.debug("Hayward Connection thing: getTelemetry XML response was null");
return false;
}
if (!evaluateXPath("/Response/Parameters//Parameter[@name='StatusMessage']/text()", xmlResponse).isEmpty()) {
logger.debug("Hayward Connection thing: getTelemetry XML response: {}", xmlResponse);
return false;
}
for (Thing thing : getThing().getThings()) {
if (thing.getHandler() instanceof HaywardThingHandler) {
HaywardThingHandler handler = (HaywardThingHandler) thing.getHandler();
if (handler != null) {
handler.getTelemetry(xmlResponse);
}
}
}
return true;
}
public synchronized boolean getAlarmList() throws HaywardException {
for (Thing thing : getThing().getThings()) {
Map<String, String> properties = thing.getProperties();
if ("BACKYARD".equals(properties.get(HaywardBindingConstants.PROPERTY_TYPE))) {
HaywardBackyardHandler handler = (HaywardBackyardHandler) thing.getHandler();
if (handler != null) {
String systemID = properties.get(HaywardBindingConstants.PROPERTY_SYSTEM_ID);
if (systemID != null) {
return handler.getAlarmList(systemID);
}
}
}
}
return false;
}
private synchronized void initPolling(int initalDelay) {
pollTelemetryFuture = scheduler.scheduleWithFixedDelay(() -> {
try {
if (commFailureCount >= 5) {
commFailureCount = 0;
clearPolling(pollTelemetryFuture);
clearPolling(pollAlarmsFuture);
initialize();
return;
}
if (!(getTelemetryData())) {
commFailureCount++;
return;
}
} catch (HaywardException e) {
logger.debug("Hayward Connection thing: Exception during poll: {}", e.getMessage());
} catch (InterruptedException e) {
return;
}
}, initalDelay, config.telemetryPollTime, TimeUnit.SECONDS);
return;
}
private synchronized void initAlarmPolling(int initalDelay) {
pollAlarmsFuture = scheduler.scheduleWithFixedDelay(() -> {
try {
getAlarmList();
} catch (HaywardException e) {
logger.debug("Hayward Connection thing: Exception during poll: {}", e.getMessage());
}
}, initalDelay, config.alarmPollTime, TimeUnit.SECONDS);
}
private void clearPolling(@Nullable ScheduledFuture<?> pollJob) {
if (pollJob != null) {
pollJob.cancel(false);
}
}
@Nullable
Thing getThingForType(HaywardTypeToRequest type, int num) {
for (Thing thing : getThing().getThings()) {
Map<String, String> properties = thing.getProperties();
if (Integer.toString(num).equals(properties.get(HaywardBindingConstants.PROPERTY_SYSTEM_ID))) {
if (type.toString().equals(properties.get(HaywardBindingConstants.PROPERTY_TYPE))) {
return thing;
}
}
}
return null;
}
public List<String> evaluateXPath(String xpathExp, String xmlResponse) {
List<String> values = new ArrayList<>();
try {
InputSource inputXML = new InputSource(new StringReader(xmlResponse));
XPath xPath = XPathFactory.newInstance().newXPath();
NodeList nodes = (NodeList) xPath.evaluate(xpathExp, inputXML, XPathConstants.NODESET);
for (int i = 0; i < nodes.getLength(); i++) {
values.add(nodes.item(i).getNodeValue());
}
} catch (XPathExpressionException e) {
logger.warn("XPathExpression exception: {}", e.getMessage());
}
return values;
}
private Request sendRequestBuilder(String url, HttpMethod method) {
return this.httpClient.newRequest(url).agent("NextGenForIPhone/16565 CFNetwork/887 Darwin/17.0.0")
.method(method).header(HttpHeader.ACCEPT_LANGUAGE, "en-us").header(HttpHeader.ACCEPT, "*/*")
.header(HttpHeader.ACCEPT_ENCODING, "gzip, deflate").version(HttpVersion.HTTP_1_1)
.header(HttpHeader.CONNECTION, "keep-alive").header(HttpHeader.HOST, "www.haywardomnilogic.com:80")
.timeout(10, TimeUnit.SECONDS);
}
public synchronized String httpXmlResponse(String urlParameters) throws HaywardException, InterruptedException {
String urlParameterslength = Integer.toString(urlParameters.length());
String statusMessage;
try {
ContentResponse httpResponse = sendRequestBuilder(config.endpointUrl, HttpMethod.POST)
.content(new StringContentProvider(urlParameters), "text/xml; charset=utf-8")
.header(HttpHeader.CONTENT_LENGTH, urlParameterslength).send();
int status = httpResponse.getStatus();
String xmlResponse = httpResponse.getContentAsString();
List<String> statusMessages = evaluateXPath("/Response/Parameters//Parameter[@name='StatusMessage']/text()",
xmlResponse);
if (!(statusMessages.isEmpty())) {
statusMessage = statusMessages.get(0);
} else {
statusMessage = httpResponse.getReason();
}
if (status == 200) {
if (logger.isTraceEnabled()) {
logger.trace("Hayward Connection thing: {} Hayward http command: {}", getCallingMethod(),
urlParameters);
logger.trace("Hayward Connection thing: {} Hayward http response: {} {}", getCallingMethod(),
statusMessage, xmlResponse);
}
return xmlResponse;
} else {
if (logger.isDebugEnabled()) {
logger.debug("Hayward Connection thing: {} Hayward http command: {}", getCallingMethod(),
urlParameters);
logger.debug("Hayward Connection thing: {} Hayward http response: {}", getCallingMethod(), status);
}
return "";
}
} catch (ExecutionException e) {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
"Unable to resolve host. Check Hayward hostname and your internet connection. " + e);
return "";
} catch (TimeoutException e) {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
"Connection Timeout. Check Hayward hostname and your internet connection. " + e);
return "";
}
}
private String getCallingMethod() {
StackTraceElement[] stacktrace = Thread.currentThread().getStackTrace();
StackTraceElement e = stacktrace[3];
return e.getMethodName();
}
public int convertCommand(Command command) {
if (command == OnOffType.ON) {
return 1;
} else {
return 0;
}
}
}

View File

@@ -0,0 +1,187 @@
/**
* Copyright (c) 2010-2021 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.haywardomnilogic.internal.handler;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.binding.haywardomnilogic.internal.HaywardBindingConstants;
import org.openhab.binding.haywardomnilogic.internal.HaywardException;
import org.openhab.binding.haywardomnilogic.internal.HaywardThingHandler;
import org.openhab.core.thing.Bridge;
import org.openhab.core.thing.ChannelUID;
import org.openhab.core.thing.Thing;
import org.openhab.core.thing.ThingStatus;
import org.openhab.core.thing.ThingStatusDetail;
import org.openhab.core.types.Command;
import org.openhab.core.types.RefreshType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* The Chlorinator Handler
*
* @author Matt Myers - Initial contribution
*/
@NonNullByDefault
public class HaywardChlorinatorHandler extends HaywardThingHandler {
private final Logger logger = LoggerFactory.getLogger(HaywardChlorinatorHandler.class);
public String chlorTimedPercent = "";
public String chlorState = "";
public HaywardChlorinatorHandler(Thing thing) {
super(thing);
}
@Override
public void getTelemetry(String xmlResponse) throws HaywardException {
List<String> systemIDs = new ArrayList<>();
List<String> data = new ArrayList<>();
Bridge bridge = getBridge();
if (bridge != null) {
HaywardBridgeHandler bridgehandler = (HaywardBridgeHandler) bridge.getHandler();
if (bridgehandler != null) {
systemIDs = bridgehandler.evaluateXPath("//Chlorinator/@systemId", xmlResponse);
String thingSystemID = getThing().getUID().getId();
for (int i = 0; i < systemIDs.size(); i++) {
if (systemIDs.get(i).equals(thingSystemID)) {
// Operating Mode
data = bridgehandler.evaluateXPath("//Chlorinator/@operatingMode", xmlResponse);
updateData(HaywardBindingConstants.CHANNEL_CHLORINATOR_OPERATINGMODE, data.get(i));
// Timed Percent
data = bridgehandler.evaluateXPath("//Chlorinator/@Timed-Percent", xmlResponse);
updateData(HaywardBindingConstants.CHANNEL_CHLORINATOR_TIMEDPERCENT, data.get(i));
this.chlorTimedPercent = data.get(0);
// scMode
data = bridgehandler.evaluateXPath("//Chlorinator/@scMode", xmlResponse);
updateData(HaywardBindingConstants.CHANNEL_CHLORINATOR_SCMODE, data.get(i));
// Error
data = bridgehandler.evaluateXPath("//Chlorinator/@chlrError", xmlResponse);
updateData(HaywardBindingConstants.CHANNEL_CHLORINATOR_ERROR, data.get(i));
// Alert
data = bridgehandler.evaluateXPath("//Chlorinator/@chlrAlert", xmlResponse);
updateData(HaywardBindingConstants.CHANNEL_CHLORINATOR_ALERT, data.get(i));
// Average Salt Level
data = bridgehandler.evaluateXPath("//Chlorinator/@avgSaltLevel", xmlResponse);
updateData(HaywardBindingConstants.CHANNEL_CHLORINATOR_AVGSALTLEVEL, data.get(i));
// Instant Salt Level
data = bridgehandler.evaluateXPath("//Chlorinator/@instantSaltLevel", xmlResponse);
updateData(HaywardBindingConstants.CHANNEL_CHLORINATOR_INSTANTSALTLEVEL, data.get(i));
// Status
data = bridgehandler.evaluateXPath("//Chlorinator/@status", xmlResponse);
updateData(HaywardBindingConstants.CHANNEL_CHLORINATOR_STATUS, data.get(i));
if (data.get(i).equals("0")) {
updateData(HaywardBindingConstants.CHANNEL_CHLORINATOR_ENABLE, "0");
// chlorState is used to set the chlorinator cfgState in the timedPercent command
this.chlorState = "2";
} else {
updateData(HaywardBindingConstants.CHANNEL_CHLORINATOR_ENABLE, "1");
// chlorState is used to set the chlorinator cfgState in the timedPercent command
this.chlorState = "3";
}
}
}
this.updateStatus(ThingStatus.ONLINE);
} else {
this.updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.BRIDGE_UNINITIALIZED);
}
}
}
@Override
public void handleCommand(ChannelUID channelUID, Command command) {
if ((command instanceof RefreshType)) {
return;
}
String chlorCfgState = null;
String chlorTimedPercent = "0";
String systemID = getThing().getProperties().get(HaywardBindingConstants.PROPERTY_SYSTEM_ID);
String poolID = getThing().getProperties().get(HaywardBindingConstants.PROPERTY_BOWID);
Bridge bridge = getBridge();
if (bridge != null) {
HaywardBridgeHandler bridgehandler = (HaywardBridgeHandler) bridge.getHandler();
if (bridgehandler != null) {
String cmdString = this.cmdToString(command);
try {
switch (channelUID.getId()) {
case HaywardBindingConstants.CHANNEL_CHLORINATOR_ENABLE:
if (cmdString.equals("1")) {
chlorCfgState = "3";
chlorTimedPercent = this.chlorTimedPercent;
} else {
chlorCfgState = "2";
chlorTimedPercent = this.chlorTimedPercent;
}
break;
case HaywardBindingConstants.CHANNEL_CHLORINATOR_TIMEDPERCENT:
chlorCfgState = this.chlorState;
chlorTimedPercent = cmdString;
break;
default:
logger.warn("haywardCommand Unsupported type {}", channelUID);
return;
}
String cmdURL = HaywardBindingConstants.COMMAND_PARAMETERS
+ "<Name>SetCHLORParams</Name><Parameters>"
+ "<Parameter name=\"Token\" dataType=\"String\">" + bridgehandler.account.token
+ "</Parameter>" + "<Parameter name=\"MspSystemID\" dataType=\"int\">"
+ bridgehandler.account.mspSystemID + "</Parameter>"
+ "<Parameter name=\"PoolID\" dataType=\"int\">" + poolID + "</Parameter>"
+ "<Parameter name=\"ChlorID\" dataType=\"int\" alias=\"EquipmentID\">" + systemID
+ "</Parameter>" + "<Parameter name=\"CfgState\" dataType=\"byte\" alias=\"Data1\">"
+ chlorCfgState + "</Parameter>"
+ "<Parameter name=\"OpMode\" dataType=\"byte\" alias=\"Data2\">1</Parameter>"
+ "<Parameter name=\"BOWType\" dataType=\"byte\" alias=\"Data3\">1</Parameter>"
+ "<Parameter name=\"CellType\" dataType=\"byte\" alias=\"Data4\">4</Parameter>"
+ "<Parameter name=\"TimedPercent\" dataType=\"byte\" alias=\"Data5\">" + chlorTimedPercent
+ "</Parameter>"
+ "<Parameter name=\"SCTimeout\" dataType=\"byte\" unit=\"hour\" alias=\"Data6\">24</Parameter>"
+ "<Parameter name=\"ORPTimout\" dataType=\"byte\" unit=\"hour\" alias=\"Data7\">24</Parameter>"
+ "</Parameters></Request>";
// *****Send Command to Hayward server
String xmlResponse = bridgehandler.httpXmlResponse(cmdURL);
String status = bridgehandler.evaluateXPath("//Parameter[@name='Status']/text()", xmlResponse)
.get(0);
if (!(status.equals("0"))) {
logger.debug("haywardCommand XML response: {}", xmlResponse);
return;
}
} catch (HaywardException e) {
logger.debug("Unable to send command to Hayward's server {}:{}:{}",
bridgehandler.config.endpointUrl, bridgehandler.config.username, e.getMessage());
} catch (InterruptedException e) {
return;
}
this.updateStatus(ThingStatus.ONLINE);
} else {
this.updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.BRIDGE_UNINITIALIZED);
}
}
}
}

View File

@@ -0,0 +1,154 @@
/**
* Copyright (c) 2010-2021 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.haywardomnilogic.internal.handler;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.binding.haywardomnilogic.internal.HaywardBindingConstants;
import org.openhab.binding.haywardomnilogic.internal.HaywardException;
import org.openhab.binding.haywardomnilogic.internal.HaywardThingHandler;
import org.openhab.core.library.types.OnOffType;
import org.openhab.core.thing.Bridge;
import org.openhab.core.thing.ChannelUID;
import org.openhab.core.thing.Thing;
import org.openhab.core.thing.ThingStatus;
import org.openhab.core.thing.ThingStatusDetail;
import org.openhab.core.types.Command;
import org.openhab.core.types.RefreshType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* The ColorLogic Handler
*
* @author Matt Myers - Initial contribution
*/
@NonNullByDefault
public class HaywardColorLogicHandler extends HaywardThingHandler {
private final Logger logger = LoggerFactory.getLogger(HaywardColorLogicHandler.class);
public HaywardColorLogicHandler(Thing thing) {
super(thing);
}
@Override
public void getTelemetry(String xmlResponse) throws HaywardException {
List<String> systemIDs = new ArrayList<>();
List<String> data = new ArrayList<>();
Bridge bridge = getBridge();
if (bridge != null) {
HaywardBridgeHandler bridgehandler = (HaywardBridgeHandler) bridge.getHandler();
if (bridgehandler != null) {
systemIDs = bridgehandler.evaluateXPath("//ColorLogic-Light/@systemId", xmlResponse);
String thingSystemID = getThing().getUID().getId();
for (int i = 0; i < systemIDs.size(); i++) {
if (systemIDs.get(i).equals(thingSystemID)) {
// Light State
data = bridgehandler.evaluateXPath("//ColorLogic-Light/@lightState", xmlResponse);
updateData(HaywardBindingConstants.CHANNEL_COLORLOGIC_LIGHTSTATE, data.get(i));
if (data.get(i).equals("0")) {
updateData(HaywardBindingConstants.CHANNEL_COLORLOGIC_ENABLE, "0");
} else {
updateData(HaywardBindingConstants.CHANNEL_COLORLOGIC_ENABLE, "1");
}
// Current Show
data = bridgehandler.evaluateXPath("//ColorLogic-Light/@currentShow", xmlResponse);
updateData(HaywardBindingConstants.CHANNEL_COLORLOGIC_CURRENTSHOW, data.get(0));
}
}
this.updateStatus(ThingStatus.ONLINE);
} else {
this.updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.BRIDGE_UNINITIALIZED);
}
}
}
@Override
public void handleCommand(ChannelUID channelUID, Command command) {
if ((command instanceof RefreshType)) {
return;
}
String systemID = getThing().getProperties().get(HaywardBindingConstants.PROPERTY_SYSTEM_ID);
String poolID = getThing().getProperties().get(HaywardBindingConstants.PROPERTY_BOWID);
Bridge bridge = getBridge();
if (bridge != null) {
HaywardBridgeHandler bridgehandler = (HaywardBridgeHandler) bridge.getHandler();
if (bridgehandler != null) {
String cmdString = this.cmdToString(command);
String cmdURL = null;
try {
switch (channelUID.getId()) {
case HaywardBindingConstants.CHANNEL_COLORLOGIC_ENABLE:
if (command == OnOffType.ON) {
cmdString = "1";
} else {
cmdString = "0";
}
cmdURL = HaywardBindingConstants.COMMAND_PARAMETERS
+ "<Name>SetUIEquipmentCmd</Name><Parameters>"
+ "<Parameter name=\"Token\" dataType=\"String\">" + bridgehandler.account.token
+ "</Parameter>" + "<Parameter name=\"MspSystemID\" dataType=\"int\">"
+ bridgehandler.account.mspSystemID + "</Parameter>"
+ "<Parameter name=\"PoolID\" dataType=\"int\">" + poolID + "</Parameter>"
+ "<Parameter name=\"EquipmentID\" dataType=\"int\">" + systemID + "</Parameter>"
+ "<Parameter name=\"IsOn\" dataType=\"int\">" + cmdString + "</Parameter>"
+ HaywardBindingConstants.COMMAND_SCHEDULE + "</Parameters></Request>";
break;
case HaywardBindingConstants.CHANNEL_COLORLOGIC_CURRENTSHOW:
cmdURL = HaywardBindingConstants.COMMAND_PARAMETERS
+ "<Name>SetStandAloneLightShow</Name><Parameters>"
+ "<Parameter name=\"Token\" dataType=\"String\">" + bridgehandler.account.token
+ "</Parameter>" + "<Parameter name=\"MspSystemID\" dataType=\"int\">"
+ bridgehandler.account.mspSystemID + "</Parameter>"
+ "<Parameter name=\"PoolID\" dataType=\"int\">" + poolID + "</Parameter>"
+ "<Parameter name=\"LightID\" dataType=\"int\">" + systemID + "</Parameter>"
+ "<Parameter name=\"Show\" dataType=\"int\">" + cmdString + "</Parameter>"
+ "<Parameter name=\"Speed\" dataType=\"byte\">4</Parameter>"
+ "<Parameter name=\"Brightness\" dataType=\"byte\">4</Parameter>"
+ "<Parameter name=\"Reserved\" dataType=\"byte\">0</Parameter>"
+ HaywardBindingConstants.COMMAND_SCHEDULE + "</Parameters></Request>";
break;
default:
logger.warn("haywardCommand Unsupported type {}", channelUID);
return;
}
// *****Send Command to Hayward server
String xmlResponse = bridgehandler.httpXmlResponse(cmdURL);
String status = bridgehandler.evaluateXPath("//Parameter[@name='Status']/text()", xmlResponse)
.get(0);
if (!(status.equals("0"))) {
logger.debug("haywardCommand XML response: {}", xmlResponse);
return;
}
} catch (HaywardException e) {
logger.debug("Unable to send command to Hayward's server {}:{}:{}",
bridgehandler.config.endpointUrl, bridgehandler.config.username, e.getMessage());
} catch (InterruptedException e) {
return;
}
this.updateStatus(ThingStatus.ONLINE);
} else {
this.updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.BRIDGE_UNINITIALIZED);
}
}
}
}

View File

@@ -0,0 +1,159 @@
/**
* Copyright (c) 2010-2021 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.haywardomnilogic.internal.handler;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.binding.haywardomnilogic.internal.HaywardBindingConstants;
import org.openhab.binding.haywardomnilogic.internal.HaywardException;
import org.openhab.binding.haywardomnilogic.internal.HaywardThingHandler;
import org.openhab.core.library.types.OnOffType;
import org.openhab.core.thing.Bridge;
import org.openhab.core.thing.ChannelUID;
import org.openhab.core.thing.Thing;
import org.openhab.core.thing.ThingStatus;
import org.openhab.core.thing.ThingStatusDetail;
import org.openhab.core.types.Command;
import org.openhab.core.types.RefreshType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* The Filter Handler
*
* @author Matt Myers - Initial contribution
*/
@NonNullByDefault
public class HaywardFilterHandler extends HaywardThingHandler {
private final Logger logger = LoggerFactory.getLogger(HaywardFilterHandler.class);
public HaywardFilterHandler(Thing thing) {
super(thing);
}
@Override
public void initialize() {
updateStatus(ThingStatus.ONLINE);
}
@Override
public void getTelemetry(String xmlResponse) throws HaywardException {
List<String> systemIDs = new ArrayList<>();
List<String> data = new ArrayList<>();
Bridge bridge = getBridge();
if (bridge != null) {
HaywardBridgeHandler bridgehandler = (HaywardBridgeHandler) bridge.getHandler();
if (bridgehandler != null) {
systemIDs = bridgehandler.evaluateXPath("//Filter/@systemId", xmlResponse);
String thingSystemID = getThing().getUID().getId();
for (int i = 0; i < systemIDs.size(); i++) {
if (systemIDs.get(i).equals(thingSystemID)) {
// Operating Mode
data = bridgehandler.evaluateXPath("//Chlorinator/@operatingMode", xmlResponse);
updateData(HaywardBindingConstants.CHANNEL_CHLORINATOR_OPERATINGMODE, data.get(i));
// Valve Position
data = bridgehandler.evaluateXPath("//Filter/@valvePosition", xmlResponse);
updateData(HaywardBindingConstants.CHANNEL_FILTER_VALVEPOSITION, data.get(i));
// Speed
data = bridgehandler.evaluateXPath("//Filter/@filterSpeed", xmlResponse);
updateData(HaywardBindingConstants.CHANNEL_FILTER_SPEED, data.get(i));
if (data.get(i).equals("0")) {
updateData(HaywardBindingConstants.CHANNEL_FILTER_ENABLE, "0");
} else {
updateData(HaywardBindingConstants.CHANNEL_FILTER_ENABLE, "1");
}
// State
data = bridgehandler.evaluateXPath("//Filter/@filterState", xmlResponse);
updateData(HaywardBindingConstants.CHANNEL_FILTER_STATE, data.get(i));
// lastSpeed
data = bridgehandler.evaluateXPath("//Filter/@lastSpeed", xmlResponse);
updateData(HaywardBindingConstants.CHANNEL_FILTER_LASTSPEED, data.get(i));
}
}
this.updateStatus(ThingStatus.ONLINE);
} else {
this.updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.BRIDGE_UNINITIALIZED);
}
}
}
@Override
public void handleCommand(ChannelUID channelUID, Command command) {
if ((command instanceof RefreshType)) {
return;
}
String systemID = getThing().getProperties().get(HaywardBindingConstants.PROPERTY_SYSTEM_ID);
String poolID = getThing().getProperties().get(HaywardBindingConstants.PROPERTY_BOWID);
Bridge bridge = getBridge();
if (bridge != null) {
HaywardBridgeHandler bridgehandler = (HaywardBridgeHandler) bridge.getHandler();
if (bridgehandler != null) {
String cmdString = this.cmdToString(command);
try {
switch (channelUID.getId()) {
case HaywardBindingConstants.CHANNEL_FILTER_ENABLE:
if (command == OnOffType.ON) {
cmdString = "100";
} else {
cmdString = "0";
}
break;
case HaywardBindingConstants.CHANNEL_FILTER_SPEED:
break;
default:
logger.warn("haywardCommand Unsupported type {}", channelUID);
return;
}
String cmdURL = HaywardBindingConstants.COMMAND_PARAMETERS
+ "<Name>SetUIEquipmentCmd</Name><Parameters>"
+ "<Parameter name=\"Token\" dataType=\"String\">" + bridgehandler.account.token
+ "</Parameter>" + "<Parameter name=\"MspSystemID\" dataType=\"int\">"
+ bridgehandler.account.mspSystemID + "</Parameter>"
+ "<Parameter name=\"PoolID\" dataType=\"int\">" + poolID + "</Parameter>"
+ "<Parameter name=\"EquipmentID\" dataType=\"int\">" + systemID + "</Parameter>"
+ "<Parameter name=\"IsOn\" dataType=\"int\">" + cmdString + "</Parameter>"
+ HaywardBindingConstants.COMMAND_SCHEDULE + "</Parameters></Request>";
// *****Send Command to Hayward server
String xmlResponse = bridgehandler.httpXmlResponse(cmdURL);
String status = bridgehandler.evaluateXPath("//Parameter[@name='Status']/text()", xmlResponse)
.get(0);
if (!(status.equals("0"))) {
logger.debug("haywardCommand XML response: {}", xmlResponse);
return;
}
} catch (HaywardException e) {
logger.debug("Unable to send command to Hayward's server {}:{}:{}",
bridgehandler.config.endpointUrl, bridgehandler.config.username, e.getMessage());
} catch (InterruptedException e) {
return;
}
this.updateStatus(ThingStatus.ONLINE);
} else {
this.updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.BRIDGE_UNINITIALIZED);
}
}
}
}

View File

@@ -0,0 +1,74 @@
/**
* Copyright (c) 2010-2021 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.haywardomnilogic.internal.handler;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.binding.haywardomnilogic.internal.HaywardBindingConstants;
import org.openhab.binding.haywardomnilogic.internal.HaywardException;
import org.openhab.binding.haywardomnilogic.internal.HaywardThingHandler;
import org.openhab.binding.haywardomnilogic.internal.config.HaywardConfig;
import org.openhab.core.thing.Bridge;
import org.openhab.core.thing.Thing;
import org.openhab.core.thing.ThingStatus;
import org.openhab.core.thing.ThingStatusDetail;
/**
* The Heater Handler
*
* @author Matt Myers - Initial contribution
*/
@NonNullByDefault
public class HaywardHeaterHandler extends HaywardThingHandler {
HaywardConfig config = getConfig().as(HaywardConfig.class);
public HaywardHeaterHandler(Thing thing) {
super(thing);
}
@Override
public void getTelemetry(String xmlResponse) throws HaywardException {
List<String> systemIDs = new ArrayList<>();
List<String> data = new ArrayList<>();
Bridge bridge = getBridge();
if (bridge != null) {
HaywardBridgeHandler bridgehandler = (HaywardBridgeHandler) bridge.getHandler();
if (bridgehandler != null) {
systemIDs = bridgehandler.evaluateXPath("//Heater/@systemId", xmlResponse);
String thingSystemID = getThing().getUID().getId();
for (int i = 0; i < systemIDs.size(); i++) {
if (systemIDs.get(i).equals(thingSystemID)) {
// State
data = bridgehandler.evaluateXPath("//Heater/@heaterState", xmlResponse);
updateData(HaywardBindingConstants.CHANNEL_HEATER_STATE, data.get(i));
// Enable
data = bridgehandler.evaluateXPath("//Heater/@enable", xmlResponse);
if (data.get(i).equals("0")) {
updateData(HaywardBindingConstants.CHANNEL_HEATER_ENABLE, "0");
} else {
updateData(HaywardBindingConstants.CHANNEL_HEATER_ENABLE, "1");
}
}
}
this.updateStatus(ThingStatus.ONLINE);
} else {
this.updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.BRIDGE_UNINITIALIZED);
}
}
}
}

View File

@@ -0,0 +1,123 @@
/**
* Copyright (c) 2010-2021 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.haywardomnilogic.internal.handler;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.binding.haywardomnilogic.internal.HaywardBindingConstants;
import org.openhab.binding.haywardomnilogic.internal.HaywardException;
import org.openhab.binding.haywardomnilogic.internal.HaywardThingHandler;
import org.openhab.core.thing.Bridge;
import org.openhab.core.thing.ChannelUID;
import org.openhab.core.thing.Thing;
import org.openhab.core.thing.ThingStatus;
import org.openhab.core.thing.ThingStatusDetail;
import org.openhab.core.types.Command;
import org.openhab.core.types.RefreshType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* The Relay Handler
*
* @author Matt Myers - Initial contribution
*/
@NonNullByDefault
public class HaywardRelayHandler extends HaywardThingHandler {
private final Logger logger = LoggerFactory.getLogger(HaywardRelayHandler.class);
public HaywardRelayHandler(Thing thing) {
super(thing);
}
@Override
public void getTelemetry(String xmlResponse) throws HaywardException {
List<String> systemIDs = new ArrayList<>();
List<String> data = new ArrayList<>();
Bridge bridge = getBridge();
if (bridge != null) {
HaywardBridgeHandler bridgehandler = (HaywardBridgeHandler) bridge.getHandler();
if (bridgehandler != null) {
systemIDs = bridgehandler.evaluateXPath("//Relay/@systemId", xmlResponse);
data = bridgehandler.evaluateXPath("//Relay/@relayState", xmlResponse);
String thingSystemID = getThing().getUID().getId();
for (int i = 0; i < systemIDs.size(); i++) {
if (systemIDs.get(i).equals(thingSystemID)) {
updateData(HaywardBindingConstants.CHANNEL_RELAY_STATE, data.get(i));
}
}
this.updateStatus(ThingStatus.ONLINE);
} else {
this.updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.BRIDGE_UNINITIALIZED);
}
}
}
@Override
public void handleCommand(ChannelUID channelUID, Command command) {
if ((command instanceof RefreshType)) {
return;
}
String systemID = getThing().getProperties().get(HaywardBindingConstants.PROPERTY_SYSTEM_ID);
String poolID = getThing().getProperties().get(HaywardBindingConstants.PROPERTY_BOWID);
Bridge bridge = getBridge();
if (bridge != null) {
HaywardBridgeHandler bridgehandler = (HaywardBridgeHandler) bridge.getHandler();
if (bridgehandler != null) {
String cmdString = this.cmdToString(command);
String cmdURL = null;
try {
switch (channelUID.getId()) {
case HaywardBindingConstants.CHANNEL_RELAY_STATE:
cmdURL = HaywardBindingConstants.COMMAND_PARAMETERS
+ "<Name>SetUIEquipmentCmd</Name><Parameters>"
+ "<Parameter name=\"Token\" dataType=\"String\">" + bridgehandler.account.token
+ "</Parameter>" + "<Parameter name=\"MspSystemID\" dataType=\"int\">"
+ bridgehandler.account.mspSystemID + "</Parameter>"
+ "<Parameter name=\"PoolID\" dataType=\"int\">" + poolID + "</Parameter>"
+ "<Parameter name=\"EquipmentID\" dataType=\"int\">" + systemID + "</Parameter>"
+ "<Parameter name=\"IsOn\" dataType=\"int\">" + cmdString + "</Parameter>"
+ HaywardBindingConstants.COMMAND_SCHEDULE + "</Parameters></Request>";
break;
default:
logger.warn("haywardCommand Unsupported type {}", channelUID);
return;
}
// *****Send Command to Hayward server
String xmlResponse = bridgehandler.httpXmlResponse(cmdURL);
String status = bridgehandler.evaluateXPath("//Parameter[@name='Status']/text()", xmlResponse)
.get(0);
if (!(status.equals("0"))) {
logger.debug("haywardCommand XML response: {}", xmlResponse);
return;
}
} catch (HaywardException e) {
logger.debug("Unable to send command to Hayward's server {}:{}:{}",
bridgehandler.config.endpointUrl, bridgehandler.config.username, e.getMessage());
} catch (InterruptedException e) {
return;
}
this.updateStatus(ThingStatus.ONLINE);
} else {
this.updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.BRIDGE_UNINITIALIZED);
}
}
}
}

View File

@@ -0,0 +1,62 @@
/**
* Copyright (c) 2010-2021 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.haywardomnilogic.internal.handler;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.binding.haywardomnilogic.internal.HaywardBindingConstants;
import org.openhab.binding.haywardomnilogic.internal.HaywardException;
import org.openhab.binding.haywardomnilogic.internal.HaywardThingHandler;
import org.openhab.core.thing.Bridge;
import org.openhab.core.thing.Thing;
import org.openhab.core.thing.ThingStatus;
import org.openhab.core.thing.ThingStatusDetail;
/**
* The Sensor Handler
*
* @author Matt Myers - Initial contribution
*/
@NonNullByDefault
public class HaywardSensorHandler extends HaywardThingHandler {
public HaywardSensorHandler(Thing thing) {
super(thing);
}
@Override
public void getTelemetry(String xmlResponse) throws HaywardException {
List<String> systemIDs = new ArrayList<>();
List<String> data = new ArrayList<>();
Bridge bridge = getBridge();
if (bridge != null) {
HaywardBridgeHandler bridgehandler = (HaywardBridgeHandler) bridge.getHandler();
if (bridgehandler != null) {
systemIDs = bridgehandler.evaluateXPath("//Sensor/@systemId", xmlResponse);
data = bridgehandler.evaluateXPath("//Sensor/@relayState", xmlResponse);
String thingSystemID = getThing().getUID().getId();
for (int i = 0; i < systemIDs.size(); i++) {
if (systemIDs.get(i).equals(thingSystemID)) {
updateData(HaywardBindingConstants.CHANNEL_RELAY_STATE, data.get(i));
}
}
this.updateStatus(ThingStatus.ONLINE);
} else {
this.updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.BRIDGE_UNINITIALIZED);
}
}
}
}

View File

@@ -0,0 +1,150 @@
/**
* Copyright (c) 2010-2021 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.haywardomnilogic.internal.handler;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.binding.haywardomnilogic.internal.HaywardBindingConstants;
import org.openhab.binding.haywardomnilogic.internal.HaywardException;
import org.openhab.binding.haywardomnilogic.internal.HaywardThingHandler;
import org.openhab.core.library.types.OnOffType;
import org.openhab.core.thing.Bridge;
import org.openhab.core.thing.ChannelUID;
import org.openhab.core.thing.Thing;
import org.openhab.core.thing.ThingStatus;
import org.openhab.core.thing.ThingStatusDetail;
import org.openhab.core.types.Command;
import org.openhab.core.types.RefreshType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* The Virtual Heater Handler
*
* @author Matt Myers - Initial contribution
*/
@NonNullByDefault
public class HaywardVirtualHeaterHandler extends HaywardThingHandler {
private final Logger logger = LoggerFactory.getLogger(HaywardVirtualHeaterHandler.class);
public HaywardVirtualHeaterHandler(Thing thing) {
super(thing);
}
@Override
public void getTelemetry(String xmlResponse) throws HaywardException {
List<String> systemIDs = new ArrayList<>();
List<String> data = new ArrayList<>();
Bridge bridge = getBridge();
if (bridge != null) {
HaywardBridgeHandler bridgehandler = (HaywardBridgeHandler) bridge.getHandler();
if (bridgehandler != null) {
systemIDs = bridgehandler.evaluateXPath("//VirtualHeater/@systemId", xmlResponse);
String thingSystemID = getThing().getUID().getId();
for (int i = 0; i < systemIDs.size(); i++) {
if (systemIDs.get(i).equals(thingSystemID)) {
data = bridgehandler.evaluateXPath("//VirtualHeater/@Current-Set-Point", xmlResponse);
updateData(HaywardBindingConstants.CHANNEL_VIRTUALHEATER_CURRENTSETPOINT, data.get(i));
data = bridgehandler.evaluateXPath("//VirtualHeater/@enable", xmlResponse);
if (data.get(i).equals("yes")) {
updateData(HaywardBindingConstants.CHANNEL_VIRTUALHEATER_ENABLE, "1");
} else if (data.get(i).equals("no")) {
updateData(HaywardBindingConstants.CHANNEL_VIRTUALHEATER_ENABLE, "0");
}
}
}
this.updateStatus(ThingStatus.ONLINE);
} else {
this.updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.BRIDGE_UNINITIALIZED);
}
}
}
@Override
public void handleCommand(ChannelUID channelUID, Command command) {
if ((command instanceof RefreshType)) {
return;
}
String systemID = getThing().getProperties().get(HaywardBindingConstants.PROPERTY_SYSTEM_ID);
String poolID = getThing().getProperties().get(HaywardBindingConstants.PROPERTY_BOWID);
Bridge bridge = getBridge();
if (bridge != null) {
HaywardBridgeHandler bridgehandler = (HaywardBridgeHandler) bridge.getHandler();
if (bridgehandler != null) {
String cmdString = this.cmdToString(command);
String cmdURL = null;
if (command == OnOffType.ON) {
cmdString = "True";
} else if (command == OnOffType.OFF) {
cmdString = "False";
}
try {
switch (channelUID.getId()) {
case HaywardBindingConstants.CHANNEL_VIRTUALHEATER_ENABLE:
cmdURL = HaywardBindingConstants.COMMAND_PARAMETERS
+ "<Name>SetHeaterEnable</Name><Parameters>"
+ "<Parameter name=\"Token\" dataType=\"String\">" + bridgehandler.account.token
+ "</Parameter>" + "<Parameter name=\"MspSystemID\" dataType=\"int\">"
+ bridgehandler.account.mspSystemID + "</Parameter>"
+ "<Parameter name=\"PoolID\" dataType=\"int\">" + poolID + "</Parameter>"
+ "<Parameter name=\"HeaterID\" dataType=\"int\">" + systemID + "</Parameter>"
+ "<Parameter name=\"Enabled\" dataType=\"bool\">" + cmdString + "</Parameter>"
+ "</Parameters></Request>";
break;
case HaywardBindingConstants.CHANNEL_VIRTUALHEATER_CURRENTSETPOINT:
cmdURL = HaywardBindingConstants.COMMAND_PARAMETERS
+ "<Name>SetUIHeaterCmd</Name><Parameters>"
+ "<Parameter name=\"Token\" dataType=\"String\">" + bridgehandler.account.token
+ "</Parameter>" + "<Parameter name=\"MspSystemID\" dataType=\"int\">"
+ bridgehandler.account.mspSystemID + "</Parameter>"
+ "<Parameter name=\"PoolID\" dataType=\"int\">" + poolID + "</Parameter>"
+ "<Parameter name=\"HeaterID\" dataType=\"int\">" + systemID + "</Parameter>"
+ "<Parameter name=\"Temp\" dataType=\"int\">" + cmdString + "</Parameter>"
+ "</Parameters></Request>";
break;
default:
logger.warn("haywardCommand Unsupported type {}", channelUID);
return;
}
// *****Send Command to Hayward server
String xmlResponse = bridgehandler.httpXmlResponse(cmdURL);
String status = bridgehandler.evaluateXPath("//Parameter[@name='Status']/text()", xmlResponse)
.get(0);
if (!(status.equals("0"))) {
logger.debug("haywardCommand XML response: {}", xmlResponse);
return;
}
} catch (HaywardException e) {
logger.debug("Unable to send command to Hayward's server {}:{}:{}",
bridgehandler.config.endpointUrl, bridgehandler.config.username, e.getMessage());
} catch (InterruptedException e) {
return;
}
this.updateStatus(ThingStatus.ONLINE);
} else {
this.updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.BRIDGE_UNINITIALIZED);
}
}
}
}

View File

@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<binding:binding id="haywardomnilogic" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:binding="https://openhab.org/schemas/binding/v1.0.0"
xsi:schemaLocation="https://openhab.org/schemas/binding/v1.0.0 https://openhab.org/schemas/binding-1.0.0.xsd">
<name>Hayward OmniLogix Binding</name>
<description>Binding for the Hayward OmniLogix swimming pool automation controller.</description>
<author>Matt Myers</author>
</binding:binding>

View File

@@ -0,0 +1,76 @@
<?xml version="1.0" encoding="UTF-8"?>
<thing:thing-descriptions bindingId="haywardomnilogic"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:thing="https://openhab.org/schemas/thing-description/v1.0.0"
xsi:schemaLocation="https://openhab.org/schemas/thing-description/v1.0.0 https://openhab.org/schemas/thing-description-1.0.0.xsd">
<thing-type id="backyard" listed="false">
<supported-bridge-type-refs>
<bridge-type-ref id="bridge"/>
</supported-bridge-type-refs>
<label>Backyard</label>
<description>The Hayward Backyard</description>
<channels>
<channel id="backyardAirTemp" typeId="airTemp"/>
<channel id="backyardStatus" typeId="backyardstatus"/>
<channel id="backyardState" typeId="backyardstate"/>
<channel id="backyardAlarm1" typeId="alarm"/>
<channel id="backyardAlarm2" typeId="alarm"/>
<channel id="backyardAlarm3" typeId="alarm"/>
<channel id="backyardAlarm4" typeId="alarm"/>
<channel id="backyardAlarm5" typeId="alarm"/>
</channels>
<properties>
<property name="Vendor">Hayward</property>
</properties>
<representation-property>systemID</representation-property>
</thing-type>
<channel-type id="airTemp">
<item-type>Number:Temperature</item-type>
<label>Air Temp</label>
<description>Air Temp</description>
<state pattern="%1f %unit%" readOnly="true"/>
</channel-type>
<channel-type id="backyardstatus">
<item-type>String</item-type>
<label>Status</label>
<description>Status</description>
<state readOnly="true">
<options>
<option value="1">Normal</option>
<option value="2">Alarm</option>
<option value="3">Expired</option>
<option value="4">Lost Link</option>
<option value="5">Service Mode</option>
</options>
</state>
</channel-type>
<channel-type id="backyardstate">
<item-type>String</item-type>
<label>State</label>
<description>State</description>
<state readOnly="true">
<options>
<option value="0">Powered Off</option>
<option value="1">Normal</option>
<option value="2">Service Mode</option>
<option value="3">Config Mode</option>
<option value="4">Timed Service Mode</option>
</options>
</state>
</channel-type>
<channel-type id="alarm">
<item-type>String</item-type>
<label>Alarm</label>
<description>Alarm</description>
<state readOnly="true"/>
</channel-type>
</thing:thing-descriptions>

View File

@@ -0,0 +1,40 @@
<?xml version="1.0" encoding="UTF-8"?>
<thing:thing-descriptions bindingId="haywardomnilogic"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:thing="https://openhab.org/schemas/thing-description/v1.0.0"
xsi:schemaLocation="https://openhab.org/schemas/thing-description/v1.0.0 https://openhab.org/schemas/thing-description-1.0.0.xsd">
<thing-type id="bow" listed="false">
<supported-bridge-type-refs>
<bridge-type-ref id="bridge"/>
</supported-bridge-type-refs>
<label>Body of Water</label>
<description>The Hayward Body of Water</description>
<channels>
<channel id="bowFlow" typeId="waterFlow"/>
<channel id="bowWaterTemp" typeId="waterTemp"/>
</channels>
<properties>
<property name="Vendor">Hayward</property>
</properties>
<representation-property>systemID</representation-property>
</thing-type>
<channel-type id="waterFlow">
<item-type>system.power</item-type>
<label>Flow Sensor</label>
<description>Flow Sensor</description>
<state readOnly="true"/>
</channel-type>
<channel-type id="waterTemp">
<item-type>Number:Temperature</item-type>
<label>Water Temp</label>
<description>Water Temp</description>
<state pattern="%1f %unit%" readOnly="true"/>
</channel-type>
</thing:thing-descriptions>

View File

@@ -0,0 +1,40 @@
<?xml version="1.0" encoding="UTF-8"?>
<thing:thing-descriptions bindingId="haywardomnilogic"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:thing="https://openhab.org/schemas/thing-description/v1.0.0"
xsi:schemaLocation="https://openhab.org/schemas/thing-description/v1.0.0 https://openhab.org/schemas/thing-description-1.0.0.xsd">
<!-- The bridge to communicate with Hayward's server -->
<bridge-type id="bridge">
<label>Hayward OmniLogix Connection</label>
<description>Connection to Hayward's Server</description>
<config-description>
<parameter name="endpointUrl" type="text" required="true">
<context>url</context>
<label>Endpoint URL</label>
<default>https://app1.haywardomnilogic.com/HAAPI/HomeAutomation/API.ashx</default>
<description>The URL of the Hayward API Server</description>
</parameter>
<parameter name="username" type="text" required="true">
<label>User Name</label>
<description>The username to connect to the server.</description>
</parameter>
<parameter name="password" type="text" required="true">
<context>password</context>
<label>Password</label>
<description>The password to connect to the server.</description>
</parameter>
<parameter name="telemetryPollTime" type="integer" min="10" max="60" unit="s" required="true">
<label>Telemetry Poll Delay</label>
<default>12</default>
<description>How often to request telemetry data from Hayward Server</description>
</parameter>
<parameter name="alarmPollTime" type="integer" min="0" max="120" unit="s" required="true">
<label>Alarm Poll Delay</label>
<default>60</default>
<description>How often to request alarm data from Hayward Server. Enter 0 to disable.</description>
</parameter>
</config-description>
</bridge-type>
</thing:thing-descriptions>

View File

@@ -0,0 +1,103 @@
<?xml version="1.0" encoding="UTF-8"?>
<thing:thing-descriptions bindingId="haywardomnilogic"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:thing="https://openhab.org/schemas/thing-description/v1.0.0"
xsi:schemaLocation="https://openhab.org/schemas/thing-description/v1.0.0 https://openhab.org/schemas/thing-description-1.0.0.xsd">
<thing-type id="chlorinator" listed="false">
<supported-bridge-type-refs>
<bridge-type-ref id="bridge"/>
</supported-bridge-type-refs>
<label>Chlorinator</label>
<description>Chlorinator</description>
<channels>
<channel id="chlorEnable" typeId="system.power"/>
<channel id="chlorOperatingMode" typeId="chlorOperatingMode"/>
<channel id="chlorTimedPercent" typeId="timedPercent"/>
<channel id="chlorScMode" typeId="scMode"/>
<channel id="chlorError" typeId="chlorError"/>
<channel id="chlorAlert" typeId="chlorAlert"/>
<channel id="chlorAvgSaltLevel" typeId="avgSaltLevel"/>
<channel id="chlorInstantSaltLevel" typeId="instantSaltLevel"/>
<channel id="chlorStatus" typeId="status"/>
</channels>
<properties>
<property name="Vendor">Hayward</property>
</properties>
<representation-property>systemID</representation-property>
</thing-type>
<channel-type id="chlorOperatingMode">
<item-type>String</item-type>
<label>Operating Mode</label>
<description>Operating Mode</description>
<state readOnly="true">
<options>
<option value="0">Off</option>
<option value="1">Timed Percent</option>
<option value="2">ORP Autosense</option>
</options>
</state>
</channel-type>
<channel-type id="timedPercent">
<item-type>Number:Dimensionless</item-type>
<label>Salt Output (%)</label>
<description>Current salt output setting for the chlorinator (%).</description>
<state min="0" max="100" step="1.0" pattern="%1f %unit%" readOnly="false"/>
</channel-type>
<channel-type id="scMode">
<item-type>String</item-type>
<label>scMode</label>
<description>scMode</description>
<state readOnly="true">
<options>
<option value="0">Off</option>
<option value="1">Super Chlorinating</option>
</options>
</state>
</channel-type>
<channel-type id="chlorError">
<item-type>Number</item-type>
<label>Chlorinator Error</label>
<state readOnly="true"/>
</channel-type>
<channel-type id="chlorAlert">
<item-type>String</item-type>
<label>Chlorinator Alert</label>
<description>Chlorinator Alert</description>
<state readOnly="true">
<options>
<option value="0">None</option>
<option value="16">Low T-Cell Temperature</option>
</options>
</state>
</channel-type>
<channel-type id="avgSaltLevel">
<item-type>Number:Dimensionless</item-type>
<label>Average Salt Level</label>
<description>Average Salt Level</description>
<state pattern="%1f %unit%" readOnly="true"/>
</channel-type>
<channel-type id="instantSaltLevel">
<item-type>Number:Dimensionless</item-type>
<label>Instant Salt Level</label>
<description>Instant Salt Level</description>
<state pattern="%1f %unit%" readOnly="true"/>
</channel-type>
<channel-type id="status">
<item-type>Number</item-type>
<label>Status</label>
<description>Status</description>
<state pattern="%1f" readOnly="true"/>
</channel-type>
</thing:thing-descriptions>

View File

@@ -0,0 +1,67 @@
<?xml version="1.0" encoding="UTF-8"?>
<thing:thing-descriptions bindingId="haywardomnilogic"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:thing="https://openhab.org/schemas/thing-description/v1.0.0"
xsi:schemaLocation="https://openhab.org/schemas/thing-description/v1.0.0 https://openhab.org/schemas/thing-description-1.0.0.xsd">
<thing-type id="colorlogic" listed="false">
<supported-bridge-type-refs>
<bridge-type-ref id="bridge"/>
</supported-bridge-type-refs>
<label>Color Logic Light</label>
<description>Color Logic Light</description>
<channels>
<channel id="colorLogicLightEnable" typeId="system.power"/>
<channel id="colorLogicLightState" typeId="lightState"/>
<channel id="colorLogicLightCurrentShow" typeId="currentShow"/>
</channels>
<properties>
<property name="Vendor">Hayward</property>
</properties>
<representation-property>systemID</representation-property>
</thing-type>
<channel-type id="lightState">
<item-type>String</item-type>
<label>Light State</label>
<description>Light State</description>
<state readOnly="true">
<options>
<option value="0">Off</option>
<option value="1">On</option>
<option value="4">15 Sec White Light</option>
<option value="7">Powering Off</option>
</options>
</state>
</channel-type>
<channel-type id="currentShow">
<item-type>String</item-type>
<label>Current Show</label>
<description>Current Show</description>
<state readOnly="false">
<options>
<option value="0">Voodoo Lounge</option>
<option value="1">Deep Blue Sea</option>
<option value="2">Royal Blue</option>
<option value="3">Afternoon Sky</option>
<option value="4">Aqua Green</option>
<option value="5">Emerald</option>
<option value="6">Cloud White</option>
<option value="7">Warm Red</option>
<option value="8">Flamingo</option>
<option value="9">Vivid Violet</option>
<option value="10">Sangria</option>
<option value="11">Twilight</option>
<option value="12">Tranquility</option>
<option value="13">Gemstone</option>
<option value="14">USA</option>
<option value="15">Mardi Gras</option>
<option value="16">Cool Cabaret</option>
</options>
</state>
</channel-type>
</thing:thing-descriptions>

View File

@@ -0,0 +1,83 @@
<?xml version="1.0" encoding="UTF-8"?>
<thing:thing-descriptions bindingId="haywardomnilogic"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:thing="https://openhab.org/schemas/thing-description/v1.0.0"
xsi:schemaLocation="https://openhab.org/schemas/thing-description/v1.0.0 https://openhab.org/schemas/thing-description-1.0.0.xsd">
<thing-type id="filter" listed="false">
<supported-bridge-type-refs>
<bridge-type-ref id="bridge"/>
</supported-bridge-type-refs>
<label>Filter</label>
<description>Filter Equipment</description>
<channels>
<channel id="filterEnable" typeId="system.power"/>
<channel id="filterValvePosition" typeId="valvePosition"/>
<channel id="filterSpeed" typeId="filterSpeed"/>
<channel id="filterState" typeId="filterState"/>
<channel id="filterLastSpeed" typeId="filterLastSpeed"/>
</channels>
<properties>
<property name="Vendor">Hayward</property>
<property name="Min Pump Percent"></property>
<property name="Max Pump Percent"></property>
<property name="Min Pump RPM"></property>
<property name="Max Pump RPM"></property>
</properties>
<representation-property>systemID</representation-property>
</thing-type>
<channel-type id="valvePosition">
<item-type>String</item-type>
<label>Valve Position</label>
<description>Valve Position</description>
<state readOnly="true">
<options>
<option value="0">Off</option>
<option value="1">Pool Only</option>
<option value="2">Spa Only</option>
<option value="3">Spill Over</option>
</options>
</state>
</channel-type>
<channel-type id="filterSpeed">
<item-type>Number:Dimensionless</item-type>
<label>Filter Speed</label>
<description>Filter Speed in %</description>
<state min="0" max="100" step="1.0" pattern="%1f %unit%" readOnly="false"/>
</channel-type>
<channel-type id="filterState">
<item-type>String</item-type>
<label>Filter State</label>
<description>Filter State</description>
<state readOnly="true">
<options>
<option value="0">Off</option>
<option value="1">Running</option>
<option value="2">Priming</option>
<option value="3">Waiting to Turn Off</option>
<option value="4">Waiting to Turn Off Manual</option>
<option value="5">Heater Extend</option>
<option value="6">Heater Cool Down</option>
<option value="7">Suspended</option>
<option value="8">CSAD Extend</option>
<option value="9">Filter Superchlorinate</option>
<option value="10">Filter Force Priming</option>
<option value="11">Filter Waiting for Pump to Turn Off</option>
</options>
</state>
</channel-type>
<channel-type id="filterLastSpeed">
<item-type>Number:Dimensionless</item-type>
<label>Last Speed</label>
<description>Last Speed</description>
<state pattern="%1f %unit%" readOnly="true"/>
</channel-type>
</thing:thing-descriptions>

View File

@@ -0,0 +1,39 @@
<?xml version="1.0" encoding="UTF-8"?>
<thing:thing-descriptions bindingId="haywardomnilogic"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:thing="https://openhab.org/schemas/thing-description/v1.0.0"
xsi:schemaLocation="https://openhab.org/schemas/thing-description/v1.0.0 https://openhab.org/schemas/thing-description-1.0.0.xsd">
<thing-type id="heater" listed="false">
<supported-bridge-type-refs>
<bridge-type-ref id="bridge"/>
</supported-bridge-type-refs>
<label>Heater</label>
<description>Heater</description>
<channels>
<channel id="heaterState" typeId="state"/>
<channel id="heaterEnable" typeId="enable"/>
</channels>
<properties>
<property name="Vendor">Hayward</property>
</properties>
<representation-property>systemID</representation-property>
</thing-type>
<channel-type id="state">
<item-type>Number</item-type>
<label>Heater State</label>
<description>Heater State</description>
<state readOnly="true"/>
</channel-type>
<channel-type id="enable">
<item-type>system.power</item-type>
<label>Heater Enable</label>
<description>Heater Enable</description>
<state readOnly="true"/>
</channel-type>
</thing:thing-descriptions>

View File

@@ -0,0 +1,37 @@
<?xml version="1.0" encoding="UTF-8"?>
<thing:thing-descriptions bindingId="haywardomnilogic"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:thing="https://openhab.org/schemas/thing-description/v1.0.0"
xsi:schemaLocation="https://openhab.org/schemas/thing-description/v1.0.0 https://openhab.org/schemas/thing-description-1.0.0.xsd">
<thing-type id="pump" listed="false">
<supported-bridge-type-refs>
<bridge-type-ref id="bridge"/>
</supported-bridge-type-refs>
<label>Pump</label>
<description>Pump</description>
<channels>
<channel id="pumpEnable" typeId="system.power"/>
<channel id="pumpSpeed" typeId="pumpSpeed"/>
</channels>
<properties>
<property name="Vendor">Hayward</property>
<property name="Min Pump Percent"></property>
<property name="Max Pump Percent"></property>
<property name="Min Pump RPM"></property>
<property name="Max Pump RPM"></property>
</properties>
<representation-property>systemID</representation-property>
</thing-type>
<channel-type id="pumpSpeed">
<item-type>Number:Dimensionless</item-type>
<label>Pump Speed in %</label>
<description>Pump Speed</description>
<state min="0" max="100" step="1.0" pattern="%1f %unit%" readOnly="false"/>
</channel-type>
</thing:thing-descriptions>

View File

@@ -0,0 +1,25 @@
<?xml version="1.0" encoding="UTF-8"?>
<thing:thing-descriptions bindingId="haywardomnilogic"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:thing="https://openhab.org/schemas/thing-description/v1.0.0"
xsi:schemaLocation="https://openhab.org/schemas/thing-description/v1.0.0 https://openhab.org/schemas/thing-description-1.0.0.xsd">
<thing-type id="relay" listed="false">
<supported-bridge-type-refs>
<bridge-type-ref id="bridge"/>
</supported-bridge-type-refs>
<label>Relay</label>
<description>Relay</description>
<channels>
<channel id="relayState" typeId="system.power"/>
</channels>
<properties>
<property name="Vendor">Hayward</property>
</properties>
<representation-property>systemID</representation-property>
</thing-type>
</thing:thing-descriptions>

View File

@@ -0,0 +1,39 @@
<?xml version="1.0" encoding="UTF-8"?>
<thing:thing-descriptions bindingId="haywardomnilogic"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:thing="https://openhab.org/schemas/thing-description/v1.0.0"
xsi:schemaLocation="https://openhab.org/schemas/thing-description/v1.0.0 https://openhab.org/schemas/thing-description-1.0.0.xsd">
<thing-type id="sensor" listed="false">
<supported-bridge-type-refs>
<bridge-type-ref id="bridge"/>
</supported-bridge-type-refs>
<label>Sensor</label>
<description>Sensor</description>
<channels>
<channel id="sensorData" typeId="data"/>
</channels>
<properties>
<property name="Vendor">Hayward</property>
</properties>
<representation-property>systemID</representation-property>
</thing-type>
<channel-type id="bow">
<item-type>Number</item-type>
<label>Body of Water</label>
<description>The Body of Water ID</description>
<state readOnly="true"/>
</channel-type>
<channel-type id="data">
<item-type>Number</item-type>
<label>Data</label>
<description>Sensor Data</description>
<state readOnly="true"/>
</channel-type>
</thing:thing-descriptions>

View File

@@ -0,0 +1,34 @@
<?xml version="1.0" encoding="UTF-8"?>
<thing:thing-descriptions bindingId="haywardomnilogic"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:thing="https://openhab.org/schemas/thing-description/v1.0.0"
xsi:schemaLocation="https://openhab.org/schemas/thing-description/v1.0.0 https://openhab.org/schemas/thing-description-1.0.0.xsd">
<thing-type id="virtualHeater" listed="false">
<supported-bridge-type-refs>
<bridge-type-ref id="bridge"/>
</supported-bridge-type-refs>
<label>Virtual Heater</label>
<description>Virtual Heater</description>
<channels>
<channel id="virtualHeaterEnable" typeId="system.power"/>
<channel id="virtualHeaterCurrentSetpoint" typeId="currentSetpoint"/>
</channels>
<properties>
<property name="Vendor">Hayward</property>
</properties>
<representation-property>systemID</representation-property>
</thing-type>
<channel-type id="currentSetpoint">
<item-type>Number:Temperature</item-type>
<label>Current Setpoint</label>
<description>Current Setpoint</description>
<category>Temperature</category>
<state min="65" max="90" step="1.0" pattern="%1f %unit%" readOnly="false"/>
</channel-type>
</thing:thing-descriptions>