added migrated 2.x add-ons
Signed-off-by: Kai Kreuzer <kai@openhab.org>
This commit is contained in:
@@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<features name="org.openhab.binding.hydrawise-${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-hydrawise" description="Hydrawise Binding" version="${project.version}">
|
||||
<feature>openhab-runtime-base</feature>
|
||||
<bundle start-level="80">mvn:org.openhab.addons.bundles/org.openhab.binding.hydrawise/${project.version}</bundle>
|
||||
</feature>
|
||||
</features>
|
||||
@@ -0,0 +1,69 @@
|
||||
/**
|
||||
* 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.hydrawise.internal;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.core.thing.ThingTypeUID;
|
||||
|
||||
/**
|
||||
* The {@link HydrawiseBindingConstants} class defines common constants, which are
|
||||
* used across the whole binding.
|
||||
*
|
||||
* @author Dan Cunningham - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class HydrawiseBindingConstants {
|
||||
|
||||
private static final String BINDING_ID = "hydrawise";
|
||||
|
||||
// List of all Thing Type UIDs
|
||||
public static final ThingTypeUID THING_TYPE_CLOUD = new ThingTypeUID(BINDING_ID, "cloud");
|
||||
public static final ThingTypeUID THING_TYPE_LOCAL = new ThingTypeUID(BINDING_ID, "local");
|
||||
|
||||
public static final String BASE_IMAGE_URL = "https://app.hydrawise.com/config/images/";
|
||||
|
||||
public static final String CHANNEL_GROUP_ALLZONES = "allzones";
|
||||
public static final String CHANNEL_ZONE_RUN_CUSTOM = "runcustom";
|
||||
public static final String CHANNEL_ZONE_RUN = "run";
|
||||
public static final String CHANNEL_ZONE_STOP = "stop";
|
||||
public static final String CHANNEL_ZONE_SUSPEND = "suspend";
|
||||
public static final String CHANNEL_ZONE_NAME = "name";
|
||||
public static final String CHANNEL_ZONE_ICON = "icon";
|
||||
public static final String CHANNEL_ZONE_LAST_WATER = "lastwater";
|
||||
public static final String CHANNEL_ZONE_TIME = "time";
|
||||
public static final String CHANNEL_ZONE_TYPE = "type";
|
||||
public static final String CHANNEL_ZONE_NEXT_RUN_TIME_TIME = "nextruntime";
|
||||
public static final String CHANNEL_ZONE_TIME_LEFT = "timeleft";
|
||||
public static final String CHANNEL_RUN_ALL_ZONES = "runall";
|
||||
public static final String CHANNEL_STOP_ALL_ZONES = "stopall";
|
||||
public static final String CHANNEL_SUSPEND_ALL_ZONES = "suspendall";
|
||||
public static final String CHANNEL_SENSOR_NAME = "name";
|
||||
public static final String CHANNEL_SENSOR_INPUT = "input";
|
||||
public static final String CHANNEL_SENSOR_MODE = "mode";
|
||||
public static final String CHANNEL_SENSOR_TIMER = "timer";
|
||||
public static final String CHANNEL_SENSOR_OFFTIMER = "offtimer";
|
||||
public static final String CHANNEL_SENSOR_OFFLEVEL = "offlevel";
|
||||
public static final String CHANNEL_SENSOR_ACTIVE = "active";
|
||||
public static final String CHANNEL_FORECAST_TEMPERATURE_HIGH = "temperaturehigh";
|
||||
public static final String CHANNEL_FORECAST_TEMPERATURE_LOW = "temperaturelow";
|
||||
public static final String CHANNEL_FORECAST_CONDITIONS = "conditions";
|
||||
public static final String CHANNEL_FORECAST_DAY = "day";
|
||||
public static final String CHANNEL_FORECAST_HUMIDITY = "humidity";
|
||||
public static final String CHANNEL_FORECAST_WIND = "wind";
|
||||
public static final String CHANNEL_FORECAST_ICON = "icon";
|
||||
public static final String PROPERTY_CONTROLLER_ID = "controller";
|
||||
public static final String PROPERTY_NAME = "name";
|
||||
public static final String PROPERTY_DESCRIPTION = "description";
|
||||
public static final String PROPERTY_LOCATION = "location";
|
||||
public static final String PROPERTY_ADDRESS = "address";
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
/**
|
||||
* 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.hydrawise.internal;
|
||||
|
||||
/**
|
||||
* The {@link HydrawiseCloudConfiguration} class contains fields mapping thing configuration parameters.
|
||||
*
|
||||
* @author Dan Cunningham - Initial contribution
|
||||
*/
|
||||
public class HydrawiseCloudConfiguration {
|
||||
|
||||
/**
|
||||
* Customer API key {@link https://app.hydrawise.com/config/account}
|
||||
*/
|
||||
public String apiKey;
|
||||
|
||||
/**
|
||||
* refresh interval in seconds.
|
||||
*/
|
||||
public Integer refresh;
|
||||
|
||||
/**
|
||||
* optional id of the controller to connect to
|
||||
*/
|
||||
public Integer controllerId;
|
||||
}
|
||||
@@ -0,0 +1,245 @@
|
||||
/**
|
||||
* 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.hydrawise.internal;
|
||||
|
||||
import static org.openhab.binding.hydrawise.internal.HydrawiseBindingConstants.*;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.eclipse.jdt.annotation.NonNull;
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.eclipse.jetty.client.HttpClient;
|
||||
import org.openhab.binding.hydrawise.internal.api.HydrawiseAuthenticationException;
|
||||
import org.openhab.binding.hydrawise.internal.api.HydrawiseCloudApiClient;
|
||||
import org.openhab.binding.hydrawise.internal.api.HydrawiseCommandException;
|
||||
import org.openhab.binding.hydrawise.internal.api.HydrawiseConnectionException;
|
||||
import org.openhab.binding.hydrawise.internal.api.model.Controller;
|
||||
import org.openhab.binding.hydrawise.internal.api.model.CustomerDetailsResponse;
|
||||
import org.openhab.binding.hydrawise.internal.api.model.Forecast;
|
||||
import org.openhab.binding.hydrawise.internal.api.model.Relay;
|
||||
import org.openhab.binding.hydrawise.internal.api.model.StatusScheduleResponse;
|
||||
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.thing.Thing;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* The {@link HydrawiseCloudHandler} is responsible for handling commands, which are
|
||||
* sent to one of the channels.
|
||||
*
|
||||
* @author Dan Cunningham - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class HydrawiseCloudHandler extends HydrawiseHandler {
|
||||
/**
|
||||
* 74.2 F
|
||||
*/
|
||||
private static final Pattern TEMPERATURE_PATTERN = Pattern.compile("^(\\d{1,3}.?\\d?)\\s([C,F])");
|
||||
/**
|
||||
* 9 mph
|
||||
*/
|
||||
private static final Pattern WIND_SPEED_PATTERN = Pattern.compile("^(\\d{1,3})\\s([a-z]{3})");
|
||||
private final Logger logger = LoggerFactory.getLogger(HydrawiseCloudHandler.class);
|
||||
private HydrawiseCloudApiClient client;
|
||||
private int controllerId;
|
||||
|
||||
public HydrawiseCloudHandler(Thing thing, HttpClient httpClient) {
|
||||
super(thing);
|
||||
this.client = new HydrawiseCloudApiClient(httpClient);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void configure()
|
||||
throws NotConfiguredException, HydrawiseConnectionException, HydrawiseAuthenticationException {
|
||||
HydrawiseCloudConfiguration configuration = getConfig().as(HydrawiseCloudConfiguration.class);
|
||||
|
||||
this.refresh = Math.max(configuration.refresh, MIN_REFRESH_SECONDS);
|
||||
|
||||
client.setApiKey(configuration.apiKey);
|
||||
|
||||
CustomerDetailsResponse customerDetails = client.getCustomerDetails();
|
||||
|
||||
List<Controller> controllers = customerDetails.controllers;
|
||||
if (controllers.isEmpty()) {
|
||||
throw new NotConfiguredException("No controllers found on account");
|
||||
}
|
||||
|
||||
Controller controller = null;
|
||||
// try and use ID from user configuration
|
||||
if (configuration.controllerId != null) {
|
||||
controller = getController(configuration.controllerId.intValue(), controllers);
|
||||
if (controller == null) {
|
||||
throw new NotConfiguredException("No controller found for id " + configuration.controllerId);
|
||||
}
|
||||
} else {
|
||||
// try and use ID from saved property
|
||||
String controllerId = getThing().getProperties().get(PROPERTY_CONTROLLER_ID);
|
||||
if (StringUtils.isNotBlank(controllerId)) {
|
||||
try {
|
||||
controller = getController(Integer.parseInt(controllerId), controllers);
|
||||
|
||||
} catch (NumberFormatException e) {
|
||||
logger.debug("Can not parse property vaue {}", controllerId);
|
||||
}
|
||||
}
|
||||
// use current controller ID
|
||||
if (controller == null) {
|
||||
controller = getController(customerDetails.controllerId, controllers);
|
||||
}
|
||||
}
|
||||
|
||||
if (controller == null) {
|
||||
throw new NotConfiguredException("No controller found");
|
||||
}
|
||||
|
||||
controllerId = controller.controllerId.intValue();
|
||||
updateControllerProperties(controller);
|
||||
logger.debug("Controller id {}", controllerId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Poll the controller for updates.
|
||||
*/
|
||||
@Override
|
||||
protected void pollController() throws HydrawiseConnectionException, HydrawiseAuthenticationException {
|
||||
List<Controller> controllers = client.getCustomerDetails().controllers;
|
||||
Controller controller = getController(controllerId, controllers);
|
||||
if (controller != null && !controller.online) {
|
||||
throw new HydrawiseConnectionException("Controller is offline");
|
||||
}
|
||||
StatusScheduleResponse status = client.getStatusSchedule(controllerId);
|
||||
updateSensors(status);
|
||||
updateForecast(status);
|
||||
updateZones(status);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void sendRunCommand(int seconds, @Nullable Relay relay)
|
||||
throws HydrawiseCommandException, HydrawiseConnectionException, HydrawiseAuthenticationException {
|
||||
if (relay != null) {
|
||||
client.runRelay(seconds, relay.relayId);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void sendRunCommand(@Nullable Relay relay)
|
||||
throws HydrawiseCommandException, HydrawiseConnectionException, HydrawiseAuthenticationException {
|
||||
if (relay != null) {
|
||||
client.runRelay(relay.relayId);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void sendStopCommand(@Nullable Relay relay)
|
||||
throws HydrawiseCommandException, HydrawiseConnectionException, HydrawiseAuthenticationException {
|
||||
if (relay != null) {
|
||||
client.stopRelay(relay.relayId);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void sendRunAllCommand()
|
||||
throws HydrawiseCommandException, HydrawiseConnectionException, HydrawiseAuthenticationException {
|
||||
client.runAllRelays(controllerId);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void sendRunAllCommand(int seconds)
|
||||
throws HydrawiseCommandException, HydrawiseConnectionException, HydrawiseAuthenticationException {
|
||||
client.runAllRelays(seconds, controllerId);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void sendStopAllCommand()
|
||||
throws HydrawiseCommandException, HydrawiseConnectionException, HydrawiseAuthenticationException {
|
||||
client.stopAllRelays(controllerId);
|
||||
}
|
||||
|
||||
private void updateSensors(StatusScheduleResponse status) {
|
||||
status.sensors.forEach(sensor -> {
|
||||
String group = "sensor" + sensor.input;
|
||||
updateGroupState(group, CHANNEL_SENSOR_MODE, new DecimalType(sensor.type));
|
||||
updateGroupState(group, CHANNEL_SENSOR_NAME, new StringType(sensor.name));
|
||||
updateGroupState(group, CHANNEL_SENSOR_OFFTIMER, new DecimalType(sensor.offtimer));
|
||||
updateGroupState(group, CHANNEL_SENSOR_TIMER, new DecimalType(sensor.timer));
|
||||
// Some fields are missing depending on sensor type.
|
||||
if (sensor.offlevel != null) {
|
||||
updateGroupState(group, CHANNEL_SENSOR_OFFLEVEL, new DecimalType(sensor.offlevel));
|
||||
}
|
||||
if (sensor.active != null) {
|
||||
updateGroupState(group, CHANNEL_SENSOR_ACTIVE, sensor.active > 0 ? OnOffType.ON : OnOffType.OFF);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void updateForecast(StatusScheduleResponse status) {
|
||||
int i = 1;
|
||||
for (Forecast forecast : status.forecast) {
|
||||
String group = "forecast" + (i++);
|
||||
updateGroupState(group, CHANNEL_FORECAST_CONDITIONS, new StringType(forecast.conditions));
|
||||
updateGroupState(group, CHANNEL_FORECAST_DAY, new StringType(forecast.day));
|
||||
updateGroupState(group, CHANNEL_FORECAST_HUMIDITY, new DecimalType(forecast.humidity));
|
||||
updateTemperature(forecast.tempHi, group, CHANNEL_FORECAST_TEMPERATURE_HIGH);
|
||||
updateTemperature(forecast.tempLo, group, CHANNEL_FORECAST_TEMPERATURE_LOW);
|
||||
updateWindspeed(forecast.wind, group, CHANNEL_FORECAST_WIND);
|
||||
}
|
||||
}
|
||||
|
||||
private void updateTemperature(String tempString, String group, String channel) {
|
||||
Matcher matcher = TEMPERATURE_PATTERN.matcher(tempString);
|
||||
if (matcher.matches()) {
|
||||
try {
|
||||
updateGroupState(group, channel, new QuantityType<>(Double.valueOf(matcher.group(1)),
|
||||
"C".equals(matcher.group(2)) ? SIUnits.CELSIUS : ImperialUnits.FAHRENHEIT));
|
||||
} catch (NumberFormatException e) {
|
||||
logger.debug("Could not parse temperature string {} ", tempString);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void updateWindspeed(String windString, String group, String channel) {
|
||||
Matcher matcher = WIND_SPEED_PATTERN.matcher(windString);
|
||||
if (matcher.matches()) {
|
||||
try {
|
||||
updateGroupState(group, channel, new QuantityType<>(Integer.parseInt(matcher.group(1)),
|
||||
"kph".equals(matcher.group(2)) ? SIUnits.KILOMETRE_PER_HOUR : ImperialUnits.MILES_PER_HOUR));
|
||||
} catch (NumberFormatException e) {
|
||||
logger.debug("Could not parse wind string {} ", windString);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void updateControllerProperties(Controller controller) {
|
||||
getThing().setProperty(PROPERTY_CONTROLLER_ID, String.valueOf(controller.controllerId));
|
||||
getThing().setProperty(PROPERTY_NAME, controller.name);
|
||||
getThing().setProperty(PROPERTY_DESCRIPTION, controller.description);
|
||||
getThing().setProperty(PROPERTY_LOCATION, controller.latitude + "," + controller.longitude);
|
||||
getThing().setProperty(PROPERTY_ADDRESS, controller.address);
|
||||
}
|
||||
|
||||
private @Nullable Controller getController(int controllerId, List<Controller> controllers) {
|
||||
Optional<@NonNull Controller> optionalController = controllers.stream()
|
||||
.filter(c -> controllerId == c.controllerId.intValue()).findAny();
|
||||
return optionalController.isPresent() ? optionalController.get() : null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,324 @@
|
||||
/**
|
||||
* 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.hydrawise.internal;
|
||||
|
||||
import static org.openhab.binding.hydrawise.internal.HydrawiseBindingConstants.*;
|
||||
|
||||
import java.time.ZonedDateTime;
|
||||
import java.time.temporal.ChronoUnit;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.ScheduledFuture;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.binding.hydrawise.internal.api.HydrawiseAuthenticationException;
|
||||
import org.openhab.binding.hydrawise.internal.api.HydrawiseCommandException;
|
||||
import org.openhab.binding.hydrawise.internal.api.HydrawiseConnectionException;
|
||||
import org.openhab.binding.hydrawise.internal.api.model.LocalScheduleResponse;
|
||||
import org.openhab.binding.hydrawise.internal.api.model.Relay;
|
||||
import org.openhab.binding.hydrawise.internal.api.model.Running;
|
||||
import org.openhab.core.library.types.DateTimeType;
|
||||
import org.openhab.core.library.types.DecimalType;
|
||||
import org.openhab.core.library.types.OnOffType;
|
||||
import org.openhab.core.library.types.StringType;
|
||||
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.RefreshType;
|
||||
import org.openhab.core.types.State;
|
||||
import org.openhab.core.types.UnDefType;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* The {@link HydrawiseHandler} is responsible for handling commands, which are
|
||||
* sent to one of the channels.
|
||||
*
|
||||
* @author Dan Cunningham - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public abstract class HydrawiseHandler extends BaseThingHandler {
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(HydrawiseHandler.class);
|
||||
private @Nullable ScheduledFuture<?> pollFuture;
|
||||
private Map<String, State> stateMap = Collections.synchronizedMap(new HashMap<>());
|
||||
private Map<String, Relay> relayMap = Collections.synchronizedMap(new HashMap<>());
|
||||
|
||||
/**
|
||||
* value observed being used by the Hydrawise clients as a max time value,
|
||||
*/
|
||||
private static long MAX_RUN_TIME = 157680000;
|
||||
|
||||
/**
|
||||
* Minimum amount of time we can poll for updates
|
||||
*/
|
||||
protected static final int MIN_REFRESH_SECONDS = 5;
|
||||
|
||||
/**
|
||||
* Minimum amount of time we can poll after a command
|
||||
*/
|
||||
protected static final int COMMAND_REFRESH_SECONDS = 5;
|
||||
|
||||
/**
|
||||
* Our poll rate
|
||||
*/
|
||||
protected int refresh;
|
||||
|
||||
/**
|
||||
* Future to poll for updated
|
||||
*/
|
||||
|
||||
public HydrawiseHandler(Thing thing) {
|
||||
super(thing);
|
||||
}
|
||||
|
||||
@SuppressWarnings({ "null", "unused" }) // compiler does not like relayMap.get can return null
|
||||
@Override
|
||||
public void handleCommand(ChannelUID channelUID, Command command) {
|
||||
if (getThing().getStatus() != ThingStatus.ONLINE) {
|
||||
logger.warn("Controller is NOT ONLINE and is not responding to commands");
|
||||
return;
|
||||
}
|
||||
|
||||
// remove our cached state for this, will be safely updated on next poll
|
||||
stateMap.remove(channelUID.getAsString());
|
||||
|
||||
if (command instanceof RefreshType) {
|
||||
// we already removed this from the cache
|
||||
return;
|
||||
}
|
||||
|
||||
String group = channelUID.getGroupId();
|
||||
String channelId = channelUID.getIdWithoutGroup();
|
||||
boolean allCommand = CHANNEL_GROUP_ALLZONES.equals(group);
|
||||
|
||||
Relay relay = relayMap.get(group);
|
||||
if (!allCommand && relay == null) {
|
||||
logger.debug("Zone not found {}", group);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
clearPolling();
|
||||
switch (channelId) {
|
||||
case CHANNEL_ZONE_RUN_CUSTOM:
|
||||
if (!(command instanceof DecimalType)) {
|
||||
logger.warn("Invalid command type for run custom {}", command.getClass().getName());
|
||||
return;
|
||||
}
|
||||
if (allCommand) {
|
||||
sendRunAllCommand(((DecimalType) command).intValue());
|
||||
} else {
|
||||
sendRunCommand(((DecimalType) command).intValue(), relay);
|
||||
}
|
||||
break;
|
||||
case CHANNEL_ZONE_RUN:
|
||||
if (!(command instanceof OnOffType)) {
|
||||
logger.warn("Invalid command type for run {}", command.getClass().getName());
|
||||
return;
|
||||
}
|
||||
if (allCommand) {
|
||||
if (command == OnOffType.ON) {
|
||||
sendRunAllCommand();
|
||||
} else {
|
||||
sendStopAllCommand();
|
||||
}
|
||||
} else {
|
||||
if (command == OnOffType.ON) {
|
||||
sendRunCommand(relay);
|
||||
} else {
|
||||
sendStopCommand(relay);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
initPolling(COMMAND_REFRESH_SECONDS);
|
||||
} catch (HydrawiseCommandException | HydrawiseConnectionException e) {
|
||||
logger.debug("Could not issue command", e);
|
||||
initPolling(COMMAND_REFRESH_SECONDS);
|
||||
} catch (HydrawiseAuthenticationException e) {
|
||||
logger.debug("Credentials not valid");
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, "Credentials not valid");
|
||||
configureInternal();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initialize() {
|
||||
scheduler.schedule(this::configureInternal, 0, TimeUnit.SECONDS);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
logger.debug("Handler disposed.");
|
||||
clearPolling();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void channelLinked(ChannelUID channelUID) {
|
||||
// clear our cached value so the new channel gets updated on the next poll
|
||||
stateMap.remove(channelUID.getId());
|
||||
}
|
||||
|
||||
protected abstract void configure()
|
||||
throws NotConfiguredException, HydrawiseConnectionException, HydrawiseAuthenticationException;
|
||||
|
||||
protected abstract void pollController() throws HydrawiseConnectionException, HydrawiseAuthenticationException;
|
||||
|
||||
protected abstract void sendRunCommand(int seconds, Relay relay)
|
||||
throws HydrawiseCommandException, HydrawiseConnectionException, HydrawiseAuthenticationException;
|
||||
|
||||
protected abstract void sendRunCommand(Relay relay)
|
||||
throws HydrawiseCommandException, HydrawiseConnectionException, HydrawiseAuthenticationException;
|
||||
|
||||
protected abstract void sendStopCommand(Relay relay)
|
||||
throws HydrawiseCommandException, HydrawiseConnectionException, HydrawiseAuthenticationException;
|
||||
|
||||
protected abstract void sendRunAllCommand()
|
||||
throws HydrawiseCommandException, HydrawiseConnectionException, HydrawiseAuthenticationException;
|
||||
|
||||
protected abstract void sendRunAllCommand(int seconds)
|
||||
throws HydrawiseCommandException, HydrawiseConnectionException, HydrawiseAuthenticationException;
|
||||
|
||||
protected abstract void sendStopAllCommand()
|
||||
throws HydrawiseCommandException, HydrawiseConnectionException, HydrawiseAuthenticationException;
|
||||
|
||||
protected void updateZones(LocalScheduleResponse status) {
|
||||
ZonedDateTime now = ZonedDateTime.now().truncatedTo(ChronoUnit.SECONDS);
|
||||
status.relays.forEach(r -> {
|
||||
String group = "zone" + r.getRelayNumber();
|
||||
relayMap.put(group, r);
|
||||
logger.trace("Updateing Zone {} {} ", group, r.name);
|
||||
updateGroupState(group, CHANNEL_ZONE_NAME, new StringType(r.name));
|
||||
updateGroupState(group, CHANNEL_ZONE_TYPE, new DecimalType(r.type));
|
||||
updateGroupState(group, CHANNEL_ZONE_TIME,
|
||||
r.runTimeSeconds != null ? new DecimalType(r.runTimeSeconds) : UnDefType.UNDEF);
|
||||
if (StringUtils.isNotBlank(r.icon)) {
|
||||
updateGroupState(group, CHANNEL_ZONE_ICON, new StringType(BASE_IMAGE_URL + r.icon));
|
||||
}
|
||||
if (r.time >= MAX_RUN_TIME) {
|
||||
updateGroupState(group, CHANNEL_ZONE_NEXT_RUN_TIME_TIME, UnDefType.UNDEF);
|
||||
} else {
|
||||
updateGroupState(group, CHANNEL_ZONE_NEXT_RUN_TIME_TIME,
|
||||
new DateTimeType(now.plusSeconds(r.time).truncatedTo(ChronoUnit.MINUTES)));
|
||||
}
|
||||
|
||||
Optional<Running> running = status.running.stream()
|
||||
.filter(z -> Integer.parseInt(z.relayId) == r.relayId.intValue()).findAny();
|
||||
if (running.isPresent()) {
|
||||
updateGroupState(group, CHANNEL_ZONE_RUN, OnOffType.ON);
|
||||
updateGroupState(group, CHANNEL_ZONE_TIME_LEFT, new DecimalType(running.get().timeLeft));
|
||||
logger.debug("{} Time Left {}", r.name, running.get().timeLeft);
|
||||
|
||||
} else {
|
||||
updateGroupState(group, CHANNEL_ZONE_RUN, OnOffType.OFF);
|
||||
updateGroupState(group, CHANNEL_ZONE_TIME_LEFT, new DecimalType(0));
|
||||
|
||||
}
|
||||
|
||||
updateGroupState(CHANNEL_GROUP_ALLZONES, CHANNEL_ZONE_RUN,
|
||||
!status.running.isEmpty() ? OnOffType.ON : OnOffType.OFF);
|
||||
});
|
||||
}
|
||||
|
||||
protected void updateGroupState(String group, String channelID, State state) {
|
||||
String channelName = group + "#" + channelID;
|
||||
State oldState = stateMap.put(channelName, state);
|
||||
if (!state.equals(oldState)) {
|
||||
ChannelUID channelUID = new ChannelUID(this.getThing().getUID(), channelName);
|
||||
logger.debug("updateState updating {} {}", channelUID, state);
|
||||
updateState(channelUID, state);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
@NonNullByDefault
|
||||
protected class NotConfiguredException extends Exception {
|
||||
NotConfiguredException(String message) {
|
||||
super(message);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isFutureValid(@Nullable ScheduledFuture<?> future) {
|
||||
return future != null && !future.isCancelled();
|
||||
}
|
||||
|
||||
private void configureInternal() {
|
||||
clearPolling();
|
||||
stateMap.clear();
|
||||
relayMap.clear();
|
||||
try {
|
||||
configure();
|
||||
initPolling(0);
|
||||
} catch (NotConfiguredException e) {
|
||||
logger.debug("Configuration error {}", e.getMessage());
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, e.getMessage());
|
||||
} catch (HydrawiseConnectionException e) {
|
||||
logger.debug("Could not connect to service");
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, e.getMessage());
|
||||
} catch (HydrawiseAuthenticationException e) {
|
||||
logger.debug("Credentials not valid");
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, "Credentials not valid");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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(this::pollControllerInternal, initalDelay, refresh,
|
||||
TimeUnit.SECONDS);
|
||||
}
|
||||
|
||||
/**
|
||||
* Stops/clears this thing's polling future
|
||||
*/
|
||||
private void clearPolling() {
|
||||
ScheduledFuture<?> localFuture = pollFuture;
|
||||
if (isFutureValid(localFuture)) {
|
||||
if (localFuture != null) {
|
||||
localFuture.cancel(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Poll the controller for updates.
|
||||
*/
|
||||
private void pollControllerInternal() {
|
||||
try {
|
||||
pollController();
|
||||
if (getThing().getStatus() != ThingStatus.ONLINE) {
|
||||
updateStatus(ThingStatus.ONLINE);
|
||||
}
|
||||
} catch (HydrawiseConnectionException e) {
|
||||
// poller will continue to run, set offline until next run
|
||||
logger.debug("Exception polling", e);
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, e.getMessage());
|
||||
} catch (HydrawiseAuthenticationException e) {
|
||||
// if are creds are not valid, we need to try re authorizing again
|
||||
logger.debug("Authorization exception during polling", e);
|
||||
configureInternal();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
/**
|
||||
* 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.hydrawise.internal;
|
||||
|
||||
import static org.openhab.binding.hydrawise.internal.HydrawiseBindingConstants.*;
|
||||
|
||||
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.core.io.net.http.HttpClientFactory;
|
||||
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 HydrawiseHandlerFactory} is responsible for creating things and thing
|
||||
* handlers.
|
||||
*
|
||||
* @author Dan Cunningham - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
@Component(configurationPid = "binding.hydrawise", service = ThingHandlerFactory.class)
|
||||
public class HydrawiseHandlerFactory extends BaseThingHandlerFactory {
|
||||
|
||||
private static final Set<ThingTypeUID> SUPPORTED_THING_TYPES_UIDS = Stream.of(THING_TYPE_CLOUD, THING_TYPE_LOCAL)
|
||||
.collect(Collectors.toSet());
|
||||
|
||||
private final HttpClient httpClient;
|
||||
|
||||
@Activate
|
||||
public HydrawiseHandlerFactory(@Reference final HttpClientFactory httpClientFactory) {
|
||||
this.httpClient = httpClientFactory.getCommonHttpClient();
|
||||
}
|
||||
|
||||
@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 (THING_TYPE_CLOUD.equals(thingTypeUID)) {
|
||||
return new HydrawiseCloudHandler(thing, httpClient);
|
||||
}
|
||||
|
||||
if (THING_TYPE_LOCAL.equals(thingTypeUID)) {
|
||||
return new HydrawiseLocalHandler(thing, httpClient);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
/**
|
||||
* 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.hydrawise.internal;
|
||||
|
||||
/**
|
||||
* The {@link HydrawiseLocalConfiguration} class contains fields mapping thing configuration parameters.
|
||||
*
|
||||
* @author Dan Cunningham - Initial contribution
|
||||
*/
|
||||
public class HydrawiseLocalConfiguration {
|
||||
|
||||
/**
|
||||
* Host or IP for local controller
|
||||
*/
|
||||
public String host;
|
||||
/**
|
||||
* User name (admin) for local controller
|
||||
*/
|
||||
public String username;
|
||||
/**
|
||||
* Password for local controller
|
||||
*/
|
||||
public String password;
|
||||
|
||||
/**
|
||||
* refresh interval in seconds.
|
||||
*/
|
||||
public int refresh;
|
||||
}
|
||||
@@ -0,0 +1,91 @@
|
||||
/**
|
||||
* 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.hydrawise.internal;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jetty.client.HttpClient;
|
||||
import org.openhab.binding.hydrawise.internal.api.HydrawiseAuthenticationException;
|
||||
import org.openhab.binding.hydrawise.internal.api.HydrawiseCommandException;
|
||||
import org.openhab.binding.hydrawise.internal.api.HydrawiseConnectionException;
|
||||
import org.openhab.binding.hydrawise.internal.api.HydrawiseLocalApiClient;
|
||||
import org.openhab.binding.hydrawise.internal.api.model.Relay;
|
||||
import org.openhab.core.thing.Thing;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* The {@link HydrawiseLocalHandler} is responsible for handling commands, which are
|
||||
* sent to one of the channels.
|
||||
*
|
||||
* @author Dan Cunningham - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class HydrawiseLocalHandler extends HydrawiseHandler {
|
||||
private final Logger logger = LoggerFactory.getLogger(HydrawiseLocalHandler.class);
|
||||
HydrawiseLocalApiClient client;
|
||||
|
||||
public HydrawiseLocalHandler(Thing thing, HttpClient httpClient) {
|
||||
super(thing);
|
||||
client = new HydrawiseLocalApiClient(httpClient);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void configure() throws HydrawiseConnectionException, HydrawiseAuthenticationException {
|
||||
HydrawiseLocalConfiguration configuration = getConfig().as(HydrawiseLocalConfiguration.class);
|
||||
this.refresh = Math.max(configuration.refresh, MIN_REFRESH_SECONDS);
|
||||
logger.trace("Connecting to host {}", configuration.host);
|
||||
client.setCredentials(configuration.host, configuration.username, configuration.password);
|
||||
pollController();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void pollController() throws HydrawiseConnectionException, HydrawiseAuthenticationException {
|
||||
updateZones(client.getLocalSchedule());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void sendRunCommand(int seconds, Relay relay)
|
||||
throws HydrawiseCommandException, HydrawiseConnectionException, HydrawiseAuthenticationException {
|
||||
client.runRelay(seconds, relay.relay);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void sendRunCommand(Relay relay)
|
||||
throws HydrawiseCommandException, HydrawiseConnectionException, HydrawiseAuthenticationException {
|
||||
client.runRelay(relay.relay);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void sendStopCommand(Relay relay)
|
||||
throws HydrawiseCommandException, HydrawiseConnectionException, HydrawiseAuthenticationException {
|
||||
client.stopRelay(relay.relay);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void sendRunAllCommand()
|
||||
throws HydrawiseCommandException, HydrawiseConnectionException, HydrawiseAuthenticationException {
|
||||
client.runAllRelays();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void sendRunAllCommand(int seconds)
|
||||
throws HydrawiseCommandException, HydrawiseConnectionException, HydrawiseAuthenticationException {
|
||||
client.runAllRelays(seconds);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void sendStopAllCommand()
|
||||
throws HydrawiseCommandException, HydrawiseConnectionException, HydrawiseAuthenticationException {
|
||||
client.stopAllRelays();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
/**
|
||||
* 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.hydrawise.internal.api;
|
||||
|
||||
/**
|
||||
* Thrown when the Hydrawise cloud or local API returns back a "unauthorized" response to commands
|
||||
*
|
||||
* @author Dan Cunningham - Initial contribution
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
public class HydrawiseAuthenticationException extends Exception {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,311 @@
|
||||
/**
|
||||
* 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.hydrawise.internal.api;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jetty.client.HttpClient;
|
||||
import org.eclipse.jetty.client.api.ContentResponse;
|
||||
import org.eclipse.jetty.http.HttpMethod;
|
||||
import org.openhab.binding.hydrawise.internal.api.model.CustomerDetailsResponse;
|
||||
import org.openhab.binding.hydrawise.internal.api.model.Response;
|
||||
import org.openhab.binding.hydrawise.internal.api.model.SetControllerResponse;
|
||||
import org.openhab.binding.hydrawise.internal.api.model.SetZoneResponse;
|
||||
import org.openhab.binding.hydrawise.internal.api.model.StatusScheduleResponse;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.google.gson.FieldNamingPolicy;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
|
||||
/**
|
||||
* The {@link HydrawiseCloudApiClient} communicates with the cloud based Hydrawise API service
|
||||
*
|
||||
* @author Dan Cunningham - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class HydrawiseCloudApiClient {
|
||||
private final Logger logger = LoggerFactory.getLogger(HydrawiseCloudApiClient.class);
|
||||
|
||||
private final Gson gson = new GsonBuilder().setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES)
|
||||
.create();
|
||||
private static final String BASE_URL = "https://app.hydrawise.com/api/v1/";
|
||||
private static final String STATUS_SCHEDUE_URL = BASE_URL
|
||||
+ "statusschedule.php?api_key=%s&controller_id=%d&hours=168";
|
||||
private static final String CUSTOMER_DETAILS_URL = BASE_URL + "customerdetails.php?api_key=%s&type=controllers";
|
||||
private static final String SET_CONTROLLER_URL = BASE_URL
|
||||
+ "setcontroller.php?api_key=%s&controller_id=%d&json=true";
|
||||
private static final String SET_ZONE_URL = BASE_URL + "setzone.php?period_id=999";
|
||||
private static final int TIMEOUT_SECONDS = 30;
|
||||
private final HttpClient httpClient;
|
||||
private String apiKey;
|
||||
|
||||
/**
|
||||
* Initializes the API client with a HydraWise API key from a user's account and the HTTPClient to use
|
||||
*
|
||||
*/
|
||||
public HydrawiseCloudApiClient(String apiKey, HttpClient httpClient) {
|
||||
this.apiKey = apiKey;
|
||||
this.httpClient = httpClient;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the API client with a HTTPClient to use
|
||||
*
|
||||
*/
|
||||
public HydrawiseCloudApiClient(HttpClient httpClient) {
|
||||
this("", httpClient);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a new API key to use for requests
|
||||
*
|
||||
* @param apiKey
|
||||
*/
|
||||
public void setApiKey(String apiKey) {
|
||||
this.apiKey = apiKey;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the {@link StatusScheduleResponse} for a given controller
|
||||
*
|
||||
* @param controllerId
|
||||
* @return
|
||||
* @throws HydrawiseConnectionException
|
||||
* @throws HydrawiseAuthenticationException
|
||||
*/
|
||||
public StatusScheduleResponse getStatusSchedule(int controllerId)
|
||||
throws HydrawiseConnectionException, HydrawiseAuthenticationException {
|
||||
String json = doGet(String.format(STATUS_SCHEDUE_URL, apiKey, controllerId));
|
||||
StatusScheduleResponse response = gson.fromJson(json, StatusScheduleResponse.class);
|
||||
throwExceptionIfResponseError(response);
|
||||
return response;
|
||||
}
|
||||
|
||||
/***
|
||||
* Retrieves the {@link CustomerDetailsResponse}
|
||||
*
|
||||
* @return
|
||||
* @throws HydrawiseConnectionException
|
||||
* @throws HydrawiseAuthenticationException
|
||||
*/
|
||||
public CustomerDetailsResponse getCustomerDetails()
|
||||
throws HydrawiseConnectionException, HydrawiseAuthenticationException {
|
||||
String json = doGet(String.format(CUSTOMER_DETAILS_URL, apiKey));
|
||||
CustomerDetailsResponse response = gson.fromJson(json, CustomerDetailsResponse.class);
|
||||
throwExceptionIfResponseError(response);
|
||||
return response;
|
||||
}
|
||||
|
||||
/***
|
||||
* Sets the controller with supplied {@value id} as the current controller
|
||||
*
|
||||
* @param id
|
||||
* @return SetControllerResponse
|
||||
* @throws HydrawiseConnectionException
|
||||
* @throws HydrawiseAuthenticationException
|
||||
* @throws HydrawiseCommandException
|
||||
*/
|
||||
public SetControllerResponse setController(int id)
|
||||
throws HydrawiseConnectionException, HydrawiseAuthenticationException, HydrawiseCommandException {
|
||||
String json = doGet(String.format(SET_CONTROLLER_URL, apiKey, id));
|
||||
SetControllerResponse response = gson.fromJson(json, SetControllerResponse.class);
|
||||
throwExceptionIfResponseError(response);
|
||||
if (!response.message.equals("OK")) {
|
||||
throw new HydrawiseCommandException(response.message);
|
||||
}
|
||||
return response;
|
||||
}
|
||||
|
||||
/***
|
||||
* Stops a given relay
|
||||
*
|
||||
* @param relayId
|
||||
* @return Response message
|
||||
* @throws HydrawiseConnectionException
|
||||
* @throws HydrawiseAuthenticationException
|
||||
* @throws HydrawiseCommandException
|
||||
*/
|
||||
public String stopRelay(int relayId)
|
||||
throws HydrawiseConnectionException, HydrawiseAuthenticationException, HydrawiseCommandException {
|
||||
return relayCommand(
|
||||
new HydrawiseZoneCommandBuilder(SET_ZONE_URL, apiKey).action("stop").relayId(relayId).toString());
|
||||
}
|
||||
|
||||
/**
|
||||
* Stops all relays on a given controller
|
||||
*
|
||||
* @param controllerId
|
||||
* @return Response message
|
||||
* @throws HydrawiseConnectionException
|
||||
* @throws HydrawiseAuthenticationException
|
||||
* @throws HydrawiseCommandException
|
||||
*/
|
||||
public String stopAllRelays(int controllerId)
|
||||
throws HydrawiseConnectionException, HydrawiseAuthenticationException, HydrawiseCommandException {
|
||||
return relayCommand(new HydrawiseZoneCommandBuilder(SET_ZONE_URL, apiKey).action("stopall")
|
||||
.controllerId(controllerId).toString());
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs a relay for the default amount of time
|
||||
*
|
||||
* @param relayId
|
||||
* @return Response message
|
||||
* @throws HydrawiseConnectionException
|
||||
* @throws HydrawiseAuthenticationException
|
||||
* @throws HydrawiseCommandException
|
||||
*/
|
||||
public String runRelay(int relayId)
|
||||
throws HydrawiseConnectionException, HydrawiseAuthenticationException, HydrawiseCommandException {
|
||||
return relayCommand(
|
||||
new HydrawiseZoneCommandBuilder(SET_ZONE_URL, apiKey).action("run").relayId(relayId).toString());
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs a relay for the given amount of seconds
|
||||
*
|
||||
* @param seconds
|
||||
* @param relayId
|
||||
* @return Response message
|
||||
* @throws HydrawiseConnectionException
|
||||
* @throws HydrawiseAuthenticationException
|
||||
* @throws HydrawiseCommandException
|
||||
*/
|
||||
public String runRelay(int seconds, int relayId)
|
||||
throws HydrawiseConnectionException, HydrawiseAuthenticationException, HydrawiseCommandException {
|
||||
return relayCommand(new HydrawiseZoneCommandBuilder(SET_ZONE_URL, apiKey).action("run").relayId(relayId)
|
||||
.duration(seconds).toString());
|
||||
}
|
||||
|
||||
/**
|
||||
* Run all relays on a given controller for the default amount of time
|
||||
*
|
||||
* @param controllerId
|
||||
* @return Response message
|
||||
* @throws HydrawiseConnectionException
|
||||
* @throws HydrawiseAuthenticationException
|
||||
* @throws HydrawiseCommandException
|
||||
*/
|
||||
public String runAllRelays(int controllerId)
|
||||
throws HydrawiseConnectionException, HydrawiseAuthenticationException, HydrawiseCommandException {
|
||||
return relayCommand(new HydrawiseZoneCommandBuilder(SET_ZONE_URL, apiKey).action("runall")
|
||||
.controllerId(controllerId).toString());
|
||||
}
|
||||
|
||||
/***
|
||||
* Run all relays on a given controller for the amount of seconds
|
||||
*
|
||||
* @param seconds
|
||||
* @param controllerId
|
||||
* @return Response message
|
||||
* @throws HydrawiseConnectionException
|
||||
* @throws HydrawiseAuthenticationException
|
||||
* @throws HydrawiseCommandException
|
||||
*/
|
||||
public String runAllRelays(int seconds, int controllerId)
|
||||
throws HydrawiseConnectionException, HydrawiseAuthenticationException, HydrawiseCommandException {
|
||||
return relayCommand(new HydrawiseZoneCommandBuilder(SET_ZONE_URL, apiKey).action("runall")
|
||||
.controllerId(controllerId).duration(seconds).toString());
|
||||
}
|
||||
|
||||
/**
|
||||
* Suspends a given relay
|
||||
*
|
||||
* @param relayId
|
||||
* @return Response message
|
||||
* @throws HydrawiseConnectionException
|
||||
* @throws HydrawiseAuthenticationException
|
||||
* @throws HydrawiseCommandException
|
||||
*/
|
||||
public String suspendRelay(int relayId)
|
||||
throws HydrawiseConnectionException, HydrawiseAuthenticationException, HydrawiseCommandException {
|
||||
return relayCommand(
|
||||
new HydrawiseZoneCommandBuilder(SET_ZONE_URL, apiKey).action("suspend").relayId(relayId).toString());
|
||||
}
|
||||
|
||||
/**
|
||||
* Suspends a given relay for an amount of seconds
|
||||
*
|
||||
* @param seconds
|
||||
* @param relayId
|
||||
* @return Response message
|
||||
* @throws HydrawiseConnectionException
|
||||
* @throws HydrawiseAuthenticationException
|
||||
* @throws HydrawiseCommandException
|
||||
*/
|
||||
public String suspendRelay(int seconds, int relayId)
|
||||
throws HydrawiseConnectionException, HydrawiseAuthenticationException, HydrawiseCommandException {
|
||||
return relayCommand(new HydrawiseZoneCommandBuilder(SET_ZONE_URL, apiKey).action("suspend").relayId(relayId)
|
||||
.duration(seconds).toString());
|
||||
}
|
||||
|
||||
/**
|
||||
* Suspend all relays on a given controller for an amount of seconds
|
||||
*
|
||||
* @param seconds
|
||||
* @param controllerId
|
||||
* @return Response message
|
||||
* @throws HydrawiseConnectionException
|
||||
* @throws HydrawiseAuthenticationException
|
||||
* @throws HydrawiseCommandException
|
||||
*/
|
||||
public String suspendAllRelays(int seconds, int controllerId)
|
||||
throws HydrawiseConnectionException, HydrawiseAuthenticationException, HydrawiseCommandException {
|
||||
return relayCommand(new HydrawiseZoneCommandBuilder(SET_ZONE_URL, apiKey).action("suspendall")
|
||||
.controllerId(controllerId).duration(seconds).toString());
|
||||
}
|
||||
|
||||
private String relayCommand(String url)
|
||||
throws HydrawiseConnectionException, HydrawiseAuthenticationException, HydrawiseCommandException {
|
||||
String json = doGet(url);
|
||||
SetZoneResponse response = gson.fromJson(json, SetZoneResponse.class);
|
||||
throwExceptionIfResponseError(response);
|
||||
if ("error".equals(response.messageType)) {
|
||||
throw new HydrawiseCommandException(response.message);
|
||||
}
|
||||
return response.message;
|
||||
}
|
||||
|
||||
private String doGet(String url) throws HydrawiseConnectionException {
|
||||
logger.trace("Getting {}", url);
|
||||
ContentResponse response;
|
||||
try {
|
||||
response = httpClient.newRequest(url).method(HttpMethod.GET).timeout(TIMEOUT_SECONDS, TimeUnit.SECONDS)
|
||||
.send();
|
||||
} catch (Exception e) {
|
||||
throw new HydrawiseConnectionException(e);
|
||||
}
|
||||
if (response.getStatus() != 200) {
|
||||
throw new HydrawiseConnectionException(
|
||||
"Could not connect to Hydrawise API. Response code " + response.getStatus());
|
||||
}
|
||||
String stringResponse = response.getContentAsString();
|
||||
logger.trace("Response: {}", stringResponse);
|
||||
return stringResponse;
|
||||
}
|
||||
|
||||
private void throwExceptionIfResponseError(Response response)
|
||||
throws HydrawiseConnectionException, HydrawiseAuthenticationException {
|
||||
String error = response.errorMsg;
|
||||
if (error != null) {
|
||||
if (error.equalsIgnoreCase("unauthorized")) {
|
||||
throw new HydrawiseAuthenticationException();
|
||||
} else {
|
||||
throw new HydrawiseConnectionException(response.errorMsg);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
/**
|
||||
* 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.hydrawise.internal.api;
|
||||
|
||||
/**
|
||||
* Thrown when command responses return a error message
|
||||
*
|
||||
* @author Dan Cunningham - Initial contribution
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
public class HydrawiseCommandException extends Exception {
|
||||
public HydrawiseCommandException(String message) {
|
||||
super(message);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
/**
|
||||
* 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.hydrawise.internal.api;
|
||||
|
||||
/**
|
||||
* Thrown for connection issues to the Hydrawise controller
|
||||
*
|
||||
* @author Dan Cunningham - Initial contribution
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
public class HydrawiseConnectionException extends Exception {
|
||||
|
||||
public HydrawiseConnectionException(Exception e) {
|
||||
super(e);
|
||||
}
|
||||
|
||||
public HydrawiseConnectionException(String message) {
|
||||
super(message);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,214 @@
|
||||
/**
|
||||
* 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.hydrawise.internal.api;
|
||||
|
||||
import java.net.URI;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jetty.client.HttpClient;
|
||||
import org.eclipse.jetty.client.api.AuthenticationStore;
|
||||
import org.eclipse.jetty.client.api.ContentResponse;
|
||||
import org.eclipse.jetty.client.util.BasicAuthentication;
|
||||
import org.eclipse.jetty.http.HttpMethod;
|
||||
import org.openhab.binding.hydrawise.internal.api.model.LocalScheduleResponse;
|
||||
import org.openhab.binding.hydrawise.internal.api.model.SetZoneResponse;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.google.gson.FieldNamingPolicy;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
|
||||
/**
|
||||
* The {@link HydrawiseLocalApiClient} communicates with a network local Hydrawise controller.
|
||||
*
|
||||
* @author Dan Cunningham - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class HydrawiseLocalApiClient {
|
||||
private final Logger logger = LoggerFactory.getLogger(HydrawiseLocalApiClient.class);
|
||||
|
||||
private final Gson gson = new GsonBuilder().setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES)
|
||||
.create();
|
||||
|
||||
private static final String GET_LOCAL_DATA_URL = "%s/get_sched_json.php?hours=720";
|
||||
private static final String SET_LOCAL_DATA_URL = "%s/set_manual_data.php?period_id=998";
|
||||
|
||||
private static final int TIMEOUT_SECONDS = 30;
|
||||
private HttpClient httpClient;
|
||||
private String localSetURL = "";
|
||||
private String localGetURL = "";
|
||||
|
||||
public HydrawiseLocalApiClient(HttpClient httpClient) {
|
||||
this.httpClient = httpClient;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the {@link HydrawiseLocalApiClient} to talk with the network local Hydrawise API
|
||||
*
|
||||
* @param host
|
||||
* @param username
|
||||
* @param password
|
||||
*/
|
||||
public HydrawiseLocalApiClient(String host, String username, String password, HttpClient httpClient) {
|
||||
this.httpClient = httpClient;
|
||||
setCredentials(host, username, password);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the local credentials and controller host
|
||||
*
|
||||
* @param host
|
||||
* @param username
|
||||
* @param password
|
||||
*/
|
||||
public void setCredentials(String host, String username, String password) {
|
||||
String url = "http://" + host;
|
||||
localSetURL = String.format(SET_LOCAL_DATA_URL, url);
|
||||
localGetURL = String.format(GET_LOCAL_DATA_URL, url);
|
||||
AuthenticationStore auth = httpClient.getAuthenticationStore();
|
||||
URI uri = URI.create(url);
|
||||
auth.addAuthenticationResult(new BasicAuthentication.BasicResult(uri, username, password));
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the {@link LocalScheduleResponse} for the controller
|
||||
*
|
||||
* @return the local schedule response
|
||||
* @throws HydrawiseConnectionException
|
||||
* @throws HydrawiseAuthenticationException
|
||||
*/
|
||||
public LocalScheduleResponse getLocalSchedule()
|
||||
throws HydrawiseConnectionException, HydrawiseAuthenticationException {
|
||||
String json = doGet(localGetURL);
|
||||
LocalScheduleResponse response = gson.fromJson(json, LocalScheduleResponse.class);
|
||||
return response;
|
||||
}
|
||||
|
||||
/**
|
||||
* Stops a given relay
|
||||
*
|
||||
* @param number
|
||||
* @return Response message
|
||||
* @throws HydrawiseConnectionException
|
||||
* @throws HydrawiseAuthenticationException
|
||||
* @throws HydrawiseCommandException
|
||||
*/
|
||||
public String stopRelay(int number)
|
||||
throws HydrawiseConnectionException, HydrawiseAuthenticationException, HydrawiseCommandException {
|
||||
return relayCommand(new HydrawiseZoneCommandBuilder(localSetURL).action("stop").relayNumber(number).toString());
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs a given relay for the default amount of time
|
||||
*
|
||||
* @param number
|
||||
* @return Response message
|
||||
* @throws HydrawiseConnectionException
|
||||
* @throws HydrawiseAuthenticationException
|
||||
* @throws HydrawiseCommandException
|
||||
*/
|
||||
public String runRelay(int number)
|
||||
throws HydrawiseConnectionException, HydrawiseAuthenticationException, HydrawiseCommandException {
|
||||
return relayCommand(new HydrawiseZoneCommandBuilder(localSetURL).action("run").relayNumber(number).toString());
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs a given relay for a specified numbers of seconds
|
||||
*
|
||||
* @param seconds
|
||||
* @param number
|
||||
* @return Response message
|
||||
* @throws HydrawiseConnectionException
|
||||
* @throws HydrawiseAuthenticationException
|
||||
* @throws HydrawiseCommandException
|
||||
*/
|
||||
public String runRelay(int seconds, int number)
|
||||
throws HydrawiseConnectionException, HydrawiseAuthenticationException, HydrawiseCommandException {
|
||||
return relayCommand(new HydrawiseZoneCommandBuilder(localSetURL).action("run").relayNumber(number)
|
||||
.duration(seconds).toString());
|
||||
}
|
||||
|
||||
/**
|
||||
* Stops all relays
|
||||
*
|
||||
* @return Response message
|
||||
* @throws HydrawiseConnectionException
|
||||
* @throws HydrawiseAuthenticationException
|
||||
* @throws HydrawiseCommandException
|
||||
*/
|
||||
public String stopAllRelays()
|
||||
throws HydrawiseConnectionException, HydrawiseAuthenticationException, HydrawiseCommandException {
|
||||
return relayCommand(new HydrawiseZoneCommandBuilder(localSetURL).action("stopall").toString());
|
||||
}
|
||||
|
||||
/**
|
||||
* Run all relays for the default amount of time
|
||||
*
|
||||
* @return Response message
|
||||
* @throws HydrawiseConnectionException
|
||||
* @throws HydrawiseAuthenticationException
|
||||
* @throws HydrawiseCommandException
|
||||
*/
|
||||
public String runAllRelays()
|
||||
throws HydrawiseConnectionException, HydrawiseAuthenticationException, HydrawiseCommandException {
|
||||
return relayCommand(new HydrawiseZoneCommandBuilder(localSetURL).action("runall").toString());
|
||||
}
|
||||
|
||||
/**
|
||||
* Run all relays for a given amount of seconds
|
||||
*
|
||||
* @param seconds
|
||||
* @return Response message
|
||||
* @throws HydrawiseConnectionException
|
||||
* @throws HydrawiseAuthenticationException
|
||||
* @throws HydrawiseCommandException
|
||||
*/
|
||||
public String runAllRelays(int seconds)
|
||||
throws HydrawiseConnectionException, HydrawiseAuthenticationException, HydrawiseCommandException {
|
||||
return relayCommand(new HydrawiseZoneCommandBuilder(localSetURL).action("runall").duration(seconds).toString());
|
||||
}
|
||||
|
||||
private String relayCommand(String url)
|
||||
throws HydrawiseConnectionException, HydrawiseAuthenticationException, HydrawiseCommandException {
|
||||
String json = doGet(url);
|
||||
SetZoneResponse response = gson.fromJson(json, SetZoneResponse.class);
|
||||
if (response.messageType.equals("error")) {
|
||||
throw new HydrawiseCommandException(response.message);
|
||||
}
|
||||
return response.message;
|
||||
}
|
||||
|
||||
private String doGet(String url) throws HydrawiseConnectionException, HydrawiseAuthenticationException {
|
||||
logger.trace("Getting {}", url);
|
||||
ContentResponse response;
|
||||
try {
|
||||
response = httpClient.newRequest(url).method(HttpMethod.GET).timeout(TIMEOUT_SECONDS, TimeUnit.SECONDS)
|
||||
.send();
|
||||
} catch (InterruptedException | TimeoutException | ExecutionException e) {
|
||||
throw new HydrawiseConnectionException(e);
|
||||
}
|
||||
if (response.getStatus() == 401) {
|
||||
throw new HydrawiseAuthenticationException();
|
||||
}
|
||||
if (response.getStatus() != 200) {
|
||||
throw new HydrawiseConnectionException("Error from controller. Response code " + response.getStatus());
|
||||
}
|
||||
String stringResponse = response.getContentAsString();
|
||||
logger.trace("Response: {}", stringResponse);
|
||||
return stringResponse;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,105 @@
|
||||
/**
|
||||
* 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.hydrawise.internal.api;
|
||||
|
||||
/**
|
||||
* The {@link HydrawiseZoneCommandBuilder} class builds a command URL string to use when sending commands to the
|
||||
* Hydrawise local controller or cloud based API server
|
||||
*
|
||||
* @author Dan Cunningham - Initial contribution
|
||||
*
|
||||
*/
|
||||
class HydrawiseZoneCommandBuilder {
|
||||
|
||||
private final StringBuilder builder;
|
||||
|
||||
/**
|
||||
* Construct a new {@link HydrawiseZoneCommandBuilder} class with a base URL
|
||||
*
|
||||
* @param baseURL
|
||||
*/
|
||||
public HydrawiseZoneCommandBuilder(String baseURL) {
|
||||
builder = new StringBuilder(baseURL);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a new {@link HydrawiseZoneCommandBuilder} class with a base URL and API key.
|
||||
*
|
||||
* @param baseURL
|
||||
* @param apiKey
|
||||
*/
|
||||
public HydrawiseZoneCommandBuilder(String baseURL, String apiKey) {
|
||||
this(baseURL);
|
||||
builder.append("&api_key=" + apiKey);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the action parameter
|
||||
*
|
||||
* @param action
|
||||
* @return {@link HydrawiseZoneCommandBuilder}
|
||||
*/
|
||||
public HydrawiseZoneCommandBuilder action(String action) {
|
||||
builder.append("&action=" + action);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the relayId parameter
|
||||
*
|
||||
* @param action
|
||||
* @return {@link HydrawiseZoneCommandBuilder}
|
||||
*/
|
||||
public HydrawiseZoneCommandBuilder relayId(int relayId) {
|
||||
builder.append("&relay_id=" + relayId);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the relay number parameter
|
||||
*
|
||||
* @param action
|
||||
* @return {@link HydrawiseZoneCommandBuilder}
|
||||
*/
|
||||
public HydrawiseZoneCommandBuilder relayNumber(int number) {
|
||||
builder.append("&relay=" + number);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the run duration parameter
|
||||
*
|
||||
* @param action
|
||||
* @return {@link HydrawiseZoneCommandBuilder}
|
||||
*/
|
||||
public HydrawiseZoneCommandBuilder duration(int seconds) {
|
||||
builder.append("&custom=" + seconds);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the controller Id parameter
|
||||
*
|
||||
* @param action
|
||||
* @return {@link HydrawiseZoneCommandBuilder}
|
||||
*/
|
||||
public HydrawiseZoneCommandBuilder controllerId(int controllerId) {
|
||||
builder.append("&controller_id=" + controllerId);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return builder.toString();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
/**
|
||||
* 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.hydrawise.internal.api.model;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* The {@link BocTopologyDesired} class models the actual BocTopology
|
||||
*
|
||||
* @author Dan Cunningham - Initial contribution
|
||||
*/
|
||||
public class BocTopologyActual {
|
||||
|
||||
public List<Object> bocGateways;
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
/**
|
||||
* 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.hydrawise.internal.api.model;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* The {@link BocTopologyDesired} class models the desired BocTopology
|
||||
*
|
||||
* @author Dan Cunningham - Initial contribution
|
||||
*/
|
||||
public class BocTopologyDesired {
|
||||
|
||||
public List<Object> bocGateways;
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
/**
|
||||
* 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.hydrawise.internal.api.model;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* The {@link Controller} class models a Hydrawise controller unit
|
||||
*
|
||||
* @author Dan Cunningham - Initial contribution
|
||||
*/
|
||||
public class Controller {
|
||||
|
||||
public String name;
|
||||
|
||||
public Integer lastContact;
|
||||
|
||||
public String serialNumber;
|
||||
|
||||
public Integer controllerId;
|
||||
|
||||
public String swVersion;
|
||||
|
||||
public String hardware;
|
||||
|
||||
public Boolean isBoc;
|
||||
|
||||
public String address;
|
||||
|
||||
public String timezone;
|
||||
|
||||
public Integer deviceId;
|
||||
|
||||
public Object parentDeviceId;
|
||||
|
||||
public String image;
|
||||
|
||||
public String description;
|
||||
|
||||
public Integer customerId;
|
||||
|
||||
public Double latitude;
|
||||
|
||||
public Double longitude;
|
||||
|
||||
public String lastContactReadable;
|
||||
|
||||
public String status;
|
||||
|
||||
public String statusIcon;
|
||||
|
||||
public Boolean online;
|
||||
|
||||
public List<String> tags = null;
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
/**
|
||||
* 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.hydrawise.internal.api.model;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* The {@link CustomerDetailsResponse} class models the CustomerDetails response message
|
||||
*
|
||||
* @author Dan Cunningham - Initial contribution
|
||||
*/
|
||||
public class CustomerDetailsResponse extends Response {
|
||||
|
||||
public BocTopologyDesired bocTopologyDesired;
|
||||
|
||||
public BocTopologyActual bocTopologyActual;
|
||||
|
||||
public List<Controller> controllers;
|
||||
|
||||
public String currentController;
|
||||
|
||||
public Boolean isBoc;
|
||||
|
||||
public Integer tandc;
|
||||
|
||||
public Integer controllerId;
|
||||
|
||||
public Integer customerId;
|
||||
|
||||
public String sessionId;
|
||||
|
||||
public String hardwareVersion;
|
||||
|
||||
public Integer deviceId;
|
||||
|
||||
public Integer tandcVersion;
|
||||
|
||||
public Features features;
|
||||
}
|
||||
@@ -0,0 +1,101 @@
|
||||
/**
|
||||
* 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.hydrawise.internal.api.model;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* The {@link Features} class models an accounts features.
|
||||
*
|
||||
* @author Dan Cunningham - Initial contribution
|
||||
*/
|
||||
public class Features {
|
||||
|
||||
public List<PlanArray> planArray = null;
|
||||
|
||||
public Object id;
|
||||
|
||||
public String planType2;
|
||||
|
||||
public String planType2Key;
|
||||
|
||||
public Object sku;
|
||||
|
||||
public String discount;
|
||||
|
||||
public String cost;
|
||||
|
||||
public String costUs;
|
||||
|
||||
public String costAu;
|
||||
|
||||
public String costEu;
|
||||
|
||||
public String costCa;
|
||||
|
||||
public String costUk;
|
||||
|
||||
public String active;
|
||||
|
||||
public String controllerQty;
|
||||
|
||||
public String rainfall;
|
||||
|
||||
public String smsQty;
|
||||
|
||||
public String scheduledReports;
|
||||
|
||||
public String emailAlerts;
|
||||
|
||||
public String defineSensor;
|
||||
|
||||
public String addUser;
|
||||
|
||||
public String contractor;
|
||||
|
||||
public Object description;
|
||||
|
||||
public String sensorPack;
|
||||
|
||||
public String filelimit;
|
||||
|
||||
public String filetypeall;
|
||||
|
||||
public String planType;
|
||||
|
||||
public String pushNotification;
|
||||
|
||||
public String weatherQty;
|
||||
|
||||
public String weatherFreeQty;
|
||||
|
||||
public String reportingDays;
|
||||
|
||||
public String weatherHourlyUpdates;
|
||||
|
||||
public String freeEnthusiastPlans;
|
||||
|
||||
public String visible;
|
||||
|
||||
public Object contractorPurchasable;
|
||||
|
||||
public Integer boc;
|
||||
|
||||
public Object expiry;
|
||||
|
||||
public Object start;
|
||||
|
||||
public String customerplanId;
|
||||
|
||||
public Integer smsUsed;
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
/**
|
||||
* 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.hydrawise.internal.api.model;
|
||||
|
||||
/**
|
||||
* The {@link Forecast} class models a daily weather forecast
|
||||
*
|
||||
* @author Dan Cunningham - Initial contribution
|
||||
*/
|
||||
public class Forecast {
|
||||
|
||||
public String tempHi;
|
||||
|
||||
public String tempLo;
|
||||
|
||||
public String conditions;
|
||||
|
||||
public String day;
|
||||
|
||||
public Integer pop;
|
||||
|
||||
public Integer humidity;
|
||||
|
||||
public String wind;
|
||||
|
||||
public String icon;
|
||||
|
||||
public String iconLocal;
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
/**
|
||||
* 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.hydrawise.internal.api.model;
|
||||
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* The {@link LocalScheduleResponse} class models the LocalSchedule response message
|
||||
*
|
||||
* @author Dan Cunningham - Initial contribution
|
||||
*/
|
||||
public class LocalScheduleResponse extends Response {
|
||||
|
||||
public List<Running> running = new LinkedList<>();
|
||||
|
||||
public List<Relay> relays = new LinkedList<>();
|
||||
|
||||
public String name;
|
||||
|
||||
public Integer time;
|
||||
}
|
||||
@@ -0,0 +1,91 @@
|
||||
/**
|
||||
* 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.hydrawise.internal.api.model;
|
||||
|
||||
/**
|
||||
* The {@link PlanArray} class models am account plan.
|
||||
*
|
||||
* @author Dan Cunningham - Initial contribution
|
||||
*/
|
||||
public class PlanArray {
|
||||
|
||||
public String id;
|
||||
|
||||
public Object sku;
|
||||
|
||||
public String discount;
|
||||
|
||||
public String cost;
|
||||
|
||||
public String costUs;
|
||||
|
||||
public String costAu;
|
||||
|
||||
public String costEu;
|
||||
|
||||
public String costCa;
|
||||
|
||||
public String costUk;
|
||||
|
||||
public String active;
|
||||
|
||||
public String controllerQty;
|
||||
|
||||
public String rainfall;
|
||||
|
||||
public String smsQty;
|
||||
|
||||
public String scheduledReports;
|
||||
|
||||
public String emailAlerts;
|
||||
|
||||
public String defineSensor;
|
||||
|
||||
public String addUser;
|
||||
|
||||
public String contractor;
|
||||
|
||||
public String description;
|
||||
|
||||
public String sensorPack;
|
||||
|
||||
public String filelimit;
|
||||
|
||||
public String filetypeall;
|
||||
|
||||
public String plan_type;
|
||||
|
||||
public String pushNotification;
|
||||
|
||||
public String weatherQty;
|
||||
|
||||
public String weatherFreeQty;
|
||||
|
||||
public String reportingDays;
|
||||
|
||||
public String weatherHourlyUpdates;
|
||||
|
||||
public String freeEnthusiastPlans;
|
||||
|
||||
public String visible;
|
||||
|
||||
public String contractorPurchasable;
|
||||
|
||||
public String boc;
|
||||
|
||||
public String expiry;
|
||||
|
||||
public String start;
|
||||
|
||||
public String customerplanId;
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
/**
|
||||
* 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.hydrawise.internal.api.model;
|
||||
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
|
||||
/**
|
||||
* The {@link Relay} class models the Relay response message
|
||||
*
|
||||
* @author Dan Cunningham - Initial contribution
|
||||
*/
|
||||
public class Relay {
|
||||
|
||||
public Integer relayId;
|
||||
|
||||
public Integer relay;
|
||||
|
||||
public String name;
|
||||
|
||||
public String icon;
|
||||
|
||||
public String lastwater;
|
||||
|
||||
public Integer time;
|
||||
|
||||
public Integer type;
|
||||
|
||||
@SerializedName("run")
|
||||
public String runTime;
|
||||
|
||||
@SerializedName("run_seconds")
|
||||
public Integer runTimeSeconds;
|
||||
|
||||
public String nicetime;
|
||||
|
||||
public String id;
|
||||
|
||||
/**
|
||||
* Returns back the actual relay number when multiple controllers are chained.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public int getRelayNumber() {
|
||||
int quotient = relay / 100;
|
||||
return (relay - (quotient * 100)) + (quotient * 12);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
/**
|
||||
* 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.hydrawise.internal.api.model;
|
||||
|
||||
/**
|
||||
* The {@link Response} class models Response messages
|
||||
*
|
||||
* @author Dan Cunningham - Initial contribution
|
||||
*/
|
||||
public class Response {
|
||||
|
||||
public String errorMsg;
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
/**
|
||||
* 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.hydrawise.internal.api.model;
|
||||
|
||||
/**
|
||||
* The {@link Running} class models a running relay
|
||||
*
|
||||
* @author Dan Cunningham - Initial contribution
|
||||
*/
|
||||
public class Running {
|
||||
|
||||
public String relay;
|
||||
|
||||
public String relayId;
|
||||
|
||||
public Integer timeLeft;
|
||||
|
||||
public String run;
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
/**
|
||||
* 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.hydrawise.internal.api.model;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* The {@link Sensor} class models a sensor
|
||||
*
|
||||
* @author Dan Cunningham - Initial contribution
|
||||
*/
|
||||
public class Sensor {
|
||||
|
||||
public Integer input;
|
||||
|
||||
public Integer type;
|
||||
|
||||
public Integer mode;
|
||||
|
||||
public Integer timer;
|
||||
|
||||
public Integer offtimer;
|
||||
|
||||
public String name;
|
||||
|
||||
public Integer offlevel;
|
||||
|
||||
public Integer active;
|
||||
|
||||
public List<Object> relays = null;
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
/**
|
||||
* 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.hydrawise.internal.api.model;
|
||||
|
||||
/**
|
||||
* The {@link SetControllerResponse} class models the SetController response message
|
||||
*
|
||||
* @author Dan Cunningham - Initial contribution
|
||||
*/
|
||||
public class SetControllerResponse extends Response {
|
||||
|
||||
public String name;
|
||||
|
||||
public String controllerId;
|
||||
|
||||
public String message;
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
/**
|
||||
* 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.hydrawise.internal.api.model;
|
||||
|
||||
/**
|
||||
* The {@link SetZoneResponse} class models the SetZone response message
|
||||
*
|
||||
* @author Dan Cunningham - Initial contribution
|
||||
*/
|
||||
public class SetZoneResponse extends Response {
|
||||
|
||||
public String message;
|
||||
|
||||
public String messageType;
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
/**
|
||||
* 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.hydrawise.internal.api.model;
|
||||
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* The {@link StatusScheduleResponse} class models the Status and Schedule response message
|
||||
*
|
||||
* @author Dan Cunningham - Initial contribution
|
||||
*/
|
||||
public class StatusScheduleResponse extends LocalScheduleResponse {
|
||||
|
||||
public Integer controllerId;
|
||||
|
||||
public Integer customerId;
|
||||
|
||||
public Integer userId;
|
||||
|
||||
public Integer nextpoll;
|
||||
|
||||
public List<Sensor> sensors = new LinkedList<>();
|
||||
|
||||
public String message;
|
||||
|
||||
public String obsRain;
|
||||
|
||||
public String obsRainWeek;
|
||||
|
||||
public String obsMaxtemp;
|
||||
|
||||
public Integer obsRainUpgrade;
|
||||
|
||||
public String obsRainText;
|
||||
|
||||
public String obsCurrenttemp;
|
||||
|
||||
public String wateringTime;
|
||||
|
||||
public Integer waterSaving;
|
||||
|
||||
public String lastContact;
|
||||
|
||||
public List<Forecast> forecast = new LinkedList<>();
|
||||
|
||||
public String status;
|
||||
|
||||
public String statusIcon;
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<binding:binding id="hydrawise" 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>Hydrawise Binding</name>
|
||||
<description>This is the binding for Hydrawise irrigation systems.</description>
|
||||
<author>Dan Cunningham</author>
|
||||
|
||||
</binding:binding>
|
||||
@@ -0,0 +1,223 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<thing:thing-descriptions bindingId="hydrawise"
|
||||
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">
|
||||
|
||||
<channel-group-type id="zone">
|
||||
<label>Zone</label>
|
||||
<description>Hydrawise zone</description>
|
||||
<channels>
|
||||
<channel id="name" typeId="name"/>
|
||||
<channel id="icon" typeId="icon"/>
|
||||
<channel id="time" typeId="time"/>
|
||||
<channel id="type" typeId="type"/>
|
||||
<channel id="runcustom" typeId="runcustom"/>
|
||||
<channel id="run" typeId="run"/>
|
||||
<channel id="nextruntime" typeId="nextruntime"/>
|
||||
<channel id="timeleft" typeId="timeleft"/>
|
||||
</channels>
|
||||
</channel-group-type>
|
||||
|
||||
<channel-group-type id="allzones">
|
||||
<label>All Zones</label>
|
||||
<description>Commands that control all Hydrawise zones</description>
|
||||
<channels>
|
||||
<channel id="runcustom" typeId="runcustom"/>
|
||||
<channel id="run" typeId="run"/>
|
||||
</channels>
|
||||
</channel-group-type>
|
||||
|
||||
<channel-group-type id="sensor">
|
||||
<label>Sensor</label>
|
||||
<description>Hydrawise sensor</description>
|
||||
<channels>
|
||||
<channel id="name" typeId="name"/>
|
||||
<channel id="input" typeId="input"/>
|
||||
<channel id="mode" typeId="mode"/>
|
||||
<channel id="timer" typeId="timer"/>
|
||||
<channel id="offtimer" typeId="offtimer"/>
|
||||
<channel id="offlevel" typeId="offlevel"/>
|
||||
<channel id="active" typeId="active"/>
|
||||
</channels>
|
||||
</channel-group-type>
|
||||
|
||||
<channel-group-type id="forecast">
|
||||
<label>Weather Forecast</label>
|
||||
<description>Hydrawise weather forecast</description>
|
||||
<channels>
|
||||
<channel id="temperaturehigh" typeId="temperaturehigh"/>
|
||||
<channel id="temperaturelow" typeId="temperaturelow"/>
|
||||
<channel id="conditions" typeId="conditions"/>
|
||||
<channel id="day" typeId="day"/>
|
||||
<channel id="humidity" typeId="humidity"/>
|
||||
<channel id="wind" typeId="wind"/>
|
||||
</channels>
|
||||
</channel-group-type>
|
||||
|
||||
<!-- Controller -->
|
||||
<channel-type id="name">
|
||||
<item-type>String</item-type>
|
||||
<label>Name</label>
|
||||
<description>Name</description>
|
||||
<state readOnly="true"></state>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="icon">
|
||||
<item-type>String</item-type>
|
||||
<label>Icon URL</label>
|
||||
<description>Icon URL for this zone</description>
|
||||
<state readOnly="true"></state>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="time" advanced="true">
|
||||
<item-type>Number</item-type>
|
||||
<label>Start Time</label>
|
||||
<description>Zone start time in seconds</description>
|
||||
<state readOnly="true"></state>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="type" advanced="true">
|
||||
<item-type>Number</item-type>
|
||||
<label>Type</label>
|
||||
<description>Zone Type</description>
|
||||
<state readOnly="true"></state>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="nextruntime">
|
||||
<item-type>DateTime</item-type>
|
||||
<label>Next Run Time</label>
|
||||
<description>Next time this zone is scheduled to run</description>
|
||||
<state readOnly="true"></state>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="run">
|
||||
<item-type>Switch</item-type>
|
||||
<label>Run Zones</label>
|
||||
<description>Run or stop zones for the default time.</description>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="runcustom">
|
||||
<item-type>Number</item-type>
|
||||
<label>Run Zones With Custom Duration </label>
|
||||
<description>Run zones now for a custom duration of time in seconds</description>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="timeleft">
|
||||
<item-type>Number</item-type>
|
||||
<label>Time Left Seconds</label>
|
||||
<description>Time left that zone will run for</description>
|
||||
<state readOnly="true"></state>
|
||||
</channel-type>
|
||||
|
||||
<!-- Sensor -->
|
||||
|
||||
<channel-type id="input" advanced="true">
|
||||
<item-type>Number</item-type>
|
||||
<label>Input</label>
|
||||
<description>Sensor input</description>
|
||||
<state readOnly="true"></state>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="type" advanced="true">
|
||||
<item-type>Number</item-type>
|
||||
<label>Type</label>
|
||||
<description>Sensor type</description>
|
||||
<state readOnly="true"></state>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="mode" advanced="true">
|
||||
<item-type>Number</item-type>
|
||||
<label>Mode</label>
|
||||
<description>Sensor mode</description>
|
||||
<state readOnly="true"></state>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="timer" advanced="true">
|
||||
<item-type>Number</item-type>
|
||||
<label>Timer</label>
|
||||
<description>Sensor timer</description>
|
||||
<state readOnly="true"></state>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="offtimer" advanced="true">
|
||||
<item-type>Number</item-type>
|
||||
<label>Off Timer</label>
|
||||
<description>Sensor off timer</description>
|
||||
<state readOnly="true"></state>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="name" advanced="true">
|
||||
<item-type>String</item-type>
|
||||
<label>Name</label>
|
||||
<description>Sensor name</description>
|
||||
<state readOnly="true"></state>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="offlevel" advanced="true">
|
||||
<item-type>Number</item-type>
|
||||
<label>Off Level</label>
|
||||
<description>Sensor off level</description>
|
||||
<state readOnly="true"></state>
|
||||
</channel-type>
|
||||
<channel-type id="active">
|
||||
<item-type>Switch</item-type>
|
||||
<label>Active</label>
|
||||
<description>Sensor active</description>
|
||||
<state readOnly="true"></state>
|
||||
</channel-type>
|
||||
|
||||
<!-- Weather Forecast -->
|
||||
<channel-type id="temperaturehigh">
|
||||
<item-type>Number:Temperature</item-type>
|
||||
<label>High temperature</label>
|
||||
<description>High temperature</description>
|
||||
<category>Temperature</category>
|
||||
<state readOnly="true" pattern="%.1f %unit%"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="temperaturelow">
|
||||
<item-type>Number:Temperature</item-type>
|
||||
<label>Low Temperature</label>
|
||||
<description>Low Temperature</description>
|
||||
<category>Temperature</category>
|
||||
<state readOnly="true" pattern="%.1f %unit%"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="conditions">
|
||||
<item-type>String</item-type>
|
||||
<label>Conditions</label>
|
||||
<description>Weather conditions</description>
|
||||
<state readOnly="true"></state>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="conditions">
|
||||
<item-type>String</item-type>
|
||||
<label>Conditions</label>
|
||||
<description>Weather conditions</description>
|
||||
<state readOnly="true"></state>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="day">
|
||||
<item-type>String</item-type>
|
||||
<label>Day of Week</label>
|
||||
<description>Day of week for the weather forecast</description>
|
||||
<state readOnly="true"></state>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="humidity">
|
||||
<item-type>Number</item-type>
|
||||
<label>Humidity</label>
|
||||
<description>Humidity percentage</description>
|
||||
<category>Temperature</category>
|
||||
<state readOnly="true" pattern="%d%%"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="wind">
|
||||
<item-type>Number:Speed</item-type>
|
||||
<label>Wind Speed</label>
|
||||
<description>Wind speed</description>
|
||||
<category>Wind</category>
|
||||
<state readOnly="true" pattern="%.1f %unit%"/>
|
||||
</channel-type>
|
||||
</thing:thing-descriptions>
|
||||
@@ -0,0 +1,388 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<thing:thing-descriptions bindingId="hydrawise"
|
||||
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">
|
||||
|
||||
<!-- Sample Thing Type -->
|
||||
<thing-type id="cloud">
|
||||
<label>Hydrawise Cloud Thing</label>
|
||||
<description>Hydrawise cloud connected irrigation system</description>
|
||||
|
||||
<!-- Until we have https://github.com/eclipse/smarthome/issues/1118 fixed, we need to list all possible channel groups.
|
||||
Once this is fixed we can dynamically add them to the thing and not list them here. -->
|
||||
<channel-groups>
|
||||
<channel-group id="sensor1" typeId="sensor">
|
||||
<label>Sensor 1</label>
|
||||
<description>Sensor 1</description>
|
||||
</channel-group>
|
||||
<channel-group id="sensor2" typeId="sensor">
|
||||
<label>Sensor 2</label>
|
||||
<description>Sensor 2</description>
|
||||
</channel-group>
|
||||
<channel-group id="sensor3" typeId="sensor">
|
||||
<label>Sensor 3</label>
|
||||
<description>Sensor 3</description>
|
||||
</channel-group>
|
||||
<channel-group id="sensor4" typeId="sensor">
|
||||
<label>Sensor 4</label>
|
||||
<description>Sensor 4</description>
|
||||
</channel-group>
|
||||
|
||||
<channel-group id="forecast1" typeId="forecast">
|
||||
<label>Today's Weather</label>
|
||||
<description>Today's weather forecast</description>
|
||||
</channel-group>
|
||||
<channel-group id="forecast2" typeId="forecast">
|
||||
<label>Day 2 Weather</label>
|
||||
<description>Day 2 weather forecast</description>
|
||||
</channel-group>
|
||||
<channel-group id="forecast3" typeId="forecast">
|
||||
<label>Day 3 Weather</label>
|
||||
<description>Day 3 weather forecast</description>
|
||||
</channel-group>
|
||||
<channel-group id="forecast4" typeId="forecast">
|
||||
<label>Day 4 Weather</label>
|
||||
<description>Day 4 weather forecast</description>
|
||||
</channel-group>
|
||||
|
||||
<channel-group id="allzones" typeId="allzones"/>
|
||||
|
||||
<channel-group id="zone1" typeId="zone">
|
||||
<label>Zone 1</label>
|
||||
<description>Sprinkler Zone 1</description>
|
||||
</channel-group>
|
||||
<channel-group id="zone2" typeId="zone">
|
||||
<label>Zone 2</label>
|
||||
<description>Sprinkler Zone 2</description>
|
||||
</channel-group>
|
||||
<channel-group id="zone3" typeId="zone">
|
||||
<label>Zone 3</label>
|
||||
<description>Sprinkler Zone 3</description>
|
||||
</channel-group>
|
||||
<channel-group id="zone4" typeId="zone">
|
||||
<label>Zone 4</label>
|
||||
<description>Sprinkler Zone 4</description>
|
||||
</channel-group>
|
||||
<channel-group id="zone5" typeId="zone">
|
||||
<label>Zone 5</label>
|
||||
<description>Sprinkler Zone 5</description>
|
||||
</channel-group>
|
||||
<channel-group id="zone6" typeId="zone">
|
||||
<label>Zone 6</label>
|
||||
<description>Sprinkler Zone 6</description>
|
||||
</channel-group>
|
||||
<channel-group id="zone7" typeId="zone">
|
||||
<label>Zone 7</label>
|
||||
<description>Sprinkler Zone 7</description>
|
||||
</channel-group>
|
||||
<channel-group id="zone8" typeId="zone">
|
||||
<label>Zone 8</label>
|
||||
<description>Sprinkler Zone 8</description>
|
||||
</channel-group>
|
||||
<channel-group id="zone9" typeId="zone">
|
||||
<label>Zone 9</label>
|
||||
<description>Sprinkler Zone 9</description>
|
||||
</channel-group>
|
||||
<channel-group id="zone10" typeId="zone">
|
||||
<label>Zone 10</label>
|
||||
<description>Sprinkler Zone 10</description>
|
||||
</channel-group>
|
||||
<channel-group id="zone11" typeId="zone">
|
||||
<label>Zone 11</label>
|
||||
<description>Sprinkler Zone 11</description>
|
||||
</channel-group>
|
||||
<channel-group id="zone12" typeId="zone">
|
||||
<label>Zone 12</label>
|
||||
<description>Sprinkler Zone 12</description>
|
||||
</channel-group>
|
||||
<channel-group id="zone13" typeId="zone">
|
||||
<label>Zone 13</label>
|
||||
<description>Sprinkler Zone 13</description>
|
||||
</channel-group>
|
||||
<channel-group id="zone14" typeId="zone">
|
||||
<label>Zone 14</label>
|
||||
<description>Sprinkler Zone 14</description>
|
||||
</channel-group>
|
||||
<channel-group id="zone15" typeId="zone">
|
||||
<label>Zone 15</label>
|
||||
<description>Sprinkler Zone 15</description>
|
||||
</channel-group>
|
||||
<channel-group id="zone16" typeId="zone">
|
||||
<label>Zone 16</label>
|
||||
<description>Sprinkler Zone 16</description>
|
||||
</channel-group>
|
||||
<channel-group id="zone17" typeId="zone">
|
||||
<label>Zone 17</label>
|
||||
<description>Sprinkler Zone 17</description>
|
||||
</channel-group>
|
||||
<channel-group id="zone18" typeId="zone">
|
||||
<label>Zone 18</label>
|
||||
<description>Sprinkler Zone 18</description>
|
||||
</channel-group>
|
||||
<channel-group id="zone19" typeId="zone">
|
||||
<label>Zone 19</label>
|
||||
<description>Sprinkler Zone 19</description>
|
||||
</channel-group>
|
||||
<channel-group id="zone20" typeId="zone">
|
||||
<label>Zone 20</label>
|
||||
<description>Sprinkler Zone 20</description>
|
||||
</channel-group>
|
||||
<channel-group id="zone21" typeId="zone">
|
||||
<label>Zone 21</label>
|
||||
<description>Sprinkler Zone 21</description>
|
||||
</channel-group>
|
||||
<channel-group id="zone22" typeId="zone">
|
||||
<label>Zone 22</label>
|
||||
<description>Sprinkler Zone 22</description>
|
||||
</channel-group>
|
||||
<channel-group id="zone23" typeId="zone">
|
||||
<label>Zone 23</label>
|
||||
<description>Sprinkler Zone 23</description>
|
||||
</channel-group>
|
||||
<channel-group id="zone24" typeId="zone">
|
||||
<label>Zone 24</label>
|
||||
<description>Sprinkler Zone 24</description>
|
||||
</channel-group>
|
||||
<channel-group id="zone25" typeId="zone">
|
||||
<label>Zone 25</label>
|
||||
<description>Sprinkler Zone 25</description>
|
||||
</channel-group>
|
||||
<channel-group id="zone26" typeId="zone">
|
||||
<label>Zone 26</label>
|
||||
<description>Sprinkler Zone 26</description>
|
||||
</channel-group>
|
||||
<channel-group id="zone27" typeId="zone">
|
||||
<label>Zone 27</label>
|
||||
<description>Sprinkler Zone 27</description>
|
||||
</channel-group>
|
||||
<channel-group id="zone28" typeId="zone">
|
||||
<label>Zone 28</label>
|
||||
<description>Sprinkler Zone 28</description>
|
||||
</channel-group>
|
||||
<channel-group id="zone29" typeId="zone">
|
||||
<label>Zone 29</label>
|
||||
<description>Sprinkler Zone 29</description>
|
||||
</channel-group>
|
||||
<channel-group id="zone30" typeId="zone">
|
||||
<label>Zone 30</label>
|
||||
<description>Sprinkler Zone 30</description>
|
||||
</channel-group>
|
||||
<channel-group id="zone31" typeId="zone">
|
||||
<label>Zone 31</label>
|
||||
<description>Sprinkler Zone 31</description>
|
||||
</channel-group>
|
||||
<channel-group id="zone32" typeId="zone">
|
||||
<label>Zone 32</label>
|
||||
<description>Sprinkler Zone 32</description>
|
||||
</channel-group>
|
||||
<channel-group id="zone33" typeId="zone">
|
||||
<label>Zone 33</label>
|
||||
<description>Sprinkler Zone 33</description>
|
||||
</channel-group>
|
||||
<channel-group id="zone34" typeId="zone">
|
||||
<label>Zone 34</label>
|
||||
<description>Sprinkler Zone 34</description>
|
||||
</channel-group>
|
||||
<channel-group id="zone35" typeId="zone">
|
||||
<label>Zone 35</label>
|
||||
<description>Sprinkler Zone 35</description>
|
||||
</channel-group>
|
||||
<channel-group id="zone36" typeId="zone">
|
||||
<label>Zone 36</label>
|
||||
<description>Sprinkler Zone 36</description>
|
||||
</channel-group>
|
||||
</channel-groups>
|
||||
<config-description>
|
||||
<parameter name="apiKey" type="text" required="true">
|
||||
<label>API Key</label>
|
||||
<description>API Key from https://app.hydrawise.com/config/account</description>
|
||||
</parameter>
|
||||
<parameter name="refresh" type="integer" required="true">
|
||||
<label>Refresh interval</label>
|
||||
<description>Specifies the refresh interval in seconds</description>
|
||||
<default>30</default>
|
||||
</parameter>
|
||||
<parameter name="controllerId" type="integer" required="false">
|
||||
<label>Optional Controller ID interval</label>
|
||||
<description>Optional parameter to specify the Hydrawise controller ID if you have more then one associated with
|
||||
your account.
|
||||
</description>
|
||||
</parameter>
|
||||
</config-description>
|
||||
</thing-type>
|
||||
|
||||
<thing-type id="local">
|
||||
<label>Hydrawise Local Thing</label>
|
||||
<description>Hydrawise local connected irrigation system</description>
|
||||
<channel-groups>
|
||||
<channel-group id="zone1" typeId="zone">
|
||||
<label>Zone 1</label>
|
||||
<description>Sprinkler Zone 1</description>
|
||||
</channel-group>
|
||||
<channel-group id="zone2" typeId="zone">
|
||||
<label>Zone 2</label>
|
||||
<description>Sprinkler Zone 2</description>
|
||||
</channel-group>
|
||||
<channel-group id="zone3" typeId="zone">
|
||||
<label>Zone 3</label>
|
||||
<description>Sprinkler Zone 3</description>
|
||||
</channel-group>
|
||||
<channel-group id="zone4" typeId="zone">
|
||||
<label>Zone 4</label>
|
||||
<description>Sprinkler Zone 4</description>
|
||||
</channel-group>
|
||||
<channel-group id="zone5" typeId="zone">
|
||||
<label>Zone 5</label>
|
||||
<description>Sprinkler Zone 5</description>
|
||||
</channel-group>
|
||||
<channel-group id="zone6" typeId="zone">
|
||||
<label>Zone 6</label>
|
||||
<description>Sprinkler Zone 6</description>
|
||||
</channel-group>
|
||||
<channel-group id="zone7" typeId="zone">
|
||||
<label>Zone 7</label>
|
||||
<description>Sprinkler Zone 7</description>
|
||||
</channel-group>
|
||||
<channel-group id="zone8" typeId="zone">
|
||||
<label>Zone 8</label>
|
||||
<description>Sprinkler Zone 8</description>
|
||||
</channel-group>
|
||||
<channel-group id="zone9" typeId="zone">
|
||||
<label>Zone 9</label>
|
||||
<description>Sprinkler Zone 9</description>
|
||||
</channel-group>
|
||||
<channel-group id="zone10" typeId="zone">
|
||||
<label>Zone 10</label>
|
||||
<description>Sprinkler Zone 10</description>
|
||||
</channel-group>
|
||||
<channel-group id="zone11" typeId="zone">
|
||||
<label>Zone 11</label>
|
||||
<description>Sprinkler Zone 11</description>
|
||||
</channel-group>
|
||||
<channel-group id="zone12" typeId="zone">
|
||||
<label>Zone 12</label>
|
||||
<description>Sprinkler Zone 12</description>
|
||||
</channel-group>
|
||||
<channel-group id="zone13" typeId="zone">
|
||||
<label>Zone 13</label>
|
||||
<description>Sprinkler Zone 13</description>
|
||||
</channel-group>
|
||||
<channel-group id="zone14" typeId="zone">
|
||||
<label>Zone 14</label>
|
||||
<description>Sprinkler Zone 14</description>
|
||||
</channel-group>
|
||||
<channel-group id="zone15" typeId="zone">
|
||||
<label>Zone 15</label>
|
||||
<description>Sprinkler Zone 15</description>
|
||||
</channel-group>
|
||||
<channel-group id="zone16" typeId="zone">
|
||||
<label>Zone 16</label>
|
||||
<description>Sprinkler Zone 16</description>
|
||||
</channel-group>
|
||||
<channel-group id="zone17" typeId="zone">
|
||||
<label>Zone 17</label>
|
||||
<description>Sprinkler Zone 17</description>
|
||||
</channel-group>
|
||||
<channel-group id="zone18" typeId="zone">
|
||||
<label>Zone 18</label>
|
||||
<description>Sprinkler Zone 18</description>
|
||||
</channel-group>
|
||||
<channel-group id="zone19" typeId="zone">
|
||||
<label>Zone 19</label>
|
||||
<description>Sprinkler Zone 19</description>
|
||||
</channel-group>
|
||||
<channel-group id="zone20" typeId="zone">
|
||||
<label>Zone 20</label>
|
||||
<description>Sprinkler Zone 20</description>
|
||||
</channel-group>
|
||||
<channel-group id="zone21" typeId="zone">
|
||||
<label>Zone 21</label>
|
||||
<description>Sprinkler Zone 21</description>
|
||||
</channel-group>
|
||||
<channel-group id="zone22" typeId="zone">
|
||||
<label>Zone 22</label>
|
||||
<description>Sprinkler Zone 22</description>
|
||||
</channel-group>
|
||||
<channel-group id="zone23" typeId="zone">
|
||||
<label>Zone 23</label>
|
||||
<description>Sprinkler Zone 23</description>
|
||||
</channel-group>
|
||||
<channel-group id="zone24" typeId="zone">
|
||||
<label>Zone 24</label>
|
||||
<description>Sprinkler Zone 24</description>
|
||||
</channel-group>
|
||||
<channel-group id="zone25" typeId="zone">
|
||||
<label>Zone 25</label>
|
||||
<description>Sprinkler Zone 25</description>
|
||||
</channel-group>
|
||||
<channel-group id="zone26" typeId="zone">
|
||||
<label>Zone 26</label>
|
||||
<description>Sprinkler Zone 26</description>
|
||||
</channel-group>
|
||||
<channel-group id="zone27" typeId="zone">
|
||||
<label>Zone 27</label>
|
||||
<description>Sprinkler Zone 27</description>
|
||||
</channel-group>
|
||||
<channel-group id="zone28" typeId="zone">
|
||||
<label>Zone 28</label>
|
||||
<description>Sprinkler Zone 28</description>
|
||||
</channel-group>
|
||||
<channel-group id="zone29" typeId="zone">
|
||||
<label>Zone 29</label>
|
||||
<description>Sprinkler Zone 29</description>
|
||||
</channel-group>
|
||||
<channel-group id="zone30" typeId="zone">
|
||||
<label>Zone 30</label>
|
||||
<description>Sprinkler Zone 30</description>
|
||||
</channel-group>
|
||||
<channel-group id="zone31" typeId="zone">
|
||||
<label>Zone 31</label>
|
||||
<description>Sprinkler Zone 31</description>
|
||||
</channel-group>
|
||||
<channel-group id="zone32" typeId="zone">
|
||||
<label>Zone 32</label>
|
||||
<description>Sprinkler Zone 32</description>
|
||||
</channel-group>
|
||||
<channel-group id="zone33" typeId="zone">
|
||||
<label>Zone 33</label>
|
||||
<description>Sprinkler Zone 33</description>
|
||||
</channel-group>
|
||||
<channel-group id="zone34" typeId="zone">
|
||||
<label>Zone 34</label>
|
||||
<description>Sprinkler Zone 34</description>
|
||||
</channel-group>
|
||||
<channel-group id="zone35" typeId="zone">
|
||||
<label>Zone 35</label>
|
||||
<description>Sprinkler Zone 35</description>
|
||||
</channel-group>
|
||||
<channel-group id="zone36" typeId="zone">
|
||||
<label>Zone 36</label>
|
||||
<description>Sprinkler Zone 36</description>
|
||||
</channel-group>
|
||||
</channel-groups>
|
||||
<config-description>
|
||||
<parameter name="host" type="text" required="true">
|
||||
<label>Host</label>
|
||||
<description>Host or IP address of local controller</description>
|
||||
</parameter>
|
||||
<parameter name="username" type="text" required="true">
|
||||
<default>admin</default>
|
||||
<label>User Name</label>
|
||||
<description>User name for controller, usually "admin"</description>
|
||||
</parameter>
|
||||
<parameter name="password" type="text" required="true">
|
||||
<label>password</label>
|
||||
<context>password</context>
|
||||
<description>Password for local controller, found in the settings menu on the controller itself.</description>
|
||||
</parameter>
|
||||
<parameter name="refresh" type="integer" required="true">
|
||||
<label>Refresh interval</label>
|
||||
<description>Specifies the refresh interval in seconds</description>
|
||||
<default>30</default>
|
||||
</parameter>
|
||||
</config-description>
|
||||
</thing-type>
|
||||
|
||||
|
||||
</thing:thing-descriptions>
|
||||
Reference in New Issue
Block a user