First post here and first attempt at developing a binding. Thank you in advance for reading. The binding is for my swimming pool automation and communicates with the manufacturer’s server to pull back config and status data via XML files. I have the XML decoding tucked away in the connection class, but need to call the a public interface/listener in the discovery service to add things. Maybe this isn’t the correct approach as the XML data comes right back and I don’t really need a call back, but is the only method I’m finding in the bindings I’ve examined. The issue I’m pulling my hair out over is as follows:
In the Bridgehandler initialize routine I’m attempting to add a listener with the following call:
connection.addHaywardHandlerListener(this);
but receive the following error…
The method addHaywardHandlerListener(HaywardHandlerListener) in the type HaywardOmniLogixConnection is not applicable for the arguments (HaywardOmniLogixBridgeHandler)
Out of all of the example bindings I’ve reviewed, I just can’t seem to find out what I’m doing different that is causing the error.
package org.openhab.binding.haywardomnilogix.internal.handler;
/**
* The {@link HaywardHandlerListener} is notified when a light status has changed or a light has been removed or added.
*
* @author Matt Myers - Initial contribution
*/
// @NonNullByDefault
public interface HaywardHandlerListener {
void onFilterDiscovered(int systemID, String label);
void onHeaterDiscovered(int systemID, String label);
}
/**
* Copyright (c) 2014-2017 by the respective copyright holders.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*/
package org.openhab.binding.haywardomnilogix.internal.handler;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import org.eclipse.smarthome.core.thing.ChannelUID;
import org.eclipse.smarthome.core.thing.Bridge;
import org.eclipse.smarthome.core.thing.Thing;
import org.eclipse.smarthome.core.thing.ThingStatus;
import org.eclipse.smarthome.core.thing.ThingStatusDetail;
import org.eclipse.smarthome.core.thing.binding.BaseBridgeHandler;
import org.eclipse.smarthome.core.types.Command;
import org.openhab.binding.haywardomnilogix.internal.HaywardOmniLogixBindingConstants;
import org.openhab.binding.haywardomnilogix.internal.config.HaywardOmniLogixConfig;
import org.openhab.binding.haywardomnilogix.internal.hayward.HaywardOmniLogixConnection;
import org.openhab.binding.haywardomnilogix.internal.hayward.HaywardTypeToRequest;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* The {@link ElkM1BridgeHandler} is responsible for handling commands, which are
* sent to one of the channels.
*
* @author Matt Myers - Initial contribution
*/
public class HaywardOmniLogixBridgeHandler extends BaseBridgeHandler {
private final Logger logger = LoggerFactory.getLogger(HaywardOmniLogixBridgeHandler.class);
private List<HaywardHandlerListener> listeners = new ArrayList<HaywardHandlerListener>();
private HaywardOmniLogixConnection connection;
public HaywardOmniLogixBridgeHandler(Bridge thing) {
super(thing);
}
@Override
public void handleCommand(ChannelUID channelUID, Command command) {
// Needed to instantiate class
}
/**
* Initialize the bridge to do stuff.
*/
@Override
public void initialize() {
// Long running initialization should be done asynchronously in background.
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_PENDING,
"Opening connection to Hayward's Server");
// Load up the config and then get the connection to Hayward setup.
// messageFactory = new ElkMessageFactory();
HaywardOmniLogixConfig config = getConfigAs(HaywardOmniLogixConfig.class);
connection = new HaywardOmniLogixConnection(config);
connection.addHaywardHandlerListener(this);
if (connection.initialize()) {
// TODO Need to return pass/fail
connection.getConfig();
updateStatus(ThingStatus.ONLINE, ThingStatusDetail.CONFIGURATION_PENDING, "Logged into Hayward server");
} else {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
"Unable to open connection to Hayward's server");
}
}
/**
* Copyright (c) 2014-2017 by the respective copyright holders.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*/
package org.openhab.binding.haywardomnilogix.internal.hayward;
import java.io.StringReader;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;
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.haywardomnilogix.internal.config.HaywardOmniLogixConfig;
import org.openhab.binding.haywardomnilogix.internal.handler.HaywardHandlerListener;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;
/**
* The connection to the Hayward server.
*
* @author Matt Myers
*/
public class HaywardOmniLogixConnection {
private final HaywardOmniLogixConfig config;
private final Logger logger = LoggerFactory.getLogger(HaywardOmniLogixConnection.class);
private HttpClient httpClient = new HttpClient();
private List<HaywardHandlerListener> listeners = new ArrayList<HaywardHandlerListener>();
// private HaywardOmniLogixBridgeHandler bridge;
/**
* Create the connection to the server.
*
* @param config The configuration of the Hayward connection
*/
public HaywardOmniLogixConnection(HaywardOmniLogixConfig config) {
this.config = config;
// this.response = response;
}
/**
* Adds the elk listener into the list of things listening for messages.
*/
public void addHaywardHandlerListener(HaywardHandlerListener listener) {
synchronized (listeners) {
listeners.add(listener);
}
}
public void removeHaywardHandlerListener(HaywardHandlerListener listener) {
synchronized (listeners) {
listeners.remove(listener);
}
}
/**
* Initializes the connection
*
* @return true if successfully initialized.
*/
public boolean initialize() {
String xmlStr;
String status;
String statusMessage;
try {
// *****Login to Hayward server
String url = "http://209.114.50.126/MobileInterface/MobileInterface.ashx";
String urlParameters = "<?xml version=\"1.0\" encoding=\"utf-8\"?><Request xmlns=\"http://nextgen.hayward.com/api\"><Name>Login</Name><Paramenters><Parameter name=\"UserName\" dataType=\"String\">"
+ config.username + "</Parameter><Parameter name=\"Password\" dataType=\"String\">"
+ config.password + "</Parameter></Paramenters></Request>";
xmlStr = httpXmlResponse(url, urlParameters);
status = (evaluateXPath("/Response/Parameters//Parameter[@name='Status']/text()", xmlStr)).get(0);
statusMessage = (evaluateXPath("/Response/Parameters//Parameter[@name='StatusMessage']/text()", xmlStr))
.get(0);
if (status.equals("0")) {
// System.out.println(evaluateXPath("/Response/Parameters//Parameter[@name='Status']/text()", xmlStr));
config.token = (evaluateXPath("/Response/Parameters//Parameter[@name='Token']/text()", xmlStr)).get(0);
config.UserID = (evaluateXPath("/Response/Parameters//Parameter[@name='UserID']/text()", xmlStr))
.get(0);
config.firstName = (evaluateXPath("/Response/Parameters//Parameter[@name='Firstname']/text()", xmlStr))
.get(0);
config.lastName = (evaluateXPath("/Response/Parameters//Parameter[@name='Lastname']/text()", xmlStr))
.get(0);
config.roleType = (evaluateXPath("/Response/Parameters//Parameter[@name='RoleType']/text()", xmlStr))
.get(0);
} else {
logger.info("Login response: {}", statusMessage);
return false;
}
// *****Get MSP
url = "http://209.114.50.126/MobileInterface/MobileInterface.ashx";
urlParameters = "<?xml version=\"1.0\" encoding=\"utf-8\"?><Request xmlns=\"http://nextgen.hayward.com/api\"><Name>GetMspList</Name><Paramenters>"
+ "<Parameter name=\"Token\" dataType=\"String\">" + config.token
+ "</Parameter><Parameter name=\"OwnerID\" dataType=\"String\">" + config.UserID
+ "</Parameter></Paramenters></Request>";
xmlStr = httpXmlResponse(url, urlParameters);
status = (evaluateXPath("/Response/Parameters//Parameter[@name='Status']/text()", xmlStr)).get(0);
statusMessage = (evaluateXPath("/Response/Parameters//Parameter[@name='StatusMessage']/text()", xmlStr))
.get(0);
if (status.equals("0")) {
config.mspSystemID = (evaluateXPath(
"/Response/Parameters/Parameter/Item//Property[@name='MspSystemID']/text()", xmlStr)).get(0);
config.backyardName = (evaluateXPath(
"/Response/Parameters/Parameter/Item//Property[@name='BackyardName']/text()", xmlStr)).get(0);
config.address = (evaluateXPath("/Response/Parameters/Parameter/Item//Property[@name='Address']/text()",
xmlStr)).get(0);
} else {
logger.info("Login response: {}", statusMessage);
return false;
}
} catch (Exception e) {
logger.error("Unable to open connection to Hayward's server {}:{}", config.hostname, config.username, e);
return false;
}
return true;
}
public boolean getConfig() {
String status;
String statusMessage;
String xmlResponse;
List<String> systemIDs = new ArrayList<>();
try {
// *****Login to Hayward server
String url = "http://209.114.50.126/MobileInterface/MobileInterface.ashx";
String urlParameters = "<?xml version=\"1.0\" encoding=\"utf-8\"?><Request xmlns=\"http://nextgen.hayward.com/api\"><Name>RequestConfiguration</Name><Paramenters>"
+ "<Parameter name=\"Token\" dataType=\"String\">" + config.token + "</Parameter>"
+ "<Parameter name=\"MspSystemID\" dataType=\"int\">" + config.mspSystemID
+ "</Parameter></Paramenters></Request>";
xmlResponse = httpXmlResponse(url, urlParameters);
if (xmlResponse.length() > 0) {
systemIDs = (evaluateXPath("/MSPConfig/Backyard/Body-of-water/System-Id/text()", xmlResponse));
for (int i = 0; i < systemIDs.size(); i++) {
systemIDs.get(i);
// Once we have a description, see if this zone exists.
// Thing thing = thing.getThingForType("BOW", 31);
// if (thing == null) {
for (HaywardHandlerListener listener : this.listeners) {
listener.onFilterDiscovered(32, "Test 32");
}
HaywardOmniLogixDiscoveryHandler.
// }
}
System.out.println(
evaluateXPath("/MSPConfig/Backyard/Body-of-water/Filter/System-Id/text()", xmlResponse));
System.out.println(
evaluateXPath("/MSPConfig/Backyard/Body-of-water/Heater/System-Id/text()", xmlResponse));
System.out.println(
evaluateXPath("/MSPConfig/Backyard/Body-of-water/Chlorinator/System-Id/text()", xmlResponse));
System.out.println(
evaluateXPath("/MSPConfig/Backyard/Body-of-water/Relay/System-Id/text()", xmlResponse));
System.out.println(evaluateXPath("/MSPConfig/Backyard/Body-of-water/ColorLogic-Light/System-Id/text()",
xmlResponse));
System.out.println(
evaluateXPath("/MSPConfig/Backyard/Body-of-water/Sensor/System-Id/text()", xmlResponse));
} else
{
logger.info("GetMsp Returned null");
return false;
}
} catch (Exception e) {
logger.error("Unable to open connection to Hayward's server {}:{}", config.hostname, config.username, e);
return false;
}
return true;
}
private static List<String> evaluateXPath(String xpathExp, String xmlStr) throws Exception {
List<String> values = new ArrayList<>();
try {
InputSource inputXML = new InputSource(new StringReader(xmlStr));
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) {
e.printStackTrace();
}
return values;
}
private String httpXmlResponse(String url, String urlParameters) {
int status;
try {
if (httpClient.isStarted()) {
httpClient.stop();
}
httpClient.start();
String urlParameters_length = Integer.toString(urlParameters.length());
ContentResponse httpResponse = sendRequestBuilder(url, HttpMethod.POST)
.content(new StringContentProvider(urlParameters), "text/xml; charset=utf-8")
.header(HttpHeader.CONTENT_LENGTH, urlParameters_length).send();
status = httpResponse.getStatus();
String xmlStr = httpResponse.getContentAsString();
if (status == 200) {
return xmlStr;
} else {
logger.info("Login response: {}", httpResponse.getContentAsString());
return null;
}
} catch (Exception e) {
logger.error("Unable to open connection to Hayward's server {}:{}", config.hostname, config.username, e);
return null;
}
}
private Request sendRequestBuilder(String url, HttpMethod method) {
return 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")
// .header(HttpHeader.CONTENT_TYPE, "text/xml; charset=utf-8")
.timeout(5, TimeUnit.SECONDS);
}
}