added migrated 2.x add-ons

Signed-off-by: Kai Kreuzer <kai@openhab.org>
This commit is contained in:
Kai Kreuzer
2020-09-21 01:58:32 +02:00
parent bbf1a7fd29
commit 6df6783b60
11662 changed files with 1302875 additions and 11 deletions

View File

@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<features name="org.openhab.binding.autelis-${project.version}" xmlns="http://karaf.apache.org/xmlns/features/v1.4.0">
<repository>mvn:org.openhab.core.features.karaf/org.openhab.core.features.karaf.openhab-core/${ohc.version}/xml/features</repository>
<feature name="openhab-binding-autelis" description="Autelis Binding" version="${project.version}">
<feature>openhab-runtime-base</feature>
<feature>openhab-transport-upnp</feature>
<bundle start-level="80">mvn:org.openhab.addons.bundles/org.openhab.binding.autelis/${project.version}</bundle>
</feature>
</features>

View File

@@ -0,0 +1,48 @@
/**
* Copyright (c) 2010-2020 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.autelis.internal;
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.openhab.core.thing.ThingTypeUID;
/**
* The {@link AutelisBinding} class defines common constants, which are used
* across the whole binding.
*
* @author Dan Cunningham - Initial contribution
*/
@NonNullByDefault
public class AutelisBindingConstants {
public static final String BINDING_ID = "autelis";
// poolcontrol is here for backwards compatibility before we had separate things for jandy and pentair
public static final ThingTypeUID POOLCONTROL_THING_TYPE_UID = new ThingTypeUID(BINDING_ID, "poolcontrol");
public static final ThingTypeUID PENTAIR_THING_TYPE_UID = new ThingTypeUID(BINDING_ID, "pentair");
public static final ThingTypeUID JANDY_THING_TYPE_UID = new ThingTypeUID(BINDING_ID, "jandy");
public static final Set<ThingTypeUID> SUPPORTED_THING_TYPES_UIDS = Collections.unmodifiableSet(Stream
.of(POOLCONTROL_THING_TYPE_UID, PENTAIR_THING_TYPE_UID, JANDY_THING_TYPE_UID).collect(Collectors.toSet()));
public static final String CMD_LIGHTS = "lightscmd";
public static final String CMD_REBOOT = "reboot";
public static final String CMD_EQUIPMENT = "equipment";
public static final String CMD_TEMP = "temp";
public static final String CMD_CHEM = "chem";
public static final String CMD_PUMPS = "pumps";
}

View File

@@ -0,0 +1,50 @@
/**
* Copyright (c) 2010-2020 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.autelis.internal;
import static org.openhab.binding.autelis.internal.AutelisBindingConstants.SUPPORTED_THING_TYPES_UIDS;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.binding.autelis.internal.handler.AutelisHandler;
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.Component;
/**
* The {@link AutelisHandlerFactory} is responsible for creating things and
* thing handlers.
*
* @author Dan Cunningham - Initial contribution
*/
@NonNullByDefault
@Component(service = ThingHandlerFactory.class, configurationPid = "binding.autelis")
public class AutelisHandlerFactory extends BaseThingHandlerFactory {
@Override
public boolean supportsThingType(ThingTypeUID thingTypeUID) {
return SUPPORTED_THING_TYPES_UIDS.contains(thingTypeUID);
}
@Override
protected @Nullable ThingHandler createHandler(Thing thing) {
ThingTypeUID thingTypeUID = thing.getThingTypeUID();
if (SUPPORTED_THING_TYPES_UIDS.contains(thingTypeUID)) {
return new AutelisHandler(thing);
}
return null;
}
}

View File

@@ -0,0 +1,46 @@
/**
* Copyright (c) 2010-2020 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.autelis.internal.config;
/**
* Configuration properties for connecting to a Autelis Controller
*
* @author Dan Cunningham - Initial contribution
*
*/
public class AutelisConfiguration {
/**
* Host of the Autelis controller
*/
public String host;
/**
* port of the Autelis controller
*/
public Integer port;
/**
* user to us when connecting to the Autelis controller
*/
public String user;
/**
* password to us when connecting to the Autelis controller
*/
public String password;
/**
* Rate we poll for new data
*/
public Integer refresh;
}

View File

@@ -0,0 +1,100 @@
/**
* Copyright (c) 2010-2020 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.autelis.internal.discovery;
import java.net.URL;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.jupnp.model.meta.RemoteDevice;
import org.openhab.binding.autelis.internal.AutelisBindingConstants;
import org.openhab.core.config.discovery.DiscoveryResult;
import org.openhab.core.config.discovery.DiscoveryResultBuilder;
import org.openhab.core.config.discovery.upnp.UpnpDiscoveryParticipant;
import org.openhab.core.thing.ThingTypeUID;
import org.openhab.core.thing.ThingUID;
import org.osgi.service.component.annotations.Component;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
*
* Discovery Service for Autelis Pool Controllers.
*
* @author Dan Cunningham - Initial contribution
*
*/
@NonNullByDefault
@Component(immediate = true)
public class AutelisDiscoveryParticipant implements UpnpDiscoveryParticipant {
private final Logger logger = LoggerFactory.getLogger(AutelisDiscoveryParticipant.class);
private static final String MANUFACTURER = "autelis";
private static final String MODEL_PENTAIR = "pc100p";
private static final String MODEL_JANDY = "pc100j";
@Override
public Set<ThingTypeUID> getSupportedThingTypeUIDs() {
return AutelisBindingConstants.SUPPORTED_THING_TYPES_UIDS;
}
@Override
public @Nullable DiscoveryResult createResult(RemoteDevice device) {
ThingUID uid = getThingUID(device);
if (uid != null) {
Map<String, Object> properties = new HashMap<>(3);
URL url = device.getDetails().getBaseURL();
String label = device.getDetails().getFriendlyName();
int port = url.getPort() > 0 ? url.getPort() : 80;
properties.put("host", url.getHost());
properties.put("user", "admin");
properties.put("password", "admin");
properties.put("port", new Integer(port));
DiscoveryResult result = DiscoveryResultBuilder.create(uid).withProperties(properties).withLabel(label)
.build();
logger.debug("Created a DiscoveryResult for device '{}' with UDN '{}'",
device.getDetails().getFriendlyName(), device.getIdentity().getUdn().getIdentifierString());
return result;
} else {
return null;
}
}
@Override
public @Nullable ThingUID getThingUID(RemoteDevice device) {
if (device.getDetails().getManufacturerDetails().getManufacturer() != null
&& device.getDetails().getModelDetails().getModelNumber() != null) {
logger.trace("UPNP {} : {}", device.getDetails().getManufacturerDetails().getManufacturer(),
device.getDetails().getModelDetails().getModelNumber());
if (device.getDetails().getManufacturerDetails().getManufacturer().toLowerCase().startsWith(MANUFACTURER)) {
logger.debug("Autelis Pool Control Found at {}", device.getDetails().getBaseURL());
String id = device.getIdentity().getUdn().getIdentifierString().replaceAll(":", "").toUpperCase();
if (device.getDetails().getModelDetails().getModelNumber().toLowerCase().startsWith(MODEL_PENTAIR)) {
return new ThingUID(AutelisBindingConstants.PENTAIR_THING_TYPE_UID, id);
}
if (device.getDetails().getModelDetails().getModelNumber().toLowerCase().startsWith(MODEL_JANDY)) {
return new ThingUID(AutelisBindingConstants.JANDY_THING_TYPE_UID, id);
}
}
}
return null;
}
}

View File

@@ -0,0 +1,554 @@
/**
* Copyright (c) 2010-2020 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.autelis.internal.handler;
import java.io.StringReader;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;
import org.apache.commons.lang.StringUtils;
import org.eclipse.jetty.client.HttpClient;
import org.eclipse.jetty.client.api.ContentResponse;
import org.eclipse.jetty.client.api.Request;
import org.eclipse.jetty.http.HttpHeader;
import org.eclipse.jetty.http.HttpStatus;
import org.eclipse.jetty.util.B64Code;
import org.eclipse.jetty.util.StringUtil;
import org.openhab.binding.autelis.internal.AutelisBindingConstants;
import org.openhab.binding.autelis.internal.config.AutelisConfiguration;
import org.openhab.core.library.types.DecimalType;
import org.openhab.core.library.types.IncreaseDecreaseType;
import org.openhab.core.library.types.OnOffType;
import org.openhab.core.library.types.StringType;
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.ThingStatusDetail;
import org.openhab.core.thing.binding.BaseThingHandler;
import org.openhab.core.types.Command;
import org.openhab.core.types.State;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.xml.sax.InputSource;
/**
*
* Autelis Pool Control Binding
*
* Autelis controllers allow remote access to many common pool systems. This
* binding allows openHAB to both monitor and control a pool system through
* these controllers.
*
* @see <a href="http://Autelis.com">http://autelis.com</a>
* @see <a href="http://www.autelis.com/wiki/index.php?title=Pool_Control_HTTP_Command_Reference"</a> for Jandy API
* @see <a href="http://www.autelis.com/wiki/index.php?title=Pool_Control_(PI)_HTTP_Command_Reference"</a> for Pentair
* API
*
* The {@link AutelisHandler} is responsible for handling commands, which
* are sent to one of the channels.
*
* @author Dan Cunningham - Initial contribution
* @author Svilen Valkanov - Replaced Apache HttpClient with Jetty
*/
public class AutelisHandler extends BaseThingHandler {
private final Logger logger = LoggerFactory.getLogger(AutelisHandler.class);
/**
* Default timeout for http connections to a Autelis controller
*/
static final int TIMEOUT_SECONDS = 5;
/**
* Autelis controllers will not update their XML immediately after we change
* a value. To compensate we cache previous values for a {@link Channel}
* using the item name as a key. After a polling run has been executed we
* only update an channel if the value is different then what's in the
* cache. This cache is cleared after a fixed time period when commands are
* sent.
*/
private Map<String, State> stateMap = Collections.synchronizedMap(new HashMap<>());
/**
* Clear our state every hour
*/
private static final int NORMAL_CLEARTIME_SECONDS = 60 * 60;
/**
* Default poll rate rate, this is derived from the Autelis web UI
*/
private static final int DEFAULT_REFRESH_SECONDS = 3;
/**
* How long should we wait to poll after we send an update, derived from trial and error
*/
private static final int COMMAND_UPDATE_TIME_SECONDS = 6;
/**
* The autelis unit will 'loose' commands if sent to fast
*/
private static final int THROTTLE_TIME_MILLISECONDS = 500;
/**
* Autelis web port
*/
private static final int WEB_PORT = 80;
/**
* Pentair values for pump response
*/
private static final String[] PUMP_TYPES = { "watts", "rpm", "gpm", "filer", "error" };
/**
* Matcher for pump channel names for Pentair
*/
private static final Pattern PUMPS_PATTERN = Pattern.compile("(pumps/pump\\d?)-(watts|rpm|gpm|filter|error)");
/**
* Holds the next clear time in millis
*/
private long clearTime;
/**
* Constructed URL consisting of host and port
*/
private String baseURL;
/**
* Our poll rate
*/
private int refresh;
/**
* The http client used for polling requests
*/
private HttpClient client = new HttpClient();
/**
* last time we finished a request
*/
private long lastRequestTime = 0;
/**
* Authentication for login
*/
private String basicAuthentication;
/**
* Regex expression to match XML responses from the Autelis, this is used to
* combine similar XML docs into a single document, {@link XPath} is still
* used for XML querying
*/
private Pattern responsePattern = Pattern.compile("<response>(.+?)</response>", Pattern.DOTALL);
/**
* Future to poll for updated
*/
private ScheduledFuture<?> pollFuture;
public AutelisHandler(Thing thing) {
super(thing);
}
@Override
public void initialize() {
startHttpClient(client);
configure();
}
@Override
public void dispose() {
logger.debug("Handler disposed.");
clearPolling();
stopHttpClient(client);
}
@Override
public void channelLinked(ChannelUID channelUID) {
// clear our cached values so the new channel gets updated
clearState(true);
}
@Override
public void handleCommand(ChannelUID channelUID, Command command) {
logger.debug("handleCommand channel: {} command: {}", channelUID.getId(), command);
if (AutelisBindingConstants.CMD_LIGHTS.equals(channelUID.getId())) {
/*
* 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
*/
getUrl(baseURL + "/lights.cgi?val=" + command.toString(), TIMEOUT_SECONDS);
} else if (AutelisBindingConstants.CMD_REBOOT.equals(channelUID.getId()) && command == OnOffType.ON) {
getUrl(baseURL + "/userreboot.cgi?do=true" + command.toString(), TIMEOUT_SECONDS);
updateState(channelUID, OnOffType.OFF);
} else {
String[] args = channelUID.getId().split("-");
if (args.length < 2) {
logger.warn("Unown channel {} for command {}", channelUID, command);
return;
}
String type = args[0];
String name = args[1];
if (AutelisBindingConstants.CMD_EQUIPMENT.equals(type)) {
String cmd = "value";
int value;
if (command == OnOffType.OFF) {
value = 0;
} else if (command == OnOffType.ON) {
value = 1;
} else if (command instanceof DecimalType) {
value = ((DecimalType) command).intValue();
if (!isJandy() && value >= 3) {
// this is a autelis dim type. not sure what 2 does
cmd = "dim";
}
} else {
logger.error("command type {} is not supported", command);
return;
}
String response = getUrl(baseURL + "/set.cgi?name=" + name + "&" + cmd + "=" + value, TIMEOUT_SECONDS);
logger.debug("equipment set {} {} {} : result {}", name, cmd, value, response);
} else if (AutelisBindingConstants.CMD_TEMP.equals(type)) {
String value;
if (command == IncreaseDecreaseType.INCREASE) {
value = "up";
} else if (command == IncreaseDecreaseType.DECREASE) {
value = "down";
} else if (command == OnOffType.OFF) {
value = "0";
} else if (command == OnOffType.ON) {
value = "1";
} else {
value = command.toString();
}
String cmd;
// name ending in sp are setpoints, ht are heater?
if (name.endsWith("sp")) {
cmd = "temp";
} else if (name.endsWith("ht")) {
cmd = "hval";
} else {
logger.error("Unknown temp type {}", name);
return;
}
String response = getUrl(baseURL + "/set.cgi?wait=1&name=" + name + "&" + cmd + "=" + value,
TIMEOUT_SECONDS);
logger.debug("temp set name:{} cmd:{} value:{} : result {}", name, cmd, value, response);
} else if (AutelisBindingConstants.CMD_CHEM.equals(type)) {
String response = getUrl(baseURL + "/set.cgi?name=" + name + "&chem=" + command.toString(),
TIMEOUT_SECONDS);
logger.debug("chlrp {} {}: result {}", name, command, response);
} else if (AutelisBindingConstants.CMD_PUMPS.equals(type)) {
String response = getUrl(baseURL + "/set.cgi?name=" + name + "&speed=" + command.toString(),
TIMEOUT_SECONDS);
logger.debug("pumps {} {}: result {}", name, command, response);
} else {
logger.error("Unsupported type {}", type);
}
}
clearState(true);
// reset the schedule for our next poll which at that time will reflect if our command was successful or not.
initPolling(COMMAND_UPDATE_TIME_SECONDS);
}
/**
* Configures this thing
*/
private void configure() {
clearPolling();
AutelisConfiguration configuration = getConfig().as(AutelisConfiguration.class);
Integer refreshOrNull = configuration.refresh;
Integer portOrNull = configuration.port;
String host = configuration.host;
String username = configuration.user;
String password = configuration.password;
if (StringUtils.isBlank(username)) {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, "username must not be empty");
return;
}
if (StringUtils.isBlank(password)) {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, "password must not be empty");
return;
}
if (StringUtils.isBlank(host)) {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, "hostname must not be empty");
return;
}
refresh = DEFAULT_REFRESH_SECONDS;
if (refreshOrNull != null) {
refresh = refreshOrNull.intValue();
}
int port = WEB_PORT;
if (portOrNull != null) {
port = portOrNull.intValue();
}
baseURL = "http://" + host + ":" + port;
basicAuthentication = "Basic " + B64Code.encode(username + ":" + password, StringUtil.__ISO_8859_1);
logger.debug("Autelius binding configured with base url {} and refresh period of {}", baseURL, refresh);
initPolling(0);
}
/**
* Starts/Restarts polling with an initial delay. This allows changes in the poll cycle for when commands are sent
* and we need to poll sooner then the next refresh cycle.
*/
private synchronized void initPolling(int initalDelay) {
clearPolling();
pollFuture = scheduler.scheduleWithFixedDelay(() -> {
try {
pollAutelisController();
} catch (Exception e) {
logger.debug("Exception during poll", e);
}
}, initalDelay, DEFAULT_REFRESH_SECONDS, TimeUnit.SECONDS);
}
/**
* Stops/clears this thing's polling future
*/
private void clearPolling() {
if (pollFuture != null && !pollFuture.isCancelled()) {
logger.trace("Canceling future");
pollFuture.cancel(false);
}
}
/**
* Poll the Autelis controller for updates. This will retrieve various xml documents and update channel states from
* its contents.
*/
private void pollAutelisController() {
logger.trace("Connecting to {}", baseURL);
// clear our cached stated IF it is time.
clearState(false);
// we will reconstruct the document with all the responses combined for XPATH
StringBuilder sb = new StringBuilder("<response>");
// pull down the three xml documents
String[] statuses = { "status", "chem", "pumps" };
for (String status : statuses) {
String response = getUrl(baseURL + "/" + status + ".xml", TIMEOUT_SECONDS);
logger.trace("{}/{}.xml \n {}", baseURL, status, response);
if (response == null) {
// all models and versions have the status.xml endpoint
if (status.equals("status")) {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.OFFLINE.COMMUNICATION_ERROR);
return;
} else {
// not all models have the other endpoints, so we ignore errors
continue;
}
}
// 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("</response>");
if (!ThingStatus.ONLINE.equals(getThing().getStatus())) {
updateStatus(ThingStatus.ONLINE);
}
/*
* This xmlDoc will now contain the three XML documents we retrieved
* wrapped in response tags for easier querying in XPath.
*/
HashMap<String, String> pumps = new HashMap<>();
String xmlDoc = sb.toString();
for (Channel channel : getThing().getChannels()) {
String key = channel.getUID().getId().replaceFirst("-", "/");
XPathFactory xpathFactory = XPathFactory.newInstance();
XPath xpath = xpathFactory.newXPath();
try {
InputSource is = new InputSource(new StringReader(xmlDoc));
String value = null;
/**
* Work around for Pentair pumps. Rather then have child XML elements, the response rather uses commas
* on the pump response to separate the different values like so:
*
* watts,rpm,gpm,filter,error
*
* Also, some pools will only report the first 3 out of the 5 values.
*/
Matcher matcher = PUMPS_PATTERN.matcher(key);
if (matcher.matches()) {
if (!pumps.containsKey(key)) {
String pumpValue = xpath.evaluate("response/" + matcher.group(1), is);
String[] values = pumpValue.split(",");
for (int i = 0; i < PUMP_TYPES.length; i++) {
// this will be something like pump/pump1-rpm
String newKey = matcher.group(1) + '-' + PUMP_TYPES[i];
// some Pentair models only have the first 3 values
if (i < values.length) {
pumps.put(newKey, values[i]);
} else {
pumps.put(newKey, "");
}
}
}
value = pumps.get(key);
} else {
value = xpath.evaluate("response/" + key, is);
// Convert pentair salt levels to PPM.
if ("chlor/salt".equals(key)) {
try {
value = String.valueOf(Integer.parseInt(value) * 50);
} catch (NumberFormatException ignored) {
logger.debug("Failed to parse pentair salt level as integer");
}
}
}
if (StringUtils.isEmpty((value))) {
continue;
}
State state = toState(channel.getAcceptedItemType(), value);
State oldState = stateMap.put(channel.getUID().getAsString(), state);
if (!state.equals(oldState)) {
logger.trace("updating channel {} with state {} (old state {})", channel.getUID(), state, oldState);
updateState(channel.getUID(), state);
}
} catch (XPathExpressionException e) {
logger.error("could not parse xml", e);
}
}
}
/**
* Simple logic to perform a authenticated GET request
*
* @param url
* @param timeout
* @return
*/
private synchronized String getUrl(String url, int timeout) {
// throttle commands for a very short time to avoid 'loosing' them
long now = System.currentTimeMillis();
long nextReq = lastRequestTime + THROTTLE_TIME_MILLISECONDS;
if (nextReq > now) {
try {
logger.trace("Throttling request for {} mills", nextReq - now);
Thread.sleep(nextReq - now);
} catch (InterruptedException ignored) {
}
}
String getURL = url + (url.contains("?") ? "&" : "?") + "timestamp=" + System.currentTimeMillis();
logger.trace("Getting URL {} ", getURL);
Request request = client.newRequest(getURL).timeout(TIMEOUT_SECONDS, TimeUnit.SECONDS);
request.header(HttpHeader.AUTHORIZATION, basicAuthentication);
try {
ContentResponse response = request.send();
int statusCode = response.getStatus();
if (statusCode != HttpStatus.OK_200) {
logger.trace("Method failed: {}", response.getStatus() + " " + response.getReason());
return null;
}
lastRequestTime = System.currentTimeMillis();
return response.getContentAsString();
} catch (Exception e) {
logger.debug("Could not make http connection", e);
}
return null;
}
/**
* Converts a {@link String} value to a {@link State} for a given
* {@link String} accepted type
*
* @param itemType
* @param value
* @return {@link State}
*/
private State toState(String type, String value) throws NumberFormatException {
if ("Number".equals(type)) {
return new DecimalType(value);
} else if ("Switch".equals(type)) {
return Integer.parseInt(value) > 0 ? OnOffType.ON : OnOffType.OFF;
} else {
return StringType.valueOf(value);
}
}
/**
* Clears our state if it is time
*/
private void clearState(boolean force) {
if (force || System.currentTimeMillis() >= clearTime) {
stateMap.clear();
clearTime = System.currentTimeMillis() + (NORMAL_CLEARTIME_SECONDS * 1000);
}
}
private void startHttpClient(HttpClient client) {
if (!client.isStarted()) {
try {
client.start();
} catch (Exception e) {
logger.error("Could not stop HttpClient", e);
}
}
}
private void stopHttpClient(HttpClient client) {
if (client != null) {
client.getAuthenticationStore().clearAuthentications();
client.getAuthenticationStore().clearAuthenticationResults();
if (client.isStarted()) {
try {
client.stop();
} catch (Exception e) {
logger.error("Could not stop HttpClient", e);
}
}
}
}
private boolean isJandy() {
return getThing().getThingTypeUID() == AutelisBindingConstants.JANDY_THING_TYPE_UID;
}
}

View File

@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<binding:binding id="autelis" 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>Autelis Pool Control Binding</name>
<description>This is the binding for a Autelis pool controller.</description>
<author>Dan Cunningham</author>
</binding:binding>

View File

@@ -0,0 +1,485 @@
<?xml version="1.0" encoding="UTF-8"?>
<thing:thing-descriptions bindingId="autelis"
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="jandy">
<label>Jandy Pool Controller</label>
<description>A Jandy pool control thing represents a Autelis pool controller for Jandy systems</description>
<channels>
<channel id="system-runstate" typeId="system-runstate"/>
<channel id="system-model" typeId="system-model"/>
<channel id="system-dip" typeId="system-dip"/>
<channel id="system-opmode" typeId="system-opmode"/>
<channel id="system-vbat" typeId="system-vbat"/>
<channel id="system-lowbat" typeId="system-lowbat"/>
<channel id="system-time" typeId="system-time"/>
<channel id="equipment-pump" typeId="equipment-switch">
<label>Pump</label>
<description>The current state of the pump</description>
</channel>
<channel id="equipment-pumplo" typeId="equipment-switch">
<label>Lowspeed Pump</label>
<description>The current state of the lowspeed pump</description>
</channel>
<channel id="equipment-spa" typeId="equipment-switch">
<label>Spa Pump</label>
<description>The current state of the spa pump</description>
</channel>
<channel id="equipment-waterfall" typeId="equipment-switch">
<label>Waterfall Pump</label>
<description>The current state of the waterfall pump</description>
</channel>
<channel id="equipment-cleaner" typeId="equipment-switch">
<label>Cleaner Pump</label>
<description>The current state of the cleaner pump</description>
</channel>
<channel id="equipment-poolht" typeId="equipment-ht">
<label>Pool Heater</label>
<description>The current state of the pool heater</description>
</channel>
<channel id="equipment-poolht2" typeId="equipment-ht">
<label>Pool Heater @</label>
<description>The current state of the pool heater 2</description>
</channel>
<channel id="equipment-spaht" typeId="equipment-ht">
<label>Spa Heater</label>
<description>The current state of the spa heater</description>
</channel>
<channel id="equipment-solarht" typeId="equipment-ht">
<label>Solar Heater</label>
<description>The current state of the solar heater</description>
</channel>
<channel id="equipment-htpmp" typeId="equipment-switch">
<label>Heat Pump</label>
<description>The current state of the heat pump</description>
</channel>
<channel id="equipment-aux1" typeId="equipment-aux">
<label>Auxiliary 1</label>
<description>The current state of auxiliary 1</description>
</channel>
<channel id="equipment-aux2" typeId="equipment-aux">
<label>Auxiliary 2</label>
<description>The current state of auxiliary 2</description>
</channel>
<channel id="equipment-aux3" typeId="equipment-aux">
<label>Auxiliary 3</label>
<description>The current state of auxiliary 3</description>
</channel>
<channel id="equipment-aux4" typeId="equipment-aux">
<label>Auxiliary 4</label>
<description>The current state of auxiliary 4</description>
</channel>
<channel id="equipment-aux5" typeId="equipment-aux">
<label>Auxiliary 5</label>
<description>The current state of auxiliary 5</description>
</channel>
<channel id="equipment-aux6" typeId="equipment-aux">
<label>Auxiliary 6</label>
<description>The current state of auxiliary 6</description>
</channel>
<channel id="equipment-aux7" typeId="equipment-aux">
<label>Auxiliary 7</label>
<description>The current state of auxiliary 7</description>
</channel>
<channel id="equipment-aux8" typeId="equipment-aux">
<label>Auxiliary 8</label>
<description>The current state of auxiliary 8</description>
</channel>
<channel id="equipment-aux9" typeId="equipment-aux">
<label>Auxiliary 9</label>
<description>The current state of auxiliary 9</description>
</channel>
<channel id="equipment-aux10" typeId="equipment-aux">
<label>Auxiliary 10</label>
<description>The current state of auxiliary 10</description>
</channel>
<channel id="equipment-aux11" typeId="equipment-aux">
<label>Auxiliary 11</label>
<description>The current state of auxiliary 11</description>
</channel>
<channel id="equipment-aux12" typeId="equipment-aux">
<label>Auxiliary 12</label>
<description>The current state of auxiliary 12</description>
</channel>
<channel id="equipment-aux13" typeId="equipment-aux">
<label>Auxiliary 13</label>
<description>The current state of auxiliary 13</description>
</channel>
<channel id="equipment-aux14" typeId="equipment-aux">
<label>Auxiliary 14</label>
<description>The current state of auxiliary 14</description>
</channel>
<channel id="equipment-aux15" typeId="equipment-aux">
<label>Auxiliary 15</label>
<description>The current state of auxiliary 15</description>
</channel>
<channel id="equipment-aux16" typeId="equipment-aux">
<label>Auxiliary 16</label>
<description>The current state of auxiliary 16</description>
</channel>
<channel id="equipment-aux17" typeId="equipment-aux">
<label>Auxiliary 17</label>
<description>The current state of auxiliary 17</description>
</channel>
<channel id="equipment-aux18" typeId="equipment-aux">
<label>Auxiliary 18</label>
<description>The current state of auxiliary 18</description>
</channel>
<channel id="equipment-aux19" typeId="equipment-aux">
<label>Auxiliary 19</label>
<description>The current state of auxiliary 19</description>
</channel>
<channel id="equipment-aux20" typeId="equipment-aux">
<label>Auxiliary 20</label>
<description>The current state of auxiliary 20</description>
</channel>
<channel id="equipment-aux21" typeId="equipment-aux">
<label>Auxiliary 21</label>
<description>The current state of auxiliary 21</description>
</channel>
<channel id="equipment-aux22" typeId="equipment-aux">
<label>Auxiliary 22</label>
<description>The current state of auxiliary 22</description>
</channel>
<channel id="equipment-aux23" typeId="equipment-aux">
<label>Auxiliary 23</label>
<description>The current state of auxiliary 23</description>
</channel>
<channel id="temp-poolsp" typeId="temp-sp">
<label>Pool Setpoint</label>
<description>The current pool setpoint</description>
</channel>
<channel id="temp-poolsp2" typeId="temp-sp">
<label>Pool Setpoint 2</label>
<description>The current pool setpoint 2</description>
</channel>
<channel id="temp-spasp" typeId="temp-sp">
<label>Spa Setpoint</label>
<description>The current spa setpoint</description>
</channel>
<channel id="temp-pooltemp" typeId="temp-temperature">
<label>Pool Temperature</label>
<description>The current pool temperature. Note: Only accurate when pool is running</description>
</channel>
<channel id="temp-spatemp" typeId="temp-temperature">
<label>Spa Temperature</label>
<description>The current spa temperature. Note: Only accurate when spa is running</description>
</channel>
<channel id="temp-airtemp" typeId="temp-temperature">
<label>Air Temperature</label>
<description>The current air temperature</description>
</channel>
<channel id="temp-solartemp" typeId="temp-temperature">
<label>Solar Temperature</label>
<description>The current solar temperature</description>
</channel>
<channel id="temp-tempunits" typeId="temp-tempunits"/>
<channel id="pumps-vsp1" typeId="pumps-vsp1"/>
<channel id="pumps-vsp2" typeId="pumps-vsp2"/>
<channel id="pumps-vsp3" typeId="pumps-vsp3"/>
<channel id="pumps-vsp4" typeId="pumps-vsp4"/>
<channel id="chem-avail" typeId="chem-avail"/>
<channel id="chem-chlrp" typeId="chem-chlrp"/>
<channel id="chem-saltp" typeId="chem-saltp"/>
<channel id="chem-chlrs" typeId="chem-chlrs"/>
<channel id="chem-salts" typeId="chem-salts"/>
<channel id="chem-orp1" typeId="chem-orp1"/>
<channel id="chem-orp2" typeId="chem-orp2"/>
<channel id="chem-ph1" typeId="chem-ph1"/>
<channel id="chem-ph2" typeId="chem-ph2"/>
<channel id="chem-orpfd1" typeId="chem-orpfd1"/>
<channel id="chem-orpfd2" typeId="chem-orpfd2"/>
<channel id="chem-phfd1" typeId="chem-phfd1"/>
<channel id="chem-phfd2" typeId="chem-phfd2"/>
<channel id="reboot" typeId="reboot"/>
</channels>
<config-description>
<parameter name="host" type="text" required="true">
<context>network-address</context>
<label>Host or IP</label>
<description>The host name or IP address of the Autelis Controller.</description>
</parameter>
<parameter name="port" type="integer" min="1" max="65535" required="false">
<context>network-address</context>
<label>Port</label>
<description>The port the Autelis Controller is listening on.</description>
<default>80</default>
</parameter>
<parameter name="user" type="text" required="true">
<label>User Name</label>
<description>The user name to use when connecting to a Autelis Controller.</description>
</parameter>
<parameter name="password" type="text" required="true">
<label>Password</label>
<description>The password to use when connecting to a Autelis Controller.</description>
</parameter>
<parameter name="refresh" type="integer" required="false">
<label>Refresh Interval</label>
<description>Specifies the refresh interval in seconds</description>
<default>5</default>
</parameter>
</config-description>
</thing-type>
<!-- System Channels -->
<channel-type id="system-runstate" advanced="true">
<item-type>Number</item-type>
<label>Runstate</label>
<description>The controller's runstate. 1 = Not Connected, 2-7 = Startup Initialization Sequence, 8 = Connected and
Ready, 9-12 = Connected and Busy Executing Command
</description>
<state readOnly="true">
</state>
</channel-type>
<channel-type id="system-model" advanced="true">
<item-type>Number</item-type>
<label>Model</label>
<description>The model number of the Aqualink® controller</description>
<state readOnly="true">
</state>
</channel-type>
<channel-type id="system-dip" advanced="true">
<item-type>Number</item-type>
<label>Dip Switches</label>
<description>The current state of the Aqualink® controller's dip switches. Possible values: 8 binary digits
representing S1-S8 from left to right
</description>
<state readOnly="true">
</state>
</channel-type>
<channel-type id="system-opmode">
<item-type>Number</item-type>
<label>Operation Mode</label>
<description>The current state of the Aqualink® controller</description>
<state>
<options>
<option value="0">Auto</option>
<option value="1">Service</option>
<option value="2">Timeout</option>
</options>
</state>
</channel-type>
<channel-type id="system-vbat">
<item-type>Number</item-type>
<label>Battery Voltage</label>
<description>The voltage of the Aqualink® controller's battery</description>
<state readOnly="true">
</state>
</channel-type>
<channel-type id="system-lowbat">
<item-type>Number</item-type>
<label>Battery State</label>
<description>The current state of the Aqualink® controller's battery</description>
<state readOnly="true">
<options>
<option value="0">Normal</option>
<option value="1">Low</option>
</options>
</state>
</channel-type>
<channel-type id="system-version" advanced="true">
<item-type>String</item-type>
<label>Version</label>
<description>The firmware version of the Pool Control device </description>
</channel-type>
<channel-type id="system-time" advanced="true">
<item-type>Number</item-type>
<label>Time</label>
<description>The time as kept by the Pool Control device</description>
</channel-type>
<!-- Equipment Channels -->
<channel-type id="equipment-switch">
<item-type>Switch</item-type>
<label>Equipment Switch</label>
<description>The current state of a equipment switch</description>
</channel-type>
<channel-type id="equipment-ht">
<item-type>Number</item-type>
<label>Heater</label>
<description>The current state of the heater</description>
<state>
<options>
<option value="0">Off</option>
<option value="1">Enabled</option>
<option value="2">On</option>
</options>
</state>
</channel-type>
<channel-type id="equipment-aux">
<item-type>Number</item-type>
<label>Auxiliary</label>
<description>The current state of auxiliary channel</description>
<state>
<options>
<option value="0">Off</option>
<option value="1">On</option>
<option value="25">25%</option>
<option value="50">50%</option>
<option value="75">75%</option>
<option value="100">100%</option>
</options>
</state>
</channel-type>
<!-- Temperature Channels -->
<channel-type id="temp-sp">
<item-type>Number</item-type>
<label>Setpoint</label>
<description>The current setpoint</description>
<category>Temperature</category>
</channel-type>
<channel-type id="temp-temperature">
<item-type>Number</item-type>
<label>Temperature</label>
<description>The current temperature. Note: Only accurate when pool is running</description>
<category>Temperature</category>
<state readOnly="true">
</state>
</channel-type>
<channel-type id="temp-airtemp">
<item-type>Number</item-type>
<label>Air Temperature</label>
<description>The current air temperature</description>
<category>Temperature</category>
<state readOnly="true">
</state>
</channel-type>
<channel-type id="temp-tempunits" advanced="true">
<item-type>String</item-type>
<label>Temperature Units</label>
<description>The selected units for temperature</description>
<state>
<options>
<option value="F">Fahrenheit</option>
<option value="C">Celsius</option>
</options>
</state>
</channel-type>
<!-- Pump Channels -->
<channel-type id="pumps-vsp1">
<item-type>String</item-type>
<label>Pump 1</label>
<description>Pump 1</description>
</channel-type>
<channel-type id="pumps-vsp2">
<item-type>String</item-type>
<label>Pump 2</label>
<description>Pump 2</description>
</channel-type>
<channel-type id="pumps-vsp3">
<item-type>String</item-type>
<label>Pump 3</label>
<description>Pump 3</description>
</channel-type>
<channel-type id="pumps-vsp4">
<item-type>String</item-type>
<label>Pump 4</label>
<description>Pump 4</description>
</channel-type>
<!-- Chem Channels -->
<channel-type id="chem-avail" advanced="true">
<item-type>Number</item-type>
<label>Equipment Is Available</label>
<description>Indicates what equipment is available</description>
<state readOnly="true">
</state>
</channel-type>
<channel-type id="chem-chlrp" advanced="true">
<item-type>Number</item-type>
<label>Pool Chlorination Setpoint</label>
<description>Pool chlorination setpoint</description>
</channel-type>
<channel-type id="chem-saltp" advanced="true">
<item-type>Number</item-type>
<label>Pool Salt Level</label>
<description>Pool salt level</description>
<state readOnly="true">
</state>
</channel-type>
<channel-type id="chem-chlrs" advanced="true">
<item-type>Number</item-type>
<label>Spa Chlorination Setpoint</label>
<description>Spa chlorination setpoint</description>
</channel-type>
<channel-type id="chem-salts" advanced="true">
<item-type>Number</item-type>
<label>Spa Salt Level</label>
<description>Spa salt level</description>
<state readOnly="true">
</state>
</channel-type>
<channel-type id="chem-orp1" advanced="true">
<item-type>Number</item-type>
<label>ORP Unit 1</label>
<description>ORP reading from unit 1</description>
<state readOnly="true">
</state>
</channel-type>
<channel-type id="chem-orp2" advanced="true">
<item-type>Number</item-type>
<label>ORP Unit 2</label>
<description>ORP reading from unit 2</description>
<state readOnly="true">
</state>
</channel-type>
<channel-type id="chem-ph1" advanced="true">
<item-type>Number</item-type>
<label>PH Unit 1</label>
<description>PH reading from unit 1</description>
<state readOnly="true">
</state>
</channel-type>
<channel-type id="chem-ph2" advanced="true">
<item-type>Number</item-type>
<label>PH Unit 2</label>
<description>PH reading from unit 2</description>
<state readOnly="true">
</state>
</channel-type>
<channel-type id="chem-orpfd1" advanced="true">
<item-type>Number</item-type>
<label>ORP Feed Unit 1</label>
<description>ORP feed from unit 1</description>
<state readOnly="true">
</state>
</channel-type>
<channel-type id="chem-orpfd2" advanced="true">
<item-type>Number</item-type>
<label>ORP Feed Unit 2</label>
<description>ORP feed from unit 2</description>
<state readOnly="true">
</state>
</channel-type>
<channel-type id="chem-phfd1" advanced="true">
<item-type>Number</item-type>
<label>PH Feed Unit 1</label>
<description>PH feed from unit 1</description>
<state readOnly="true">
</state>
</channel-type>
<channel-type id="chem-phfd2" advanced="true">
<item-type>Number</item-type>
<label>PH Feed Unit 2</label>
<description>PH feed from unit 2</description>
<state readOnly="true">
</state>
</channel-type>
<!-- Misc Channels -->
<channel-type id="reboot">
<item-type>Switch</item-type>
<label>Reboot Autelis Device</label>
<description>Reboots the Autelis device. This will not reboot any actual pool equipment.</description>
</channel-type>
</thing:thing-descriptions>

View File

@@ -0,0 +1,507 @@
<?xml version="1.0" encoding="UTF-8"?>
<thing:thing-descriptions bindingId="autelis"
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="pentair">
<label>Pentair Pool Controller</label>
<description>A Pentair pool control thing represents an Autelis pool controller for Pentair systems</description>
<channels>
<channel id="system-runstate" typeId="system-runstate"/>
<channel id="system-model" typeId="system-model"/>
<channel id="system-haddr" typeId="system-haddr"/>
<channel id="system-opmode" typeId="system-opmode"/>
<channel id="system-freeze" typeId="system-freeze"/>
<channel id="system-sensor1" typeId="system-sensor">
<label>Sensor 1</label>
<description>The state of sensor 1 (water sensor)</description>
</channel>
<channel id="system-sensor2" typeId="system-sensor">
<label>Sensor 2</label>
<description>The state of sensor 2 (water sensor)</description>
</channel>
<channel id="system-sensor3" typeId="system-sensor">
<label>Sensor 3</label>
<description>The state of sensor 3 (water sensor)</description>
</channel>
<channel id="system-sensor4" typeId="system-sensor">
<label>Sensor 4</label>
<description>The state of sensor 4 (water sensor)</description>
</channel>
<channel id="system-sensor5" typeId="system-sensor">
<label>Sensor 5</label>
<description>The state of sensor 5 (water sensor)</description>
</channel>
<channel id="system-version" typeId="system-version"/>
<channel id="system-time" typeId="system-time"/>
<channel id="equipment-circuit1" typeId="equipment-circuit">
<label>Circuit 1</label>
<description>The current state of circuit 1 (Spa or Lo-Temp)</description>
</channel>
<channel id="equipment-circuit2" typeId="equipment-circuit">
<label>Circuit 2</label>
<description>The current state of circuit 2 (Spa or Lo-Temp)</description>
</channel>
<channel id="equipment-circuit3" typeId="equipment-circuit">
<label>Circuit 3</label>
<description>The current state of circuit 3 (Spa or Lo-Temp)</description>
</channel>
<channel id="equipment-circuit4" typeId="equipment-circuit">
<label>Circuit 4</label>
<description>The current state of circuit 4 (Spa or Lo-Temp)</description>
</channel>
<channel id="equipment-circuit5" typeId="equipment-circuit">
<label>Circuit 5</label>
<description>The current state of circuit 5 (Spa or Lo-Temp)</description>
</channel>
<channel id="equipment-circuit6" typeId="equipment-circuit">
<label>Circuit 6</label>
<description>The current state of circuit 6 (Spa or Lo-Temp)</description>
</channel>
<channel id="equipment-circuit7" typeId="equipment-circuit">
<label>Circuit 7</label>
<description>The current state of circuit 7 (Spa or Lo-Temp)</description>
</channel>
<channel id="equipment-circuit8" typeId="equipment-circuit">
<label>Circuit 8</label>
<description>The current state of circuit 8 (Spa or Lo-Temp)</description>
</channel>
<channel id="equipment-circuit9" typeId="equipment-circuit">
<label>Circuit 9</label>
<description>The current state of circuit 9 (Spa or Lo-Temp)</description>
</channel>
<channel id="equipment-circuit10" typeId="equipment-circuit">
<label>Circuit 10</label>
<description>The current state of circuit 10 (Spa or Lo-Temp)</description>
</channel>
<channel id="equipment-feature1" typeId="equipment-feature">
<label>Feature 1</label>
<description>The current state of feature/macro 1</description>
</channel>
<channel id="equipment-feature2" typeId="equipment-feature">
<label>Feature 2</label>
<description>The current state of feature/macro 2</description>
</channel>
<channel id="equipment-feature3" typeId="equipment-feature">
<label>Feature 3</label>
<description>The current state of feature/macro 3</description>
</channel>
<channel id="equipment-feature4" typeId="equipment-feature">
<label>Feature 4</label>
<description>The current state of feature/macro 4</description>
</channel>
<channel id="equipment-feature5" typeId="equipment-feature">
<label>Feature 5</label>
<description>The current state of feature/macro 5</description>
</channel>
<channel id="equipment-feature6" typeId="equipment-feature">
<label>Feature 6</label>
<description>The current state of feature/macro 6</description>
</channel>
<channel id="equipment-feature7" typeId="equipment-feature">
<label>Feature 7</label>
<description>The current state of feature/macro 7</description>
</channel>
<channel id="equipment-feature8" typeId="equipment-feature">
<label>Feature 8</label>
<description>The current state of feature/macro 8</description>
</channel>
<channel id="equipment-feature9" typeId="equipment-feature">
<label>Feature 9</label>
<description>The current state of feature/macro 9</description>
</channel>
<channel id="equipment-feature10" typeId="equipment-feature">
<label>Feature 10</label>
<description>The current state of feature/macro 10</description>
</channel>
<channel id="temp-poolht" typeId="temp-ht">
<label>Pool Heater Status</label>
<description>The current pool/hi-temp heater settings</description>
</channel>
<channel id="temp-spaht" typeId="temp-ht">
<label>Spa Heater Status</label>
<description>The current spa/hi-temp heater settings</description>
</channel>
<channel id="temp-htstatus" typeId="temp-htstatus"/>
<channel id="temp-poolsp" typeId="temp-poolsp"/>
<channel id="temp-spasp" typeId="temp-spasp"/>
<channel id="temp-pooltemp" typeId="temp-pooltemp"/>
<channel id="temp-spatemp" typeId="temp-spatemp"/>
<channel id="temp-airtemp" typeId="temp-airtemp"/>
<channel id="temp-soltemp" typeId="temp-soltemp"/>
<channel id="temp-tempunits" typeId="temp-tempunits"/>
<channel id="temp-htpump" typeId="temp-htpump"/>
<channel id="pumps-pump1" typeId="pumps-pump1"/>
<channel id="pumps-pump1-watts" typeId="pumps-pump1-watts"/>
<channel id="pumps-pump1-rpm" typeId="pumps-pump1-rpm"/>
<channel id="pumps-pump1-gpm" typeId="pumps-pump1-gpm"/>
<channel id="pumps-pump1-filter" typeId="pumps-pump1-filter"/>
<channel id="pumps-pump1-error" typeId="pumps-pump1-error"/>
<channel id="pumps-pump2" typeId="pumps-pump">
<label>Pump 2</label>
<description>Pump 2</description>
</channel>
<channel id="pumps-pump3" typeId="pumps-pump">
<label>Pump 3</label>
<description>Pump 3</description>
</channel>
<channel id="pumps-pump4" typeId="pumps-pump">
<label>Pump 4</label>
<description>Pump 4</description>
</channel>
<channel id="pumps-pump5" typeId="pumps-pump">
<label>Pump 5</label>
<description>Pump 5</description>
</channel>
<channel id="pumps-pump6" typeId="pumps-pump">
<label>Pump 6</label>
<description>Pump 6</description>
</channel>
<channel id="pumps-pump7" typeId="pumps-pump">
<label>Pump 7</label>
<description>Pump 7</description>
</channel>
<channel id="pumps-pump8" typeId="pumps-pump">
<label>Pump 8</label>
<description>Pump 8</description>
</channel>
<channel id="chlor-chloren" typeId="chlor-chloren"/>
<channel id="chlor-poolsp" typeId="chlor-poolsp"/>
<channel id="chlor-spasp" typeId="chlor-spasp"/>
<channel id="chlor-salt" typeId="chlor-salt"/>
<channel id="chlor-super" typeId="chlor-super"/>
<channel id="chlor-chlorerr" typeId="chlor-chlorerr"/>
<channel id="chlor-chlorname" typeId="chlor-chlorname"/>
<channel id="lightscmd" typeId="lightscmd"/>
<channel id="reboot" typeId="reboot"/>
</channels>
<config-description>
<parameter name="host" type="text" required="true">
<context>network-address</context>
<label>Host or IP</label>
<description>The host name or IP address of the Autelis Controller.</description>
</parameter>
<parameter name="port" type="integer" min="1" max="65535" required="false">
<context>network-address</context>
<label>Port</label>
<description>The port the Autelis Controller is listening on.</description>
<default>80</default>
</parameter>
<parameter name="user" type="text" required="true">
<label>User Name</label>
<description>The user name to use when connecting to a Autelis Controller.</description>
</parameter>
<parameter name="password" type="text" required="true">
<label>Password</label>
<description>The password to use when connecting to a Autelis Controller.</description>
</parameter>
<parameter name="refresh" type="integer" required="false">
<label>Refresh Interval</label>
<description>Specifies the refresh interval in seconds</description>
<default>5</default>
</parameter>
</config-description>
</thing-type>
<!-- System Channels -->
<channel-type id="system-runstate" advanced="true">
<item-type>Number</item-type>
<label>Runstate</label>
<description>The controller's runstate. 1 = Starting Up, 2-49 = Getting Data, 50 = Ready</description>
<state readOnly="true">
</state>
</channel-type>
<channel-type id="system-model" advanced="true">
<item-type>Number</item-type>
<label>Model</label>
<description>The model of the Intellitouch® controller</description>
<state readOnly="true">
</state>
</channel-type>
<channel-type id="system-haddr" advanced="true">
<item-type>Number</item-type>
<label>Hardware Address</label>
<description>The controller's harware address</description>
<state readOnly="true">
</state>
</channel-type>
<channel-type id="system-opmode">
<item-type>Number</item-type>
<label>Operation Mode</label>
<description>The current state of the Intellitouch® controller</description>
<state readOnly="true">
<options>
<option value="0">Auto</option>
<option value="1">Service/Timeout</option>
</options>
</state>
</channel-type>
<channel-type id="system-freeze">
<item-type>Number</item-type>
<label>Freeze State</label>
<description>The state of freeze protect</description>
<state readOnly="true">
<options>
<option value="0">Off</option>
<option value="1">On</option>
</options>
</state>
</channel-type>
<channel-type id="system-sensor">
<item-type>Number</item-type>
<label>Sensor</label>
<description>The state of a sensor (water sensor)</description>
<state readOnly="true">
<options>
<option value="0">OK</option>
<option value="1">ERROR</option>
</options>
</state>
</channel-type>
<channel-type id="system-version" advanced="true">
<item-type>String</item-type>
<label>Version</label>
<description>The firmware version of the Pool Control device </description>
</channel-type>
<channel-type id="system-time" advanced="true">
<item-type>Number</item-type>
<label>Time</label>
<description>The time as kept by the Pool Control device</description>
</channel-type>
<!-- Equipment Channels -->
<channel-type id="equipment-circuit">
<item-type>Switch</item-type>
<label>Circuit 1</label>
<description>The current state of a circuit (Spa or Lo-Temp)</description>
</channel-type>
<channel-type id="equipment-feature">
<item-type>Number</item-type>
<label>Feature</label>
<description>The current state of a feature/macro</description>
</channel-type>
<!-- Temperature Channels -->
<channel-type id="temp-ht">
<item-type>Number</item-type>
<label>Heater Status</label>
<description>The current hi-temp heater settings</description>
<category>Temperature</category>
<state>
<options>
<option value="0">Off</option>
<option value="1">Heater</option>
<option value="2">Solar Preferred</option>
<option value="3">Solar Only</option>
</options>
</state>
</channel-type>
<channel-type id="temp-htstatus" advanced="true">
<item-type>Number</item-type>
<label>Heat Status</label>
<description>Heat Status</description>
<state readOnly="true">
</state>
</channel-type>
<channel-type id="temp-poolsp">
<item-type>Number</item-type>
<label>Pool Heat Setpoint</label>
<description>The current pool/hi-temp setpoint</description>
<category>Temperature</category>
</channel-type>
<channel-type id="temp-spasp">
<item-type>Number</item-type>
<label>Spa Heat Setpoint</label>
<description>The current spa/lo-temp setpoint</description>
<category>Temperature</category>
</channel-type>
<channel-type id="temp-pooltemp">
<item-type>Number</item-type>
<label>Pool Temp</label>
<description>The current pool temperature. Note: Only accurate when pool is running</description>
<category>Temperature</category>
<state readOnly="true">
</state>
</channel-type>
<channel-type id="temp-spatemp">
<item-type>Number</item-type>
<label>Spa Temperature</label>
<description>The current spa temperature. Note: Only accurate when spa is running</description>
<category>Temperature</category>
<state readOnly="true">
</state>
</channel-type>
<channel-type id="temp-airtemp">
<item-type>Number</item-type>
<label>Air Temperature</label>
<description>The current temperature measured by the air sensor</description>
<category>Temperature</category>
<state readOnly="true">
</state>
</channel-type>
<channel-type id="temp-soltemp">
<item-type>Number</item-type>
<label>Solar Temperature</label>
<description>The current temperature measured by the solar sensor</description>
<category>Temperature</category>
<state readOnly="true">
</state>
</channel-type>
<channel-type id="temp-tempunits" advanced="true">
<item-type>String</item-type>
<label>Temperature Units</label>
<description>The selected units for temperature</description>
<state readOnly="true">
<options>
<option value="F">Fahrenheit</option>
<option value="C">Celsius</option>
</options>
</state>
</channel-type>
<channel-type id="temp-htpump" advanced="true">
<item-type>Number</item-type>
<label>Heat Pump</label>
<description>Heat Pump</description>
<state readOnly="true">
</state>
</channel-type>
<!-- Pump Channels -->
<channel-type id="pumps-pump1" advanced="true">
<item-type>String</item-type>
<label>Pump 1</label>
<description>Pump 1 raw value</description>
<state readOnly="true">
</state>
</channel-type>
<channel-type id="pumps-pump1-watts">
<item-type>Number</item-type>
<label>Pump 1 Watts</label>
<description>Pump 1 watts</description>
<state readOnly="true">
</state>
</channel-type>
<channel-type id="pumps-pump1-rpm">
<item-type>Number</item-type>
<label>Pump 1 RPM</label>
<description>Pump 1 RPM</description>
<state readOnly="true">
</state>
</channel-type>
<channel-type id="pumps-pump1-gpm">
<item-type>Number</item-type>
<label>Pump 1 GPM</label>
<description>Pump 1 GPM</description>
<state readOnly="true">
</state>
</channel-type>
<channel-type id="pumps-pump1-filter">
<item-type>Number</item-type>
<label>Pump 1 Filter</label>
<description>Pump 1</description>
<state readOnly="true">
</state>
</channel-type>
<channel-type id="pumps-pump1-error">
<item-type>Number</item-type>
<label>Pump 1 Error</label>
<description>Pump 1 error status</description>
<state readOnly="true">
</state>
</channel-type>
<channel-type id="pumps-pump">
<item-type>String</item-type>
<label>Pump 2</label>
<description>Pump 2</description>
<state readOnly="true">
</state>
</channel-type>
<!-- Chem Channels -->
<channel-type id="chlor-chloren" advanced="true">
<item-type>Number</item-type>
<label>Chlorine</label>
<description>Chlorine</description>
<state readOnly="true">
</state>
</channel-type>
<channel-type id="chlor-poolsp" advanced="true">
<item-type>Number</item-type>
<label>Chlorine Pool Setpoint</label>
<description>Chlorine Pool Setpoint</description>
</channel-type>
<channel-type id="chlor-spasp" advanced="true">
<item-type>Number</item-type>
<label>Chlorine Spa Setpoint</label>
<description>Chlorine Sap Setpoint</description>
</channel-type>
<channel-type id="chlor-salt">
<item-type>Number</item-type>
<label>Chlorine Salt Level</label>
<description>Chlorine Salt Level</description>
<state readOnly="true">
</state>
</channel-type>
<channel-type id="chlor-super" advanced="true">
<item-type>Number</item-type>
<label>Chlorine Super Level</label>
<description>Chlorine Super Level</description>
<state readOnly="true">
</state>
</channel-type>
<channel-type id="chlor-chlorerr" advanced="true">
<item-type>Number</item-type>
<label>Chlorine Error</label>
<description>Chlorine Error value</description>
<state readOnly="true">
</state>
</channel-type>
<channel-type id="chlor-chlorname" advanced="true">
<item-type>String</item-type>
<label>Chlorine Model Name</label>
<description>Chlorine Model Name</description>
<state readOnly="true">
</state>
</channel-type>
<channel-type id="lightscmd">
<item-type>String</item-type>
<label>Lighting Cmd</label>
<description>Send A lighting command</description>
<category>ColorLight</category>
<state>
<options>
<option value="alloff">All Off</option>
<option value="allon">All On</option>
<option value="csync">C Sync</option>
<option value="cset">C Set</option>
<option value="cswim">C Swim</option>
<option value="party">Party</option>
<option value="romance">Romance</option>
<option value="caribbean">Caribbean</option>
<option value="american">American</option>
<option value="sunset">Sunset</option>
<option value="royalty">Royalty</option>
<option value="blue">Blue</option>
<option value="green">Green</option>
<option value="red">Red</option>
<option value="white">White</option>
<option value="magenta">Magenta</option>
<option value="hold">Hold</option>
<option value="recall">Recall</option>
</options>
</state>
</channel-type>
<!-- Misc Channels -->
<channel-type id="reboot">
<item-type>Switch</item-type>
<label>Reboot Autelis Device</label>
<description>Reboots the Autelis device. This will not reboot any actual pool equipment.</description>
</channel-type>
</thing:thing-descriptions>