configuration){
+ String refreshIntervalString = (String) configuration.get("refresh");
+ if (StringUtils.isNotBlank(refreshIntervalString)) {
+ refreshInterval = Long.parseLong(refreshIntervalString);
+ }
+
+ int port = DEFAULT_PORT;
+ String host = (String) configuration.get("host");
+ String username = (String) configuration.get("username");
+ String password = (String) configuration.get("password");
+
+ if(StringUtils.isBlank(host)){
+ logger.error("Host config parameter is missing");
+ setProperlyConfigured(false);
+ return;
+ }
+
+ String portString = (String) configuration.get("port");
+ if(StringUtils.isNotBlank(portString))
+ port = Integer.parseInt(portString);
+
+ String prefix = "";
+ if(username != null) {
+ prefix = username + ":" + password + "@";
+ }
+
+ baseURL = "http://" + prefix + host + ":" + port;
+
+ logger.debug("Autelius binding configured for host {}", host);
+
+ setProperlyConfigured(true);
+ }
+
+ /**
+ * @{inheritDoc}
+ */
+ @Override
+ protected long getRefreshInterval() {
+ return refreshInterval;
+ }
+
+ /**
+ * @{inheritDoc}
+ */
+ @Override
+ protected String getName() {
+ return "autelis";
+ }
+
+ /**
+ * @{inheritDoc}
+ */
+ @Override
+ protected void execute() {
+ logger.trace("Connecting to {}" + baseURL);
+
+ clearState();
+
+
+ String xmlDoc = fetchStateFromController();
+
+ if(xmlDoc == null)
+ return;
+
+ for (AutelisBindingProvider provider : providers) {
+ for (String itemName : provider.getItemNames()) {
+ Item item = provider.getItem(itemName);
+ String config = provider.getAutelisBindingConfigString(itemName);
+ XPathFactory xpathFactory = XPathFactory.newInstance();
+ XPath xpath = xpathFactory.newXPath();
+ try {
+ InputSource is = new InputSource(new StringReader(xmlDoc));
+ String value = xpath.evaluate("response/" + config.replace('.', '/'), is);
+ State state = toState(item.getClass(), value);
+ State oldState = stateMap.put(itemName, state);
+ if(!state.equals(oldState)){
+ logger.debug("updating item {} with state {}", itemName, state);
+ eventPublisher.postUpdate(itemName, state);
+ }
+ } catch (XPathExpressionException e) {
+ logger.warn("could not parse xml",e);
+ }
+
+ }
+ }
+ }
+
+ /**
+ * @{inheritDoc}
+ */
+ @Override
+ protected void internalReceiveCommand(String itemName, Command command) {
+ logger.trace("internalReceiveCommand({},{}) is called!", itemName, command);
+ for (AutelisBindingProvider provider : providers) {
+ Item item = provider.getItem(itemName);
+ String config = provider.getAutelisBindingConfigString(itemName);
+ Matcher m = commandPattern.matcher(config);
+ if (m.find() && m.groupCount() > 1) {
+ String type = m.group(1);
+ String name = m.group(2);
+ if(type.equals(AUTELIS_TYPES_EQUIP)){
+ String cmd = AUTELIS_CMD_VALUE;
+ int value;
+ if(command == OnOffType.OFF){
+ value = 0;
+ } else if(command == OnOffType.ON){
+ value = 1;
+ } else if(command instanceof DecimalType){
+ value = ((DecimalType)item.getStateAs(DecimalType.class)).intValue();
+ if(value >= 3){
+ //this is a dim type. not sure what 2 does
+ cmd = AUTELIS_CMD_DIM;
+ }
+ } else {
+ logger.error("Equipment commands must be of Decimal type not {}", command);
+ break;
+ }
+ String response = HttpUtil.executeUrl("GET", baseURL + "/set.cgi?name=" + name + "&" + cmd + "=" + value, TIMEOUT);
+ logger.trace("equipment set {} {} {} : result {}", name, cmd, value, response);
+ } else if(type.equals(AUTELIS_TYPES_TEMP)){
+ String value;
+ if(command == IncreaseDecreaseType.INCREASE){
+ value = AUTELIS_CMD_UP;
+ }else if(command == IncreaseDecreaseType.DECREASE){
+ value = AUTELIS_CMD_DOWN;
+ }else {
+ value = command.toString();
+ }
+
+ String cmd;
+ //name ending in sp are setpoints, ht are heat types?
+ if(name.endsWith(AUTELIS_SETPOINT)){
+ cmd = AUTELIS_TYPES_TEMP;
+ } else if(name.endsWith(AUTELIS_HEATTYPE)){
+ cmd = AUTELIS_CMD_HEAT;
+ } else {
+ logger.error("Unknown temp type {}", name);
+ break;
+ }
+
+ String response = HttpUtil.executeUrl("GET", baseURL + "/set.cgi?wait=1&name=" + name + "&" + cmd + "=" + value, TIMEOUT);
+ logger.trace("temp set {} {} : result {}", cmd, value, response);
+ }
+ } else if(config.equals(AUTELIS_TYPES_LIGHTS)){
+ /*
+ * lighting command
+ * possible values, but we will let anything through.
+ * alloff, allon, csync, cset, cswim, party, romance, caribbean, american,
+ * sunset, royalty, blue, green, red, white, magenta, hold, recall
+ */
+ String response = HttpUtil.executeUrl("GET", baseURL + "lights.cgi?val=" + command.toString(), TIMEOUT);
+ logger.trace("lights set {} : result {}", command.toString(), response);
+ } else {
+ logger.error("Unsupported set config {}", config);
+ }
+ }
+ scheduleClearTime(UPDATE_CLEARTIME);
+ }
+
+ /**
+ * Fetches the XML string from a Autelis controller.
+ * @return
+ */
+ private String fetchStateFromController() {
+ // we will reconstruct the document with all the responses combined for
+ // XPATH
+ StringBuilder sb = new StringBuilder("");
+
+ // pull down the three xml documents
+ String[] statuses = { AUTELIS_TYPES_STATUS, AUTELIS_TYPES_CHEMISTRY, AUTELIS_TYPES_PUMPS };
+ for (String status : statuses) {
+ String response = HttpUtil.executeUrl("GET", baseURL + "/" + status
+ + ".xml", TIMEOUT);
+ logger.trace(baseURL + "/" + status + ".xml \n {}", response);
+ if (response == null) {
+ logger.warn("No response from Autelis controller!");
+ return null;
+ }
+ // get the xml data between the response tags and append to our main
+ // doc
+ Matcher m = responsePattern.matcher(response);
+ if (m.find()) {
+ sb.append(m.group(1));
+ }
+ }
+ // finish our "new" XML Document
+ sb.append("");
+
+ /*
+ * This xmlDoc will now contain the three XML documents we retrieved
+ * wrapped in response tags for easier querying in XPath.
+ */
+ return sb.toString();
+ }
+
+ /**
+ * Converts a {@link String} value to a {@link State} for a given {@link Item}
+ * @param itemType
+ * @param value
+ * @return {@link State}
+ */
+ private State toState(Class extends Item> itemType, String value) {
+ if (itemType.isAssignableFrom(NumberItem.class)) {
+ return new DecimalType(value);
+ } else if (itemType.isAssignableFrom(SwitchItem.class)) {
+ return Integer.parseInt(value) > 0 ? OnOffType.ON : OnOffType.OFF;
+ } else {
+ return StringType.valueOf(value);
+ }
+ }
+
+ /**
+ * Clears our state if it is time
+ */
+ private void clearState(){
+ if(System.currentTimeMillis() >= clearTime){
+ stateMap.clear();
+ scheduleClearTime(NORMAL_CLEARTIME);
+ }
+ }
+
+ /**
+ * Schedule when our next clear cycle will be
+ * @param secs
+ */
+ private void scheduleClearTime(int secs){
+ clearTime = System.currentTimeMillis() + (secs * 1000);
+ }
+}
diff --git a/bundles/binding/org.openhab.binding.autelis/src/main/java/org/openhab/binding/autelis/internal/AutelisGenericBindingProvider.java b/bundles/binding/org.openhab.binding.autelis/src/main/java/org/openhab/binding/autelis/internal/AutelisGenericBindingProvider.java
new file mode 100644
index 00000000000..7a92dddfdd2
--- /dev/null
+++ b/bundles/binding/org.openhab.binding.autelis/src/main/java/org/openhab/binding/autelis/internal/AutelisGenericBindingProvider.java
@@ -0,0 +1,139 @@
+/**
+w * Copyright (c) 2010-2015, openHAB.org and others.
+ *
+ * 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.autelis.internal;
+
+import java.util.HashSet;
+import java.util.Set;
+
+import org.openhab.binding.autelis.AutelisBindingProvider;
+import org.openhab.core.binding.BindingConfig;
+import org.openhab.core.items.Item;
+import org.openhab.core.library.items.DimmerItem;
+import org.openhab.core.library.items.NumberItem;
+import org.openhab.core.library.items.StringItem;
+import org.openhab.core.library.items.SwitchItem;
+import org.openhab.model.item.binding.AbstractGenericBindingProvider;
+import org.openhab.model.item.binding.BindingConfigParseException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * Autelis Pool control binding configurations.
+ * Sample configuration strings:
+ *
+ * {autelis="system.version"}
+ * {autelis="temp.poolsp"}
+ * {autelis="temp.pooltemp"}
+ * {autelis="chlor.salt"}
+ * {autelis="equipment.circuit1"}
+ * {autelis="pumps.pump1"}
+ * {autelis="lightscmd"}
+ *
+ * only 'equipment.*', 'temp.*' and 'lightscmd' items can be updated from openhab, everything else is read only.
+ *
+ * @author Dan Cunningham
+ * @since 1.7.0
+ */
+public class AutelisGenericBindingProvider extends AbstractGenericBindingProvider implements AutelisBindingProvider {
+ private static final Logger logger =
+ LoggerFactory.getLogger(AutelisGenericBindingProvider.class);
+ /**
+ * {@inheritDoc}
+ */
+ public String getBindingType() {
+ return "autelis";
+ }
+
+ /**
+ * @{inheritDoc}
+ */
+ @Override
+ public void validateItemType(Item item, String bindingConfig) throws BindingConfigParseException {
+ if (!(item instanceof SwitchItem || item instanceof DimmerItem || item instanceof NumberItem || item instanceof StringItem)) {
+ throw new BindingConfigParseException("item '" + item.getName()
+ + "' is of type '" + item.getClass().getSimpleName()
+ + "', only Switch, Dimmer, Number and String Items are allowed - please check your *.items configuration");
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void processBindingConfiguration(String context, Item item, String bindingConfig) throws BindingConfigParseException {
+ super.processBindingConfiguration(context, item, bindingConfig);
+
+
+ //read values must contain a '.' like equipment.circuit1 or be lightcmd
+ if(bindingConfig.indexOf('.') < 0 && !bindingConfig.equalsIgnoreCase("lightscmd")){
+ logger.warn("Item {}'s configuration ({}) is not valid, please use the pattern 'parentType.childType' or lightscmd ", item.getName(), bindingConfig);
+ return;
+ }
+
+ AutelisBindingConfig config = new AutelisBindingConfig(bindingConfig);
+
+ addBindingConfig(item, config);
+
+ Set- items = contextMap.get(context);
+ if (items == null) {
+ items = new HashSet
- ();
+ contextMap.put(context, items);
+ }
+ items.add(item);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public Item getItem(String itemName) {
+ for (Set
- items : contextMap.values()) {
+ if (items != null) {
+ for (Item item : items) {
+ if (itemName.equals(item.getName())) {
+ return item;
+ }
+ }
+ }
+ }
+ return null;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public String getAutelisBindingConfigString(String itemName){
+ return ((AutelisBindingConfig) this.bindingConfigs.get(itemName)).getConfig();
+ }
+
+ /**
+ * Class to hold binding specific configuration details
+ *
+ * @author Dan Cunningham
+ * @since 1.7.0
+ */
+ public class AutelisBindingConfig implements BindingConfig {
+ String config;
+
+ public AutelisBindingConfig(String config) {
+ super();
+ this.config = config;
+ }
+
+ public String getConfig() {
+ return config;
+ }
+
+ public void setConfig(String config) {
+ this.config = config;
+ }
+ }
+}
diff --git a/bundles/binding/pom.xml b/bundles/binding/pom.xml
index ead1bde2cb2..bf4402cf97b 100644
--- a/bundles/binding/pom.xml
+++ b/bundles/binding/pom.xml
@@ -141,6 +141,7 @@
org.openhab.binding.wago
org.openhab.binding.networkupstools
org.openhab.binding.ecobee
+ org.openhab.binding.autelis
org.openhab.binding.nest
org.openhab.binding.satel
org.openhab.binding.harmonyhub
diff --git a/distribution/openhabhome/configurations/openhab_default.cfg b/distribution/openhabhome/configurations/openhab_default.cfg
index cc3d0d15f77..5fe145d5973 100644
--- a/distribution/openhabhome/configurations/openhab_default.cfg
+++ b/distribution/openhabhome/configurations/openhab_default.cfg
@@ -1724,6 +1724,19 @@ tcp:refreshinterval=250
# UPS server pass (optional)
#networkupstools:ups1.pass=
+############################### Autelis Pool Control Binding #########################
+#
+# Host (name or ip) to connect to
+# optional port (default 80)
+# optional username and password (no default)
+# optional refresh rate in millis (default 5000)
+#
+#autelis:refresh=5000
+#autelis:host=poolcontrol
+#autelis:port=80
+#autelis:username=admin
+#autelis:password=admin
+
############################## Nest binding ########################################
#
# Data refresh interval in ms (optional, defaults to 60000)