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,32 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="src" output="target/classes" path="src/main/java">
<attributes>
<attribute name="optional" value="true"/>
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry excluding="**" kind="src" output="target/classes" path="src/main/resources">
<attributes>
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="src" output="target/test-classes" path="src/test/java">
<attributes>
<attribute name="optional" value="true"/>
<attribute name="maven.pomderived" value="true"/>
<attribute name="test" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-11">
<attributes>
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="con" path="org.eclipse.m2e.MAVEN2_CLASSPATH_CONTAINER">
<attributes>
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="output" path="target/classes"/>
</classpath>

View File

@@ -0,0 +1,23 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>org.openhab.binding.gardena</name>
<comment></comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>org.eclipse.jdt.core.javabuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.m2e.core.maven2Builder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>org.eclipse.jdt.core.javanature</nature>
<nature>org.eclipse.m2e.core.maven2Nature</nature>
</natures>
</projectDescription>

View File

@@ -0,0 +1,13 @@
This content is produced and maintained by the openHAB project.
* Project home: https://www.openhab.org
== Declared Project Licenses
This program and the accompanying materials are made available under the terms
of the Eclipse Public License 2.0 which is available at
https://www.eclipse.org/legal/epl-2.0/.
== Source Code
https://github.com/openhab/openhab-addons

View File

@@ -0,0 +1,157 @@
# Gardena Binding
This is the binding for [Gardena smart system](https://www.gardena.com/de/rasenpflege/smartsystem/).
This binding allows you to integrate, view and control Gardena smart system devices in the openHAB environment.
## Supported Things
Devices connected to Gardena smart system, currently:
| Thing type | Name |
|--------------------------|--------------------------|
| bridge | smart Garden Gateway |
| mower | smart Sileno(+) Mower |
| watering_computer | smart Water Control |
| sensor | smart Sensor |
| electronic_pressure_pump | smart Pressure Pump |
| power | smart Power |
| ic24 | smart Irrigation Control |
The schedules are not yet integrated!
## Discovery
An account must be specified, all things for an account are discovered automatically.
## Account Configuration
There are several settings for an account:
| Name | Required | Description |
|-----------------------|----------|------------------------------------------------------------------------------------------|
| **email** | yes | The email address for logging into the Gardena smart system |
| **password** | yes | The password for logging into the Gardena smart system |
| **sessionTimeout** | no | The timeout in minutes for a session to Gardena smart system (default = 30) |
| **connectionTimeout** | no | The timeout in seconds for connections to Gardena smart system (default = 10) |
| **refresh** | no | The interval in seconds for refreshing the data from Gardena smart system (default = 60) |
**Example**
### Things
Minimal Thing configuration:
```java
Bridge gardena:account:home [ email="...", password="..." ]
```
Configuration with refresh:
```java
Bridge gardena:account:home [ email="...", password="...", refresh=30 ]
```
Configuration of multiple bridges:
```java
Bridge gardena:account:home1 [ email="...", password="..." ]
Bridge gardena:account:home2 [ email="...", password="..." ]
```
Once a connection to an account is established, connected Things are discovered automatically.
Alternatively, you can manually configure a Thing:
```perl
Bridge gardena:account:home [ email="...", password="..." ]
{
Thing mower myMower [ deviceId="c81ad682-6e45-42ce-bed1-6b4eff5620c8" ]
}
```
## Items
In the items file, you can link items to channels of your Things:
```java
Number Battery_Level "Battery [%d %%]" {channel="gardena:mower:home:myMower:battery#level"}
```
## Sensor refresh
You can send a REFRESH command to items linked to these Sensor channels:
- ambient_temperature#temperature
- soil_temperature#temperature
- humidity#humidity
- light#light
In the console:
```shell
smarthome:send ITEM_NAME REFRESH
```
In scripts:
```
import org.openhab.core.types.RefreshType
...
sendCommand(ITEM_NAME, RefreshType.REFRESH)
```
## Examples
```
// smart Water Control
Switch Watering_Valve "Valve" { channel="gardena:watering_computer:home:myValve:outlet#valve_open" }
Number Watering_Duration "Duration [%d min]" { channel="gardena:watering_computer:home:myValve:outlet#button_manual_override_time" }
// smart Power Plug
String Power_Timer "Power Timer [%s]" { channel="gardena:power:home:myPowerplug:power#power_timer" }
// smart Irrigation Control
Number Watering_Timer_1 "Watering Timer 1 [%d min] { channel="gardena:ic24:home:myIrrigationController:watering#watering_timer_1" }
// smart Pressure Pump
Number Pump_Timer "Pump Timer [%d min] { channel="gardena:electronic_pressure_pump:home:myPressurePump:manual_watering#manual_watering_timer" }
```
```
Watering_Duration.sendCommand(30) // 30 minutes
Watering_Valve.sendCommand(ON)
Power_Timer.sendCommand("on")
Power_Timer.sendCommand("off")
Power_Timer.sendCommand("180") // on for 180 seconds
Watering_Timer_1.sendCommand(0) // turn off watering
Watering_Timer_1.sendCommand(30) // turn on for 30 minutes
Pump_Timer.sendCommand(0) // turn the pump off
Pump_Timer.sendCommand(30) // turn the pump on for 30 minutes
```
### Debugging and Tracing
If you want to see what's going on in the binding, switch the loglevel to TRACE in the Karaf console
```
log:set TRACE org.openhab.binding.gardena
```
Set the logging back to normal
```
log:set INFO org.openhab.binding.gardena
```
**Note:** The Online/Offline status is not always valid. I'm using the ```connection_status``` property Gardena sends for each device, but it seems not to be very reliable.
My watering control for example shows offline, but it is still working.
I have to press the button on the device, then the status changed to online.
My mower always shows online, regardless of whether it is switched on or off.
This is not a binding issue, it must be fixed by Gardena.
When the binding sends a command to a device, it communicates only with the Gardena online service.
It has not control over, whether the command is sent from the online service via your gateway to the device.
It is the same as if you send the command in the Gardena App.

View File

@@ -0,0 +1,17 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.openhab.addons.bundles</groupId>
<artifactId>org.openhab.addons.reactor.bundles</artifactId>
<version>3.0.0-SNAPSHOT</version>
</parent>
<artifactId>org.openhab.binding.gardena</artifactId>
<name>openHAB Add-ons :: Bundles :: Gardena Binding</name>
</project>

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>