added migrated 2.x add-ons

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

View File

@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<features name="org.openhab.binding.gardena-${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-gardena" description="Gardena Binding" version="${project.version}">
<feature>openhab-runtime-base</feature>
<bundle start-level="80">mvn:org.openhab.addons.bundles/org.openhab.binding.gardena/${project.version}</bundle>
</feature>
</features>

View File

@@ -0,0 +1,47 @@
/**
* 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.gardena.internal;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.core.thing.ThingTypeUID;
/**
* The {@link GardenaBinding} class defines common constants, which are used across the whole binding.
*
* @author Gerhard Riegler - Initial contribution
*/
@NonNullByDefault
public class GardenaBindingConstants {
public static final String BINDING_ID = "gardena";
public static final ThingTypeUID THING_TYPE_ACCOUNT = new ThingTypeUID(BINDING_ID, "account");
public static final String PROPERTY_MANUFACTURER = "manufacturer";
public static final String PROPERTY_PRODUCT = "product";
public static final String PROPERTY_SERIALNUMBER = "serial_number";
public static final String PROPERTY_SGTIN = "sgtin";
public static final String PROPERTY_VERSION = "version";
public static final String PROPERTY_CATEGORY = "category";
public static final String PROPERTY_CONNECTION_STATUS = "connection_status";
public static final String PROPERTY_CONNECTION_STATUS_UNREACH_VALUE = "status_device_unreachable";
public static final String PROPERTY_STATE = "state";
public static final String ABILITY_DEVICE_INFO = "device_info";
public static final String ABILITY_RADIO = "radio";
public static final String SETTING_LEAKAGE_DETECTION = "leakage_detection";
public static final String SETTING_OPERATION_MODE = "operating_mode";
public static final String SETTING_TURN_ON_PRESSURE = "turn_on_pressure";
}

View File

@@ -0,0 +1,71 @@
/**
* 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.gardena.internal;
import java.util.Set;
import java.util.concurrent.ScheduledExecutorService;
import org.openhab.binding.gardena.internal.config.GardenaConfig;
import org.openhab.binding.gardena.internal.exception.GardenaException;
import org.openhab.binding.gardena.internal.model.Device;
import org.openhab.binding.gardena.internal.model.Location;
import org.openhab.binding.gardena.internal.model.Setting;
/**
* Describes the methods required for the communication with Gardens Smart Home.
*
* @author Gerhard Riegler - Initial contribution
*/
public interface GardenaSmart {
/**
* Initializes Gardena Smart Home and loads all devices from all locations.
*/
public void init(String id, GardenaConfig config, GardenaSmartEventListener eventListener,
ScheduledExecutorService scheduler) throws GardenaException;
/**
* Disposes Gardena Smart Home.
*/
public void dispose();
/**
* Loads all devices from all locations.
*/
public void loadAllDevices() throws GardenaException;
/**
* Returns all locations.
*/
public Set<Location> getLocations();
/**
* Returns a device with the given id.
*/
public Device getDevice(String deviceId) throws GardenaException;
/**
* Sends a command to Gardena Smart Home.
*/
public void sendCommand(Device device, GardenaSmartCommandName commandName, Object value) throws GardenaException;
/**
* Sends a setting to Gardena Smart Home.
*/
public void sendSetting(Setting setting, Object value) throws GardenaException;
/**
* Returns the id.
*/
public String getId();
}

View File

@@ -0,0 +1,51 @@
/**
* 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.gardena.internal;
/**
* A names of all GardenaSmart commands.
*
* @author Gerhard Riegler - Initial contribution
*/
public enum GardenaSmartCommandName {
// mower
PARK_UNTIL_FURTHER_NOTICE,
PARK_UNTIL_NEXT_TIMER,
START_OVERRIDE_TIMER,
START_RESUME_SCHEDULE,
DURATION_PROPERTY,
// sensor
MEASURE_AMBIENT_TEMPERATURE,
MEASURE_LIGHT,
MEASURE_SOIL_HUMIDITY,
MEASURE_SOIL_TEMPERATURE,
// outlet
OUTLET_MANUAL_OVERRIDE_TIME,
OUTLET_VALVE,
// power
POWER_TIMER,
// irrigation control
WATERING_TIMER_VALVE_1,
WATERING_TIMER_VALVE_2,
WATERING_TIMER_VALVE_3,
WATERING_TIMER_VALVE_4,
WATERING_TIMER_VALVE_5,
WATERING_TIMER_VALVE_6,
// pump
PUMP_MANUAL_WATERING_TIMER
}

View File

@@ -0,0 +1,48 @@
/**
* Copyright (c) 2010-2020 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.gardena.internal;
import org.openhab.binding.gardena.internal.model.Device;
/**
* Listener with methods called from events within the {@link GardenaSmart} class.
*
* @author Gerhard Riegler - Initial contribution
*/
public interface GardenaSmartEventListener {
/**
* Called when a device has been updated.
*/
public void onDeviceUpdated(Device device);
/**
* Called when a new device has been detected.
*/
public void onNewDevice(Device device);
/**
* Called when a device has been deleted.
*/
public void onDeviceDeleted(Device device);
/**
* Called when the connection is lost to Gardena Smart Home.
*/
public void onConnectionLost();
/**
* Called when the connection is resumed to Gardena Smart Home.
*/
public void onConnectionResumed();
}

View File

@@ -0,0 +1,573 @@
/**
* 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.gardena.internal;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
import org.apache.commons.lang.ObjectUtils;
import org.apache.commons.lang.StringUtils;
import org.eclipse.jetty.client.HttpClient;
import org.eclipse.jetty.client.HttpResponseException;
import org.eclipse.jetty.client.api.ContentResponse;
import org.eclipse.jetty.client.api.Request;
import org.eclipse.jetty.client.util.StringContentProvider;
import org.eclipse.jetty.http.HttpHeader;
import org.eclipse.jetty.http.HttpMethod;
import org.eclipse.jetty.util.ssl.SslContextFactory;
import org.openhab.binding.gardena.internal.config.GardenaConfig;
import org.openhab.binding.gardena.internal.config.GardenaConfigWrapper;
import org.openhab.binding.gardena.internal.exception.GardenaDeviceNotFoundException;
import org.openhab.binding.gardena.internal.exception.GardenaException;
import org.openhab.binding.gardena.internal.exception.GardenaUnauthorizedException;
import org.openhab.binding.gardena.internal.model.Ability;
import org.openhab.binding.gardena.internal.model.Device;
import org.openhab.binding.gardena.internal.model.Devices;
import org.openhab.binding.gardena.internal.model.Errors;
import org.openhab.binding.gardena.internal.model.Location;
import org.openhab.binding.gardena.internal.model.Locations;
import org.openhab.binding.gardena.internal.model.NoResult;
import org.openhab.binding.gardena.internal.model.Property;
import org.openhab.binding.gardena.internal.model.PropertyValue;
import org.openhab.binding.gardena.internal.model.Session;
import org.openhab.binding.gardena.internal.model.SessionWrapper;
import org.openhab.binding.gardena.internal.model.Setting;
import org.openhab.binding.gardena.internal.model.command.Command;
import org.openhab.binding.gardena.internal.model.command.MowerParkUntilFurtherNoticeCommand;
import org.openhab.binding.gardena.internal.model.command.MowerParkUntilNextTimerCommand;
import org.openhab.binding.gardena.internal.model.command.MowerStartOverrideTimerCommand;
import org.openhab.binding.gardena.internal.model.command.MowerStartResumeScheduleCommand;
import org.openhab.binding.gardena.internal.model.command.SensorMeasureAmbientTemperatureCommand;
import org.openhab.binding.gardena.internal.model.command.SensorMeasureLightCommand;
import org.openhab.binding.gardena.internal.model.command.SensorMeasureSoilHumidityCommand;
import org.openhab.binding.gardena.internal.model.command.SensorMeasureSoilTemperatureCommand;
import org.openhab.binding.gardena.internal.model.command.SettingCommand;
import org.openhab.binding.gardena.internal.model.command.SettingCommandWrapper;
import org.openhab.binding.gardena.internal.model.command.WateringCancelOverrideCommand;
import org.openhab.binding.gardena.internal.model.command.WateringManualOverrideCommand;
import org.openhab.binding.gardena.internal.model.deser.DateDeserializer;
import org.openhab.binding.gardena.internal.model.deser.PropertyValueDeserializer;
import org.openhab.binding.gardena.internal.model.property.BaseProperty;
import org.openhab.binding.gardena.internal.model.property.IrrigationControlWateringProperty;
import org.openhab.binding.gardena.internal.model.property.PropertyWrapper;
import org.openhab.binding.gardena.internal.model.property.StringProperty;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
/**
* {@link GardenaSmart} implementation to access Gardena Smart Home.
*
* @author Gerhard Riegler - Initial contribution
*/
public class GardenaSmartImpl implements GardenaSmart {
private final Logger logger = LoggerFactory.getLogger(GardenaSmartImpl.class);
public static final String DEVICE_CATEGORY_PUMP = "electronic_pressure_pump";
private static final String ABILITY_MOWER = "mower";
private static final String ABILITY_OUTLET = "outlet";
private static final String ABILITY_HUMIDITY = "humidity";
private static final String ABILITY_LIGHT = "light";
private static final String ABILITY_AMBIENT_TEMPERATURE = "ambient_temperature";
private static final String ABILITY_SOIL_TEMPERATURE = "soil_temperature";
private static final String ABILITY_POWER = "power";
private static final String ABILITY_WATERING = "watering";
private static final String ABILITY_MANUAL_WATERING = "manual_watering";
private static final String PROPERTY_BUTTON_MANUAL_OVERRIDE_TIME = "button_manual_override_time";
private static final String PROPERTY_POWER_TIMER = "power_timer";
private static final String PROPERTY_WATERING_TIMER = "watering_timer_";
private static final String PROPERTY_MANUAL_WATERING_TIMER = "manual_watering_timer";
private static final String DEVICE_CATEGORY_MOWER = "mower";
private static final String DEVICE_CATEGORY_GATEWAY = "gateway";
private static final String DEFAULT_MOWER_DURATION = "180";
private static final String URL = "https://smart.gardena.com";
private static final String URL_LOGIN = URL + "/v1/auth/token";
private static final String URL_LOCATIONS = URL + "/v1/locations/?user_id=";
private static final String URL_DEVICES = URL + "/v1/devices/?locationId=";
private static final String URL_COMMAND = URL + "/v1/devices/%s/abilities/%s/command?locationId=%s";
private static final String URL_PROPERTY = URL + "/v1/devices/%s/abilities/%s/properties/%s?locationId=%s";
private static final String URL_SETTING = URL + "/v1/devices/%s/settings/%s?locationId=%s";
private Gson gson = new GsonBuilder().registerTypeAdapter(Date.class, new DateDeserializer())
.registerTypeAdapter(PropertyValue.class, new PropertyValueDeserializer()).create();
private HttpClient httpClient;
private String mowerDuration = DEFAULT_MOWER_DURATION;
private Session session;
private GardenaConfig config;
private String id;
private ScheduledExecutorService scheduler;
private ScheduledFuture<?> refreshThreadFuture;
private RefreshDevicesThread refreshDevicesThread = new RefreshDevicesThread();
private GardenaSmartEventListener eventListener;
private Map<String, Device> allDevicesById = new HashMap<>();
private Set<Location> allLocations = new HashSet<>();
@Override
public void init(String id, GardenaConfig config, GardenaSmartEventListener eventListener,
ScheduledExecutorService scheduler) throws GardenaException {
this.id = id;
this.config = config;
this.eventListener = eventListener;
this.scheduler = scheduler;
if (!config.isValid()) {
throw new GardenaException("Invalid config, no email or password specified");
}
httpClient = new HttpClient(new SslContextFactory(true));
httpClient.setConnectTimeout(config.getConnectionTimeout() * 1000L);
try {
httpClient.start();
} catch (Exception ex) {
throw new GardenaException(ex.getMessage(), ex);
}
loadAllDevices();
}
@Override
public void dispose() {
stopRefreshThread(true);
if (httpClient != null) {
try {
httpClient.stop();
} catch (Exception e) {
// ignore
}
httpClient.destroy();
}
allLocations.clear();
allDevicesById.clear();
}
/**
* Schedules the device refresh thread.
*/
private void startRefreshThread() {
refreshThreadFuture = scheduler.scheduleWithFixedDelay(refreshDevicesThread, 6, config.getRefresh(),
TimeUnit.SECONDS);
}
/**
* Stops the device refresh thread.
*/
private void stopRefreshThread(boolean force) {
if (refreshThreadFuture != null) {
refreshThreadFuture.cancel(force);
}
}
@Override
public String getId() {
return id;
}
@Override
public Set<Location> getLocations() {
return allLocations;
}
@Override
public Device getDevice(String deviceId) throws GardenaException {
Device device = allDevicesById.get(deviceId);
if (device == null) {
throw new GardenaDeviceNotFoundException(
String.format("Device with id '%s' not found on gateway '%s'", deviceId, id));
}
return device;
}
@Override
public void loadAllDevices() throws GardenaException {
stopRefreshThread(false);
try {
allLocations.clear();
allDevicesById.clear();
verifySession();
Locations locations = executeRequest(HttpMethod.GET,
URL_LOCATIONS + session.getSessionAttributes().getUserId(), null, Locations.class);
for (Location location : locations.getLocations()) {
allLocations.add(location);
Devices devices = loadDevices(location);
for (Device device : devices.getDevices()) {
if (DEVICE_CATEGORY_GATEWAY.equals(device.getCategory())) {
location.getDeviceIds().remove(device.getId());
} else {
allDevicesById.put(device.getId(), device);
}
}
}
} finally {
startRefreshThread();
}
}
/**
* Loads all devices for the location, adds virtual properties for commands.
*/
private Devices loadDevices(Location location) throws GardenaException {
Devices devices = executeRequest(HttpMethod.GET, URL_DEVICES + location.getId(), null, Devices.class);
for (Device device : devices.getDevices()) {
device.setLocation(location);
for (Ability ability : device.getAbilities()) {
ability.setDevice(device);
for (Property property : ability.getProperties()) {
property.setAbility(ability);
if (device.getCategory().equals(DEVICE_CATEGORY_PUMP)) {
if (property.getName().equals(PROPERTY_MANUAL_WATERING_TIMER)) {
Integer duration = getIntegerValue(property.getValueAsString());
if (duration == null) {
duration = 0;
}
property.setValue(new PropertyValue(String.valueOf(duration / 60)));
}
}
}
}
for (Setting setting : device.getSettings()) {
setting.setDevice(device);
}
if (DEVICE_CATEGORY_MOWER.equals(device.getCategory())) {
Ability mower = device.getAbility(ABILITY_MOWER);
mower.addProperty(new Property(GardenaSmartCommandName.PARK_UNTIL_NEXT_TIMER, "false"));
mower.addProperty(new Property(GardenaSmartCommandName.PARK_UNTIL_FURTHER_NOTICE, "false"));
mower.addProperty(new Property(GardenaSmartCommandName.START_RESUME_SCHEDULE, "false"));
mower.addProperty(new Property(GardenaSmartCommandName.START_OVERRIDE_TIMER, "false"));
mower.addProperty(new Property(GardenaSmartCommandName.DURATION_PROPERTY, mowerDuration));
}
}
return devices;
}
@Override
public void sendCommand(Device device, GardenaSmartCommandName commandName, Object value) throws GardenaException {
Ability ability = null;
Command command = null;
switch (commandName) {
case PARK_UNTIL_NEXT_TIMER:
ability = device.getAbility(ABILITY_MOWER);
command = new MowerParkUntilNextTimerCommand();
break;
case PARK_UNTIL_FURTHER_NOTICE:
ability = device.getAbility(ABILITY_MOWER);
command = new MowerParkUntilFurtherNoticeCommand();
break;
case START_RESUME_SCHEDULE:
ability = device.getAbility(ABILITY_MOWER);
command = new MowerStartResumeScheduleCommand();
break;
case START_OVERRIDE_TIMER:
ability = device.getAbility(ABILITY_MOWER);
command = new MowerStartOverrideTimerCommand(mowerDuration);
break;
case DURATION_PROPERTY:
if (value == null) {
throw new GardenaException("Command '" + commandName + "' requires a value");
}
mowerDuration = ObjectUtils.toString(value);
return;
case MEASURE_AMBIENT_TEMPERATURE:
ability = device.getAbility(ABILITY_AMBIENT_TEMPERATURE);
command = new SensorMeasureAmbientTemperatureCommand();
break;
case MEASURE_LIGHT:
ability = device.getAbility(ABILITY_LIGHT);
command = new SensorMeasureLightCommand();
break;
case MEASURE_SOIL_HUMIDITY:
ability = device.getAbility(ABILITY_HUMIDITY);
command = new SensorMeasureSoilHumidityCommand();
break;
case MEASURE_SOIL_TEMPERATURE:
ability = device.getAbility(ABILITY_SOIL_TEMPERATURE);
command = new SensorMeasureSoilTemperatureCommand();
break;
case OUTLET_MANUAL_OVERRIDE_TIME:
if (value == null) {
throw new GardenaException("Command '" + commandName + "' requires a value");
}
StringProperty prop = new StringProperty(PROPERTY_BUTTON_MANUAL_OVERRIDE_TIME,
ObjectUtils.toString(value));
executeSetProperty(device, ABILITY_OUTLET, PROPERTY_BUTTON_MANUAL_OVERRIDE_TIME, prop);
break;
case OUTLET_VALVE:
ability = device.getAbility(ABILITY_OUTLET);
if (value != null && value == Boolean.TRUE) {
String wateringDuration = device.getAbility(ABILITY_OUTLET)
.getProperty(PROPERTY_BUTTON_MANUAL_OVERRIDE_TIME).getValueAsString();
command = new WateringManualOverrideCommand(wateringDuration);
} else {
command = new WateringCancelOverrideCommand();
}
break;
case POWER_TIMER:
if (value == null) {
throw new GardenaException("Command '" + commandName + "' requires a value");
}
prop = new StringProperty(PROPERTY_POWER_TIMER, ObjectUtils.toString(value));
executeSetProperty(device, ABILITY_POWER, PROPERTY_POWER_TIMER, prop);
break;
case WATERING_TIMER_VALVE_1:
case WATERING_TIMER_VALVE_2:
case WATERING_TIMER_VALVE_3:
case WATERING_TIMER_VALVE_4:
case WATERING_TIMER_VALVE_5:
case WATERING_TIMER_VALVE_6:
if (value == null) {
throw new GardenaException("Command '" + commandName + "' requires a value");
} else if (!(value instanceof Integer)) {
throw new GardenaException("Watering duration value '" + value + "' not a number");
}
int valveId = Integer.parseInt(StringUtils.right(commandName.toString(), 1));
String wateringTimerProperty = PROPERTY_WATERING_TIMER + valveId;
IrrigationControlWateringProperty irrigationProp = new IrrigationControlWateringProperty(
wateringTimerProperty, (Integer) value, valveId);
executeSetProperty(device, ABILITY_WATERING, wateringTimerProperty, irrigationProp);
break;
case PUMP_MANUAL_WATERING_TIMER:
Integer duration = getIntegerValue(value);
if (duration == null) {
throw new GardenaException("Command '" + commandName + "' requires a number value");
}
prop = new StringProperty(PROPERTY_MANUAL_WATERING_TIMER, String.valueOf(duration * 60));
executeSetProperty(device, ABILITY_MANUAL_WATERING, PROPERTY_MANUAL_WATERING_TIMER, prop);
break;
default:
throw new GardenaException("Unknown command " + commandName);
}
if (command != null) {
stopRefreshThread(false);
executeRequest(HttpMethod.POST, getCommandUrl(device, ability), command, NoResult.class);
startRefreshThread();
}
}
private Integer getIntegerValue(Object value) {
try {
return Integer.valueOf(ObjectUtils.toString(value));
} catch (NumberFormatException ex) {
return null;
}
}
/**
* Sends the new property value for the ability.
*/
private void executeSetProperty(Device device, String ability, String property, BaseProperty value)
throws GardenaException {
String propertyUrl = String.format(URL_PROPERTY, device.getId(), ability, property,
device.getLocation().getId());
stopRefreshThread(false);
executeRequest(HttpMethod.PUT, propertyUrl, new PropertyWrapper(value), NoResult.class);
device.getAbility(ability).getProperty(property).setValue(new PropertyValue(value.getValue()));
startRefreshThread();
}
@Override
public void sendSetting(Setting setting, Object value) throws GardenaException {
SettingCommand settingCommand = new SettingCommand(setting.getName());
settingCommand.setDeviceId(setting.getDevice().getId());
settingCommand.setValue(value);
stopRefreshThread(false);
executeRequest(HttpMethod.PUT, getSettingUrl(setting), new SettingCommandWrapper(settingCommand),
NoResult.class);
startRefreshThread();
}
/**
* Returns the command url.
*/
private String getCommandUrl(Device device, Ability ability) throws GardenaException {
return String.format(URL_COMMAND, device.getId(), ability.getName(), device.getLocation().getId());
}
/**
* Returns the settings url.
*/
private String getSettingUrl(Setting setting) {
Device device = setting.getDevice();
return String.format(URL_SETTING, device.getId(), setting.getId(), device.getLocation().getId());
}
/**
* Communicates with Gardena Smart Home and parses the result.
*/
private synchronized <T> T executeRequest(HttpMethod method, String url, Object contentObject, Class<T> result)
throws GardenaException {
try {
if (logger.isTraceEnabled()) {
logger.trace("{} request: {}", method, url);
if (contentObject != null) {
logger.trace("{} data : {}", method, gson.toJson(contentObject));
}
}
Request request = httpClient.newRequest(url).method(method)
.timeout(config.getConnectionTimeout(), TimeUnit.SECONDS)
.idleTimeout(config.getConnectionTimeout(), TimeUnit.SECONDS)
.header(HttpHeader.CONTENT_TYPE, "application/json").header(HttpHeader.ACCEPT, "application/json")
.header(HttpHeader.ACCEPT_ENCODING, "gzip");
if (contentObject != null) {
StringContentProvider content = new StringContentProvider(gson.toJson(contentObject));
request.content(content);
}
if (!result.equals(SessionWrapper.class)) {
verifySession();
request.header("authorization", "Bearer " + session.getToken());
request.header("authorization-provider", session.getSessionAttributes().getProvider());
}
ContentResponse contentResponse = request.send();
int status = contentResponse.getStatus();
if (logger.isTraceEnabled()) {
logger.trace("Status : {}", status);
logger.trace("Response: {}", contentResponse.getContentAsString());
}
if (status == 500) {
throw new GardenaException(
gson.fromJson(contentResponse.getContentAsString(), Errors.class).toString());
} else if (status != 200 && status != 204 && status != 201) {
throw new GardenaException(String.format("Error %s %s", status, contentResponse.getReason()));
}
if (result == NoResult.class) {
return null;
}
return gson.fromJson(contentResponse.getContentAsString(), result);
} catch (ExecutionException ex) {
Throwable cause = ex.getCause();
if (cause instanceof HttpResponseException) {
HttpResponseException responseException = (HttpResponseException) ex.getCause();
int status = responseException.getResponse().getStatus();
if (status == 401) {
throw new GardenaUnauthorizedException(ex.getCause());
}
}
throw new GardenaException(ex.getMessage(), ex);
} catch (Exception ex) {
throw new GardenaException(ex.getMessage(), ex);
}
}
/**
* Verifies the Gardena Smart Home session and reconnects if necessary.
*/
private void verifySession() throws GardenaException {
if (session == null
|| session.getCreated() + (config.getSessionTimeout() * 60000) <= System.currentTimeMillis()) {
logger.trace("(Re)logging in to Gardena Smart Home");
session = executeRequest(HttpMethod.POST, URL_LOGIN, new GardenaConfigWrapper(config), SessionWrapper.class)
.getSession();
}
}
/**
* Thread which refreshes the data from Gardena Smart Home.
*/
private class RefreshDevicesThread implements Runnable {
private boolean connectionLost = false;
@Override
public void run() {
try {
logger.debug("Refreshing gardena device data");
final Map<String, Device> newDevicesById = new HashMap<>();
for (Location location : allLocations) {
Devices devices = loadDevices(location);
for (Device device : devices.getDevices()) {
if (DEVICE_CATEGORY_GATEWAY.equals(device.getCategory())) {
location.getDeviceIds().remove(device.getId());
} else {
newDevicesById.put(device.getId(), device);
}
}
}
if (connectionLost) {
connectionLost = false;
logger.info("Connection resumed to Gardena Smart Home with id '{}'", id);
eventListener.onConnectionResumed();
}
// determine deleted devices
Collection<Device> deletedDevices = allDevicesById.values().stream()
.filter(d -> !newDevicesById.values().contains(d)).collect(Collectors.toSet());
// determine new devices
Collection<Device> newDevices = newDevicesById.values().stream()
.filter(d -> !allDevicesById.values().contains(d)).collect(Collectors.toSet());
// determine updated devices
Collection<Device> updatedDevices = allDevicesById.values().stream().distinct()
.filter(newDevicesById.values()::contains).collect(Collectors.toSet());
allDevicesById = newDevicesById;
for (Device deletedDevice : deletedDevices) {
eventListener.onDeviceDeleted(deletedDevice);
}
for (Device newDevice : newDevices) {
eventListener.onNewDevice(newDevice);
}
for (Device updatedDevice : updatedDevices) {
eventListener.onDeviceUpdated(updatedDevice);
}
} catch (GardenaException ex) {
if (!connectionLost) {
connectionLost = true;
logger.warn("Connection lost to Gardena Smart Home with id '{}'", id);
logger.trace("{}", ex.getMessage(), ex);
eventListener.onConnectionLost();
}
}
}
}
}

View File

@@ -0,0 +1,132 @@
/**
* 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.gardena.internal.config;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.builder.ToStringBuilder;
import org.apache.commons.lang.builder.ToStringStyle;
import com.google.gson.annotations.SerializedName;
/**
* The main Gardena config class.
*
* @author Gerhard Riegler - Initial contribution
*/
public class GardenaConfig {
private static final Integer DEFAULT_SESSION_TIMEOUT = 30;
private static final Integer DEFAULT_CONNECTION_TIMEOUT = 10;
private static final Integer DEFAULT_REFRESH = 60;
@SerializedName("username")
private String email;
private String password;
private transient Integer sessionTimeout = DEFAULT_SESSION_TIMEOUT;
private transient Integer connectionTimeout = DEFAULT_CONNECTION_TIMEOUT;
private transient Integer refresh = DEFAULT_REFRESH;
public GardenaConfig() {
}
public GardenaConfig(String email, String password) {
this.email = email;
this.password = password;
}
/**
* Returns the email to connect to Gardena Smart Home.
*/
public String getEmail() {
return email;
}
/**
* Sets the email to connect to Gardena Smart Home.
*/
public void setEmail(String email) {
this.email = email;
}
/**
* Returns the password to connect to Gardena Smart Home.
*/
public String getPassword() {
return password;
}
/**
* Sets the password to connect to Gardena Smart Home.
*/
public void setPassword(String password) {
this.password = password;
}
/**
* Returns the session timeout to Gardena Smart Home.
*/
public int getSessionTimeout() {
return sessionTimeout;
}
/**
* Sets the session timeout to Gardena Smart Home.
*/
public void setSessionTimeout(int sessionTimeout) {
this.sessionTimeout = sessionTimeout;
}
/**
* Returns the connection timeout to Gardena Smart Home.
*/
public Integer getConnectionTimeout() {
return connectionTimeout;
}
/**
* Sets the connection timeout to Gardena Smart Home.
*/
public void setConnectionTimeout(Integer connectionTimeout) {
this.connectionTimeout = connectionTimeout;
}
/**
* Returns the refresh interval to fetch new data from Gardena Smart Home.
*/
public Integer getRefresh() {
return refresh;
}
/**
* Returns the refresh interval to fetch new data from Gardena Smart Home.
*/
public void setRefresh(Integer refresh) {
this.refresh = refresh;
}
/**
* Validate the config, if at least email and password is specified.
*/
public boolean isValid() {
return StringUtils.isNotBlank(email) && StringUtils.isNotBlank(password);
}
@Override
public String toString() {
return new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE).append("email", email)
.append("password", StringUtils.isBlank(password) ? "" : StringUtils.repeat("*", password.length()))
.append("sessionTimeout", sessionTimeout).append("connectionTimeout", connectionTimeout)
.append("refresh", refresh).toString();
}
}

View File

@@ -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.gardena.internal.config;
import com.google.gson.annotations.SerializedName;
/**
* GardenaConfgData wrapper for valid Gardena JSON serialization.
*
* @author Gerhard Riegler - Initial contribution
*/
public class GardenaConfigDataWrapper {
@SerializedName("attributes")
private GardenaConfig config;
@SerializedName("type")
private String typeToken = "token";
public GardenaConfigDataWrapper() {
}
public GardenaConfigDataWrapper(GardenaConfig config) {
this.config = config;
}
}

View File

@@ -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.gardena.internal.config;
import com.google.gson.annotations.SerializedName;
/**
* GardenaConfg wrapper for valid Gardena JSON serialization.
*
* @author Gerhard Riegler - Initial contribution
*/
public class GardenaConfigWrapper {
@SerializedName("data")
private GardenaConfigDataWrapper dataWrapper;
public GardenaConfigWrapper() {
}
public GardenaConfigWrapper(GardenaConfig config) {
this.dataWrapper = new GardenaConfigDataWrapper(config);
}
}

View File

@@ -0,0 +1,176 @@
/**
* 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.gardena.internal.discovery;
import static org.openhab.binding.gardena.internal.GardenaBindingConstants.BINDING_ID;
import java.util.Collections;
import java.util.concurrent.CancellationException;
import java.util.concurrent.Future;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.binding.gardena.internal.GardenaSmart;
import org.openhab.binding.gardena.internal.exception.GardenaException;
import org.openhab.binding.gardena.internal.handler.GardenaAccountHandler;
import org.openhab.binding.gardena.internal.model.Device;
import org.openhab.binding.gardena.internal.model.Location;
import org.openhab.binding.gardena.internal.util.UidUtils;
import org.openhab.core.config.discovery.AbstractDiscoveryService;
import org.openhab.core.config.discovery.DiscoveryResult;
import org.openhab.core.config.discovery.DiscoveryResultBuilder;
import org.openhab.core.config.discovery.DiscoveryService;
import org.openhab.core.thing.Thing;
import org.openhab.core.thing.ThingTypeUID;
import org.openhab.core.thing.ThingUID;
import org.openhab.core.thing.binding.ThingHandler;
import org.openhab.core.thing.binding.ThingHandlerService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* The {@link GardenaDeviceDiscoveryService} is used to discover devices that are connected to Gardena Smart Home.
*
* @author Gerhard Riegler - Initial contribution
*/
public class GardenaDeviceDiscoveryService extends AbstractDiscoveryService
implements DiscoveryService, ThingHandlerService {
private final Logger logger = LoggerFactory.getLogger(GardenaDeviceDiscoveryService.class);
private static final int DISCOVER_TIMEOUT_SECONDS = 30;
private @NonNullByDefault({}) GardenaAccountHandler accountHandler;
private Future<?> scanFuture;
public GardenaDeviceDiscoveryService() {
super(Collections.unmodifiableSet(Stream.of(new ThingTypeUID(BINDING_ID, "-")).collect(Collectors.toSet())),
DISCOVER_TIMEOUT_SECONDS, false);
}
@Override
public void setThingHandler(@Nullable ThingHandler handler) {
if (handler instanceof GardenaAccountHandler) {
this.accountHandler = (GardenaAccountHandler) handler;
this.accountHandler.setDiscoveryService(this);
}
}
@Override
public @Nullable ThingHandler getThingHandler() {
return accountHandler;
}
/**
* Called on component activation.
*/
@Override
public void activate() {
super.activate(null);
}
@Override
public void deactivate() {
super.deactivate();
}
@Override
protected void startScan() {
logger.debug("Starting Gardena discovery scan");
loadDevices();
}
@Override
public void stopScan() {
logger.debug("Stopping Gardena discovery scan");
if (scanFuture != null) {
scanFuture.cancel(true);
}
super.stopScan();
}
/**
* Starts a thread which loads all Gardena devices registered in the account
*/
public void loadDevices() {
if (scanFuture == null) {
scanFuture = scheduler.submit(() -> {
try {
GardenaSmart gardena = accountHandler.getGardenaSmart();
gardena.loadAllDevices();
for (Location location : gardena.getLocations()) {
for (String deviceId : location.getDeviceIds()) {
deviceDiscovered(gardena.getDevice(deviceId));
}
}
for (Thing thing : accountHandler.getThing().getThings()) {
try {
gardena.getDevice(UidUtils.getGardenaDeviceId(thing));
} catch (GardenaException ex) {
thingRemoved(thing.getUID());
}
}
logger.debug("Finished Gardena device discovery scan on gateway '{}'",
accountHandler.getGardenaSmart().getId());
} catch (GardenaException ex) {
logger.error("{}", ex.getMessage(), ex);
} finally {
scanFuture = null;
removeOlderResults(getTimestampOfLastScan());
}
});
} else {
logger.debug("Gardena device discovery scan in progress");
}
}
/**
* Waits for the discovery scan to finish and then returns.
*/
public void waitForScanFinishing() {
if (scanFuture != null) {
logger.debug("Waiting for finishing Gardena device discovery scan");
try {
scanFuture.get();
logger.debug("Gardena device discovery scan finished");
} catch (CancellationException ex) {
// ignore
} catch (Exception ex) {
logger.error("Error waiting for device discovery scan: {}", ex.getMessage(), ex);
}
}
}
/**
* Generates the DiscoveryResult from a Gardena device.
*/
public void deviceDiscovered(Device device) {
ThingUID accountUID = accountHandler.getThing().getUID();
ThingUID thingUID = UidUtils.generateThingUID(device, accountHandler.getThing());
DiscoveryResult discoveryResult = DiscoveryResultBuilder.create(thingUID).withBridge(accountUID)
.withLabel(device.getName()).build();
thingDiscovered(discoveryResult);
}
/**
* Removes the Gardena device.
*/
public void deviceRemoved(Device device) {
ThingUID thingUID = UidUtils.generateThingUID(device, accountHandler.getThing());
thingRemoved(thingUID);
}
}

View File

@@ -0,0 +1,28 @@
/**
* 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.gardena.internal.exception;
/**
* Exception if a device is not found, this happens if a device is requested and the data from Gardena Smart Home has
* not been loaded.
*
* @author Gerhard Riegler - Initial contribution
*/
public class GardenaDeviceNotFoundException extends GardenaException {
private static final long serialVersionUID = 2704767320916725490L;
public GardenaDeviceNotFoundException(String message) {
super(message);
}
}

View File

@@ -0,0 +1,37 @@
/**
* 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.gardena.internal.exception;
import java.io.IOException;
/**
* Exception if something happens in the communication to Gardena Smart Home.
*
* @author Gerhard Riegler - Initial contribution
*/
public class GardenaException extends IOException {
private static final long serialVersionUID = 8568935118878542270L;
public GardenaException(String message) {
super(message);
}
public GardenaException(Throwable ex) {
super(ex);
}
public GardenaException(String message, Throwable cause) {
super(message, cause);
}
}

View File

@@ -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.gardena.internal.exception;
/**
* Exception for invalid user and password.
*
* @author Gerhard Riegler - Initial contribution
*/
public class GardenaUnauthorizedException extends GardenaException {
private static final long serialVersionUID = 4343137351443555679L;
public GardenaUnauthorizedException(Throwable ex) {
super(ex);
}
}

View File

@@ -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.gardena.internal.handler;
/**
* Exception if the AccountHandler is not available.
*
* @author Gerhard Riegler - Initial contribution
*/
public class AccountHandlerNotAvailableException extends Exception {
private static final long serialVersionUID = -1895774551653276530L;
public AccountHandlerNotAvailableException(String message) {
super(message);
}
}

View File

@@ -0,0 +1,188 @@
/**
* 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.gardena.internal.handler;
import java.util.Collection;
import java.util.Collections;
import java.util.concurrent.TimeUnit;
import org.openhab.binding.gardena.internal.GardenaSmart;
import org.openhab.binding.gardena.internal.GardenaSmartEventListener;
import org.openhab.binding.gardena.internal.GardenaSmartImpl;
import org.openhab.binding.gardena.internal.config.GardenaConfig;
import org.openhab.binding.gardena.internal.discovery.GardenaDeviceDiscoveryService;
import org.openhab.binding.gardena.internal.exception.GardenaException;
import org.openhab.binding.gardena.internal.model.Device;
import org.openhab.binding.gardena.internal.util.UidUtils;
import org.openhab.core.thing.Bridge;
import org.openhab.core.thing.Channel;
import org.openhab.core.thing.ChannelUID;
import org.openhab.core.thing.Thing;
import org.openhab.core.thing.ThingStatus;
import org.openhab.core.thing.ThingStatusDetail;
import org.openhab.core.thing.ThingUID;
import org.openhab.core.thing.binding.BaseBridgeHandler;
import org.openhab.core.thing.binding.ThingHandlerService;
import org.openhab.core.types.Command;
import org.openhab.core.types.RefreshType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* The {@link GardenaAccountHandler} is the handler for a Gardena Smart Home access and connects it to the framework.
*
* @author Gerhard Riegler - Initial contribution
*/
public class GardenaAccountHandler extends BaseBridgeHandler implements GardenaSmartEventListener {
private final Logger logger = LoggerFactory.getLogger(GardenaAccountHandler.class);
private static final long REINITIALIZE_DELAY_SECONDS = 10;
private GardenaDeviceDiscoveryService discoveryService;
private GardenaSmart gardenaSmart = new GardenaSmartImpl();
private GardenaConfig gardenaConfig;
public GardenaAccountHandler(Bridge bridge) {
super(bridge);
}
@Override
public void initialize() {
logger.debug("Initializing Gardena account '{}'", getThing().getUID().getId());
gardenaConfig = getThing().getConfiguration().as(GardenaConfig.class);
logger.debug("{}", gardenaConfig);
initializeGardena();
}
public void setDiscoveryService(GardenaDeviceDiscoveryService discoveryService) {
this.discoveryService = discoveryService;
}
/**
* Initializes the GardenaSmart account.
*/
private void initializeGardena() {
final GardenaAccountHandler instance = this;
scheduler.execute(() -> {
try {
String id = getThing().getUID().getId();
gardenaSmart.init(id, gardenaConfig, instance, scheduler);
discoveryService.startScan(null);
discoveryService.waitForScanFinishing();
updateStatus(ThingStatus.ONLINE);
} catch (GardenaException ex) {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, ex.getMessage());
disposeGardena();
scheduleReinitialize();
logger.debug("{}", ex.getMessage(), ex);
}
});
}
/**
* Schedules a reinitialization, if Gardea Smart Home account is not reachable at startup.
*/
private void scheduleReinitialize() {
scheduler.schedule(() -> {
initializeGardena();
}, REINITIALIZE_DELAY_SECONDS, TimeUnit.SECONDS);
}
@Override
public void dispose() {
super.dispose();
disposeGardena();
}
/**
* Disposes the GardenaSmart account.
*/
private void disposeGardena() {
logger.debug("Disposing Gardena account '{}'", getThing().getUID().getId());
discoveryService.stopScan();
gardenaSmart.dispose();
}
/**
* Returns the Gardena Smart Home implementation.
*/
public GardenaSmart getGardenaSmart() {
return gardenaSmart;
}
@Override
public Collection<Class<? extends ThingHandlerService>> getServices() {
return Collections.singleton(GardenaDeviceDiscoveryService.class);
}
@Override
public void handleCommand(ChannelUID channelUID, Command command) {
if (RefreshType.REFRESH == command) {
logger.debug("Refreshing Gardena account '{}'", getThing().getUID().getId());
disposeGardena();
initializeGardena();
}
}
@Override
public void onDeviceUpdated(Device device) {
for (ThingUID thingUID : UidUtils.getThingUIDs(device, getThing())) {
Thing gardenaThing = getThing().getThing(thingUID);
try {
GardenaThingHandler gardenaThingHandler = (GardenaThingHandler) gardenaThing.getHandler();
gardenaThingHandler.updateProperties(device);
for (Channel channel : gardenaThing.getChannels()) {
gardenaThingHandler.updateChannel(channel.getUID());
}
gardenaThingHandler.updateSettings(device);
gardenaThingHandler.updateStatus(device);
} catch (GardenaException ex) {
logger.error("There is something wrong with your thing '{}', please check or recreate it: {}",
gardenaThing.getUID(), ex.getMessage());
logger.debug("Gardena exception caught on device update.", ex);
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, ex.getMessage());
} catch (AccountHandlerNotAvailableException ignore) {
}
}
}
@Override
public void onNewDevice(Device device) {
if (discoveryService != null) {
discoveryService.deviceDiscovered(device);
}
onDeviceUpdated(device);
}
@Override
public void onDeviceDeleted(Device device) {
if (discoveryService != null) {
discoveryService.deviceRemoved(device);
}
}
@Override
public void onConnectionLost() {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, "Connection lost");
}
@Override
public void onConnectionResumed() {
updateStatus(ThingStatus.ONLINE);
}
}

View File

@@ -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.gardena.internal.handler;
/**
* The {@link GardenaDeviceConfig} class represents the configuration for a device connected to an Gardena account.
*
* @author Gerhard Riegler - Initial contribution
*/
public class GardenaDeviceConfig {
public String deviceId;
}

View File

@@ -0,0 +1,46 @@
/**
* Copyright (c) 2010-2020 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.gardena.internal.handler;
import static org.openhab.binding.gardena.internal.GardenaBindingConstants.*;
import org.openhab.core.thing.Bridge;
import org.openhab.core.thing.Thing;
import org.openhab.core.thing.ThingTypeUID;
import org.openhab.core.thing.binding.BaseThingHandlerFactory;
import org.openhab.core.thing.binding.ThingHandler;
import org.openhab.core.thing.binding.ThingHandlerFactory;
import org.osgi.service.component.annotations.Component;
/**
* The {@link GardenaHandlerFactory} is responsible for creating Gardena things and thing handlers.
*
* @author Gerhard Riegler - Initial contribution
*/
@Component(service = ThingHandlerFactory.class, configurationPid = "binding.gardena")
public class GardenaHandlerFactory extends BaseThingHandlerFactory {
@Override
public boolean supportsThingType(ThingTypeUID thingTypeUID) {
return BINDING_ID.equals(thingTypeUID.getBindingId());
}
@Override
protected ThingHandler createHandler(Thing thing) {
if (THING_TYPE_ACCOUNT.equals(thing.getThingTypeUID())) {
return new GardenaAccountHandler((Bridge) thing);
} else {
return new GardenaThingHandler(thing);
}
}
}

View File

@@ -0,0 +1,372 @@
/**
* 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.gardena.internal.handler;
import static org.openhab.binding.gardena.internal.GardenaBindingConstants.*;
import static org.openhab.binding.gardena.internal.GardenaSmartCommandName.*;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.util.Calendar;
import java.util.Map;
import java.util.Map.Entry;
import org.apache.commons.lang.ObjectUtils;
import org.apache.commons.lang.StringUtils;
import org.openhab.binding.gardena.internal.GardenaSmart;
import org.openhab.binding.gardena.internal.GardenaSmartCommandName;
import org.openhab.binding.gardena.internal.GardenaSmartImpl;
import org.openhab.binding.gardena.internal.exception.GardenaDeviceNotFoundException;
import org.openhab.binding.gardena.internal.exception.GardenaException;
import org.openhab.binding.gardena.internal.model.Ability;
import org.openhab.binding.gardena.internal.model.Device;
import org.openhab.binding.gardena.internal.model.Setting;
import org.openhab.binding.gardena.internal.util.DateUtils;
import org.openhab.binding.gardena.internal.util.UidUtils;
import org.openhab.core.config.core.Configuration;
import org.openhab.core.config.core.validation.ConfigValidationException;
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.Type;
import org.openhab.core.types.UnDefType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* The {@link GardenaThingHandler} is responsible for handling commands, which are sent to one of the channels.
*
* @author Gerhard Riegler - Initial contribution
*/
public class GardenaThingHandler extends BaseThingHandler {
private final Logger logger = LoggerFactory.getLogger(GardenaThingHandler.class);
private final Calendar VALID_DATE_START = DateUtils.parseToCalendar("1970-01-02T00:00Z");
public GardenaThingHandler(Thing thing) {
super(thing);
}
@Override
public void initialize() {
try {
Device device = getDevice();
updateProperties(device);
updateSettings(device);
updateStatus(device);
} catch (GardenaException ex) {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, ex.getMessage());
} catch (AccountHandlerNotAvailableException ex) {
// ignore
}
}
/**
* Updates the thing configuration from the Gardena device.
*/
protected void updateSettings(Device device) throws GardenaException {
if (GardenaSmartImpl.DEVICE_CATEGORY_PUMP.equals(device.getCategory())) {
Configuration config = editConfiguration();
if (!equalsSetting(config, device, SETTING_LEAKAGE_DETECTION)
|| !equalsSetting(config, device, SETTING_OPERATION_MODE)
|| !equalsSetting(config, device, SETTING_TURN_ON_PRESSURE)) {
config.put(SETTING_LEAKAGE_DETECTION, device.getSetting(SETTING_LEAKAGE_DETECTION).getValue());
config.put(SETTING_OPERATION_MODE, device.getSetting(SETTING_OPERATION_MODE).getValue());
config.put(SETTING_TURN_ON_PRESSURE,
ObjectUtils.toString(device.getSetting(SETTING_TURN_ON_PRESSURE).getValue()));
updateConfiguration(config);
}
}
}
private boolean equalsSetting(Configuration config, Device device, String key) throws GardenaException {
return config.get(key) != null
&& config.get(key).equals(ObjectUtils.toString(device.getSetting(key).getValue()));
}
/**
* Updates the thing properties from the Gardena device.
*/
protected void updateProperties(Device device) throws GardenaException {
Map<String, String> properties = editProperties();
Ability deviceInfo = device.getAbility(ABILITY_DEVICE_INFO);
setProperty(properties, deviceInfo, PROPERTY_MANUFACTURER);
setProperty(properties, deviceInfo, PROPERTY_PRODUCT);
setProperty(properties, deviceInfo, PROPERTY_SERIALNUMBER);
setProperty(properties, deviceInfo, PROPERTY_SGTIN);
setProperty(properties, deviceInfo, PROPERTY_VERSION);
setProperty(properties, deviceInfo, PROPERTY_CATEGORY);
updateProperties(properties);
}
private void setProperty(Map<String, String> properties, Ability deviceInfo, String propertyName) {
try {
properties.put(propertyName, deviceInfo.getProperty(propertyName).getValueAsString());
} catch (GardenaException ex) {
logger.debug("Ignoring missing device property {}", propertyName);
}
}
@Override
public void channelLinked(ChannelUID channelUID) {
try {
updateChannel(channelUID);
} catch (GardenaDeviceNotFoundException | AccountHandlerNotAvailableException ex) {
logger.debug("{}", ex.getMessage(), ex);
} catch (GardenaException ex) {
logger.error("{}", ex.getMessage(), ex);
}
}
/**
* Updates the channel from the Gardena device.
*/
protected void updateChannel(ChannelUID channelUID) throws GardenaException, AccountHandlerNotAvailableException {
Device device = getDevice();
State state = convertToState(device, channelUID);
if (state != null) {
updateState(channelUID, state);
}
}
/**
* Converts a Gardena property value to a openHAB state.
*/
private State convertToState(Device device, ChannelUID channelUID) throws GardenaException {
String abilityName = channelUID.getGroupId();
String propertyName = channelUID.getIdWithoutGroup();
try {
String value = device.getAbility(abilityName).getProperty(propertyName).getValueAsString();
if (StringUtils.trimToNull(value) == null || StringUtils.equals(value, "N/A")) {
return UnDefType.NULL;
}
switch (getThing().getChannel(channelUID.getId()).getAcceptedItemType()) {
case "String":
return new StringType(value);
case "Number":
if (ABILITY_RADIO.equals(abilityName) && PROPERTY_STATE.equals(propertyName)) {
switch (value) {
case "poor":
return new DecimalType(1);
case "good":
return new DecimalType(2);
case "excellent":
return new DecimalType(4);
default:
return UnDefType.NULL;
}
}
return new DecimalType(value);
case "Switch":
return Boolean.TRUE.toString().equalsIgnoreCase(value) || "on".equalsIgnoreCase(value)
? OnOffType.ON
: OnOffType.OFF;
case "DateTime":
Calendar cal = DateUtils.parseToCalendar(value);
if (cal != null && !cal.before(VALID_DATE_START)) {
return new DateTimeType(ZonedDateTime.ofInstant(cal.toInstant(), ZoneId.systemDefault()));
} else {
return UnDefType.NULL;
}
}
} catch (GardenaException e) {
logger.warn("Channel '{}' cannot be updated as device does not contain property '{}:{}'", channelUID,
abilityName, propertyName);
}
return null;
}
/**
* Converts an openHAB type to a Gardena command property.
*/
private Object convertFromType(Type type) {
if (type instanceof OnOffType) {
return type == OnOffType.ON ? Boolean.TRUE : Boolean.FALSE;
} else if (type instanceof DecimalType) {
return ((DecimalType) type).intValue();
} else if (type instanceof StringType) {
return ((StringType) type).toFullString();
}
return null;
}
@Override
public void handleCommand(ChannelUID channelUID, Command command) {
try {
GardenaSmartCommandName commandName = getCommandName(channelUID);
logger.debug("Received Gardena command: {}", commandName);
if (RefreshType.REFRESH == command) {
logger.debug("Refreshing channel '{}'", channelUID);
if (commandName != null && commandName.toString().startsWith("MEASURE_")) {
getGardenaSmart().sendCommand(getDevice(), commandName, null);
} else {
updateChannel(channelUID);
}
} else if (commandName != null) {
getGardenaSmart().sendCommand(getDevice(), commandName, convertFromType(command));
}
} catch (AccountHandlerNotAvailableException | GardenaDeviceNotFoundException ex) {
// ignore
} catch (Exception ex) {
logger.warn("{}", ex.getMessage(), ex);
}
}
/**
* Returns the Gardena command from the channel.
*/
private GardenaSmartCommandName getCommandName(ChannelUID channelUID) {
switch (channelUID.getId()) {
case "mower#park_until_further_notice":
return PARK_UNTIL_FURTHER_NOTICE;
case "mower#park_until_next_timer":
return PARK_UNTIL_NEXT_TIMER;
case "mower#start_override_timer":
return START_OVERRIDE_TIMER;
case "mower#start_resume_schedule":
return START_RESUME_SCHEDULE;
case "mower#duration_property":
return DURATION_PROPERTY;
case "ambient_temperature#temperature":
return MEASURE_AMBIENT_TEMPERATURE;
case "soil_temperature#temperature":
return MEASURE_SOIL_TEMPERATURE;
case "humidity#humidity":
return MEASURE_SOIL_HUMIDITY;
case "light#light":
return MEASURE_LIGHT;
case "outlet#button_manual_override_time":
return OUTLET_MANUAL_OVERRIDE_TIME;
case "outlet#valve_open":
return OUTLET_VALVE;
case "power#power_timer":
return POWER_TIMER;
case "watering#watering_timer_1":
return WATERING_TIMER_VALVE_1;
case "watering#watering_timer_2":
return WATERING_TIMER_VALVE_2;
case "watering#watering_timer_3":
return WATERING_TIMER_VALVE_3;
case "watering#watering_timer_4":
return WATERING_TIMER_VALVE_4;
case "watering#watering_timer_5":
return WATERING_TIMER_VALVE_5;
case "watering#watering_timer_6":
return WATERING_TIMER_VALVE_6;
case "manual_watering#manual_watering_timer":
return PUMP_MANUAL_WATERING_TIMER;
default:
return null;
}
}
/**
* Updates the thing status based on the Gardena device status.
*/
protected void updateStatus(Device device) {
String connectionStatus = "";
try {
connectionStatus = device.getAbility(ABILITY_RADIO).getProperty(PROPERTY_CONNECTION_STATUS)
.getValueAsString();
} catch (GardenaException ex) {
// ignore, device has no connection status property
}
boolean isUnreach = PROPERTY_CONNECTION_STATUS_UNREACH_VALUE.equals(connectionStatus);
ThingStatus oldStatus = thing.getStatus();
ThingStatus newStatus = ThingStatus.ONLINE;
ThingStatusDetail newDetail = ThingStatusDetail.NONE;
if (isUnreach) {
newStatus = ThingStatus.OFFLINE;
newDetail = ThingStatusDetail.COMMUNICATION_ERROR;
} else if (!device.isConfigurationSynchronized()) {
newStatus = thing.getStatus();
newDetail = ThingStatusDetail.CONFIGURATION_PENDING;
}
if (oldStatus != newStatus || thing.getStatusInfo().getStatusDetail() != newDetail) {
updateStatus(newStatus, newDetail);
}
}
@Override
public void handleConfigurationUpdate(Map<String, Object> configurationParameters)
throws ConfigValidationException {
validateConfigurationParameters(configurationParameters);
try {
GardenaSmart gardena = getGardenaSmart();
Device device = gardena.getDevice(UidUtils.getGardenaDeviceId(getThing()));
for (Entry<String, Object> configurationParmeter : configurationParameters.entrySet()) {
String key = configurationParmeter.getKey();
Object newValue = configurationParmeter.getValue();
if (newValue != null && SETTING_TURN_ON_PRESSURE.equals(key)) {
newValue = new Double((String) newValue);
}
Setting setting = device.getSetting(key);
if (ObjectUtils.notEqual(setting.getValue(), newValue)) {
gardena.sendSetting(setting, newValue);
setting.setValue(newValue);
}
}
updateSettings(device);
} catch (GardenaException | AccountHandlerNotAvailableException ex) {
logger.warn("Error setting thing properties: {}", ex.getMessage(), ex);
}
}
/**
* Returns the Gardena device for this ThingHandler.
*/
private Device getDevice() throws GardenaException, AccountHandlerNotAvailableException {
return getGardenaSmart().getDevice(UidUtils.getGardenaDeviceId(getThing()));
}
/**
* Returns the Gardena Smart Home implementation if the bridge is available.
*/
private GardenaSmart getGardenaSmart() throws AccountHandlerNotAvailableException {
if (getBridge() == null || getBridge().getHandler() == null
|| ((GardenaAccountHandler) getBridge().getHandler()).getGardenaSmart() == null) {
if (thing.getStatus() != ThingStatus.INITIALIZING) {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.HANDLER_MISSING_ERROR);
}
throw new AccountHandlerNotAvailableException("Gardena AccountHandler not yet available!");
}
return ((GardenaAccountHandler) getBridge().getHandler()).getGardenaSmart();
}
}

View File

@@ -0,0 +1,87 @@
/**
* 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.gardena.internal.model;
import java.util.ArrayList;
import java.util.List;
import org.openhab.binding.gardena.internal.exception.GardenaException;
/**
* Represents a Gardena ability.
*
* @author Gerhard Riegler - Initial contribution
*/
public class Ability {
private String name;
private String type;
private transient Device device;
private List<Property> properties = new ArrayList<>();
/**
* Returns the name of the ability.
*/
public String getName() {
return name;
}
/**
* Returns the type of the ability.
*/
public String getType() {
return type;
}
/**
* Returns a list of properties of the ability.
*/
public List<Property> getProperties() {
return properties;
}
/**
* Adds a property to this ability.
*/
public void addProperty(Property property) {
property.setAbility(this);
properties.add(property);
}
/**
* Returns the property with the specified name.
*/
public Property getProperty(String name) throws GardenaException {
for (Property property : properties) {
if (property.getName().equals(name)) {
return property;
}
}
throw new GardenaException("Property '" + name + "' not found in ability '" + this.name + "'");
}
/**
* Returns the device of the ability.
*/
public Device getDevice() {
return device;
}
/**
* Sets the name of the ability.
*/
public void setDevice(Device device) {
this.device = device;
}
}

View File

@@ -0,0 +1,147 @@
/**
* 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.gardena.internal.model;
import java.util.ArrayList;
import java.util.List;
import org.apache.commons.lang.builder.EqualsBuilder;
import org.apache.commons.lang.builder.HashCodeBuilder;
import org.openhab.binding.gardena.internal.exception.GardenaException;
import com.google.gson.annotations.SerializedName;
/**
* Represents a Gardena device.
*
* @author Gerhard Riegler - Initial contribution
*/
public class Device {
private String id;
private String name;
private String description;
private String category;
@SerializedName("configuration_synchronized")
private boolean configurationSynchronized;
private List<Ability> abilities = new ArrayList<>();
@SerializedName("scheduled_events")
private List<ScheduledEvent> scheduledEvents = new ArrayList<>();
private transient Location location;
private List<Setting> settings = new ArrayList<>();
/**
* Returns the id of the device.
*/
public String getId() {
return id;
}
/**
* Returns the name of the device.
*/
public String getName() {
return name;
}
/**
* Returns the description of the device.
*/
public String getDescription() {
return description;
}
/**
* Returns the category of the device.
*/
public String getCategory() {
return category;
}
/**
* Returns true, if all configurations are synchronized.
*/
public boolean isConfigurationSynchronized() {
return configurationSynchronized;
}
/**
* Returns a list of abilities of the device.
*/
public List<Ability> getAbilities() {
return abilities;
}
/**
* Returns a list of scheduled events of the device.
*/
public List<ScheduledEvent> getScheduledEvents() {
return scheduledEvents;
}
/**
* Returns the location of the device.
*/
public Location getLocation() {
return location;
}
/**
* Sets the location of the device.
*/
public void setLocation(Location location) {
this.location = location;
}
/**
* Returns the ability with the specified name.
*/
public Ability getAbility(String name) throws GardenaException {
for (Ability ability : abilities) {
if (ability.getName().equals(name)) {
return ability;
}
}
throw new GardenaException("Ability '" + name + "' not found in device '" + this.name + "'");
}
public List<Setting> getSettings() {
return settings;
}
/**
* Returns the setting with the specified name.
*/
public Setting getSetting(String name) throws GardenaException {
for (Setting setting : settings) {
if (setting.getName().equals(name)) {
return setting;
}
}
throw new GardenaException("Setting '" + name + "' not found in device '" + this.name + "'");
}
@Override
public int hashCode() {
return new HashCodeBuilder().append(id).toHashCode();
}
@Override
public boolean equals(Object obj) {
if (obj == null || !(obj instanceof Device)) {
return false;
}
Device comp = (Device) obj;
return new EqualsBuilder().append(comp.getId(), id).isEquals();
}
}

View File

@@ -0,0 +1,33 @@
/**
* 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.gardena.internal.model;
import java.util.ArrayList;
import java.util.List;
/**
* Represents a List of Gardena devices.
*
* @author Gerhard Riegler - Initial contribution
*/
public class Devices {
private List<Device> devices = new ArrayList<>();
/**
* Returns a list of Gardena devices.
*/
public List<Device> getDevices() {
return devices;
}
}

View File

@@ -0,0 +1,63 @@
/**
* 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.gardena.internal.model;
import org.apache.commons.lang.builder.ToStringBuilder;
import org.apache.commons.lang.builder.ToStringStyle;
/**
* Represents a Gardena error.
*
* @author Gerhard Riegler - Initial contribution
*/
public class Error {
private String id;
private String status;
private String title;
private String detail;
/**
* Returns the id of the error.
*/
public String getId() {
return id;
}
/**
* Returns the status of the error.
*/
public String getStatus() {
return status;
}
/**
* Returns the title of the error.
*/
public String getTitle() {
return title;
}
/**
* Returns the detail of the error.
*/
public String getDetail() {
return detail;
}
@Override
public String toString() {
return new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE).append("id", id).append("status", status)
.append("title", title).append("detail", detail).toString();
}
}

View File

@@ -0,0 +1,45 @@
/**
* 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.gardena.internal.model;
import java.util.ArrayList;
import java.util.List;
import org.apache.commons.lang.builder.ToStringBuilder;
import org.apache.commons.lang.builder.ToStringStyle;
/**
* Represents a List of Gardena errors.
*
* @author Gerhard Riegler - Initial contribution
*/
public class Errors {
private List<Error> errors = new ArrayList<>();
/**
* Returns a list of Gardena errors.
*/
public List<Error> getErrors() {
return errors;
}
@Override
public String toString() {
ToStringBuilder tsb = new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE);
for (Error error : errors) {
tsb.append(error);
}
return tsb.toString();
}
}

View File

@@ -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.gardena.internal.model;
import java.util.ArrayList;
import java.util.List;
import org.apache.commons.lang.builder.EqualsBuilder;
import org.apache.commons.lang.builder.HashCodeBuilder;
import com.google.gson.annotations.SerializedName;
/**
* Represents a Gardena location.
*
* @author Gerhard Riegler - Initial contribution
*/
public class Location {
private String id;
private String name;
@SerializedName("devices")
public List<String> deviceIds = new ArrayList<>();
/**
* Returns the id of the location.
*/
public String getId() {
return id;
}
/**
* Returns the name of the location.
*/
public String getName() {
return name;
}
/**
* Returns the device ids of the location.
*/
public List<String> getDeviceIds() {
return deviceIds;
}
@Override
public int hashCode() {
return new HashCodeBuilder().append(id).toHashCode();
}
@Override
public boolean equals(Object obj) {
if (obj == null || !(obj instanceof Location)) {
return false;
}
Location comp = (Location) obj;
return new EqualsBuilder().append(comp.getId(), id).isEquals();
}
}

View File

@@ -0,0 +1,33 @@
/**
* 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.gardena.internal.model;
import java.util.ArrayList;
import java.util.List;
/**
* Represents a List of Gardena locations.
*
* @author Gerhard Riegler - Initial contribution
*/
public class Locations {
private List<Location> locations = new ArrayList<>();
/**
* Returns a list of Gardena locations.
*/
public List<Location> getLocations() {
return locations;
}
}

View File

@@ -0,0 +1,22 @@
/**
* 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.gardena.internal.model;
/**
* Empty class that represents a emtpy result from Gardena Smart Home.
*
* @author Gerhard Riegler - Initial contribution
*/
public class NoResult {
}

View File

@@ -0,0 +1,117 @@
/**
* 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.gardena.internal.model;
import java.util.Date;
import java.util.List;
import org.openhab.binding.gardena.internal.GardenaSmartCommandName;
import com.google.gson.annotations.SerializedName;
/**
* Represents a Gardena property.
*
* @author Gerhard Riegler - Initial contribution
*/
public class Property {
private String name;
private PropertyValue value;
private Date timestamp;
private String unit;
private boolean writeable;
@SerializedName("supported_values")
private List<String> supportedValues;
private transient Ability ability;
public Property() {
}
public Property(GardenaSmartCommandName commandName, String value) {
this.name = commandName.toString().toLowerCase();
this.value = new PropertyValue(value);
}
/**
* Returns the name of the property.
*/
public String getName() {
return name;
}
/**
* Returns the value of the property.
*/
public String getValueAsString() {
return value != null ? value.getValue() : null;
}
/**
* Returns the value of the property.
*/
public PropertyValue getValue() {
return value;
}
/**
* Sets the value of the property.
*/
public void setValue(PropertyValue value) {
this.value = value;
}
/**
* Returns the timestamp of the property.
*/
public Date getTimestamp() {
return timestamp;
}
/**
* Returns the unit of the property.
*/
public String getUnit() {
return unit;
}
/**
* Returns true, if the property is writeable.
*/
public boolean isWriteable() {
return writeable;
}
/**
* Returns a list of supported values.
*/
public List<String> getSupportedValues() {
return supportedValues;
}
/**
* Returns the ability of the property.
*/
public Ability getAbility() {
return ability;
}
/**
* Sets the ability of the property.
*/
public void setAbility(Ability ability) {
this.ability = ability;
}
}

View File

@@ -0,0 +1,43 @@
/**
* 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.gardena.internal.model;
/**
* Represents a Gardena property value.
*
* @author Gerhard Riegler - Initial contribution
*/
public class PropertyValue {
private String value;
public PropertyValue() {
}
public PropertyValue(String value) {
this.value = value;
}
/**
* Returns the value of the property.
*/
public String getValue() {
return value;
}
/**
* Sets the value of the property.
*/
public void setValue(String value) {
this.value = value;
}
}

View File

@@ -0,0 +1,40 @@
/**
* 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.gardena.internal.model;
import java.util.List;
/**
* Represents a Gardena recurrence.
*
* @author Gerhard Riegler - Initial contribution
*/
public class Recurrence {
private String type;
private List<String> weekdays;
/**
* Returns the type of the recurrence.
*/
public String getType() {
return type;
}
/**
* Returns a list of weekdays.
*/
public List<String> getWeekdays() {
return weekdays;
}
}

View File

@@ -0,0 +1,75 @@
/**
* 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.gardena.internal.model;
import com.google.gson.annotations.SerializedName;
/**
* Represents a Gardena scheduled event.
*
* @author Gerhard Riegler - Initial contribution
*/
public class ScheduledEvent {
private String id;
private String type;
@SerializedName("start_at")
private String start;
@SerializedName("end_at")
private String end;
private String weekday;
private Recurrence recurrence = new Recurrence();
/**
* Returns the id of the scheduled event.
*/
public String getId() {
return id;
}
/**
* Returns the type of the scheduled event.
*/
public String getType() {
return type;
}
/**
* Returns the start of the scheduled event.
*/
public String getStart() {
return start;
}
/**
* Returns the end of the scheduled event.
*/
public String getEnd() {
return end;
}
/**
* Returns the weekday of the scheduled event.
*/
public String getWeekday() {
return weekday;
}
/**
* Returns the recurrence of the scheduled event.
*/
public Recurrence getRecurrence() {
return recurrence;
}
}

View File

@@ -0,0 +1,54 @@
/**
* 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.gardena.internal.model;
import com.google.gson.annotations.SerializedName;
/**
* Represents a Gardena session.
*
* @author Gerhard Riegler - Initial contribution
*/
public class Session {
@SerializedName("id")
private String token;
private long created;
@SerializedName("attributes")
private SessionAttributes sessionAttributes = new SessionAttributes();
public Session() {
this.created = System.currentTimeMillis();
}
/**
* Returns the token of the session.
*/
public String getToken() {
return token;
}
/**
* Returns the creation timestamp of the session.
*/
public long getCreated() {
return created;
}
/**
* Returns the session attributes.
*/
public SessionAttributes getSessionAttributes() {
return sessionAttributes;
}
}

View File

@@ -0,0 +1,56 @@
/**
* 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.gardena.internal.model;
import com.google.gson.annotations.SerializedName;
/**
* Session attributes for valid Gardena JSON serialization.
*
* @author Gerhard Riegler - Initial contribution
*/
public class SessionAttributes {
@SerializedName("user_id")
private String userId;
@SerializedName("provider")
private String provider;
/**
* Returns the user id.
*/
public String getUserId() {
return userId;
}
/**
* Sets the user id.
*/
public void setUserId(String userId) {
this.userId = userId;
}
/**
* Returns the provider.
*/
public String getProvider() {
return provider;
}
/**
* Sets the provider.
*/
public void setProvider(String provider) {
this.provider = provider;
}
}

View File

@@ -0,0 +1,46 @@
/**
* Copyright (c) 2010-2020 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.gardena.internal.model;
import com.google.gson.annotations.SerializedName;
/**
* Session wrapper for valid Gardena JSON serialization.
*
* @author Gerhard Riegler - Initial contribution
*/
public class SessionWrapper {
@SerializedName("data")
private Session session;
public SessionWrapper() {
}
public SessionWrapper(Session session) {
this.session = session;
}
/**
* Returns the session.
*/
public Session getSession() {
return session;
}
/**
* Sets the session.
*/
public void setSession(Session session) {
this.session = session;
}
}

View File

@@ -0,0 +1,68 @@
/**
* 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.gardena.internal.model;
/**
* Represents a Gardena setting.
*
* @author Gerhard Riegler - Initial contribution
*/
public class Setting {
private String name;
private String id;
private Object value;
private transient Device device;
/**
* Returns the name of the setting.
*/
public String getName() {
return name;
}
/**
* Returns the id of the setting.
*/
public String getId() {
return id;
}
/**
* Returns the value of the setting.
*/
public Object getValue() {
return value;
}
/**
* Sets the name of the setting.
*/
public void setValue(Object value) {
this.value = value;
}
/**
* Returns the device of the setting.
*/
public Device getDevice() {
return device;
}
/**
* Sets the name of the setting.
*/
public void setDevice(Device device) {
this.device = device;
}
}

View File

@@ -0,0 +1,94 @@
/**
* 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.gardena.internal.model.command;
import com.google.gson.annotations.SerializedName;
/**
* Base class for a Gardena command with parameters.
*
* @author Gerhard Riegler - Initial contribution
*/
public abstract class Command {
@SerializedName(value = "name")
protected String command;
protected CommandParameters parameters;
/**
* Creates a command with the given name.
*/
public Command(String command) {
this.command = command;
}
/**
* Returns the command name.
*/
public String getCommand() {
return command;
}
/**
* Returns the parameters of the command.
*/
public CommandParameters getParameters() {
return parameters;
}
/**
* Sets the parameters of the command.
*/
public void setParameters(CommandParameters parameters) {
this.parameters = parameters;
}
/**
* Class to hold the command parameters.
*
* @author Gerhard Riegler - Initial contribution
*/
public class CommandParameters {
private String duration;
@SerializedName("manual_override")
private String manualOverride;
/**
* Returns the duration parameter.
*/
public String getDuration() {
return duration;
}
/**
* Sets the duration parameter.
*/
public void setDuration(String duration) {
this.duration = duration;
}
/**
* Returns the manual override parameter.
*/
public String getManualOverride() {
return manualOverride;
}
/**
* Sets the manual override parameter.
*/
public void setManualOverride(String manualOverride) {
this.manualOverride = manualOverride;
}
}
}

View File

@@ -0,0 +1,26 @@
/**
* 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.gardena.internal.model.command;
/**
* Command to park a mower until further notice.
*
* @author Gerhard Riegler - Initial contribution
*/
public class MowerParkUntilFurtherNoticeCommand extends Command {
private static final String COMMAND = "park_until_further_notice";
public MowerParkUntilFurtherNoticeCommand() {
super(COMMAND);
}
}

View File

@@ -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.gardena.internal.model.command;
/**
* Command to park a mower until next timer.
*
* @author Gerhard Riegler - Initial contribution
*/
public class MowerParkUntilNextTimerCommand extends Command {
private static final String COMMAND = "park_until_next_timer";
public MowerParkUntilNextTimerCommand() {
super(COMMAND);
}
}

View File

@@ -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.gardena.internal.model.command;
/**
* Command to manually override the mower timer.
*
* @author Gerhard Riegler - Initial contribution
*/
public class MowerStartOverrideTimerCommand extends Command {
private static final String COMMAND = "start_override_timer";
public MowerStartOverrideTimerCommand(String durationInMinutes) {
super(COMMAND);
parameters = new CommandParameters();
parameters.setDuration(durationInMinutes);
}
}

View File

@@ -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.gardena.internal.model.command;
/**
* Command to resume the mower scheduler.
*
* @author Gerhard Riegler - Initial contribution
*/
public class MowerStartResumeScheduleCommand extends Command {
private static final String COMMAND = "start_resume_schedule";
public MowerStartResumeScheduleCommand() {
super(COMMAND);
}
}

View File

@@ -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.gardena.internal.model.command;
/**
* Sensor command to measure the ambient temperatur.
*
* @author Gerhard Riegler - Initial contribution
*/
public class SensorMeasureAmbientTemperatureCommand extends Command {
private static final String COMMAND = "measure_ambient_temperature";
public SensorMeasureAmbientTemperatureCommand() {
super(COMMAND);
}
}

View File

@@ -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.gardena.internal.model.command;
/**
* Sensor command to measure the light.
*
* @author Gerhard Riegler - Initial contribution
*/
public class SensorMeasureLightCommand extends Command {
private static final String COMMAND = "measure_light";
public SensorMeasureLightCommand() {
super(COMMAND);
}
}

View File

@@ -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.gardena.internal.model.command;
/**
* Sensor command to measure the soil humidity.
*
* @author Gerhard Riegler - Initial contribution
*/
public class SensorMeasureSoilHumidityCommand extends Command {
private static final String COMMAND = "measure_soil_humidity";
public SensorMeasureSoilHumidityCommand() {
super(COMMAND);
}
}

View File

@@ -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.gardena.internal.model.command;
/**
* Sensor command to measure the soil temperature.
*
* @author Gerhard Riegler - Initial contribution
*/
public class SensorMeasureSoilTemperatureCommand extends Command {
private static final String COMMAND = "measure_soil_temperature";
public SensorMeasureSoilTemperatureCommand() {
super(COMMAND);
}
}

View File

@@ -0,0 +1,58 @@
/**
* 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.gardena.internal.model.command;
import com.google.gson.annotations.SerializedName;
/**
* Common command to set a device setting.
*
* @author Gerhard Riegler - Initial contribution
*/
public class SettingCommand extends Command {
private Object value;
@SerializedName("device")
private String deviceId;
public SettingCommand(String name) {
super(name);
}
/**
* Returns the value of the setting command.
*/
public Object getValue() {
return value;
}
/**
* Sets the value of the setting command.
*/
public void setValue(Object value) {
this.value = value;
}
/**
* Returns the device id of the setting command.
*/
public String getDeviceId() {
return deviceId;
}
/**
* Sets the device id of the setting command.
*/
public void setDeviceId(String deviceId) {
this.deviceId = deviceId;
}
}

View File

@@ -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.gardena.internal.model.command;
import com.google.gson.annotations.SerializedName;
/**
* SettingComand wrapper for valid Gardena JSON serialization.
*
* @author Gerhard Riegler - Initial contribution
*/
public class SettingCommandWrapper {
@SerializedName("settings")
private SettingCommand command;
public SettingCommandWrapper(SettingCommand command) {
this.command = command;
}
/**
* Returns the setting command.
*/
public SettingCommand getCommand() {
return command;
}
}

View File

@@ -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.gardena.internal.model.command;
/**
* Command to cancel the manual watering.
*
* @author Gerhard Riegler - Initial contribution
*/
public class WateringCancelOverrideCommand extends Command {
private static final String COMMAND = "cancel_override";
public WateringCancelOverrideCommand() {
super(COMMAND);
}
}

View File

@@ -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.gardena.internal.model.command;
/**
* Command to start the manual watering.
*
* @author Gerhard Riegler - Initial contribution
*/
public class WateringManualOverrideCommand extends Command {
private static final String COMMAND = "manual_override";
public WateringManualOverrideCommand(String durationInMinutes) {
super(COMMAND);
parameters = new CommandParameters();
parameters.setDuration(durationInMinutes);
parameters.setManualOverride("open");
}
}

View File

@@ -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.gardena.internal.model.deser;
import java.lang.reflect.Type;
import java.util.Date;
import org.openhab.binding.gardena.internal.util.DateUtils;
import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonDeserializer;
import com.google.gson.JsonElement;
import com.google.gson.JsonParseException;
/**
* Custom deserializer for date types.
*
* @author Gerhard Riegler - Initial contribution
*/
public class DateDeserializer implements JsonDeserializer<Date> {
@Override
public Date deserialize(JsonElement element, Type type, JsonDeserializationContext ctx) throws JsonParseException {
return DateUtils.parseToDate(element.getAsString());
}
}

View File

@@ -0,0 +1,70 @@
/**
* 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.gardena.internal.model.deser;
import java.lang.reflect.Type;
import org.apache.commons.lang.StringUtils;
import org.openhab.binding.gardena.internal.model.PropertyValue;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.gson.JsonArray;
import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonDeserializer;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParseException;
/**
* Custom deserializer for Gardena complex property value type.
*
* @author Gerhard Riegler - Initial contribution
*/
public class PropertyValueDeserializer implements JsonDeserializer<PropertyValue> {
private final Logger logger = LoggerFactory.getLogger(PropertyValueDeserializer.class);
private static final String PROPERTY_DURATION = "duration";
private static final String PROPERTY_TYPE = "type";
private static final String PROPERTY_MAC = "mac";
private static final String PROPERTY_ISCONNECTED = "isconnected";
@Override
public PropertyValue deserialize(JsonElement element, Type type, JsonDeserializationContext ctx)
throws JsonParseException {
if (element.isJsonObject()) {
JsonObject jsonObj = element.getAsJsonObject();
if (jsonObj.has(PROPERTY_DURATION)) {
long duration = jsonObj.get(PROPERTY_DURATION).getAsLong();
if (duration != 0) {
duration = Math.round(duration / 60.0);
}
return new PropertyValue(String.valueOf(duration));
} else if (jsonObj.has(PROPERTY_TYPE)) {
return new PropertyValue(jsonObj.get(PROPERTY_TYPE).getAsString());
} else if (jsonObj.has(PROPERTY_MAC) && jsonObj.has(PROPERTY_ISCONNECTED)) {
// ignore known gateway properties
return new PropertyValue();
} else {
logger.warn("Unsupported json value object, returning empty value");
return new PropertyValue();
}
} else if (element.isJsonArray()) {
JsonArray jsonArray = element.getAsJsonArray();
return new PropertyValue(StringUtils.join(jsonArray.iterator(), ","));
} else {
return new PropertyValue(element.getAsString());
}
}
}

View File

@@ -0,0 +1,38 @@
/**
* 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.gardena.internal.model.property;
/**
* Base class to send properties to Gardena.
*
* @author Gerhard Riegler - Initial contribution
*/
public abstract class BaseProperty {
private String name;
public BaseProperty(String name) {
this.name = name;
}
/**
* Returns the property name.
*/
public String getName() {
return name;
}
/**
* Returns the value of the property.
*/
public abstract String getValue();
}

View File

@@ -0,0 +1,46 @@
/**
* Copyright (c) 2010-2020 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.gardena.internal.model.property;
import com.google.gson.annotations.SerializedName;
/**
* Represents a Gardena complex property value for the irrigation control.
*
* @author Gerhard Riegler - Initial contribution
*/
public class IrrigationControlWateringProperty extends BaseProperty {
private IrrigationControlWateringValue value = new IrrigationControlWateringValue();
public IrrigationControlWateringProperty(String name, int duration, int valveId) {
super(name);
value.state = duration == 0 ? "idle" : "manual";
value.duration = duration;
value.valveId = valveId;
}
@Override
public String getValue() {
return String.valueOf(value.duration);
}
@SuppressWarnings("unused")
private class IrrigationControlWateringValue {
public String state;
public int duration;
@SerializedName("valve_id")
public int valveId;
}
}

View File

@@ -0,0 +1,46 @@
/**
* Copyright (c) 2010-2020 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.gardena.internal.model.property;
import com.google.gson.annotations.SerializedName;
/**
* Property wrapper for valid Gardena JSON serialization.
*
* @author Gerhard Riegler - Initial contribution
*/
public class PropertyWrapper {
@SerializedName("properties")
private BaseProperty property;
public PropertyWrapper() {
}
public PropertyWrapper(BaseProperty property) {
this.property = property;
}
/**
* Returns the property.
*/
public BaseProperty getProperty() {
return property;
}
/**
* Sets the property.
*/
public void setProperties(BaseProperty property) {
this.property = property;
}
}

View File

@@ -0,0 +1,35 @@
/**
* 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.gardena.internal.model.property;
/**
* Represents a String Gardena property.
*
* @author Gerhard Riegler - Initial contribution
*/
public class StringProperty extends BaseProperty {
private String value;
public StringProperty(String name, String value) {
super(name);
this.value = value;
}
/**
* Returns the property value.
*/
@Override
public String getValue() {
return value;
}
}

View File

@@ -0,0 +1,75 @@
/**
* 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.gardena.internal.util;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.ZoneOffset;
import java.time.ZonedDateTime;
import java.util.Calendar;
import java.util.Date;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Utility class to convert a String to a date or calendar.
*
* @author Gerhard Riegler - Initial contribution
*/
public class DateUtils {
private static final Logger LOGGER = LoggerFactory.getLogger(DateUtils.class);
private static final String[] DATE_FORMATS = new String[] { "yyyy-MM-dd'T'HH:mm:ss'Z'",
"yyyy-MM-dd'T'HH:mm:ss.SSS'Z'", "yyyy-MM-dd'T'HH:mm'Z'" };
/**
* Converts a string to a Date, trying different date formats used by Gardena.
*/
public static Date parseToDate(String text) {
if (StringUtils.isNotBlank(text)) {
Date parsedDate = null;
for (String dateFormat : DATE_FORMATS) {
try {
parsedDate = new SimpleDateFormat(dateFormat).parse(text);
ZonedDateTime gmt = ZonedDateTime.ofInstant(parsedDate.toInstant(), ZoneOffset.UTC);
LocalDateTime here = gmt.withZoneSameInstant(ZoneId.systemDefault()).toLocalDateTime();
parsedDate = Date.from(here.toInstant(ZoneOffset.UTC));
break;
} catch (ParseException ex) {
}
}
if (parsedDate == null) {
LOGGER.error("Can't parse date {}", text);
}
return parsedDate;
} else {
return null;
}
}
/**
* Converts a string to a Calendar, trying different date formats used by Gardena.
*/
public static Calendar parseToCalendar(String text) {
Date parsedDate = parseToDate(text);
if (parsedDate != null) {
Calendar cal = Calendar.getInstance();
cal.setTime(parsedDate);
return cal;
}
return null;
}
}

View File

@@ -0,0 +1,70 @@
/**
* 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.gardena.internal.util;
import static org.openhab.binding.gardena.internal.GardenaBindingConstants.BINDING_ID;
import java.util.ArrayList;
import java.util.List;
import org.openhab.binding.gardena.internal.handler.GardenaDeviceConfig;
import org.openhab.binding.gardena.internal.model.Device;
import org.openhab.core.thing.Bridge;
import org.openhab.core.thing.Thing;
import org.openhab.core.thing.ThingTypeUID;
import org.openhab.core.thing.ThingUID;
/**
* Utility class for converting between a Thing and a Gardena device.
*
* @author Gerhard Riegler - Initial contribution
*/
public class UidUtils {
/**
* Generates the ThingUID for the given device in the given account.
*/
public static ThingUID generateThingUID(Device device, Bridge account) {
ThingTypeUID thingTypeUID = new ThingTypeUID(BINDING_ID, device.getCategory());
return new ThingUID(thingTypeUID, account.getUID(), device.getId());
}
/**
* Returns all ThingUIDs for a given device.
*/
public static List<ThingUID> getThingUIDs(Device device, Bridge account) {
List<ThingUID> thingUIDs = new ArrayList<>();
for (Thing thing : account.getThings()) {
String deviceId = thing.getConfiguration().as(GardenaDeviceConfig.class).deviceId;
if (deviceId == null) {
deviceId = thing.getUID().getId();
}
if (deviceId.equals(device.getId())) {
thingUIDs.add(thing.getUID());
}
}
return thingUIDs;
}
/**
* Returns the device id of the Gardena device from the given thing.
*/
public static String getGardenaDeviceId(Thing thing) {
String deviceId = thing.getConfiguration().as(GardenaDeviceConfig.class).deviceId;
if (deviceId != null) {
return deviceId;
}
return thing.getUID().getId();
}
}

View File

@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<binding:binding id="gardena" 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>Gardena Smart Home Binding</name>
<description>This is the binding for Gardena Smart Home.</description>
<author>Gerhard Riegler</author>
</binding:binding>

View File

@@ -0,0 +1,462 @@
# binding
binding.gardena.description=Das ist das Binding für Gardena Smart Home Produkte.
# thing types
thing-type.gardena.bridge.description=ein Gardena Smart Home Online Account
thing-type.config.gardena.bridge.email.description=Email Addresse für den Gardena Smart Home Login
thing-type.config.gardena.bridge.password.label=Passwort
thing-type.config.gardena.bridge.password.description=Passwort für den Gardena Smart Home Login
thing-type.config.gardena.bridge.sessionTimeout.description=Timeout der Gardena Smart Home Session in Minuten
thing-type.config.gardena.bridge.connectionTimeout.label=Verbindungstimeout
thing-type.config.gardena.bridge.connectionTimeout.description=Timeout des Verbindungsaufbaus zu Gardena Smart Home in Sekunden
thing-type.config.gardena.bridge.refresh.label=Refreshintervall
thing-type.config.gardena.bridge.refresh.description=Der Intervall für die Datenabholung von Gardena Smart Home in Sekunden
thing-type.gardena.mower.label=Gardena Smart Sileno Mäher
thing-type.gardena.mower.description=ein Gardena Smart Sileno Mäher
thing-type.gardena.watering_computer.label=Gardena Smart Bewässerungscomputer
thing-type.gardena.watering_computer.description=ein Gardena Smart Bewässerungscomputer
thing-type.gardena.sensor.label=Gardena Smart Sensor
thing-type.gardena.sensor.description=ein Gardena Smart Sensor
thing-type.gardena.electronic_pressure_pump.label=Gardena Smart Druckpumpe
thing-type.gardena.electronic_pressure_pump.description=Eine Gardena Smart Druckpumpe
thing-type.gardena.power.label=Gardena Smart Power Zwischenstecker
thing-type.gardena.power.description=Eine Gardena Smart Power Zwischenstecker
thing-type.gardena.ic24.label=Gardena Smart Bewässerungssteuerung
thing-type.gardena.ic24.description=Eine Gardena Smart Bewässerungssteuerung
# config
thing-type.config.gardena.electronic_pressure_pump.leakage_detection.label=Leckage-Erkennung
thing-type.config.gardena.electronic_pressure_pump.leakage_detection.state.option.watering=Bewässerung
thing-type.config.gardena.electronic_pressure_pump.leakage_detection.state.option.washing_machine=Waschmaschine
thing-type.config.gardena.electronic_pressure_pump.leakage_detection.state.option.domestic_water_supply=Häusliche Wasserversorgung
thing-type.config.gardena.electronic_pressure_pump.leakage_detection.state.option.off=Aus
thing-type.config.gardena.electronic_pressure_pump.operating_mode.label=Betriebsmodus
thing-type.config.gardena.electronic_pressure_pump.operating_mode.state.option.automatic=Automatisch
thing-type.config.gardena.electronic_pressure_pump.operating_mode.state.option.scheduled=Zeitgesteuert
thing-type.config.gardena.electronic_pressure_pump.turn_on_pressure.label=Einschaltdruck
# channel group
channel-group-type.gardena.deviceInfo.label=Geräteinfo
channel-group-type.gardena.deviceInfo.description=Informationen über das Gerät
channel-group-type.gardena.rechargeableBattery.label=Wiederaufladbare Batterie Info
channel-group-type.gardena.rechargeableBattery.description=Informationen über die wiederaufladbare Batterie
channel-group-type.gardena.radio.label=Funkverbindung
channel-group-type.gardena.radio.description=Informationen über die Funkverbindung
channel-group-type.gardena.mower.label=Mähroboter
channel-group-type.gardena.mower.description=Informationen über den Mähroboter
channel-group-type.gardena.internalTemperature.label=Interne Temperatur
channel-group-type.gardena.internalTemperature.description=Die interne Temperatur des Mähroboters
channel-group-type.gardena.battery.label=Batterieinfo
channel-group-type.gardena.battery.description=Informationen über die Batterie
channel-group-type.gardena.outlet.label=Wasserauslass
channel-group-type.gardena.outlet.description=Informationen über den Wasserauslass
channel-group-type.gardena.ambientTemperature.label=Umgebungstemperatur
channel-group-type.gardena.ambientTemperature.description=Informationen über die Umgebungstemperatur
channel-group-type.gardena.soilTemperature.label=Bodentemperatur
channel-group-type.gardena.soilTemperature.description=Die Temperatur des Bodens
channel-group-type.gardena.humidity.label=Feuchtigkeit
channel-group-type.gardena.humidity.description=Die Feuchtigkeit
channel-group-type.gardena.light.label=Helligkeit
channel-group-type.gardena.light.description=Die Helligkeit
channel-group-type.gardena.firmware.label=Firmware
channel-group-type.gardena.firmware.description=Informationen über die Firmware
channel-group-type.gardena.outletTemperature.label=Auslauftemperatur
channel-group-type.gardena.outletTemperature.description=Die Auslauftemperatur
channel-group-type.gardena.pump.label=Pumpe
channel-group-type.gardena.pump.description=Die Pumpe
channel-group-type.gardena.outletPressure.label=Auslassdruck
channel-group-type.gardena.outletPressure.description=Der Auslassdruck
channel-group-type.gardena.outletPressureMax.label=Maximum Auslassdruck
channel-group-type.gardena.outletPressureMax.description=Der maximale Auslassdruck
channel-group-type.gardena.flow.label=Förderung
channel-group-type.gardena.flow.description=Die Förderung
channel-group-type.gardena.manualWatering.label=Manuelle Bewässerung
channel-group-type.gardena.manualWatering.description=Die manuelle Bewässerung
channel-group-type.gardena.scheduling.label=Zeitplan
channel-group-type.gardena.scheduling.description=Der Zeitplan
channel-group-type.gardena.mowerStats.label=Mähroboter Statistiken
channel-group-type.gardena.mowerStats.description=Statistiken über den Mähroboter
channel-group-type.gardena.power.label=Energie
channel-group-type.gardena.power.description=Energie
channel-group-type.gardena.watering.label=Bewässerung
channel-group-type.gardena.watering.description=Die Bewässerung
channel-group-type.gardena.ic24.label=Bewässerungssteuerung
channel-group-type.gardena.ic24.description=Die Bewässerungssteuerung
channel-group-type.gardena.ic24scheduling.label=Zeitplanung
channel-group-type.gardena.ic24scheduling.description=Die Zeitplanung
# channel types
channel-type.gardena.mowerDurationProperty.label=Mähdauer
channel-type.gardena.mowerDurationProperty.description=Mähdauer in Minuten
channel-type.gardena.parkUntilFurtherNotice.label=Parken und pausieren
channel-type.gardena.parkUntilFurtherNotice.description=Parken und alle Zeitpläne pausieren
channel-type.gardena.parkUntilNextTimer.label=Parken
channel-type.gardena.parkUntilNextTimer.description=Bis zum nächsten regulären Zeitplan parken
channel-type.gardena.startResumeSchedule.label=Zeitpläne fortsetzen
channel-type.gardena.startResumeSchedule.description=Alle Zeitpläne werden fortgesetze
channel-type.gardena.startOverrideTimer.label=Manuelles mähen
channel-type.gardena.startOverrideTimer.description=Sofort mähen für die eingestellte Mähdauer
channel-type.gardena.lastTimeOnline.label=Zuletzt online
channel-type.gardena.lastTimeOnline.description=Die Zeit wann das Gerät zuletzt online war
channel-type.gardena.rechargeableBatteryStatus.label=Akkuzustand
channel-type.gardena.rechargeableBatteryStatus.description=Der Zustand des Akkus
channel-type.gardena.rechargeableBatteryStatus.state.option.weak=Schwach
channel-type.gardena.rechargeableBatteryStatus.state.option.undefined=Undefiniert
channel-type.gardena.charging.label=Batterie wird geladen
channel-type.gardena.charging.description=Batterie wird geladen
channel-type.gardena.radioQuality.label=Verbindungsqualität
channel-type.gardena.radioQuality.description=Die Qualität der Funk Verbindung
channel-type.gardena.connectionStatus.label=Verbindungsstatus
channel-type.gardena.connectionStatus.description=Der Status der Verbindung
channel-type.gardena.connectionStatus.state.option.status_device_unreachable=Nicht erreichbar
channel-type.gardena.connectionStatus.state.option.status_device_alive=Erreichbar
channel-type.gardena.connectionStatus.state.option.unknown=Unbekannt
channel-type.gardena.radioState.label=Verbindungszustand
channel-type.gardena.radioState.description=Der Zustand der Funk Verbindung
channel-type.gardena.radioState.state.option.poor=Schlecht
channel-type.gardena.radioState.state.option.good=Gut
channel-type.gardena.radioState.state.option.excellent=Exzellent
channel-type.gardena.radioState.state.option.undefined=Undefiniert
channel-type.gardena.manualOperation.label=Manuelle Steuerung
channel-type.gardena.manualOperation.description=Der Mäher wird manuell gesteuert
channel-type.gardena.status.label=Mäherstatus
channel-type.gardena.status.description=Der Status des Mähers
channel-type.gardena.status.state.option.uninitialised=Nicht initialisiert
channel-type.gardena.status.state.option.paused=Pausiert
channel-type.gardena.status.state.option.ok_cutting=Mähen
channel-type.gardena.status.state.option.ok_searching=Suche Ladestation
channel-type.gardena.status.state.option.ok_charging=Lädt
channel-type.gardena.status.state.option.ok_leaving=Mähen
channel-type.gardena.status.state.option.wait_updating=Wird aktualisiert ...
channel-type.gardena.status.state.option.wait_power_up=Wird eingeschaltet ...
channel-type.gardena.status.state.option.parked_timer=Geparkt nach Zeitplan
channel-type.gardena.status.state.option.parked_park_selected=Geparkt
channel-type.gardena.status.state.option.off_disabled=Der Mäher ist ausgeschaltet
channel-type.gardena.status.state.option.off_hatch_open=Deaktiviert. Abdeckung ist offen oder PIN-Code erforderlich
channel-type.gardena.status.state.option.unknown=Unbekannter Status
channel-type.gardena.status.state.option.error=Fehler
channel-type.gardena.status.state.option.error_at_power_up=Neustart ...
channel-type.gardena.status.state.option.off_hatch_closed=Deaktiviert. Manueller Start erforderlich
channel-type.gardena.status.state.option.ok_cutting_timer_overridden=Manuelles Mähen
channel-type.gardena.status.state.option.parked_autotimer=Geparkt durch SensorControl
channel-type.gardena.status.state.option.parked_daily_limit_reached=Abgeschlossen
channel-type.gardena.status.state.option.undefined=Undefiniert
channel-type.gardena.error.label=Mäherfehler
channel-type.gardena.error.description=Der Fehler des Mähers
channel-type.gardena.error.state.option.no_message=Kein Fehler
channel-type.gardena.error.state.option.outside_working_area=Außerhalb des Arbeitsbereichs
channel-type.gardena.error.state.option.no_loop_signal=Kein Schleifensignal
channel-type.gardena.error.state.option.wrong_loop_signal=Falsches Schleifensignal
channel-type.gardena.error.state.option.loop_sensor_problem_front=Problem Schleifensensor, vorne
channel-type.gardena.error.state.option.loop_sensor_problem_rear=Problem Schleifensensor, hinten
channel-type.gardena.error.state.option.loop_sensor_problem_left=Problem Schleifensensor, links
channel-type.gardena.error.state.option.loop_sensor_problem_right=Problem Schleifensensor, rechts
channel-type.gardena.error.state.option.wrong_pin_code=Falscher PIN Code
channel-type.gardena.error.state.option.trapped=Eingeschlossen
channel-type.gardena.error.state.option.upside_down=Steht auf dem Kopf
channel-type.gardena.error.state.option.low_battery=Niedriger Batteriestand
channel-type.gardena.error.state.option.empty_battery=empty_battery
channel-type.gardena.error.state.option.no_drive=no_drive
channel-type.gardena.error.state.option.temporarily_lifted=Vorübergehend angehoben
channel-type.gardena.error.state.option.lifted=Angehoben
channel-type.gardena.error.state.option.stuck_in_charging_station=Eingeklemmt in Ladestation
channel-type.gardena.error.state.option.charging_station_blocked=Ladestation blockiert
channel-type.gardena.error.state.option.collision_sensor_problem_rear=Problem Stoßsensor hinten
channel-type.gardena.error.state.option.collision_sensor_problem_front=Problem Stoßsensor vorne
channel-type.gardena.error.state.option.wheel_motor_blocked_right=Radmotor rechts blockiert
channel-type.gardena.error.state.option.wheel_motor_blocked_left=Radmotor links blockiert
channel-type.gardena.error.state.option.wheel_drive_problem_right=Problem Antrieb, rechts
channel-type.gardena.error.state.option.wheel_drive_problem_left=Problem Antrieb, links
channel-type.gardena.error.state.option.cutting_motor_drive_defect=Schneidmotorantrieb defekt
channel-type.gardena.error.state.option.cutting_system_blocked=Schneidsystem blockiert
channel-type.gardena.error.state.option.invalid_sub_device_combination=Fehlerhafte Verbindung
channel-type.gardena.error.state.option.settings_restored=Standardeinstellungen
channel-type.gardena.error.state.option.memory_circuit_problem=Speicherschaltkreisproblem
channel-type.gardena.error.state.option.slope_too_steep=Steigung zu steil
channel-type.gardena.error.state.option.charging_system_problem=Problem Ladesystem
channel-type.gardena.error.state.option.stop_button_problem=Stop button Problem
channel-type.gardena.error.state.option.tilt_sensor_problem=Kippsensorproblem
channel-type.gardena.error.state.option.mower_tilted=Mäher gekippt
channel-type.gardena.error.state.option.wheel_motor_overloaded_right=Rechter Radmotor überlastet
channel-type.gardena.error.state.option.wheel_motor_overloaded_left=Linker Radmotor überlastet
channel-type.gardena.error.state.option.charging_current_too_high=Ladestrom zu hoch
channel-type.gardena.error.state.option.electronic_problem=Elektronisches Problem
channel-type.gardena.error.state.option.cutting_motor_problem=Schneidmotorisches Problem
channel-type.gardena.error.state.option.limited_cutting_height_range=Begrenzter Schneidhöhenbereich
channel-type.gardena.error.state.option.unexpected_cutting_height_adj=Unerwartete Schnitthöhe
channel-type.gardena.error.state.option.cutting_height_problem_drive=Schnitthöhenproblem Antrieb
channel-type.gardena.error.state.option.cutting_height_problem_curr=Schnitthöhenproblem
channel-type.gardena.error.state.option.cutting_height_problem_dir=Schnitthöhenproblem
channel-type.gardena.error.state.option.cutting_height_blocked=Schnitthöhe blockiert
channel-type.gardena.error.state.option.cutting_height_problem=Schnitthöhenproblem
channel-type.gardena.error.state.option.no_response_from_charger=Keine Antwort vom Ladegerät
channel-type.gardena.error.state.option.ultrasonic_problem=Ultraschallproblem
channel-type.gardena.error.state.option.temporary_problem=Vorübergehendes Problem
channel-type.gardena.error.state.option.guide_1_not_found=SK 1 nicht gefunden
channel-type.gardena.error.state.option.guide_2_not_found=SK 2 nicht gefunden
channel-type.gardena.error.state.option.guide_3_not_found=SK 3 nicht gefunden
channel-type.gardena.error.state.option.gps_tracker_module_error=GPS tracker Modul Fehler
channel-type.gardena.error.state.option.weak_gps_signal=Schwaches GPS Signal
channel-type.gardena.error.state.option.difficult_finding_home=Problem die Ladestation zu finden
channel-type.gardena.error.state.option.guide_calibration_accomplished=Kalibration des Suchkabels beendet
channel-type.gardena.error.state.option.guide_calibration_failed=Kalibration des Suchkabels fehlgeschlagen
channel-type.gardena.error.state.option.temporary_battery_problem=Kurzzeitiges Batterieproblem
channel-type.gardena.error.state.option.battery_problem=Batterieproblem
channel-type.gardena.error.state.option.too_many_batteries=Zu viele Batterien
channel-type.gardena.error.state.option.alarm_mower_switched_off=Alarm! Mäher ausgeschalten
channel-type.gardena.error.state.option.alarm_mower_stopped=Alarm! Mäher gestoppt
channel-type.gardena.error.state.option.alarm_mower_lifted=Alarm! Mäher angehoben
channel-type.gardena.error.state.option.alarm_mower_tilted=Alarm! Mäher gekippt
channel-type.gardena.error.state.option.alarm_mower_in_motion=Alarm! Mäher in Bewegung
channel-type.gardena.error.state.option.alarm_outside_geofence=Alarm! Außerhalb des Geofence
channel-type.gardena.error.state.option.connection_changed=Verbindung geändert
channel-type.gardena.error.state.option.connection_not_changed=Verbindung nicht geändert
channel-type.gardena.error.state.option.com_board_not_available=COM board nicht verfügbar
channel-type.gardena.error.state.option.slipped=Rutscht
channel-type.gardena.error.state.option.invalid_battery_combination=Ungültige Batterie Kombination
channel-type.gardena.error.state.option.imbalanced_cutting_disc=Unwuchte Schneidscheibe
channel-type.gardena.error.state.option.safety_function_faulty=Sicherheitsfunktion fehlerhaft
channel-type.gardena.sourceForNextStart.label=Quelle für den nächsten Start
channel-type.gardena.sourceForNextStart.description=Die Quelle für den nächsten Start
channel-type.gardena.sourceForNextStart.state.option.no_source=Keine Quelle
channel-type.gardena.sourceForNextStart.state.option.completed_cutting_daily_limit=Tägliches Mählimit erreicht
channel-type.gardena.sourceForNextStart.state.option.week_timer=Wochen timer
channel-type.gardena.sourceForNextStart.state.option.countdown_timer=Countdown timer
channel-type.gardena.sourceForNextStart.state.option.mower_charging=Mäher lädt
channel-type.gardena.sourceForNextStart.state.option.completed_cutting_autotimer=Fertig gemäht
channel-type.gardena.sourceForNextStart.state.option.undefined=Undefiniert
channel-type.gardena.timestampNextStart.label=Nächster Startzeitpunkt
channel-type.gardena.timestampNextStart.description=Zeitpunkt des nächsten Starts
channel-type.gardena.overrideEndTime.label=Überschreiben der Endzeit
channel-type.gardena.overrideEndTime.description=Überschreiben der Endzeit
channel-type.gardena.temperature.label=Temperatur
channel-type.gardena.temperature.description=Die Temperatur
channel-type.gardena.disposableBatteryStatus.label=Einweg Batterie Status
channel-type.gardena.disposableBatteryStatus.description=Der Status der Einweg Batterie
channel-type.gardena.disposableBatteryStatus.state.option.out_of_operation=Ausser Betrieb
channel-type.gardena.disposableBatteryStatus.state.option.replace_now=Kritischer Batteriestand, wechseln Sie jetzt
channel-type.gardena.disposableBatteryStatus.state.option.low=Niedrig
channel-type.gardena.disposableBatteryStatus.state.option.ok=OK
channel-type.gardena.disposableBatteryStatus.state.option.undefined=Undefiniert
channel-type.gardena.valveOpen.label=Ventil geöffnet
channel-type.gardena.valveOpen.description=Ventil geöffnet
channel-type.gardena.manualOverride.label=Manuelle Steuerung
channel-type.gardena.manualOverride.description=Manuelle Steuerung
channel-type.gardena.manualOverride.state.option.inactive=Inaktiv
channel-type.gardena.manualOverride.state.option.open=Offen
channel-type.gardena.manualOverride.state.option.undefined=Undefiniert
channel-type.gardena.buttonManualOverrideTime.label=Zeit manuelle Steuerung
channel-type.gardena.buttonManualOverrideTime.description=Die Zeit die das Ventil geöffnet ist, wenn der Knopf am Gerät gedrückt wird
channel-type.gardena.outletCommand.label=Ventil
channel-type.gardena.outletCommand.description=Öffnen und Schließen des Ventils
channel-type.gardena.frostWarning.label=Frostwarnung
channel-type.gardena.frostWarning.description=Frostwarnung
channel-type.gardena.frostWarning.state.option.no_frost=Kein Frost
channel-type.gardena.frostWarning.state.option.frost=Frost
channel-type.gardena.frostWarning.state.option.undefined=Undefiniert
channel-type.gardena.humidity.label=Feuchtigkeit
channel-type.gardena.humidity.description=Die Feuchtigkeit
channel-type.gardena.light.label=Helligkeit
channel-type.gardena.light.description=Die Helligkeit
channel-type.gardena.firmwareStatus.label=Status
channel-type.gardena.firmwareStatus.description=Der Firmware Status
channel-type.gardena.firmwareUploadProgress.label=Upload Fortschritt
channel-type.gardena.firmwareUploadProgress.description=Der Firmware upload Fortschritt
channel-type.gardena.firmwareAvailableVersion.label=Verfügbare Version
channel-type.gardena.firmwareAvailableVersion.description=Verfügbare Firmware Version
channel-type.gardena.pumpMode.label=Modus
channel-type.gardena.pumpMode.description=Der Modus
channel-type.gardena.pumpMode.state.option.off=Aus
channel-type.gardena.pumpMode.state.option.auto=Automatik
channel-type.gardena.pumpOnOff.label=Pumpe
channel-type.gardena.pumpOnOff.description=Die Pumpe
channel-type.gardena.pumpOnOff.state.option.off=Aus
channel-type.gardena.pumpOnOff.state.option.on=Ein
channel-type.gardena.turnOnPressure.label=Einschaltdruck
channel-type.gardena.turnOnPressure.description=Der Einschaltdruck
channel-type.gardena.operatingMode.label=Betriebsmodus
channel-type.gardena.operatingMode.description=Der Betriebsmodus
channel-type.gardena.operatingMode.state.option.scheduled=Zeitgesteuert
channel-type.gardena.operatingMode.state.option.automatic=Automatisch
channel-type.gardena.counter.label=Zähler
channel-type.gardena.counter.description=Der Zähler
channel-type.gardena.outletPressure.label=Auslassdruck
channel-type.gardena.outletPressure.description=Der Auslassdruck
channel-type.gardena.flowRate.label=Fördermenge
channel-type.gardena.flowRate.description=Die Fördermenge
channel-type.gardena.flowSinceLastReset.label=Durchfluss seit letztem Reset
channel-type.gardena.flowSinceLastReset.description=Der Durchfluss seit letztem Reset
channel-type.gardena.flowTotal.label=Gesamtdurchfluss
channel-type.gardena.flowTotal.description=Der Gesamtdurchfluss
channel-type.gardena.drippingAlert.label=Leckage-Erkennung
channel-type.gardena.drippingAlert.description=Die Leckage-Erkennung
channel-type.gardena.drippingAlert.state.option.sixty=Sechzig
channel-type.gardena.drippingAlert.state.option.two=Zwei
channel-type.gardena.drippingAlert.state.option.off=Aus
channel-type.gardena.manualWatering.label=Manuelle Bewässerung
channel-type.gardena.manualWatering.description=Die manuelle Bewässerung
channel-type.gardena.manualWateringTimer.label=Manueller Bewässerungs-Timer
channel-type.gardena.manualWateringTimer.description=Der manuelle Bewässerungs-Timer
channel-type.gardena.manualWateringTimer.state.option.0=Aus
channel-type.gardena.lastManualOverrideTime.label=Letzte manuelle Betätigung
channel-type.gardena.lastManualOverrideTime.description=Die letzte manuelle Betätigung
channel-type.gardena.adaptiveSchedulingLastDecision.label=Intelligente Zeitplanung
channel-type.gardena.adaptiveSchedulingLastDecision.description=Die letzte Entscheidung der intelligenten Zeitplanung
channel-type.gardena.adaptiveSchedulingLastDecision.state.option.undefined=Undefiniert
channel-type.gardena.adaptiveSchedulingLastDecision.state.option.watered_sensor_timeout=Keine Sensordaten
channel-type.gardena.adaptiveSchedulingLastDecision.state.option.skipped=Zeiplan ausgesetzt
channel-type.gardena.adaptiveSchedulingLastDecision.state.option.watered=Nach Zeitplan
channel-type.gardena.temperatureMin.label=Minimum Temperatur
channel-type.gardena.temperatureMin.description=Die minimale Temperatur
channel-type.gardena.temperatureMax.label=Maximum Temperatur
channel-type.gardena.temperatureMax.description=Die maximale Temperatur
channel-type.gardena.errorCounter.label=Fehlerzähler
channel-type.gardena.errorCounter.description=Der Fehlerzähler
channel-type.gardena.errorCounterOne.label=Fehlerzähler 1
channel-type.gardena.errorCounterOne.description=Der 1 Fehlerzähler
channel-type.gardena.errorCounterTwo.label=Fehlerzähler 2
channel-type.gardena.errorCounterTwo.description=Der 2 Fehlerzähler
channel-type.gardena.errorCounterThree.label=Fehlerzähler 3
channel-type.gardena.errorCounterThree.description=Der 3 Fehlerzähler
channel-type.gardena.errorCounterFour.label=Fehlerzähler 4
channel-type.gardena.errorCounterFour.description=Der vierte Fehlerzähler
channel-type.gardena.operatingDays.label=Betriebstage
channel-type.gardena.operatingDays.description=Die Betriebstage
channel-type.gardena.scheduledWateringEnd.label=Geplantes Bewässerungsende
channel-type.gardena.scheduledWateringEnd.description=Das geplante Bewässerungsende
channel-type.gardena.scheduledWateringNextStart.label=Nächste geplante Bewässerung
channel-type.gardena.scheduledWateringNextStart.description=Die nächste geplante Bewässerung
channel-type.gardena.cuttingTime.label=Mähdauer
channel-type.gardena.cuttingTime.description=Die gesamte Mähdauer
channel-type.gardena.chargingCycles.label=Ladezyklen
channel-type.gardena.chargingCycles.description=Die Anzahl der Ladezyklen
channel-type.gardena.collisions.label=Kollisionen
channel-type.gardena.collisions.description=Die Anzahl der Kollisionen
channel-type.gardena.runningTime.label=Laufzeit
channel-type.gardena.runningTime.description=Die gesamte Laufzeit
channel-type.gardena.powerTimer.label=Einschaltzeit
channel-type.gardena.powerTimer.description=Die Einschaltzeit
channel-type.gardena.powerTimer.state.option.on=Ein
channel-type.gardena.powerTimer.state.option.off=Aus
channel-type.gardena.powerTimer.state.option.60=1 Minute
channel-type.gardena.powerTimer.state.option.300=5 Minuten
channel-type.gardena.powerTimer.state.option.900=15 Minuten
channel-type.gardena.powerTimer.state.option.3600=1 Stunde
channel-type.gardena.powerTimer.state.option.7200=2 Stunden
channel-type.gardena.powerTimer.state.option.18000=5 Stunden
channel-type.gardena.powerTimer.state.option.43200=12 Stunden
channel-type.gardena.powerTimer.state.option.86400=1 Tag
channel-type.gardena.powerTimer.state.option.259200=3 Tage
channel-type.gardena.powerTimer.state.option.604800=1 Woche
channel-type.gardena.powerTimer.state.option.1209600=2 Wochen
channel-type.gardena.powerError.label=Fehler
channel-type.gardena.powerError.description=Fehler
channel-type.gardena.powerError.state.option.ok=OK
channel-type.gardena.powerError.state.option.timer_cancelled=Timer abgebrochen
channel-type.gardena.powerError.state.option.unknown=Unbekannt
channel-type.gardena.wateringTimer.label=Bewässerungstimer
channel-type.gardena.wateringTimer.description=Der Bewässerungstimer
channel-type.gardena.valvesConnected.label=Angeschlossenen Ventile
channel-type.gardena.valvesConnected.description=Die angeschlossenen Ventile
channel-type.gardena.valvesMasterConfig.label=Ventile Hauptkonfiguration
channel-type.gardena.valvesMasterConfig.description=Die Hauptkonfiguration der Ventile
channel-type.gardena.ic24error.label=Bewässerungssteuerung Fehler
channel-type.gardena.ic24error.description=Der Fehler der Bewässerungssteuerung
channel-type.gardena.ic24error.state.option.voltage_drop=Spannungsabfall
channel-type.gardena.ic24error.state.option.wrong_power_supply=Falsche Stromversorgung
channel-type.gardena.ic24error.state.option.no_mcu_connection=Keine MCU verbunden
channel-type.gardena.ic24error.state.option.unknown=Unbekannt

View File

@@ -0,0 +1,42 @@
<?xml version="1.0" encoding="UTF-8"?>
<thing:thing-descriptions bindingId="gardena"
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">
<!-- Gardena Smart Home Account -->
<bridge-type id="account">
<label>Gardena Smart Home Account</label>
<description>The Gardena Smart Home Account</description>
<config-description>
<parameter name="email" type="text" required="true">
<label>Email</label>
<description>Email address for logging in to Gardena Smart Home</description>
</parameter>
<parameter name="password" type="text" required="true">
<label>Password</label>
<context>password</context>
<description>Password for logging in to Gardena Smart Home</description>
</parameter>
<parameter name="sessionTimeout" type="integer">
<label>Session Timeout</label>
<description>The timeout in minutes for a session to Gardena Smart Home</description>
<advanced>true</advanced>
<default>30</default>
</parameter>
<parameter name="connectionTimeout" type="integer">
<label>Connection Timeout</label>
<description>The timeout in seconds for connections to Gardena Smart Home</description>
<advanced>true</advanced>
<default>10</default>
</parameter>
<parameter name="refresh" type="integer">
<label>Refresh Interval</label>
<description>The interval in seconds for refreshing the data from Gardena Smart Home</description>
<advanced>true</advanced>
<default>60</default>
</parameter>
</config-description>
</bridge-type>
</thing:thing-descriptions>