/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
<artifactId>org.openhab.binding.harmonyhub</artifactId>
<version>${project.version}</version>
</dependency>
+ <dependency>
+ <groupId>org.openhab.addons.bundles</groupId>
+ <artifactId>org.openhab.binding.haywardomnilogic</artifactId>
+ <version>${project.version}</version>
+ </dependency>
<dependency>
<groupId>org.openhab.addons.bundles</groupId>
<artifactId>org.openhab.binding.hdanywhere</artifactId>
--- /dev/null
+
+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
--- /dev/null
+# 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" }
+
+```
+
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+
+ <modelVersion>4.0.0</modelVersion>
+
+ <parent>
+ <groupId>org.openhab.addons.bundles</groupId>
+ <artifactId>org.openhab.addons.reactor.bundles</artifactId>
+ <version>3.1.0-SNAPSHOT</version>
+ </parent>
+
+ <artifactId>org.openhab.binding.haywardomnilogic</artifactId>
+
+ <name>openHAB Add-ons :: Bundles :: Hayward OmniLogic Binding</name>
+
+</project>
--- /dev/null
+/**
+ * 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 = "";
+}
--- /dev/null
+/**
+ * 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>";
+}
--- /dev/null
+/**
+ * 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);
+ }
+}
--- /dev/null
+/**
+ * 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;
+ }
+}
--- /dev/null
+/**
+ * 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);
+ }
+ }
+ }
+}
--- /dev/null
+/**
+ * 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 = "";
+}
--- /dev/null
+/**
+ * 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
+}
--- /dev/null
+/**
+ * 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;
+}
--- /dev/null
+/**
+ * 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;
+ }
+}
--- /dev/null
+/**
+ * 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;
+ }
+ }
+}
--- /dev/null
+/**
+ * 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);
+ }
+ }
+ }
+}
--- /dev/null
+/**
+ * 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;
+ }
+ }
+}
--- /dev/null
+/**
+ * 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);
+ }
+ }
+ }
+}
--- /dev/null
+/**
+ * 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);
+ }
+ }
+ }
+}
--- /dev/null
+/**
+ * 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);
+ }
+ }
+ }
+}
--- /dev/null
+/**
+ * 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);
+ }
+ }
+ }
+}
--- /dev/null
+/**
+ * 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);
+ }
+ }
+ }
+}
--- /dev/null
+/**
+ * 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);
+ }
+ }
+ }
+}
--- /dev/null
+/**
+ * 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);
+ }
+ }
+ }
+}
--- /dev/null
+<?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>
--- /dev/null
+<?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>
--- /dev/null
+<?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>
--- /dev/null
+<?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>
--- /dev/null
+<?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>
--- /dev/null
+<?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>
--- /dev/null
+<?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>
--- /dev/null
+<?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>
--- /dev/null
+<?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>
--- /dev/null
+<?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>
--- /dev/null
+<?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>
--- /dev/null
+<?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>
<module>org.openhab.binding.gree</module>
<module>org.openhab.binding.groheondus</module>
<module>org.openhab.binding.harmonyhub</module>
+ <module>org.openhab.binding.haywardomnilogic</module>
<module>org.openhab.binding.hdanywhere</module>
<module>org.openhab.binding.hdpowerview</module>
<module>org.openhab.binding.helios</module>