diff --git a/CODEOWNERS b/CODEOWNERS
index 1f5619a95051f..adc1b1474d378 100644
--- a/CODEOWNERS
+++ b/CODEOWNERS
@@ -91,6 +91,7 @@
/bundles/org.openhab.binding.gree/ @markus7017
/bundles/org.openhab.binding.groheondus/ @FlorianSW
/bundles/org.openhab.binding.harmonyhub/ @digitaldan
+/bundles/org.openhab.binding.haywardomnilogic/ @matchews
/bundles/org.openhab.binding.hdanywhere/ @kgoderis
/bundles/org.openhab.binding.hdpowerview/ @beowulfe
/bundles/org.openhab.binding.helios/ @kgoderis
diff --git a/bom/openhab-addons/pom.xml b/bom/openhab-addons/pom.xml
index b8219428eec77..d418a1638e82c 100644
--- a/bom/openhab-addons/pom.xml
+++ b/bom/openhab-addons/pom.xml
@@ -441,6 +441,11 @@
org.openhab.binding.harmonyhub
${project.version}
+
+ org.openhab.addons.bundles
+ org.openhab.binding.haywardomnilogic
+ ${project.version}
+
org.openhab.addons.bundles
org.openhab.binding.hdanywhere
diff --git a/bundles/org.openhab.binding.haywardomnilogic/NOTICE b/bundles/org.openhab.binding.haywardomnilogic/NOTICE
new file mode 100644
index 0000000000000..c5ec8e3e4864f
--- /dev/null
+++ b/bundles/org.openhab.binding.haywardomnilogic/NOTICE
@@ -0,0 +1,14 @@
+
+This content is produced and maintained by the openHAB project.
+
+* Project home: https://www.openhab.org
+
+== Declared Project Licenses
+
+This program and the accompanying materials are made available under the terms
+of the Eclipse Public License 2.0 which is available at
+https://www.eclipse.org/legal/epl-2.0/.
+
+== Source Code
+
+https://github.com/openhab/openhab-addons
\ No newline at end of file
diff --git a/bundles/org.openhab.binding.haywardomnilogic/README.md b/bundles/org.openhab.binding.haywardomnilogic/README.md
new file mode 100644
index 0000000000000..0d7fa6dc3470b
--- /dev/null
+++ b/bundles/org.openhab.binding.haywardomnilogic/README.md
@@ -0,0 +1,171 @@
+# Hayward Omnilogic Binding
+
+The Hayward Omnilogic binding integrates the Omnilogic pool controller using the Hayward API.
+
+The Hayward Omnilogic API interacts with Hayward's cloud server requiring a connection with the Internet for sending and receiving information.
+
+## Supported Things
+
+The table below lists the Hayward OmniLogic binding thing types:
+
+| Things | Description | Thing Type |
+|------------------------------|---------------------------------------------------------------------------------|---------------|
+| Hayward OmniLogix Connection | Connection to Hayward's Server | bridge |
+| Backyard | Backyard | backyard |
+| Body of Water | Body of Water | bow |
+| Chlorinator | Chlorinator | chlorinator |
+| Colorlogic Light | Colorlogic Light | colorlogic |
+| Filter | Filter control | filter |
+| Heater Equipment | Actual heater (i.e. gas, solar, electric) | heater |
+| Pump | Auxillary pump control (i.e. spillover) | pump |
+| Relay | Accessory relay control (deck jet sprinklers, lights, etc.) | relay |
+| Virtaul Heater | A Virtual Heater that can control all of the heater equipment based on priority | virtualHeater |
+
+## Discovery
+
+The binding will automatically discover the Omnilogic pool things from the cloud server using your Hayward Omnilogic credentials.
+
+## Thing Configuration
+
+Hayward OmniLogic Connection Parameters:
+
+| Property | Default | Required | Description |
+|----------------------|----------------------------------------------------------------|----------|----------------------------------------------|
+| Host Name | https://app1.haywardomnilogic.com/HAAPI/HomeAutomation/API.ash | Yes | Host name of the Hayward API server |
+| User Name | None | Yes | Your Hayward User Name (not email address) |
+| Password | None | Yes | Your Hayward User Password |
+| Telemetry Poll Delay | 12 | Yes | Telemetry Poll Delay (10-60 seconds) |
+| Alarm Poll Delay | 60 | Yes | Alarm Poll Delay (0-120 seconds, 0 disabled) |
+
+## Channels
+
+### Backyard Channels
+
+| backyardAirTemp | Number:Temperature | Backyard air temp sensor reading | R |
+|-----------------|--------------------|----------------------------------|:-:|
+| backyardStatus | String | Backyard status | R |
+| backyardState | String | Backyard state | R |
+| backyardAlarm1 | String | Backyard alarm #1 | R |
+| backyardAlarm2 | String | Backyard alarm #2 | R |
+| backyardAlarm3 | String | Backyard alarm #3 | R |
+| backyardAlarm4 | String | Backyard alarm #4 | R |
+| backyardAlarm5 | String | Backyard alarm #5 | R |
+
+### Body of Water Channels
+
+| Channel Type ID | Item Type | Description | Read Write |
+|-----------------|--------------------|------------------------------------|:----------:|
+| bowFlow | Switch | Body of Water flow sensor feedback | R |
+| bowWaterTemp | Number:Temperature | Body of Water temperature | R |
+
+### Chlorinator Channels
+
+| Channel Type ID | Item Type | Description | Read Write |
+|-----------------------|----------------------|----------------------------------------------------------|:----------:|
+| chlorEnable | Switch | Chlorinator enable | R/W |
+| chlorOperatingMode | String | Chlorinator operating mode | R |
+| chlorTimedPercent | Number:Dimensionless | Chlorinator timed percent | R/W |
+| chlorOperatingState | Number | Chlorinator operating state | R |
+| chlorScMode | String | Chlorinator super chlorinate mode | R |
+| chlorError | Number | Chlorinator error | R |
+| chlorAlert | String | Chlorinator alert | R |
+| chlorAvgSaltLevel | Number:Dimensionless | Chlorinator average salt level in Part per Million (ppm) | R |
+| chlorInstantSaltLevel | Number:Dimensionless | Chlorinator instant salt level in Part per Million (ppm) | R |
+| chlorStatus | Number | Chlorinator K1/K2 relay status | R |
+
+### Colorlogic Light Channels
+
+| Channel Type ID | Item Type | Description | Read Write |
+|----------------------------|-----------|-------------------------------|:----------:|
+| colorLogicLightEnable | Switch | Colorlogic Light enable | R/W |
+| colorLogicLightState | String | Colorlogic Light state | R |
+| colorLogicLightCurrentShow | String | Colorlogic Light current show | R/W |
+
+### Filter Channels
+
+| Channel Type ID | Item Type | Description | Read Write |
+|---------------------|----------------------|------------------------|:----------:|
+| filterEnable | Switch | Filter enable | R/W |
+| filterValvePosition | String | Filter valve position | R |
+| filterSpeed | Number:Dimensionless | Filter speed in % | R/W |
+| filterState | String | Filter state | R |
+| filterLastSpeed | Number:Dimensionless | Filter last speed in % | R |
+
+### Heater Channels
+
+| Channel Type ID | Item Type | Description | Read Write |
+|-----------------|-----------|---------------|:----------:|
+| heaterState | Number | Heater state | R |
+| heaterEnable | Switch | Heater enable | R |
+
+### Pump Channels
+
+| Channel Type ID | Item Type | Description | Read Write |
+|-----------------|----------------------|-----------------|:----------:|
+| pumpEnable | Switch | Pump enable | R |
+| pumpSpeed | Number:Dimensionless | Pump speed in % | R |
+
+### Relay Channels
+
+| Channel Type ID | Item Type | Description | Read Write |
+|-----------------|-----------|-------------|:----------:|
+| relayState | Switch | Relay state | R/W |
+
+### Virtual Heater Channels
+
+| Channel Type ID | Item Type | Description | Read Write |
+|-----------------------|--------------------|-------------------------|:----------:|
+| heaterEnable | Number | Heater enable | R |
+| heaterCurrentSetpoint | Number:Temperature | Heater Current Setpoint | R/W |
+
+## Full Example
+
+After installing the binding, you will need to manually add the Hayward Connection thing and enter your credentials.
+All pool items can be autmatically discovered by scanning the bridge
+Goto the inbox and add the things.
+
+### demo.items:
+
+```text
+Group gPool "Pool" ["Location"]
+
+Group gHaywardChlorinator "Hayward Chlorinator" (gPool) ["Equipment"]
+Switch HaywardChlorinator_Power "Power" (gHaywardChlorinator) ["Point"] { channel="haywardomnilogic:chlorinator:3766402f00:34:chlorEnable" }
+String HaywardChlorinator_OperatingMode "Operating Mode" (gHaywardChlorinator) ["Point"] { channel="haywardomnilogic:chlorinator:3766402f00:34:chlorOperatingMode" }
+Number:Dimensionless HaywardChlorinator_SaltOutput "Salt Output (%)" (gHaywardChlorinator) ["Point"] { channel="haywardomnilogic:chlorinator:3766402f00:34:chlorTimedPercent" }
+String HaywardChlorinator_scMode "scMode" (gHaywardChlorinator) ["Point"] { channel="haywardomnilogic:chlorinator:3766402f00:34:chlorScMode" }
+Number HaywardChlorinator_ChlorinatorError "Chlorinator Error" (gHaywardChlorinator) ["Point"] { channel="haywardomnilogic:chlorinator:3766402f00:34:chlorError" }
+String HaywardChlorinator_ChlorinatorAlert "Chlorinator Alert" (gHaywardChlorinator) ["Point"] { channel="haywardomnilogic:chlorinator:3766402f00:34:chlorAlert" }
+Number:Dimensionless HaywardChlorinator_AverageSaltLevel "Average Salt Level" (gHaywardChlorinator) ["Point"] { channel="haywardomnilogic:chlorinator:3766402f00:34:chlorAvgSaltLevel" }
+Number:Dimensionless HaywardChlorinator_InstantSaltLevel "Instant Salt Level" (gHaywardChlorinator) ["Point"] { channel="haywardomnilogic:chlorinator:3766402f00:34:chlorInstantSaltLevel" }
+Number HaywardChlorinator_Status "Status" (gHaywardChlorinator) ["Point"] { channel="haywardomnilogic:chlorinator:3766402f00:34:chlorStatus" }
+
+
+Group gHaywardBackyard "Hayward Backyard" (gPool) ["Equipment"]
+Number:Temperature HaywardBackyard_AirTemp "Air Temp" (gHaywardBackyard) ["Point"] { channel="haywardomnilogic:backyard:3766402f00:35940:backyardAirTemp" }
+String HaywardBackyard_Status "Status" (gHaywardBackyard) ["Point"] { channel="haywardomnilogic:backyard:3766402f00:35940:backyardStatus" }
+String HaywardBackyard_State "State" (gHaywardBackyard) ["Point"] { channel="haywardomnilogic:backyard:3766402f00:35940:backyardState" }
+String HaywardBackyard_BackyardAlarm1 "Alarm" (gHaywardBackyard) ["Point"] { channel="haywardomnilogic:backyard:3766402f00:35940:backyardAlarm1" }
+String HaywardBackyard_BackyardAlarm2 "Alarm" (gHaywardBackyard) ["Point"] { channel="haywardomnilogic:backyard:3766402f00:35940:backyardAlarm2" }
+String HaywardBackyard_BackyardAlarm3 "Alarm" (gHaywardBackyard) ["Point"] { channel="haywardomnilogic:backyard:3766402f00:35940:backyardAlarm3" }
+String HaywardBackyard_BackyardAlarm4 "Alarm" (gHaywardBackyard) ["Point"] { channel="haywardomnilogic:backyard:3766402f00:35940:backyardAlarm4" }
+String HaywardBackyard_BackyardAlarm5 "Alarm" (gHaywardBackyard) ["Point"] { channel="haywardomnilogic:backyard:3766402f00:35940:backyardAlarm5" }
+
+Group gHaywardGas "Hayward Gas" (gPool) ["Equipment"]
+Number HaywardGas_HeaterState "Heater State" (gHaywardGas) ["Point"] { channel="haywardomnilogic:heater:3766402f00:33:heaterState" }
+Switch HaywardGas_HeaterEnable "Heater Enable" (gHaywardGas) ["Point"] { channel="haywardomnilogic:heater:3766402f00:33:heaterEnable" }
+
+Group gHaywardJets "Hayward Jets" (gPool) ["Equipment"]
+Switch HaywardJets_Power "Power" (gHaywardJets) ["Point"] { channel="haywardomnilogic:relay:3766402f00:37:relayState" }
+
+Group gHaywardPool "Hayward Pool" (gPool) ["Equipment"]
+Switch HaywardPool_FlowSensor "Flow Sensor" (gHaywardPool) ["Point"] { channel="haywardomnilogic:bow:3766402f00:30:bowFlow" }
+Number:Temperature HaywardPool_WaterTemp "Water Temp" (gHaywardPool) ["Point"] { channel="haywardomnilogic:bow:3766402f00:30:bowWaterTemp" }
+
+Group gHaywardPoolLight "Hayward Pool Light" (gPool) ["Equipment"]
+Switch HaywardPoolLight_Power "Power" (gHaywardPoolLight) ["Point"] { channel="haywardomnilogic:colorlogic:3766402f00:38:colorLogicLightEnable" }
+String HaywardPoolLight_LightState "Light State" (gHaywardPoolLight) ["Point"] { channel="haywardomnilogic:colorlogic:3766402f00:38:colorLogicLightState" }
+String HaywardPoolLight_CurrentShow "Current Show" (gHaywardPoolLight) ["Point"] { channel="haywardomnilogic:colorlogic:3766402f00:38:colorLogicLightCurrentShow" }
+
+```
+
diff --git a/bundles/org.openhab.binding.haywardomnilogic/pom.xml b/bundles/org.openhab.binding.haywardomnilogic/pom.xml
new file mode 100644
index 0000000000000..68bb5c0031187
--- /dev/null
+++ b/bundles/org.openhab.binding.haywardomnilogic/pom.xml
@@ -0,0 +1,17 @@
+
+
+
+ 4.0.0
+
+
+ org.openhab.addons.bundles
+ org.openhab.addons.reactor.bundles
+ 3.1.0-SNAPSHOT
+
+
+ org.openhab.binding.haywardomnilogic
+
+ openHAB Add-ons :: Bundles :: Hayward OmniLogic Binding
+
+
diff --git a/bundles/org.openhab.binding.haywardomnilogic/src/main/java/org/openhab/binding/haywardomnilogic/internal/HaywardAccount.java b/bundles/org.openhab.binding.haywardomnilogic/src/main/java/org/openhab/binding/haywardomnilogic/internal/HaywardAccount.java
new file mode 100644
index 0000000000000..6b60270e8c6db
--- /dev/null
+++ b/bundles/org.openhab.binding.haywardomnilogic/src/main/java/org/openhab/binding/haywardomnilogic/internal/HaywardAccount.java
@@ -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 = "";
+}
diff --git a/bundles/org.openhab.binding.haywardomnilogic/src/main/java/org/openhab/binding/haywardomnilogic/internal/HaywardBindingConstants.java b/bundles/org.openhab.binding.haywardomnilogic/src/main/java/org/openhab/binding/haywardomnilogic/internal/HaywardBindingConstants.java
new file mode 100644
index 0000000000000..2346547e93e39
--- /dev/null
+++ b/bundles/org.openhab.binding.haywardomnilogic/src/main/java/org/openhab/binding/haywardomnilogic/internal/HaywardBindingConstants.java
@@ -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 BRIDGE_THING_TYPES_UIDS = Set.of(THING_TYPE_BRIDGE);
+
+ public static final Set 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 = "";
+
+ public static final String COMMAND_SCHEDULE = "false"
+ + "0"
+ + "0"
+ + "0"
+ + "0"
+ + "0"
+ + "false";
+}
diff --git a/bundles/org.openhab.binding.haywardomnilogic/src/main/java/org/openhab/binding/haywardomnilogic/internal/HaywardException.java b/bundles/org.openhab.binding.haywardomnilogic/src/main/java/org/openhab/binding/haywardomnilogic/internal/HaywardException.java
new file mode 100644
index 0000000000000..4553a4c22ac2a
--- /dev/null
+++ b/bundles/org.openhab.binding.haywardomnilogic/src/main/java/org/openhab/binding/haywardomnilogic/internal/HaywardException.java
@@ -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);
+ }
+}
diff --git a/bundles/org.openhab.binding.haywardomnilogic/src/main/java/org/openhab/binding/haywardomnilogic/internal/HaywardHandlerFactory.java b/bundles/org.openhab.binding.haywardomnilogic/src/main/java/org/openhab/binding/haywardomnilogic/internal/HaywardHandlerFactory.java
new file mode 100644
index 0000000000000..cba37b0749df3
--- /dev/null
+++ b/bundles/org.openhab.binding.haywardomnilogic/src/main/java/org/openhab/binding/haywardomnilogic/internal/HaywardHandlerFactory.java
@@ -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 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;
+ }
+}
diff --git a/bundles/org.openhab.binding.haywardomnilogic/src/main/java/org/openhab/binding/haywardomnilogic/internal/HaywardThingHandler.java b/bundles/org.openhab.binding.haywardomnilogic/src/main/java/org/openhab/binding/haywardomnilogic/internal/HaywardThingHandler.java
new file mode 100644
index 0000000000000..89f311fccffeb
--- /dev/null
+++ b/bundles/org.openhab.binding.haywardomnilogic/src/main/java/org/openhab/binding/haywardomnilogic/internal/HaywardThingHandler.java
@@ -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);
+ }
+ }
+ }
+}
diff --git a/bundles/org.openhab.binding.haywardomnilogic/src/main/java/org/openhab/binding/haywardomnilogic/internal/HaywardThingProperties.java b/bundles/org.openhab.binding.haywardomnilogic/src/main/java/org/openhab/binding/haywardomnilogic/internal/HaywardThingProperties.java
new file mode 100644
index 0000000000000..06692f98bf43d
--- /dev/null
+++ b/bundles/org.openhab.binding.haywardomnilogic/src/main/java/org/openhab/binding/haywardomnilogic/internal/HaywardThingProperties.java
@@ -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 = "";
+}
diff --git a/bundles/org.openhab.binding.haywardomnilogic/src/main/java/org/openhab/binding/haywardomnilogic/internal/HaywardTypeToRequest.java b/bundles/org.openhab.binding.haywardomnilogic/src/main/java/org/openhab/binding/haywardomnilogic/internal/HaywardTypeToRequest.java
new file mode 100644
index 0000000000000..6eaff765e2472
--- /dev/null
+++ b/bundles/org.openhab.binding.haywardomnilogic/src/main/java/org/openhab/binding/haywardomnilogic/internal/HaywardTypeToRequest.java
@@ -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
+}
diff --git a/bundles/org.openhab.binding.haywardomnilogic/src/main/java/org/openhab/binding/haywardomnilogic/internal/config/HaywardConfig.java b/bundles/org.openhab.binding.haywardomnilogic/src/main/java/org/openhab/binding/haywardomnilogic/internal/config/HaywardConfig.java
new file mode 100644
index 0000000000000..8b8a749018b06
--- /dev/null
+++ b/bundles/org.openhab.binding.haywardomnilogic/src/main/java/org/openhab/binding/haywardomnilogic/internal/config/HaywardConfig.java
@@ -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;
+}
diff --git a/bundles/org.openhab.binding.haywardomnilogic/src/main/java/org/openhab/binding/haywardomnilogic/internal/discovery/HaywardDiscoveryService.java b/bundles/org.openhab.binding.haywardomnilogic/src/main/java/org/openhab/binding/haywardomnilogic/internal/discovery/HaywardDiscoveryService.java
new file mode 100644
index 0000000000000..93fe883f06b16
--- /dev/null
+++ b/bundles/org.openhab.binding.haywardomnilogic/src/main/java/org/openhab/binding/haywardomnilogic/internal/discovery/HaywardDiscoveryService.java
@@ -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 systemIDs = new ArrayList<>();
+ List names = new ArrayList<>();
+ Map backyardProperties = new HashMap<>();
+ Map 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 filterProperty1 = bridgehandler.evaluateXPath("//Filter/Min-Pump-Speed/text()", xmlResponse);
+ final List filterProperty2 = bridgehandler.evaluateXPath("//Filter/Max-Pump-Speed/text()", xmlResponse);
+ final List filterProperty3 = bridgehandler.evaluateXPath("//Filter/Min-Pump-RPM/text()", xmlResponse);
+ final List 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 pumpProperty1 = bridgehandler.evaluateXPath("//Pump/Min-Pump-Speed/text()", xmlResponse);
+ final List pumpProperty2 = bridgehandler.evaluateXPath("//Pump/Max-Pump-Speed/text()", xmlResponse);
+ final List pumpProperty3 = bridgehandler.evaluateXPath("//Pump/Min-Pump-RPM/text()", xmlResponse);
+ final List 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";
+
+ // *****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);
+ }
+ }
+ }
+}
diff --git a/bundles/org.openhab.binding.haywardomnilogic/src/main/java/org/openhab/binding/haywardomnilogic/internal/handler/HaywardColorLogicHandler.java b/bundles/org.openhab.binding.haywardomnilogic/src/main/java/org/openhab/binding/haywardomnilogic/internal/handler/HaywardColorLogicHandler.java
new file mode 100644
index 0000000000000..bb42b06eb97c1
--- /dev/null
+++ b/bundles/org.openhab.binding.haywardomnilogic/src/main/java/org/openhab/binding/haywardomnilogic/internal/handler/HaywardColorLogicHandler.java
@@ -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 systemIDs = new ArrayList<>();
+ List 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
+ + "SetUIEquipmentCmd"
+ + "" + bridgehandler.account.token
+ + "" + ""
+ + bridgehandler.account.mspSystemID + ""
+ + "" + poolID + ""
+ + "" + systemID + ""
+ + "" + cmdString + ""
+ + HaywardBindingConstants.COMMAND_SCHEDULE + "";
+ break;
+ case HaywardBindingConstants.CHANNEL_COLORLOGIC_CURRENTSHOW:
+ cmdURL = HaywardBindingConstants.COMMAND_PARAMETERS
+ + "SetStandAloneLightShow"
+ + "" + bridgehandler.account.token
+ + "" + ""
+ + bridgehandler.account.mspSystemID + ""
+ + "" + poolID + ""
+ + "" + systemID + ""
+ + "" + cmdString + ""
+ + "4"
+ + "4"
+ + "0"
+ + HaywardBindingConstants.COMMAND_SCHEDULE + "";
+ 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);
+ }
+ }
+ }
+}
diff --git a/bundles/org.openhab.binding.haywardomnilogic/src/main/java/org/openhab/binding/haywardomnilogic/internal/handler/HaywardFilterHandler.java b/bundles/org.openhab.binding.haywardomnilogic/src/main/java/org/openhab/binding/haywardomnilogic/internal/handler/HaywardFilterHandler.java
new file mode 100644
index 0000000000000..b39740cd8d38d
--- /dev/null
+++ b/bundles/org.openhab.binding.haywardomnilogic/src/main/java/org/openhab/binding/haywardomnilogic/internal/handler/HaywardFilterHandler.java
@@ -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 systemIDs = new ArrayList<>();
+ List 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
+ + "SetUIEquipmentCmd"
+ + "" + bridgehandler.account.token
+ + "" + ""
+ + bridgehandler.account.mspSystemID + ""
+ + "" + poolID + ""
+ + "" + systemID + ""
+ + "" + cmdString + ""
+ + HaywardBindingConstants.COMMAND_SCHEDULE + "";
+
+ // *****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);
+ }
+ }
+ }
+}
diff --git a/bundles/org.openhab.binding.haywardomnilogic/src/main/java/org/openhab/binding/haywardomnilogic/internal/handler/HaywardHeaterHandler.java b/bundles/org.openhab.binding.haywardomnilogic/src/main/java/org/openhab/binding/haywardomnilogic/internal/handler/HaywardHeaterHandler.java
new file mode 100644
index 0000000000000..bf469f0fa92fc
--- /dev/null
+++ b/bundles/org.openhab.binding.haywardomnilogic/src/main/java/org/openhab/binding/haywardomnilogic/internal/handler/HaywardHeaterHandler.java
@@ -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 systemIDs = new ArrayList<>();
+ List 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);
+ }
+ }
+ }
+}
diff --git a/bundles/org.openhab.binding.haywardomnilogic/src/main/java/org/openhab/binding/haywardomnilogic/internal/handler/HaywardRelayHandler.java b/bundles/org.openhab.binding.haywardomnilogic/src/main/java/org/openhab/binding/haywardomnilogic/internal/handler/HaywardRelayHandler.java
new file mode 100644
index 0000000000000..f890cd8e708c2
--- /dev/null
+++ b/bundles/org.openhab.binding.haywardomnilogic/src/main/java/org/openhab/binding/haywardomnilogic/internal/handler/HaywardRelayHandler.java
@@ -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 systemIDs = new ArrayList<>();
+ List 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
+ + "SetUIEquipmentCmd"
+ + "" + bridgehandler.account.token
+ + "" + ""
+ + bridgehandler.account.mspSystemID + ""
+ + "" + poolID + ""
+ + "" + systemID + ""
+ + "" + cmdString + ""
+ + HaywardBindingConstants.COMMAND_SCHEDULE + "";
+ 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);
+ }
+ }
+ }
+}
diff --git a/bundles/org.openhab.binding.haywardomnilogic/src/main/java/org/openhab/binding/haywardomnilogic/internal/handler/HaywardSensorHandler.java b/bundles/org.openhab.binding.haywardomnilogic/src/main/java/org/openhab/binding/haywardomnilogic/internal/handler/HaywardSensorHandler.java
new file mode 100644
index 0000000000000..a811e69607995
--- /dev/null
+++ b/bundles/org.openhab.binding.haywardomnilogic/src/main/java/org/openhab/binding/haywardomnilogic/internal/handler/HaywardSensorHandler.java
@@ -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 systemIDs = new ArrayList<>();
+ List 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);
+ }
+ }
+ }
+}
diff --git a/bundles/org.openhab.binding.haywardomnilogic/src/main/java/org/openhab/binding/haywardomnilogic/internal/handler/HaywardVirtualHeaterHandler.java b/bundles/org.openhab.binding.haywardomnilogic/src/main/java/org/openhab/binding/haywardomnilogic/internal/handler/HaywardVirtualHeaterHandler.java
new file mode 100644
index 0000000000000..6ee8246a85628
--- /dev/null
+++ b/bundles/org.openhab.binding.haywardomnilogic/src/main/java/org/openhab/binding/haywardomnilogic/internal/handler/HaywardVirtualHeaterHandler.java
@@ -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 systemIDs = new ArrayList<>();
+ List 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
+ + "SetHeaterEnable"
+ + "" + bridgehandler.account.token
+ + "" + ""
+ + bridgehandler.account.mspSystemID + ""
+ + "" + poolID + ""
+ + "" + systemID + ""
+ + "" + cmdString + ""
+ + "";
+ break;
+
+ case HaywardBindingConstants.CHANNEL_VIRTUALHEATER_CURRENTSETPOINT:
+ cmdURL = HaywardBindingConstants.COMMAND_PARAMETERS
+ + "SetUIHeaterCmd"
+ + "" + bridgehandler.account.token
+ + "" + ""
+ + bridgehandler.account.mspSystemID + ""
+ + "" + poolID + ""
+ + "" + systemID + ""
+ + "" + cmdString + ""
+ + "";
+ 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);
+ }
+ }
+ }
+}
diff --git a/bundles/org.openhab.binding.haywardomnilogic/src/main/resources/OH-INF/binding/binding.xml b/bundles/org.openhab.binding.haywardomnilogic/src/main/resources/OH-INF/binding/binding.xml
new file mode 100644
index 0000000000000..2c6eab0bf76a9
--- /dev/null
+++ b/bundles/org.openhab.binding.haywardomnilogic/src/main/resources/OH-INF/binding/binding.xml
@@ -0,0 +1,9 @@
+
+
+
+ Hayward OmniLogix Binding
+ Binding for the Hayward OmniLogix swimming pool automation controller.
+ Matt Myers
+
diff --git a/bundles/org.openhab.binding.haywardomnilogic/src/main/resources/OH-INF/thing/backyard.xml b/bundles/org.openhab.binding.haywardomnilogic/src/main/resources/OH-INF/thing/backyard.xml
new file mode 100644
index 0000000000000..c947bc3077633
--- /dev/null
+++ b/bundles/org.openhab.binding.haywardomnilogic/src/main/resources/OH-INF/thing/backyard.xml
@@ -0,0 +1,76 @@
+
+
+
+
+
+
+
+
+
+ The Hayward Backyard
+
+
+
+
+
+
+
+
+
+
+
+
+ Hayward
+
+ systemID
+
+
+
+
+ Number:Temperature
+
+ Air Temp
+
+
+
+
+ String
+
+ Status
+
+
+
+
+
+
+
+
+
+
+
+
+ String
+
+ State
+
+
+
+
+
+
+
+
+
+
+
+
+ String
+
+ Alarm
+
+
+
+
diff --git a/bundles/org.openhab.binding.haywardomnilogic/src/main/resources/OH-INF/thing/bow.xml b/bundles/org.openhab.binding.haywardomnilogic/src/main/resources/OH-INF/thing/bow.xml
new file mode 100644
index 0000000000000..aa594741bb4c3
--- /dev/null
+++ b/bundles/org.openhab.binding.haywardomnilogic/src/main/resources/OH-INF/thing/bow.xml
@@ -0,0 +1,40 @@
+
+
+
+
+
+
+
+
+
+ The Hayward Body of Water
+
+
+
+
+
+
+ Hayward
+
+ systemID
+
+
+
+
+ system.power
+
+ Flow Sensor
+
+
+
+
+ Number:Temperature
+
+ Water Temp
+
+
+
+
diff --git a/bundles/org.openhab.binding.haywardomnilogic/src/main/resources/OH-INF/thing/bridge.xml b/bundles/org.openhab.binding.haywardomnilogic/src/main/resources/OH-INF/thing/bridge.xml
new file mode 100644
index 0000000000000..1b5c8f9534bfd
--- /dev/null
+++ b/bundles/org.openhab.binding.haywardomnilogic/src/main/resources/OH-INF/thing/bridge.xml
@@ -0,0 +1,40 @@
+
+
+
+
+
+
+ Connection to Hayward's Server
+
+
+
+ url
+
+ https://app1.haywardomnilogic.com/HAAPI/HomeAutomation/API.ashx
+ The URL of the Hayward API Server
+
+
+
+ The username to connect to the server.
+
+
+ password
+
+ The password to connect to the server.
+
+
+
+ 12
+ How often to request telemetry data from Hayward Server
+
+
+
+ 60
+ How often to request alarm data from Hayward Server. Enter 0 to disable.
+
+
+
+
diff --git a/bundles/org.openhab.binding.haywardomnilogic/src/main/resources/OH-INF/thing/chlorinator.xml b/bundles/org.openhab.binding.haywardomnilogic/src/main/resources/OH-INF/thing/chlorinator.xml
new file mode 100644
index 0000000000000..4b77e92ca29a3
--- /dev/null
+++ b/bundles/org.openhab.binding.haywardomnilogic/src/main/resources/OH-INF/thing/chlorinator.xml
@@ -0,0 +1,103 @@
+
+
+
+
+
+
+
+
+
+ Chlorinator
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Hayward
+
+ systemID
+
+
+
+
+ String
+
+ Operating Mode
+
+
+
+
+
+
+
+
+
+
+ Number:Dimensionless
+
+ Current salt output setting for the chlorinator (%).
+
+
+
+
+ String
+
+ scMode
+
+
+
+
+
+
+
+
+
+ Number
+
+
+
+
+
+ String
+
+ Chlorinator Alert
+
+
+
+
+
+
+
+
+
+ Number:Dimensionless
+
+ Average Salt Level
+
+
+
+
+ Number:Dimensionless
+
+ Instant Salt Level
+
+
+
+
+ Number
+
+ Status
+
+
+
diff --git a/bundles/org.openhab.binding.haywardomnilogic/src/main/resources/OH-INF/thing/colorlogic.xml b/bundles/org.openhab.binding.haywardomnilogic/src/main/resources/OH-INF/thing/colorlogic.xml
new file mode 100644
index 0000000000000..25d882eb2445f
--- /dev/null
+++ b/bundles/org.openhab.binding.haywardomnilogic/src/main/resources/OH-INF/thing/colorlogic.xml
@@ -0,0 +1,67 @@
+
+
+
+
+
+
+
+
+
+ Color Logic Light
+
+
+
+
+
+
+
+ Hayward
+
+ systemID
+
+
+
+
+ String
+
+ Light State
+
+
+
+
+
+
+
+
+
+
+
+ String
+
+ Current Show
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/bundles/org.openhab.binding.haywardomnilogic/src/main/resources/OH-INF/thing/filter.xml b/bundles/org.openhab.binding.haywardomnilogic/src/main/resources/OH-INF/thing/filter.xml
new file mode 100644
index 0000000000000..00529184bb7f9
--- /dev/null
+++ b/bundles/org.openhab.binding.haywardomnilogic/src/main/resources/OH-INF/thing/filter.xml
@@ -0,0 +1,83 @@
+
+
+
+
+
+
+
+
+
+ Filter Equipment
+
+
+
+
+
+
+
+
+
+ Hayward
+
+
+
+
+
+ systemID
+
+
+
+
+ String
+
+ Valve Position
+
+
+
+
+
+
+
+
+
+
+
+ Number:Dimensionless
+
+ Filter Speed in %
+
+
+
+
+ String
+
+ Filter State
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Number:Dimensionless
+
+ Last Speed
+
+
+
+
diff --git a/bundles/org.openhab.binding.haywardomnilogic/src/main/resources/OH-INF/thing/heater.xml b/bundles/org.openhab.binding.haywardomnilogic/src/main/resources/OH-INF/thing/heater.xml
new file mode 100644
index 0000000000000..960d9a9f72046
--- /dev/null
+++ b/bundles/org.openhab.binding.haywardomnilogic/src/main/resources/OH-INF/thing/heater.xml
@@ -0,0 +1,39 @@
+
+
+
+
+
+
+
+
+
+ Heater
+
+
+
+
+
+
+ Hayward
+
+ systemID
+
+
+
+ Number
+
+ Heater State
+
+
+
+
+ system.power
+
+ Heater Enable
+
+
+
+
diff --git a/bundles/org.openhab.binding.haywardomnilogic/src/main/resources/OH-INF/thing/pump.xml b/bundles/org.openhab.binding.haywardomnilogic/src/main/resources/OH-INF/thing/pump.xml
new file mode 100644
index 0000000000000..16f1a094b6e20
--- /dev/null
+++ b/bundles/org.openhab.binding.haywardomnilogic/src/main/resources/OH-INF/thing/pump.xml
@@ -0,0 +1,37 @@
+
+
+
+
+
+
+
+
+
+ Pump
+
+
+
+
+
+
+ Hayward
+
+
+
+
+
+ systemID
+
+
+
+
+ Number:Dimensionless
+
+ Pump Speed
+
+
+
+
diff --git a/bundles/org.openhab.binding.haywardomnilogic/src/main/resources/OH-INF/thing/relay.xml b/bundles/org.openhab.binding.haywardomnilogic/src/main/resources/OH-INF/thing/relay.xml
new file mode 100644
index 0000000000000..5c2b70e3b304a
--- /dev/null
+++ b/bundles/org.openhab.binding.haywardomnilogic/src/main/resources/OH-INF/thing/relay.xml
@@ -0,0 +1,25 @@
+
+
+
+
+
+
+
+
+
+ Relay
+
+
+
+
+
+ Hayward
+
+ systemID
+
+
+
+
diff --git a/bundles/org.openhab.binding.haywardomnilogic/src/main/resources/OH-INF/thing/sensor.xml b/bundles/org.openhab.binding.haywardomnilogic/src/main/resources/OH-INF/thing/sensor.xml
new file mode 100644
index 0000000000000..d33fc562a7064
--- /dev/null
+++ b/bundles/org.openhab.binding.haywardomnilogic/src/main/resources/OH-INF/thing/sensor.xml
@@ -0,0 +1,39 @@
+
+
+
+
+
+
+
+
+
+ Sensor
+
+
+
+
+
+ Hayward
+
+ systemID
+
+
+
+
+ Number
+
+ The Body of Water ID
+
+
+
+
+ Number
+
+ Sensor Data
+
+
+
+
diff --git a/bundles/org.openhab.binding.haywardomnilogic/src/main/resources/OH-INF/thing/virtualHeater.xml b/bundles/org.openhab.binding.haywardomnilogic/src/main/resources/OH-INF/thing/virtualHeater.xml
new file mode 100644
index 0000000000000..89d7d410c17ed
--- /dev/null
+++ b/bundles/org.openhab.binding.haywardomnilogic/src/main/resources/OH-INF/thing/virtualHeater.xml
@@ -0,0 +1,34 @@
+
+
+
+
+
+
+
+
+
+ Virtual Heater
+
+
+
+
+
+
+
+ Hayward
+
+ systemID
+
+
+
+ Number:Temperature
+
+ Current Setpoint
+ Temperature
+
+
+
+
diff --git a/bundles/pom.xml b/bundles/pom.xml
index 087005fe3c82d..13f4e56e17d3f 100644
--- a/bundles/pom.xml
+++ b/bundles/pom.xml
@@ -122,6 +122,7 @@
org.openhab.binding.gree
org.openhab.binding.groheondus
org.openhab.binding.harmonyhub
+ org.openhab.binding.haywardomnilogic
org.openhab.binding.hdanywhere
org.openhab.binding.hdpowerview
org.openhab.binding.helios