[gardena] Rewriting the Gardena binding (#8869)
* Rewriting the Gardena binding Signed-off-by: Gerhard Riegler <gerhard.riegler@gmail.com>pull/9355/head
parent
2bcb548381
commit
442a7cd31e
|
@ -1,23 +1,21 @@
|
|||
# Gardena Binding
|
||||
|
||||
This is the binding for [Gardena smart system](https://www.gardena.com/de/rasenpflege/smartsystem/).
|
||||
This is the binding for [Gardena smart system](https://www.gardena.com/smart).
|
||||
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!
|
||||
| Thing type | Name |
|
||||
|--------------------------|----------------------------------------------------|
|
||||
| bridge | smart Gateway |
|
||||
| mower | smart SILENO(+), SILENO city, SILENO life Mower |
|
||||
| sensor | smart Sensor |
|
||||
| pump | smart Pressure Pump |
|
||||
| power | smart Power Adapter |
|
||||
| water_control | smart Water Control |
|
||||
| irrigation_control | smart Irrigation Control |
|
||||
|
||||
## Discovery
|
||||
|
||||
|
@ -27,109 +25,94 @@ An account must be specified, all things for an account are discovered automatic
|
|||
|
||||
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) |
|
||||
| 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 |
|
||||
| **apiKey** | yes | The Gardena smart system integration API key |
|
||||
| **connectionTimeout** | no | The timeout in seconds for connections to Gardena smart system integration API (default = 10) |
|
||||
|
||||
**Example**
|
||||
### Obtaining your API Key
|
||||
|
||||
1. Goto https://developer.husqvarnagroup.cloud/, sign in using your GARDENA smart system account and accept the terms of use
|
||||
2. Create and save a new application via the 'Create application' button
|
||||
3. Connect both _Authentication API_ and _GARDENA smart system API_ to your application via the 'Connect new API' button
|
||||
4. Copy the application key to use with this binding as _apiKey_
|
||||
|
||||
## Examples
|
||||
|
||||
### Things
|
||||
|
||||
Minimal Thing configuration:
|
||||
|
||||
```java
|
||||
Bridge gardena:account:home [ email="...", password="..." ]
|
||||
```
|
||||
|
||||
Configuration with refresh:
|
||||
|
||||
```java
|
||||
Bridge gardena:account:home [ email="...", password="...", refresh=30 ]
|
||||
Bridge gardena:account:home [ email="...", password="...", apiKey="..." ]
|
||||
```
|
||||
|
||||
Configuration of multiple bridges:
|
||||
|
||||
```java
|
||||
Bridge gardena:account:home1 [ email="...", password="..." ]
|
||||
Bridge gardena:account:home2 [ email="...", password="..." ]
|
||||
Bridge gardena:account:home1 [ email="...", password="...", apiKey="..." ]
|
||||
Bridge gardena:account:home2 [ email="...", password="...", apiKey="..." ]
|
||||
```
|
||||
|
||||
Once a connection to an account is established, connected Things are discovered automatically.
|
||||
|
||||
Alternatively, you can manually configure a Thing:
|
||||
Alternatively, you can manually configure Things:
|
||||
|
||||
```perl
|
||||
Bridge gardena:account:home [ email="...", password="..." ]
|
||||
```java
|
||||
Bridge gardena:account:home [ email="...", password="...", apiKey="..." ]
|
||||
{
|
||||
Thing mower myMower [ deviceId="c81ad682-6e45-42ce-bed1-6b4eff5620c8" ]
|
||||
Thing water_control myWaterControl [ deviceId="c81ad682-6e45-42ce-bed1-6b4eff5620c8" ]
|
||||
Thing sensor mySensor [ deviceId="c81ad682-6e45-42ce-bed1-6b4eff5620c8" ]
|
||||
Thing pump myEPP [ deviceId="c81ad682-6e45-42ce-bed1-6b4eff5620c8" ]
|
||||
Thing power myPowerSocket [ deviceId="c81ad682-6e45-42ce-bed1-6b4eff5620c8" ]
|
||||
Thing irrigation_control myIrrigationControl [ deviceId="c81ad682-6e45-42ce-bed1-6b4eff5620c8" ]
|
||||
}
|
||||
```
|
||||
|
||||
## Items
|
||||
### 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"}
|
||||
Number Mower_Battery_Level "Battery [%d %%]" {channel="gardena:mower:home:myMower:common#batteryLevel"}
|
||||
```
|
||||
|
||||
## Sensor refresh
|
||||
### Sensor refresh
|
||||
|
||||
You can send a REFRESH command to items linked to these Sensor channels:
|
||||
Sensor refresh commands are not yet supported by the Gardena smart system integration API.
|
||||
|
||||
- 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
|
||||
### Example configuration
|
||||
|
||||
```
|
||||
// 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" }
|
||||
String WC_Valve_Activity "Valve Activity" { channel="gardena:water_control:home:myWateringComputer:valve#activity" }
|
||||
Number WC_Valve_Duration "Last Watering Duration [%d min]" { channel="gardena:water_control:home:myWateringComputer:valve#duration" }
|
||||
|
||||
// smart Power Plug
|
||||
String Power_Timer "Power Timer [%s]" { channel="gardena:power:home:myPowerplug:power#power_timer" }
|
||||
Number WC_Valve_cmd_Duration "Command Duration [%d min]" { channel="gardena:water_control:home:myWateringComputer:valve_commands#commandDuration" }
|
||||
Switch WC_Valve_cmd_OpenWithDuration "Watering Timer [%d min]" { channel="gardena:water_control:home:myWateringComputer:valve_commands#start_seconds_to_override" }
|
||||
Switch WC_Valve_cmd_CloseValve "Stop Switch" { channel="gardena:water_control:home:myWateringComputer:valve_commands#stop_until_next_task" }
|
||||
|
||||
// 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" }
|
||||
smarthome:status WC_Valve_Duration // returns the duration of the last watering request if still active, or 0
|
||||
smarthome:status WC_Valve_Activity // returns the current valve activity (CLOSED|MANUAL_WATERING|SCHEDULED_WATERING)
|
||||
```
|
||||
|
||||
All channels are read-only, except the command group and the lastUpdate timestamp
|
||||
|
||||
```
|
||||
smarthome:send WC_Valve_cmd_Duration.sendCommand(10) // set the duration for the command to 10min
|
||||
smarthome:send WC_Valve_cmd_OpenWithDuration.sendCommand(ON) // start watering
|
||||
smarthome:send WC_Valve_cmd_CloseValve.sendCommand(ON) // stop any active watering
|
||||
```
|
||||
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
|
||||
If you send a REFRESH command to the last update timestamp (no matter which thing), **ALL** items from **ALL** things are updated
|
||||
```
|
||||
DateTime LastUpdate "LastUpdate [%1$td.%1$tm.%1$tY %1$tH:%1$tM]" { channel="gardena:water_control:home:myWateringComputer:common#lastUpdate_timestamp" }
|
||||
|
||||
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
|
||||
// refresh ALL items
|
||||
smarthome:send LastUpdate REFRESH
|
||||
```
|
||||
|
||||
### Debugging and Tracing
|
||||
|
@ -146,12 +129,21 @@ 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.
|
||||
**Notes and known limitations:**
|
||||
When the binding sends a command to a device, it communicates only with the Gardena smart system integration API.
|
||||
It has no 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.
|
||||
|
||||
Schedules, sensor-refresh commands, irrigation control master valve configuration etc. are not supported.
|
||||
This binding relies on the GARDENA smart system integration API.
|
||||
Further API documentation: https://developer.1689.cloud/apis/GARDENA+smart+system+API
|
||||
|
||||
###Troubleshooting
|
||||
Occasionally it can happen that the API key is no longer valid.
|
||||
|
||||
```
|
||||
HTTP protocol violation: Authentication challenge without WWW-Authenticate header
|
||||
```
|
||||
|
||||
If this error message appears in the log file, simply renew or delete/create a new API key as described in 'Obtaining your API Key' and restart openHAB.
|
||||
|
||||
|
|
|
@ -16,32 +16,25 @@ 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.
|
||||
* The {@link GardenaBindingConstants} 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_SERIALNUMBER = "serial";
|
||||
public static final String PROPERTY_MODELTYPE = "modelType";
|
||||
|
||||
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 CONNECTION_STATUS_ONLINE = "ONLINE";
|
||||
|
||||
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";
|
||||
public static final String DEVICE_TYPE_MOWER = "mower";
|
||||
public static final String DEVICE_TYPE_PUMP = "pump";
|
||||
public static final String DEVICE_TYPE_IRRIGATION_CONTROL = "irrigation_control";
|
||||
public static final String DEVICE_TYPE_WATER_CONTROL = "water_control";
|
||||
public static final String DEVICE_TYPE_SENSOR = "sensor";
|
||||
public static final String DEVICE_TYPE_POWER = "power";
|
||||
}
|
||||
|
|
|
@ -12,60 +12,50 @@
|
|||
*/
|
||||
package org.openhab.binding.gardena.internal;
|
||||
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.Collection;
|
||||
|
||||
import org.openhab.binding.gardena.internal.config.GardenaConfig;
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.binding.gardena.internal.exception.GardenaDeviceNotFoundException;
|
||||
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;
|
||||
import org.openhab.binding.gardena.internal.model.dto.Device;
|
||||
import org.openhab.binding.gardena.internal.model.dto.api.DataItem;
|
||||
import org.openhab.binding.gardena.internal.model.dto.command.GardenaCommand;
|
||||
|
||||
/**
|
||||
* Describes the methods required for the communication with Gardens Smart Home.
|
||||
* Describes the methods required for the communication with Gardena smart system.
|
||||
*
|
||||
* @author Gerhard Riegler - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
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.
|
||||
* Disposes Gardena smart system.
|
||||
*/
|
||||
public void dispose();
|
||||
|
||||
/**
|
||||
* Loads all devices from all locations.
|
||||
* Returns all devices from all locations.
|
||||
*/
|
||||
public void loadAllDevices() throws GardenaException;
|
||||
|
||||
/**
|
||||
* Returns all locations.
|
||||
*/
|
||||
public Set<Location> getLocations();
|
||||
public Collection<Device> getAllDevices();
|
||||
|
||||
/**
|
||||
* Returns a device with the given id.
|
||||
*/
|
||||
public Device getDevice(String deviceId) throws GardenaException;
|
||||
public Device getDevice(String deviceId) throws GardenaDeviceNotFoundException;
|
||||
|
||||
/**
|
||||
* Sends a command to Gardena Smart Home.
|
||||
* Sends a command to Gardena smart system.
|
||||
*/
|
||||
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;
|
||||
public void sendCommand(DataItem<?> dataItem, GardenaCommand gardenaCommand) throws GardenaException;
|
||||
|
||||
/**
|
||||
* Returns the id.
|
||||
*/
|
||||
public String getId();
|
||||
|
||||
/**
|
||||
* Restarts all WebSocket.
|
||||
*/
|
||||
public void restartWebsockets();
|
||||
}
|
||||
|
|
|
@ -1,51 +0,0 @@
|
|||
/**
|
||||
* 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
|
||||
}
|
|
@ -12,13 +12,15 @@
|
|||
*/
|
||||
package org.openhab.binding.gardena.internal;
|
||||
|
||||
import org.openhab.binding.gardena.internal.model.Device;
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.binding.gardena.internal.model.dto.Device;
|
||||
|
||||
/**
|
||||
* Listener with methods called from events within the {@link GardenaSmart} class.
|
||||
*
|
||||
* @author Gerhard Riegler - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public interface GardenaSmartEventListener {
|
||||
|
||||
/**
|
||||
|
@ -32,17 +34,7 @@ public interface GardenaSmartEventListener {
|
|||
public void onNewDevice(Device device);
|
||||
|
||||
/**
|
||||
* Called when a device has been deleted.
|
||||
* Called when an unrecoverable error occurs.
|
||||
*/
|
||||
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();
|
||||
public void onError();
|
||||
}
|
||||
|
|
|
@ -12,179 +12,375 @@
|
|||
*/
|
||||
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 java.util.*;
|
||||
import java.util.concurrent.*;
|
||||
|
||||
import org.apache.commons.lang.ObjectUtils;
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
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.AbstractTypedContentProvider;
|
||||
import org.eclipse.jetty.client.util.FormContentProvider;
|
||||
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.eclipse.jetty.util.Fields;
|
||||
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.openhab.binding.gardena.internal.model.DataItemDeserializer;
|
||||
import org.openhab.binding.gardena.internal.model.dto.Device;
|
||||
import org.openhab.binding.gardena.internal.model.dto.api.*;
|
||||
import org.openhab.binding.gardena.internal.model.dto.command.GardenaCommand;
|
||||
import org.openhab.binding.gardena.internal.model.dto.command.GardenaCommandRequest;
|
||||
import org.openhab.core.io.net.http.HttpClientFactory;
|
||||
import org.openhab.core.io.net.http.WebSocketFactory;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
import com.google.gson.JsonSyntaxException;
|
||||
|
||||
/**
|
||||
* {@link GardenaSmart} implementation to access Gardena Smart Home.
|
||||
* {@link GardenaSmart} implementation to access Gardena smart system.
|
||||
*
|
||||
* @author Gerhard Riegler - Initial contribution
|
||||
*/
|
||||
public class GardenaSmartImpl implements GardenaSmart {
|
||||
@NonNullByDefault
|
||||
public class GardenaSmartImpl implements GardenaSmart, GardenaSmartWebSocketListener {
|
||||
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 Gson gson = new GsonBuilder().registerTypeAdapter(DataItem.class, new DataItemDeserializer()).create();
|
||||
|
||||
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 URL_API_HUSQUARNA = "https://api.authentication.husqvarnagroup.dev/v1";
|
||||
private static final String URL_API_GARDENA = "https://api.smart.gardena.dev/v1";
|
||||
private static final String URL_API_TOKEN = URL_API_HUSQUARNA + "/oauth2/token";
|
||||
private static final String URL_API_WEBSOCKET = URL_API_GARDENA + "/websocket";
|
||||
private static final String URL_API_LOCATIONS = URL_API_GARDENA + "/locations";
|
||||
private static final String URL_API_COMMAND = URL_API_GARDENA + "/command";
|
||||
|
||||
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 GardenaConfig config;
|
||||
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<>();
|
||||
private LocationsResponse locationsResponse;
|
||||
private GardenaSmartEventListener eventListener;
|
||||
|
||||
@Override
|
||||
public void init(String id, GardenaConfig config, GardenaSmartEventListener eventListener,
|
||||
ScheduledExecutorService scheduler) throws GardenaException {
|
||||
private HttpClient httpClient;
|
||||
private List<GardenaSmartWebSocket> webSockets = new ArrayList<>();
|
||||
private @Nullable PostOAuth2Response token;
|
||||
private boolean initialized = false;
|
||||
private WebSocketFactory webSocketFactory;
|
||||
|
||||
private Set<Device> devicesToNotify = ConcurrentHashMap.newKeySet();
|
||||
private @Nullable ScheduledFuture<?> deviceToNotifyFuture;
|
||||
private @Nullable ScheduledFuture<?> newDeviceFuture;
|
||||
|
||||
public GardenaSmartImpl(String id, GardenaConfig config, GardenaSmartEventListener eventListener,
|
||||
ScheduledExecutorService scheduler, HttpClientFactory httpClientFactory, WebSocketFactory webSocketFactory)
|
||||
throws GardenaException {
|
||||
this.id = id;
|
||||
this.config = config;
|
||||
this.eventListener = eventListener;
|
||||
this.scheduler = scheduler;
|
||||
this.webSocketFactory = webSocketFactory;
|
||||
|
||||
if (!config.isValid()) {
|
||||
throw new GardenaException("Invalid config, no email or password specified");
|
||||
}
|
||||
|
||||
httpClient = new HttpClient(new SslContextFactory(true));
|
||||
httpClient.setConnectTimeout(config.getConnectionTimeout() * 1000L);
|
||||
|
||||
logger.debug("Starting GardenaSmart");
|
||||
try {
|
||||
httpClient = httpClientFactory.createHttpClient(id);
|
||||
httpClient.setConnectTimeout(config.getConnectionTimeout() * 1000L);
|
||||
httpClient.setIdleTimeout(httpClient.getConnectTimeout());
|
||||
httpClient.start();
|
||||
|
||||
// initially load access token
|
||||
verifyToken();
|
||||
locationsResponse = loadLocations();
|
||||
|
||||
// assemble devices
|
||||
for (LocationDataItem location : locationsResponse.data) {
|
||||
LocationResponse locationResponse = loadLocation(location.id);
|
||||
if (locationResponse.included != null) {
|
||||
for (DataItem<?> dataItem : locationResponse.included) {
|
||||
handleDataItem(dataItem);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (Device device : allDevicesById.values()) {
|
||||
device.evaluateDeviceType();
|
||||
}
|
||||
|
||||
startWebsockets();
|
||||
initialized = true;
|
||||
} catch (Exception ex) {
|
||||
throw new GardenaException(ex.getMessage(), ex);
|
||||
}
|
||||
}
|
||||
|
||||
loadAllDevices();
|
||||
/**
|
||||
* Starts the websockets for each location.
|
||||
*/
|
||||
private void startWebsockets() throws Exception {
|
||||
for (LocationDataItem location : locationsResponse.data) {
|
||||
WebSocketCreatedResponse webSocketCreatedResponse = getWebsocketInfo(location.id);
|
||||
String socketId = id + "-" + location.attributes.name;
|
||||
webSockets.add(new GardenaSmartWebSocket(this, webSocketCreatedResponse, config, scheduler,
|
||||
webSocketFactory, token, socketId));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Stops all websockets.
|
||||
*/
|
||||
private void stopWebsockets() {
|
||||
for (GardenaSmartWebSocket webSocket : webSockets) {
|
||||
webSocket.stop();
|
||||
}
|
||||
webSockets.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* Communicates with Gardena smart home system and parses the result.
|
||||
*/
|
||||
private <T> T executeRequest(HttpMethod method, String url, @Nullable Object content, @Nullable Class<T> result)
|
||||
throws GardenaException {
|
||||
try {
|
||||
AbstractTypedContentProvider contentProvider = null;
|
||||
String contentType = "application/vnd.api+json";
|
||||
if (content != null) {
|
||||
if (content instanceof Fields) {
|
||||
contentProvider = new FormContentProvider((Fields) content);
|
||||
contentType = "application/x-www-form-urlencoded";
|
||||
} else {
|
||||
contentProvider = new StringContentProvider(gson.toJson(content));
|
||||
}
|
||||
}
|
||||
|
||||
if (logger.isTraceEnabled()) {
|
||||
logger.trace(">>> {} {}, data: {}", method, url, content == null ? null : gson.toJson(content));
|
||||
}
|
||||
|
||||
Request request = httpClient.newRequest(url).method(method).header(HttpHeader.CONTENT_TYPE, contentType)
|
||||
.header(HttpHeader.ACCEPT, "application/vnd.api+json").header(HttpHeader.ACCEPT_ENCODING, "gzip");
|
||||
|
||||
if (!URL_API_TOKEN.equals(url)) {
|
||||
verifyToken();
|
||||
final PostOAuth2Response token = this.token;
|
||||
if (token != null) {
|
||||
request.header("Authorization", token.tokenType + " " + token.accessToken);
|
||||
request.header("Authorization-provider", token.provider);
|
||||
}
|
||||
request.header("X-Api-Key", config.getApiKey());
|
||||
}
|
||||
|
||||
request.content(contentProvider);
|
||||
ContentResponse contentResponse = request.send();
|
||||
int status = contentResponse.getStatus();
|
||||
if (logger.isTraceEnabled()) {
|
||||
logger.trace("<<< status:{}, {}", status, contentResponse.getContentAsString());
|
||||
}
|
||||
|
||||
if (status != 200 && status != 204 && status != 201 && status != 202) {
|
||||
throw new GardenaException(String.format("Error %s %s, %s", status, contentResponse.getReason(),
|
||||
contentResponse.getContentAsString()));
|
||||
}
|
||||
|
||||
if (result == null) {
|
||||
return (T) null;
|
||||
}
|
||||
return (T) gson.fromJson(contentResponse.getContentAsString(), result);
|
||||
} catch (InterruptedException | TimeoutException | ExecutionException ex) {
|
||||
throw new GardenaException(ex.getMessage(), ex);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates or refreshes the access token for the Gardena smart system.
|
||||
*/
|
||||
private synchronized void verifyToken() throws GardenaException {
|
||||
Fields fields = new Fields();
|
||||
fields.add("client_id", config.getApiKey());
|
||||
|
||||
PostOAuth2Response token = this.token;
|
||||
if (token == null || token.isRefreshTokenExpired()) {
|
||||
// new token
|
||||
logger.debug("Gardena API login using password, reason: {}",
|
||||
token == null ? "no token available" : "refresh token expired");
|
||||
fields.add("grant_type", "password");
|
||||
fields.add("username", config.getEmail());
|
||||
fields.add("password", config.getPassword());
|
||||
token = executeRequest(HttpMethod.POST, URL_API_TOKEN, fields, PostOAuth2Response.class);
|
||||
token.postProcess();
|
||||
this.token = token;
|
||||
} else if (token.isAccessTokenExpired()) {
|
||||
// refresh token
|
||||
logger.debug("Gardena API login using refreshToken, reason: access token expired");
|
||||
fields.add("grant_type", "refresh_token");
|
||||
fields.add("refresh_token", token.refreshToken);
|
||||
try {
|
||||
PostOAuth2Response tempToken = executeRequest(HttpMethod.POST, URL_API_TOKEN, fields,
|
||||
PostOAuth2Response.class);
|
||||
token.accessToken = tempToken.accessToken;
|
||||
token.expiresIn = tempToken.expiresIn;
|
||||
token.postProcess();
|
||||
this.token = token;
|
||||
} catch (GardenaException ex) {
|
||||
// refresh token issue
|
||||
this.token = null;
|
||||
verifyToken();
|
||||
}
|
||||
} else {
|
||||
logger.debug("Gardena API token valid");
|
||||
}
|
||||
logger.debug("{}", token.toString());
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads all locations.
|
||||
*/
|
||||
private LocationsResponse loadLocations() throws GardenaException {
|
||||
return executeRequest(HttpMethod.GET, URL_API_LOCATIONS, null, LocationsResponse.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads all devices for a given location.
|
||||
*/
|
||||
private LocationResponse loadLocation(String locationId) throws GardenaException {
|
||||
return executeRequest(HttpMethod.GET, URL_API_LOCATIONS + "/" + locationId, null, LocationResponse.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the websocket url for a given location.
|
||||
*/
|
||||
private WebSocketCreatedResponse getWebsocketInfo(String locationId) throws GardenaException {
|
||||
return executeRequest(HttpMethod.POST, URL_API_WEBSOCKET, new CreateWebSocketRequest(locationId),
|
||||
WebSocketCreatedResponse.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Stops the client.
|
||||
*/
|
||||
public void dispose() {
|
||||
logger.debug("Disposing GardenaSmart");
|
||||
|
||||
final ScheduledFuture<?> newDeviceFuture = this.newDeviceFuture;
|
||||
if (newDeviceFuture != null) {
|
||||
newDeviceFuture.cancel(true);
|
||||
}
|
||||
|
||||
final ScheduledFuture<?> deviceToNotifyFuture = this.deviceToNotifyFuture;
|
||||
if (deviceToNotifyFuture != null) {
|
||||
deviceToNotifyFuture.cancel(true);
|
||||
}
|
||||
stopWebsockets();
|
||||
try {
|
||||
httpClient.stop();
|
||||
} catch (Exception e) {
|
||||
// ignore
|
||||
}
|
||||
httpClient.destroy();
|
||||
locationsResponse = new LocationsResponse();
|
||||
allDevicesById.clear();
|
||||
initialized = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Restarts all websockets.
|
||||
*/
|
||||
@Override
|
||||
public synchronized void restartWebsockets() {
|
||||
logger.debug("Restarting GardenaSmart Webservice");
|
||||
stopWebsockets();
|
||||
try {
|
||||
startWebsockets();
|
||||
} catch (Exception ex) {
|
||||
logger.warn("Restarting GardenaSmart Webservice failed: {}, restarting binding", ex.getMessage());
|
||||
eventListener.onError();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the dataItem from the websocket event into the correct device.
|
||||
*/
|
||||
private void handleDataItem(final DataItem<?> dataItem) throws GardenaException {
|
||||
final String deviceId = dataItem.getDeviceId();
|
||||
Device device = allDevicesById.get(deviceId);
|
||||
if (device == null && !(dataItem instanceof LocationDataItem)) {
|
||||
device = new Device(deviceId);
|
||||
allDevicesById.put(device.id, device);
|
||||
|
||||
if (initialized) {
|
||||
newDeviceFuture = scheduler.schedule(() -> {
|
||||
Device newDevice = allDevicesById.get(deviceId);
|
||||
if (newDevice != null) {
|
||||
newDevice.evaluateDeviceType();
|
||||
if (newDevice.deviceType != null) {
|
||||
eventListener.onNewDevice(newDevice);
|
||||
}
|
||||
}
|
||||
}, 3, TimeUnit.SECONDS);
|
||||
}
|
||||
}
|
||||
|
||||
if (device != null) {
|
||||
device.setDataItem(dataItem);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
stopRefreshThread(true);
|
||||
if (httpClient != null) {
|
||||
try {
|
||||
httpClient.stop();
|
||||
} catch (Exception e) {
|
||||
// ignore
|
||||
public void onWebSocketClose() {
|
||||
restartWebsockets();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onWebSocketError() {
|
||||
eventListener.onError();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onWebSocketMessage(String msg) {
|
||||
try {
|
||||
DataItem<?> dataItem = gson.fromJson(msg, DataItem.class);
|
||||
if (dataItem != null) {
|
||||
handleDataItem(dataItem);
|
||||
Device device = allDevicesById.get(dataItem.getDeviceId());
|
||||
if (device != null && device.active) {
|
||||
devicesToNotify.add(device);
|
||||
|
||||
// delay the deviceUpdated event to filter multiple events for the same device dataItem property
|
||||
if (deviceToNotifyFuture == null) {
|
||||
deviceToNotifyFuture = scheduler.schedule(() -> {
|
||||
deviceToNotifyFuture = null;
|
||||
Iterator<Device> notifyIterator = devicesToNotify.iterator();
|
||||
while (notifyIterator.hasNext()) {
|
||||
eventListener.onDeviceUpdated(notifyIterator.next());
|
||||
notifyIterator.remove();
|
||||
}
|
||||
}, 1, TimeUnit.SECONDS);
|
||||
}
|
||||
}
|
||||
}
|
||||
httpClient.destroy();
|
||||
} catch (GardenaException | JsonSyntaxException ex) {
|
||||
logger.warn("Ignoring message: {}", ex.getMessage());
|
||||
}
|
||||
allLocations.clear();
|
||||
allDevicesById.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* Schedules the device refresh thread.
|
||||
*/
|
||||
private void startRefreshThread() {
|
||||
refreshThreadFuture = scheduler.scheduleWithFixedDelay(refreshDevicesThread, 6, config.getRefresh(),
|
||||
TimeUnit.SECONDS);
|
||||
@Override
|
||||
public Device getDevice(String deviceId) throws GardenaDeviceNotFoundException {
|
||||
Device device = allDevicesById.get(deviceId);
|
||||
if (device == null) {
|
||||
throw new GardenaDeviceNotFoundException("Device with id " + deviceId + " not found");
|
||||
}
|
||||
return device;
|
||||
}
|
||||
|
||||
/**
|
||||
* Stops the device refresh thread.
|
||||
*/
|
||||
private void stopRefreshThread(boolean force) {
|
||||
if (refreshThreadFuture != null) {
|
||||
refreshThreadFuture.cancel(force);
|
||||
}
|
||||
@Override
|
||||
public void sendCommand(DataItem<?> dataItem, GardenaCommand gardenaCommand) throws GardenaException {
|
||||
executeRequest(HttpMethod.PUT, URL_API_COMMAND + "/" + dataItem.id, new GardenaCommandRequest(gardenaCommand),
|
||||
null);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -193,381 +389,7 @@ public class GardenaSmartImpl implements GardenaSmart {
|
|||
}
|
||||
|
||||
@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();
|
||||
}
|
||||
}
|
||||
}
|
||||
public Collection<Device> getAllDevices() {
|
||||
return allDevicesById.values();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,175 @@
|
|||
/**
|
||||
* 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.io.IOException;
|
||||
import java.net.URI;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.time.Instant;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.ScheduledFuture;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.eclipse.jetty.websocket.api.Session;
|
||||
import org.eclipse.jetty.websocket.api.annotations.*;
|
||||
import org.eclipse.jetty.websocket.api.extensions.Frame;
|
||||
import org.eclipse.jetty.websocket.client.WebSocketClient;
|
||||
import org.eclipse.jetty.websocket.common.WebSocketSession;
|
||||
import org.eclipse.jetty.websocket.common.frames.PongFrame;
|
||||
import org.openhab.binding.gardena.internal.config.GardenaConfig;
|
||||
import org.openhab.binding.gardena.internal.model.dto.api.PostOAuth2Response;
|
||||
import org.openhab.binding.gardena.internal.model.dto.api.WebSocketCreatedResponse;
|
||||
import org.openhab.core.io.net.http.WebSocketFactory;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* The {@link GardenaSmartWebSocket} implements the websocket for receiving constant updates from the Gardena smart
|
||||
* system.
|
||||
*
|
||||
* @author Gerhard Riegler - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
@WebSocket
|
||||
public class GardenaSmartWebSocket {
|
||||
private final Logger logger = LoggerFactory.getLogger(GardenaSmartWebSocket.class);
|
||||
private final GardenaSmartWebSocketListener socketEventListener;
|
||||
private final long WEBSOCKET_IDLE_TIMEOUT = 300;
|
||||
|
||||
private WebSocketSession session;
|
||||
private WebSocketClient webSocketClient;
|
||||
private boolean closing;
|
||||
private Instant lastPong = Instant.now();
|
||||
private ScheduledExecutorService scheduler;
|
||||
private @Nullable ScheduledFuture<?> connectionTracker;
|
||||
private ByteBuffer pingPayload = ByteBuffer.wrap("ping".getBytes(StandardCharsets.UTF_8));
|
||||
private @Nullable PostOAuth2Response token;
|
||||
private String socketId;
|
||||
|
||||
/**
|
||||
* Starts the websocket session.
|
||||
*/
|
||||
public GardenaSmartWebSocket(GardenaSmartWebSocketListener socketEventListener,
|
||||
WebSocketCreatedResponse webSocketCreatedResponse, GardenaConfig config, ScheduledExecutorService scheduler,
|
||||
WebSocketFactory webSocketFactory, @Nullable PostOAuth2Response token, String socketId) throws Exception {
|
||||
this.socketEventListener = socketEventListener;
|
||||
this.scheduler = scheduler;
|
||||
this.token = token;
|
||||
this.socketId = socketId;
|
||||
|
||||
webSocketClient = webSocketFactory.createWebSocketClient(socketId);
|
||||
webSocketClient.setConnectTimeout(config.getConnectionTimeout() * 1000L);
|
||||
webSocketClient.setStopTimeout(3000);
|
||||
webSocketClient.setMaxIdleTimeout(150000);
|
||||
webSocketClient.start();
|
||||
|
||||
logger.debug("Connecting to Gardena Webservice ({})", socketId);
|
||||
session = (WebSocketSession) webSocketClient
|
||||
.connect(this, new URI(webSocketCreatedResponse.data.attributes.url)).get();
|
||||
session.setStopTimeout(3000);
|
||||
}
|
||||
|
||||
/**
|
||||
* Stops the websocket session.
|
||||
*/
|
||||
public synchronized void stop() {
|
||||
closing = true;
|
||||
final ScheduledFuture<?> connectionTracker = this.connectionTracker;
|
||||
if (connectionTracker != null) {
|
||||
connectionTracker.cancel(true);
|
||||
}
|
||||
if (isRunning()) {
|
||||
logger.debug("Closing Gardena Webservice client ({})", socketId);
|
||||
try {
|
||||
session.close();
|
||||
} catch (Exception ex) {
|
||||
// ignore
|
||||
} finally {
|
||||
try {
|
||||
webSocketClient.stop();
|
||||
} catch (Exception e) {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true, if the websocket is running.
|
||||
*/
|
||||
public synchronized boolean isRunning() {
|
||||
return session.isOpen();
|
||||
}
|
||||
|
||||
@OnWebSocketConnect
|
||||
public void onConnect(Session session) {
|
||||
closing = false;
|
||||
logger.debug("Connected to Gardena Webservice ({})", socketId);
|
||||
|
||||
connectionTracker = scheduler.scheduleWithFixedDelay(this::sendKeepAlivePing, 2, 2, TimeUnit.MINUTES);
|
||||
}
|
||||
|
||||
@OnWebSocketFrame
|
||||
public void onFrame(Frame pong) {
|
||||
if (pong instanceof PongFrame) {
|
||||
lastPong = Instant.now();
|
||||
logger.trace("Pong received ({})", socketId);
|
||||
}
|
||||
}
|
||||
|
||||
@OnWebSocketClose
|
||||
public void onClose(int statusCode, String reason) {
|
||||
if (!closing) {
|
||||
logger.debug("Connection to Gardena Webservice was closed ({}): code: {}, reason: {}", socketId, statusCode,
|
||||
reason);
|
||||
socketEventListener.onWebSocketClose();
|
||||
}
|
||||
}
|
||||
|
||||
@OnWebSocketError
|
||||
public void onError(Throwable cause) {
|
||||
if (!closing) {
|
||||
logger.warn("Gardena Webservice error ({}): {}, restarting", socketId, cause.getMessage());
|
||||
logger.debug("{}", cause.getMessage(), cause);
|
||||
socketEventListener.onWebSocketError();
|
||||
}
|
||||
}
|
||||
|
||||
@OnWebSocketMessage
|
||||
public void onMessage(String msg) {
|
||||
if (!closing) {
|
||||
logger.trace("<<< event ({}): {}", socketId, msg);
|
||||
socketEventListener.onWebSocketMessage(msg);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends a ping to tell the Gardena smart system that the client is alive.
|
||||
*/
|
||||
private void sendKeepAlivePing() {
|
||||
try {
|
||||
logger.trace("Sending ping ({})", socketId);
|
||||
session.getRemote().sendPing(pingPayload);
|
||||
final PostOAuth2Response accessToken = token;
|
||||
if ((Instant.now().getEpochSecond() - lastPong.getEpochSecond() > WEBSOCKET_IDLE_TIMEOUT)
|
||||
|| accessToken == null || accessToken.isAccessTokenExpired()) {
|
||||
session.close(1000, "Timeout manually closing dead connection (" + socketId + ")");
|
||||
}
|
||||
} catch (IOException ex) {
|
||||
logger.debug("{}", ex.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
/**
|
||||
* 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;
|
||||
|
||||
/**
|
||||
* The {@link GardenaSmartWebSocketListener} is called by the {@link GardenaSmartWebSocket} on new Events and if the
|
||||
* {@link GardenaSmartWebSocket}
|
||||
* closed the connection.
|
||||
*
|
||||
* @author Gerhard Riegler - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public interface GardenaSmartWebSocketListener {
|
||||
/**
|
||||
* This method is called, when the evenRunner stops abnormally (statuscode <> 1000).
|
||||
*/
|
||||
void onWebSocketClose();
|
||||
|
||||
/**
|
||||
* This method is called when the Gardena websocket services throws an onError.
|
||||
*/
|
||||
void onWebSocketError();
|
||||
|
||||
/**
|
||||
* This method is called, whenever a new event comes from the Gardena service.
|
||||
*
|
||||
* @param msg
|
||||
*/
|
||||
void onWebSocketMessage(String msg);
|
||||
}
|
|
@ -12,30 +12,23 @@
|
|||
*/
|
||||
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;
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* The main Gardena config class.
|
||||
*
|
||||
* @author Gerhard Riegler - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
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 @Nullable String email;
|
||||
private @Nullable String password;
|
||||
private @Nullable String apiKey;
|
||||
|
||||
private transient Integer sessionTimeout = DEFAULT_SESSION_TIMEOUT;
|
||||
private transient Integer connectionTimeout = DEFAULT_CONNECTION_TIMEOUT;
|
||||
private transient Integer refresh = DEFAULT_REFRESH;
|
||||
|
||||
public GardenaConfig() {
|
||||
}
|
||||
|
@ -46,87 +39,78 @@ public class GardenaConfig {
|
|||
}
|
||||
|
||||
/**
|
||||
* Returns the email to connect to Gardena Smart Home.
|
||||
* Returns the email to connect to Gardena smart system.
|
||||
*/
|
||||
public String getEmail() {
|
||||
public @Nullable String getEmail() {
|
||||
return email;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the email to connect to Gardena Smart Home.
|
||||
* Sets the email to connect to Gardena smart system.
|
||||
*/
|
||||
public void setEmail(String email) {
|
||||
this.email = email;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the password to connect to Gardena Smart Home.
|
||||
* Returns the password to connect to Gardena smart system.
|
||||
*/
|
||||
public String getPassword() {
|
||||
public @Nullable String getPassword() {
|
||||
return password;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the password to connect to Gardena Smart Home.
|
||||
* Sets the password to connect to Gardena smart system.
|
||||
*/
|
||||
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.
|
||||
* Returns the connection timeout to Gardena smart system.
|
||||
*/
|
||||
public Integer getConnectionTimeout() {
|
||||
return connectionTimeout;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the connection timeout to Gardena Smart Home.
|
||||
* Sets the connection timeout to Gardena smart system.
|
||||
*/
|
||||
public void setConnectionTimeout(Integer connectionTimeout) {
|
||||
this.connectionTimeout = connectionTimeout;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the refresh interval to fetch new data from Gardena Smart Home.
|
||||
* Returns the api key.
|
||||
*/
|
||||
public Integer getRefresh() {
|
||||
return refresh;
|
||||
public @Nullable String getApiKey() {
|
||||
return apiKey;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the refresh interval to fetch new data from Gardena Smart Home.
|
||||
* Sets the api key.
|
||||
*/
|
||||
public void setRefresh(Integer refresh) {
|
||||
this.refresh = refresh;
|
||||
public void setApiKey(String apiKey) {
|
||||
this.apiKey = apiKey;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate the config, if at least email and password is specified.
|
||||
* Validate the config if email, password and apiKey is specified.
|
||||
*/
|
||||
public boolean isValid() {
|
||||
return StringUtils.isNotBlank(email) && StringUtils.isNotBlank(password);
|
||||
final String email = this.email;
|
||||
final String password = this.password;
|
||||
final String apiKey = this.apiKey;
|
||||
return email != null && !email.isBlank() && password != null && !password.isBlank() && apiKey != null
|
||||
&& !apiKey.isBlank();
|
||||
}
|
||||
|
||||
@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();
|
||||
StringBuilder sb = new StringBuilder(GardenaConfig.class.getSimpleName()).append("[");
|
||||
sb.append("email: ").append(email).append(", ");
|
||||
sb.append("connectionTimeout: ").append(connectionTimeout).append(", ");
|
||||
sb.append("apiKey: ").append(apiKey);
|
||||
return sb.append("]").toString();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,36 +0,0 @@
|
|||
/**
|
||||
* 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;
|
||||
}
|
||||
}
|
|
@ -1,32 +0,0 @@
|
|||
/**
|
||||
* 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);
|
||||
}
|
||||
}
|
|
@ -25,8 +25,8 @@ 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.model.dto.Device;
|
||||
import org.openhab.binding.gardena.internal.util.PropertyUtils;
|
||||
import org.openhab.binding.gardena.internal.util.UidUtils;
|
||||
import org.openhab.core.config.discovery.AbstractDiscoveryService;
|
||||
import org.openhab.core.config.discovery.DiscoveryResult;
|
||||
|
@ -41,18 +41,19 @@ import org.slf4j.Logger;
|
|||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* The {@link GardenaDeviceDiscoveryService} is used to discover devices that are connected to Gardena Smart Home.
|
||||
* The {@link GardenaDeviceDiscoveryService} is used to discover devices that are connected to Gardena smart system.
|
||||
*
|
||||
* @author Gerhard Riegler - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
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 static final int DISCOVER_TIMEOUT_SECONDS = 5;
|
||||
|
||||
private @NonNullByDefault({}) GardenaAccountHandler accountHandler;
|
||||
private Future<?> scanFuture;
|
||||
private @Nullable Future<?> scanFuture;
|
||||
|
||||
public GardenaDeviceDiscoveryService() {
|
||||
super(Collections.unmodifiableSet(Stream.of(new ThingTypeUID(BINDING_ID, "-")).collect(Collectors.toSet())),
|
||||
|
@ -94,6 +95,7 @@ public class GardenaDeviceDiscoveryService extends AbstractDiscoveryService
|
|||
@Override
|
||||
public void stopScan() {
|
||||
logger.debug("Stopping Gardena discovery scan");
|
||||
final Future<?> scanFuture = this.scanFuture;
|
||||
if (scanFuture != null) {
|
||||
scanFuture.cancel(true);
|
||||
}
|
||||
|
@ -101,18 +103,15 @@ public class GardenaDeviceDiscoveryService extends AbstractDiscoveryService
|
|||
}
|
||||
|
||||
/**
|
||||
* Starts a thread which loads all Gardena devices registered in the account
|
||||
* Starts a thread which loads all Gardena devices registered in the account.
|
||||
*/
|
||||
public void loadDevices() {
|
||||
private 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));
|
||||
}
|
||||
GardenaSmart gardena = accountHandler.getGardenaSmart();
|
||||
if (gardena != null) {
|
||||
for (Device device : gardena.getAllDevices()) {
|
||||
deviceDiscovered(device);
|
||||
}
|
||||
|
||||
for (Thing thing : accountHandler.getThing().getThings()) {
|
||||
|
@ -123,11 +122,7 @@ public class GardenaDeviceDiscoveryService extends AbstractDiscoveryService
|
|||
}
|
||||
}
|
||||
|
||||
logger.debug("Finished Gardena device discovery scan on gateway '{}'",
|
||||
accountHandler.getGardenaSmart().getId());
|
||||
} catch (GardenaException ex) {
|
||||
logger.error("{}", ex.getMessage(), ex);
|
||||
} finally {
|
||||
logger.debug("Finished Gardena device discovery scan on gateway '{}'", gardena.getId());
|
||||
scanFuture = null;
|
||||
removeOlderResults(getTimestampOfLastScan());
|
||||
}
|
||||
|
@ -141,6 +136,7 @@ public class GardenaDeviceDiscoveryService extends AbstractDiscoveryService
|
|||
* Waits for the discovery scan to finish and then returns.
|
||||
*/
|
||||
public void waitForScanFinishing() {
|
||||
final Future<?> scanFuture = this.scanFuture;
|
||||
if (scanFuture != null) {
|
||||
logger.debug("Waiting for finishing Gardena device discovery scan");
|
||||
try {
|
||||
|
@ -158,19 +154,19 @@ public class GardenaDeviceDiscoveryService extends AbstractDiscoveryService
|
|||
* Generates the DiscoveryResult from a Gardena device.
|
||||
*/
|
||||
public void deviceDiscovered(Device device) {
|
||||
ThingUID accountUID = accountHandler.getThing().getUID();
|
||||
ThingUID thingUID = UidUtils.generateThingUID(device, accountHandler.getThing());
|
||||
if (device.active) {
|
||||
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);
|
||||
try {
|
||||
DiscoveryResult discoveryResult = DiscoveryResultBuilder.create(thingUID).withBridge(accountUID)
|
||||
.withLabel(PropertyUtils.getPropertyValue(device, "common.attributes.name.value", String.class))
|
||||
.withProperty("id", device.id).withProperty("type", device.deviceType)
|
||||
.withRepresentationProperty("id").build();
|
||||
thingDiscovered(discoveryResult);
|
||||
} catch (GardenaException ex) {
|
||||
logger.warn("{}", ex.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,12 +12,15 @@
|
|||
*/
|
||||
package org.openhab.binding.gardena.internal.exception;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
|
||||
/**
|
||||
* Exception if a device is not found, this happens if a device is requested and the data from Gardena Smart Home has
|
||||
* Exception if a device is not found, this happens if a device is requested and the data from Gardena smart system has
|
||||
* not been loaded.
|
||||
*
|
||||
* @author Gerhard Riegler - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class GardenaDeviceNotFoundException extends GardenaException {
|
||||
|
||||
private static final long serialVersionUID = 2704767320916725490L;
|
||||
|
|
|
@ -14,11 +14,15 @@ package org.openhab.binding.gardena.internal.exception;
|
|||
|
||||
import java.io.IOException;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* Exception if something happens in the communication to Gardena Smart Home.
|
||||
* Exception if something happens in the communication to Gardena smart system.
|
||||
*
|
||||
* @author Gerhard Riegler - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class GardenaException extends IOException {
|
||||
|
||||
private static final long serialVersionUID = 8568935118878542270L;
|
||||
|
@ -31,7 +35,7 @@ public class GardenaException extends IOException {
|
|||
super(ex);
|
||||
}
|
||||
|
||||
public GardenaException(String message, Throwable cause) {
|
||||
public GardenaException(@Nullable String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,11 +12,14 @@
|
|||
*/
|
||||
package org.openhab.binding.gardena.internal.handler;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
|
||||
/**
|
||||
* Exception if the AccountHandler is not available.
|
||||
*
|
||||
* @author Gerhard Riegler - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class AccountHandlerNotAvailableException extends Exception {
|
||||
|
||||
private static final long serialVersionUID = -1895774551653276530L;
|
||||
|
|
|
@ -16,21 +16,19 @@ import java.util.Collection;
|
|||
import java.util.Collections;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
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.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.model.dto.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.io.net.http.HttpClientFactory;
|
||||
import org.openhab.core.io.net.http.WebSocketFactory;
|
||||
import org.openhab.core.thing.*;
|
||||
import org.openhab.core.thing.binding.BaseBridgeHandler;
|
||||
import org.openhab.core.thing.binding.ThingHandlerService;
|
||||
import org.openhab.core.types.Command;
|
||||
|
@ -39,31 +37,31 @@ 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.
|
||||
* The {@link GardenaAccountHandler} is the handler for a Gardena smart system access and connects it to the framework.
|
||||
*
|
||||
* @author Gerhard Riegler - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class GardenaAccountHandler extends BaseBridgeHandler implements GardenaSmartEventListener {
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(GardenaAccountHandler.class);
|
||||
private static final long REINITIALIZE_DELAY_SECONDS = 10;
|
||||
private final long REINITIALIZE_DELAY_SECONDS = 10;
|
||||
|
||||
private GardenaDeviceDiscoveryService discoveryService;
|
||||
private @Nullable GardenaDeviceDiscoveryService discoveryService;
|
||||
|
||||
private GardenaSmart gardenaSmart = new GardenaSmartImpl();
|
||||
private GardenaConfig gardenaConfig;
|
||||
private @Nullable GardenaSmart gardenaSmart;
|
||||
private HttpClientFactory httpClientFactory;
|
||||
private WebSocketFactory webSocketFactory;
|
||||
|
||||
public GardenaAccountHandler(Bridge bridge) {
|
||||
public GardenaAccountHandler(Bridge bridge, HttpClientFactory httpClientFactory,
|
||||
WebSocketFactory webSocketFactory) {
|
||||
super(bridge);
|
||||
this.httpClientFactory = httpClientFactory;
|
||||
this.webSocketFactory = webSocketFactory;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initialize() {
|
||||
logger.debug("Initializing Gardena account '{}'", getThing().getUID().getId());
|
||||
|
||||
gardenaConfig = getThing().getConfiguration().as(GardenaConfig.class);
|
||||
logger.debug("{}", gardenaConfig);
|
||||
|
||||
initializeGardena();
|
||||
}
|
||||
|
||||
|
@ -78,26 +76,35 @@ public class GardenaAccountHandler extends BaseBridgeHandler implements GardenaS
|
|||
final GardenaAccountHandler instance = this;
|
||||
scheduler.execute(() -> {
|
||||
try {
|
||||
GardenaConfig gardenaConfig = getThing().getConfiguration().as(GardenaConfig.class);
|
||||
logger.debug("{}", gardenaConfig);
|
||||
|
||||
String id = getThing().getUID().getId();
|
||||
gardenaSmart.init(id, gardenaConfig, instance, scheduler);
|
||||
discoveryService.startScan(null);
|
||||
discoveryService.waitForScanFinishing();
|
||||
gardenaSmart = new GardenaSmartImpl(id, gardenaConfig, instance, scheduler, httpClientFactory,
|
||||
webSocketFactory);
|
||||
final GardenaDeviceDiscoveryService discoveryService = this.discoveryService;
|
||||
if (discoveryService != null) {
|
||||
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);
|
||||
logger.warn("{}", ex.getMessage());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Schedules a reinitialization, if Gardea Smart Home account is not reachable at startup.
|
||||
* Schedules a reinitialization, if Gardena smart system account is not reachable.
|
||||
*/
|
||||
private void scheduleReinitialize() {
|
||||
scheduler.schedule(() -> {
|
||||
initializeGardena();
|
||||
if (getThing().getStatus() != ThingStatus.UNINITIALIZED) {
|
||||
initializeGardena();
|
||||
}
|
||||
}, REINITIALIZE_DELAY_SECONDS, TimeUnit.SECONDS);
|
||||
}
|
||||
|
||||
|
@ -112,16 +119,20 @@ public class GardenaAccountHandler extends BaseBridgeHandler implements GardenaS
|
|||
*/
|
||||
private void disposeGardena() {
|
||||
logger.debug("Disposing Gardena account '{}'", getThing().getUID().getId());
|
||||
|
||||
discoveryService.stopScan();
|
||||
|
||||
gardenaSmart.dispose();
|
||||
final GardenaDeviceDiscoveryService discoveryService = this.discoveryService;
|
||||
if (discoveryService != null) {
|
||||
discoveryService.stopScan();
|
||||
}
|
||||
final GardenaSmart gardenaSmart = this.gardenaSmart;
|
||||
if (gardenaSmart != null) {
|
||||
gardenaSmart.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the Gardena Smart Home implementation.
|
||||
* Returns the Gardena smart system implementation.
|
||||
*/
|
||||
public GardenaSmart getGardenaSmart() {
|
||||
public @Nullable GardenaSmart getGardenaSmart() {
|
||||
return gardenaSmart;
|
||||
}
|
||||
|
||||
|
@ -142,27 +153,27 @@ public class GardenaAccountHandler extends BaseBridgeHandler implements GardenaS
|
|||
@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());
|
||||
final Thing gardenaThing;
|
||||
final GardenaThingHandler gardenaThingHandler;
|
||||
if ((gardenaThing = getThing().getThing(thingUID)) != null
|
||||
&& (gardenaThingHandler = (GardenaThingHandler) gardenaThing.getHandler()) != null) {
|
||||
try {
|
||||
gardenaThingHandler.updateProperties(device);
|
||||
for (Channel channel : gardenaThing.getChannels()) {
|
||||
gardenaThingHandler.updateChannel(channel.getUID());
|
||||
}
|
||||
gardenaThingHandler.updateStatus(device);
|
||||
} catch (GardenaException ex) {
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, ex.getMessage());
|
||||
} catch (AccountHandlerNotAvailableException ignore) {
|
||||
}
|
||||
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) {
|
||||
final GardenaDeviceDiscoveryService discoveryService = this.discoveryService;
|
||||
if (discoveryService != null) {
|
||||
discoveryService.deviceDiscovered(device);
|
||||
}
|
||||
|
@ -170,19 +181,9 @@ public class GardenaAccountHandler extends BaseBridgeHandler implements GardenaS
|
|||
}
|
||||
|
||||
@Override
|
||||
public void onDeviceDeleted(Device device) {
|
||||
if (discoveryService != null) {
|
||||
discoveryService.deviceRemoved(device);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onConnectionLost() {
|
||||
public void onError() {
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, "Connection lost");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onConnectionResumed() {
|
||||
updateStatus(ThingStatus.ONLINE);
|
||||
disposeGardena();
|
||||
scheduleReinitialize();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,12 +12,15 @@
|
|||
*/
|
||||
package org.openhab.binding.gardena.internal.handler;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* The {@link GardenaDeviceConfig} class represents the configuration for a device connected to an Gardena account.
|
||||
*
|
||||
* @author Gerhard Riegler - Initial contribution
|
||||
*/
|
||||
|
||||
@NonNullByDefault
|
||||
public class GardenaDeviceConfig {
|
||||
public String deviceId;
|
||||
public @Nullable String deviceId;
|
||||
}
|
||||
|
|
|
@ -12,23 +12,43 @@
|
|||
*/
|
||||
package org.openhab.binding.gardena.internal.handler;
|
||||
|
||||
import static org.openhab.binding.gardena.internal.GardenaBindingConstants.*;
|
||||
import static org.openhab.binding.gardena.internal.GardenaBindingConstants.BINDING_ID;
|
||||
import static org.openhab.binding.gardena.internal.GardenaBindingConstants.THING_TYPE_ACCOUNT;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.core.i18n.TimeZoneProvider;
|
||||
import org.openhab.core.io.net.http.HttpClientFactory;
|
||||
import org.openhab.core.io.net.http.WebSocketFactory;
|
||||
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.Activate;
|
||||
import org.osgi.service.component.annotations.Component;
|
||||
import org.osgi.service.component.annotations.Reference;
|
||||
|
||||
/**
|
||||
* The {@link GardenaHandlerFactory} is responsible for creating Gardena things and thing handlers.
|
||||
*
|
||||
* @author Gerhard Riegler - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
@Component(service = ThingHandlerFactory.class, configurationPid = "binding.gardena")
|
||||
public class GardenaHandlerFactory extends BaseThingHandlerFactory {
|
||||
private HttpClientFactory httpClientFactory;
|
||||
private WebSocketFactory webSocketFactory;
|
||||
private TimeZoneProvider timeZoneProvider;
|
||||
|
||||
@Activate
|
||||
public GardenaHandlerFactory(final @Reference HttpClientFactory httpClientFactory,
|
||||
final @Reference WebSocketFactory webSocketFactory, final @Reference TimeZoneProvider timeZoneProvider) {
|
||||
this.httpClientFactory = httpClientFactory;
|
||||
this.webSocketFactory = webSocketFactory;
|
||||
this.timeZoneProvider = timeZoneProvider;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsThingType(ThingTypeUID thingTypeUID) {
|
||||
|
@ -36,11 +56,11 @@ public class GardenaHandlerFactory extends BaseThingHandlerFactory {
|
|||
}
|
||||
|
||||
@Override
|
||||
protected ThingHandler createHandler(Thing thing) {
|
||||
protected @Nullable ThingHandler createHandler(Thing thing) {
|
||||
if (THING_TYPE_ACCOUNT.equals(thing.getThingTypeUID())) {
|
||||
return new GardenaAccountHandler((Bridge) thing);
|
||||
return new GardenaAccountHandler((Bridge) thing, httpClientFactory, webSocketFactory);
|
||||
} else {
|
||||
return new GardenaThingHandler(thing);
|
||||
return new GardenaThingHandler(thing, timeZoneProvider);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,41 +13,37 @@
|
|||
package org.openhab.binding.gardena.internal.handler;
|
||||
|
||||
import static org.openhab.binding.gardena.internal.GardenaBindingConstants.*;
|
||||
import static org.openhab.binding.gardena.internal.GardenaSmartCommandName.*;
|
||||
import static org.openhab.binding.gardena.internal.model.dto.command.MowerCommand.MowerControl;
|
||||
import static org.openhab.binding.gardena.internal.model.dto.command.PowerSocketCommand.PowerSocketControl;
|
||||
import static org.openhab.binding.gardena.internal.model.dto.command.ValveCommand.ValveControl;
|
||||
import static org.openhab.binding.gardena.internal.model.dto.command.ValveSetCommand.ValveSetControl;
|
||||
|
||||
import java.time.ZoneId;
|
||||
import java.time.ZonedDateTime;
|
||||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.concurrent.ScheduledFuture;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.apache.commons.lang.ObjectUtils;
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
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.GardenaSmartCommandName;
|
||||
import org.openhab.binding.gardena.internal.GardenaSmartImpl;
|
||||
import org.openhab.binding.gardena.internal.GardenaSmartEventListener;
|
||||
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.model.dto.Device;
|
||||
import org.openhab.binding.gardena.internal.model.dto.api.DataItem;
|
||||
import org.openhab.binding.gardena.internal.model.dto.command.*;
|
||||
import org.openhab.binding.gardena.internal.util.PropertyUtils;
|
||||
import org.openhab.binding.gardena.internal.util.StringUtils;
|
||||
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.i18n.TimeZoneProvider;
|
||||
import org.openhab.core.library.types.*;
|
||||
import org.openhab.core.thing.*;
|
||||
import org.openhab.core.thing.binding.BaseThingHandler;
|
||||
import org.openhab.core.thing.binding.ThingHandler;
|
||||
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;
|
||||
|
@ -57,13 +53,15 @@ import org.slf4j.LoggerFactory;
|
|||
*
|
||||
* @author Gerhard Riegler - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
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");
|
||||
private TimeZoneProvider timeZoneProvider;
|
||||
private @Nullable ScheduledFuture<?> commandResetFuture;
|
||||
|
||||
public GardenaThingHandler(Thing thing) {
|
||||
public GardenaThingHandler(Thing thing, TimeZoneProvider timeZoneProvider) {
|
||||
super(thing);
|
||||
this.timeZoneProvider = timeZoneProvider;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -71,7 +69,6 @@ public class GardenaThingHandler extends BaseThingHandler {
|
|||
try {
|
||||
Device device = getDevice();
|
||||
updateProperties(device);
|
||||
updateSettings(device);
|
||||
updateStatus(device);
|
||||
} catch (GardenaException ex) {
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, ex.getMessage());
|
||||
|
@ -80,28 +77,13 @@ public class GardenaThingHandler extends BaseThingHandler {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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);
|
||||
}
|
||||
@Override
|
||||
public void dispose() {
|
||||
final ScheduledFuture<?> commandResetFuture = this.commandResetFuture;
|
||||
if (commandResetFuture != null) {
|
||||
commandResetFuture.cancel(true);
|
||||
}
|
||||
}
|
||||
|
||||
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()));
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -109,22 +91,15 @@ public class GardenaThingHandler extends BaseThingHandler {
|
|||
*/
|
||||
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);
|
||||
String serial = PropertyUtils.getPropertyValue(device, "common.attributes.serial.value", String.class);
|
||||
if (serial != null) {
|
||||
properties.put(PROPERTY_SERIALNUMBER, serial);
|
||||
}
|
||||
String modelType = PropertyUtils.getPropertyValue(device, "common.attributes.modelType.value", String.class);
|
||||
if (modelType != null) {
|
||||
properties.put(PROPERTY_MODELTYPE, modelType);
|
||||
}
|
||||
updateProperties(properties);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -142,177 +117,163 @@ public class GardenaThingHandler extends BaseThingHandler {
|
|||
* 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);
|
||||
String groupId = channelUID.getGroupId();
|
||||
if (groupId != null) {
|
||||
boolean isCommand = groupId.endsWith("_commands");
|
||||
if (!isCommand || (isCommand && isLocalDurationCommand(channelUID))) {
|
||||
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();
|
||||
private @Nullable State convertToState(Device device, ChannelUID channelUID) throws GardenaException {
|
||||
if (isLocalDurationCommand(channelUID)) {
|
||||
String dataItemProperty = getDeviceDataItemProperty(channelUID);
|
||||
return new DecimalType(Math.round(device.getLocalService(dataItemProperty).commandDuration / 60.0));
|
||||
}
|
||||
|
||||
String propertyPath = channelUID.getGroupId() + ".attributes.";
|
||||
String propertyName = channelUID.getIdWithoutGroup();
|
||||
|
||||
if (propertyName.endsWith("_timestamp")) {
|
||||
propertyPath += propertyName.replace("_", ".");
|
||||
} else {
|
||||
propertyPath += propertyName + ".value";
|
||||
}
|
||||
|
||||
String acceptedItemType = null;
|
||||
try {
|
||||
String value = device.getAbility(abilityName).getProperty(propertyName).getValueAsString();
|
||||
Channel channel = getThing().getChannel(channelUID.getId());
|
||||
if (channel != null) {
|
||||
acceptedItemType = StringUtils.substringBefore(channel.getAcceptedItemType(), ":");
|
||||
|
||||
if (StringUtils.trimToNull(value) == null || StringUtils.equals(value, "N/A")) {
|
||||
return UnDefType.NULL;
|
||||
}
|
||||
if (acceptedItemType != null) {
|
||||
boolean isNullPropertyValue = PropertyUtils.isNull(device, propertyPath);
|
||||
boolean isDurationProperty = "duration".equals(propertyName);
|
||||
|
||||
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 {
|
||||
if (isNullPropertyValue && !isDurationProperty) {
|
||||
return UnDefType.NULL;
|
||||
}
|
||||
switch (acceptedItemType) {
|
||||
case "String":
|
||||
return new StringType(PropertyUtils.getPropertyValue(device, propertyPath, String.class));
|
||||
case "Number":
|
||||
if (isNullPropertyValue) {
|
||||
return new DecimalType(0);
|
||||
} else {
|
||||
Number value = PropertyUtils.getPropertyValue(device, propertyPath, Number.class);
|
||||
// convert duration from seconds to minutes
|
||||
if (value != null) {
|
||||
if (isDurationProperty) {
|
||||
value = Math.round(value.longValue() / 60.0);
|
||||
}
|
||||
return new DecimalType(value.longValue());
|
||||
}
|
||||
return UnDefType.NULL;
|
||||
}
|
||||
case "DateTime":
|
||||
Date date = PropertyUtils.getPropertyValue(device, propertyPath, Date.class);
|
||||
if (date != null) {
|
||||
ZonedDateTime zdt = ZonedDateTime.ofInstant(date.toInstant(),
|
||||
timeZoneProvider.getTimeZone());
|
||||
return new DateTimeType(zdt);
|
||||
}
|
||||
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();
|
||||
logger.warn("Channel '{}' cannot be updated as device does not contain propertyPath '{}'", channelUID,
|
||||
propertyPath);
|
||||
} catch (ClassCastException ex) {
|
||||
logger.warn("Value of propertyPath '{}' can not be casted to {}: {}", propertyPath, acceptedItemType,
|
||||
ex.getMessage());
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleCommand(ChannelUID channelUID, Command command) {
|
||||
logger.debug("Command received: {}", command);
|
||||
try {
|
||||
GardenaSmartCommandName commandName = getCommandName(channelUID);
|
||||
logger.debug("Received Gardena command: {}", commandName);
|
||||
|
||||
boolean isOnCommand = command instanceof OnOffType && ((OnOffType) command) == OnOffType.ON;
|
||||
String dataItemProperty = getDeviceDataItemProperty(channelUID);
|
||||
if (RefreshType.REFRESH == command) {
|
||||
logger.debug("Refreshing channel '{}'", channelUID);
|
||||
if (commandName != null && commandName.toString().startsWith("MEASURE_")) {
|
||||
getGardenaSmart().sendCommand(getDevice(), commandName, null);
|
||||
logger.debug("Refreshing Gardena connection");
|
||||
getGardenaSmart().restartWebsockets();
|
||||
} else if (isLocalDurationCommand(channelUID)) {
|
||||
QuantityType<?> quantityType = (QuantityType<?>) command;
|
||||
getDevice().getLocalService(dataItemProperty).commandDuration = quantityType.intValue() * 60;
|
||||
} else if (isOnCommand) {
|
||||
GardenaCommand gardenaCommand = getGardenaCommand(dataItemProperty, channelUID);
|
||||
logger.debug("Received Gardena command: {}, {}", gardenaCommand.getClass().getSimpleName(),
|
||||
gardenaCommand.attributes.command);
|
||||
|
||||
DataItem<?> dataItem = PropertyUtils.getPropertyValue(getDevice(), dataItemProperty, DataItem.class);
|
||||
if (dataItem == null) {
|
||||
logger.warn("DataItem {} is empty, ignoring command.", dataItemProperty);
|
||||
} else {
|
||||
updateChannel(channelUID);
|
||||
getGardenaSmart().sendCommand(dataItem, gardenaCommand);
|
||||
|
||||
commandResetFuture = scheduler.schedule(() -> {
|
||||
updateState(channelUID, OnOffType.OFF);
|
||||
}, 3, TimeUnit.SECONDS);
|
||||
}
|
||||
} else if (commandName != null) {
|
||||
getGardenaSmart().sendCommand(getDevice(), commandName, convertFromType(command));
|
||||
}
|
||||
} catch (AccountHandlerNotAvailableException | GardenaDeviceNotFoundException ex) {
|
||||
// ignore
|
||||
} catch (Exception ex) {
|
||||
logger.warn("{}", ex.getMessage(), ex);
|
||||
logger.warn("{}", ex.getMessage());
|
||||
final Bridge bridge;
|
||||
final ThingHandler handler;
|
||||
if ((bridge = getBridge()) != null && (handler = bridge.getHandler()) != null) {
|
||||
((GardenaSmartEventListener) handler).onError();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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;
|
||||
private GardenaCommand getGardenaCommand(String dataItemProperty, ChannelUID channelUID)
|
||||
throws GardenaException, AccountHandlerNotAvailableException {
|
||||
String commandName = channelUID.getIdWithoutGroup().toUpperCase();
|
||||
String groupId = channelUID.getGroupId();
|
||||
if (groupId != null) {
|
||||
if (groupId.startsWith("valve") && groupId.endsWith("_commands")) {
|
||||
return new ValveCommand(ValveControl.valueOf(commandName),
|
||||
getDevice().getLocalService(dataItemProperty).commandDuration);
|
||||
} else if ("mower_commands".equals(groupId)) {
|
||||
return new MowerCommand(MowerControl.valueOf(commandName),
|
||||
getDevice().getLocalService(dataItemProperty).commandDuration);
|
||||
} else if ("valveSet_commands".equals(groupId)) {
|
||||
return new ValveSetCommand(ValveSetControl.valueOf(commandName));
|
||||
} else if ("powerSocket_commands".equals(groupId)) {
|
||||
return new PowerSocketCommand(PowerSocketControl.valueOf(commandName),
|
||||
getDevice().getLocalService(dataItemProperty).commandDuration);
|
||||
}
|
||||
}
|
||||
throw new GardenaException("Command " + channelUID.getId() + " not found or groupId 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) {
|
||||
if (!CONNECTION_STATUS_ONLINE.equals(device.common.attributes.rfLinkState.value)) {
|
||||
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) {
|
||||
|
@ -320,32 +281,22 @@ public class GardenaThingHandler extends BaseThingHandler {
|
|||
}
|
||||
}
|
||||
|
||||
@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 device property for the dataItem from the channel.
|
||||
*/
|
||||
private String getDeviceDataItemProperty(ChannelUID channelUID) throws GardenaException {
|
||||
String dataItemProperty = StringUtils.substringBeforeLast(channelUID.getGroupId(), "_");
|
||||
if (dataItemProperty != null) {
|
||||
return dataItemProperty;
|
||||
}
|
||||
throw new GardenaException("Can't extract dataItemProperty from channel group " + channelUID.getGroupId());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true, if the channel is the duration command.
|
||||
*/
|
||||
private boolean isLocalDurationCommand(ChannelUID channelUID) {
|
||||
return "commandDuration".equals(channelUID.getIdWithoutGroup());
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -356,17 +307,20 @@ public class GardenaThingHandler extends BaseThingHandler {
|
|||
}
|
||||
|
||||
/**
|
||||
* Returns the Gardena Smart Home implementation if the bridge is available.
|
||||
* Returns the Gardena smart system 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);
|
||||
final Bridge bridge;
|
||||
final ThingHandler handler;
|
||||
if ((bridge = getBridge()) != null && (handler = bridge.getHandler()) != null) {
|
||||
final GardenaSmart gardenaSmart = ((GardenaAccountHandler) handler).getGardenaSmart();
|
||||
if (gardenaSmart != null) {
|
||||
return gardenaSmart;
|
||||
}
|
||||
throw new AccountHandlerNotAvailableException("Gardena AccountHandler not yet available!");
|
||||
}
|
||||
|
||||
return ((GardenaAccountHandler) getBridge().getHandler()).getGardenaSmart();
|
||||
if (thing.getStatus() != ThingStatus.INITIALIZING) {
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.HANDLER_MISSING_ERROR);
|
||||
}
|
||||
throw new AccountHandlerNotAvailableException("Gardena AccountHandler not yet available!");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,87 +0,0 @@
|
|||
/**
|
||||
* 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;
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.binding.gardena.internal.exception.GardenaException;
|
||||
import org.openhab.binding.gardena.internal.model.dto.api.DataItem;
|
||||
|
||||
import com.google.gson.*;
|
||||
|
||||
/**
|
||||
* Custom deserializer for Gardena DataItems.
|
||||
*
|
||||
* @author Gerhard Riegler - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class DataItemDeserializer implements JsonDeserializer<DataItem<?>> {
|
||||
private static Gson gson = new GsonBuilder().create();
|
||||
|
||||
@Override
|
||||
public @Nullable DataItem<?> deserialize(JsonElement element, Type type, JsonDeserializationContext ctx)
|
||||
throws JsonParseException {
|
||||
try {
|
||||
JsonObject jsonObj = element.getAsJsonObject();
|
||||
return gson.fromJson(element, DataItemFactory.create(jsonObj.get("type").getAsString()));
|
||||
} catch (GardenaException ex) {
|
||||
throw new JsonParseException(ex.getMessage(), ex);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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.model;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.binding.gardena.internal.exception.GardenaException;
|
||||
import org.openhab.binding.gardena.internal.model.dto.api.*;
|
||||
|
||||
/**
|
||||
* Creates the dataItem object based on the device type.
|
||||
*
|
||||
* @author Gerhard Riegler - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class DataItemFactory {
|
||||
public static Class<? extends DataItem<?>> create(String type) throws GardenaException {
|
||||
switch (type) {
|
||||
case "LOCATION":
|
||||
return LocationDataItem.class;
|
||||
case "DEVICE":
|
||||
return DeviceDataItem.class;
|
||||
case "COMMON":
|
||||
return CommonServiceDataItem.class;
|
||||
case "MOWER":
|
||||
return MowerServiceDataItem.class;
|
||||
case "POWER_SOCKET":
|
||||
return PowerSocketServiceDataItem.class;
|
||||
case "VALVE":
|
||||
return ValveServiceDataItem.class;
|
||||
case "VALVE_SET":
|
||||
return ValveSetServiceDataItem.class;
|
||||
case "SENSOR":
|
||||
return SensorServiceDataItem.class;
|
||||
default:
|
||||
throw new GardenaException("Unknown DataItem type: " + type);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,147 +0,0 @@
|
|||
/**
|
||||
* 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();
|
||||
}
|
||||
}
|
|
@ -1,63 +0,0 @@
|
|||
/**
|
||||
* 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();
|
||||
}
|
||||
}
|
|
@ -1,45 +0,0 @@
|
|||
/**
|
||||
* 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();
|
||||
}
|
||||
}
|
|
@ -1,69 +0,0 @@
|
|||
/**
|
||||
* 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();
|
||||
}
|
||||
}
|
|
@ -1,117 +0,0 @@
|
|||
/**
|
||||
* 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;
|
||||
}
|
||||
}
|
|
@ -1,43 +0,0 @@
|
|||
/**
|
||||
* 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;
|
||||
}
|
||||
}
|
|
@ -1,40 +0,0 @@
|
|||
/**
|
||||
* 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;
|
||||
}
|
||||
}
|
|
@ -1,75 +0,0 @@
|
|||
/**
|
||||
* 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;
|
||||
}
|
||||
}
|
|
@ -1,54 +0,0 @@
|
|||
/**
|
||||
* 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;
|
||||
}
|
||||
}
|
|
@ -1,56 +0,0 @@
|
|||
/**
|
||||
* 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;
|
||||
}
|
||||
}
|
|
@ -1,46 +0,0 @@
|
|||
/**
|
||||
* 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;
|
||||
}
|
||||
}
|
|
@ -1,68 +0,0 @@
|
|||
/**
|
||||
* 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;
|
||||
}
|
||||
}
|
|
@ -1,94 +0,0 @@
|
|||
/**
|
||||
* 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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,29 +0,0 @@
|
|||
/**
|
||||
* 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);
|
||||
}
|
||||
}
|
|
@ -1,27 +0,0 @@
|
|||
/**
|
||||
* 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);
|
||||
}
|
||||
}
|
|
@ -1,27 +0,0 @@
|
|||
/**
|
||||
* 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);
|
||||
}
|
||||
}
|
|
@ -1,27 +0,0 @@
|
|||
/**
|
||||
* 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);
|
||||
}
|
||||
}
|
|
@ -1,58 +0,0 @@
|
|||
/**
|
||||
* 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;
|
||||
}
|
||||
}
|
|
@ -1,36 +0,0 @@
|
|||
/**
|
||||
* 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;
|
||||
}
|
||||
}
|
|
@ -1,30 +0,0 @@
|
|||
/**
|
||||
* 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");
|
||||
}
|
||||
}
|
|
@ -1,36 +0,0 @@
|
|||
/**
|
||||
* 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());
|
||||
}
|
||||
}
|
|
@ -1,70 +0,0 @@
|
|||
/**
|
||||
* 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());
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,161 @@
|
|||
/**
|
||||
* 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.dto;
|
||||
|
||||
import static org.openhab.binding.gardena.internal.GardenaBindingConstants.*;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.openhab.binding.gardena.internal.exception.GardenaException;
|
||||
import org.openhab.binding.gardena.internal.model.dto.api.*;
|
||||
import org.openhab.binding.gardena.internal.util.StringUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* Represents a Gardena device.
|
||||
*
|
||||
* @author Gerhard Riegler - Initial contribution
|
||||
*/
|
||||
public class Device {
|
||||
private final Logger logger = LoggerFactory.getLogger(Device.class);
|
||||
|
||||
private transient static final String DEVICE_TYPE_PREFIX = "gardena smart";
|
||||
public boolean active = true;
|
||||
public String id;
|
||||
public String deviceType;
|
||||
public String location;
|
||||
public CommonServiceDataItem common;
|
||||
public MowerServiceDataItem mower;
|
||||
public PowerSocketServiceDataItem powerSocket;
|
||||
public SensorServiceDataItem sensor;
|
||||
public ValveServiceDataItem valve;
|
||||
public ValveServiceDataItem valveOne;
|
||||
public ValveServiceDataItem valveTwo;
|
||||
public ValveServiceDataItem valveThree;
|
||||
public ValveServiceDataItem valveFour;
|
||||
public ValveServiceDataItem valveFive;
|
||||
public ValveServiceDataItem valveSix;
|
||||
public ValveSetServiceDataItem valveSet;
|
||||
|
||||
private Map<String, LocalService> localServices = new HashMap<>();
|
||||
|
||||
public Device(String id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the local service or creates one if it does not exist.
|
||||
*/
|
||||
public LocalService getLocalService(String key) {
|
||||
LocalService localService = localServices.get(key);
|
||||
if (localService == null) {
|
||||
localService = new LocalService();
|
||||
localServices.put(key, localService);
|
||||
localService.commandDuration = 3600;
|
||||
}
|
||||
return localService;
|
||||
}
|
||||
|
||||
/**
|
||||
* Evaluates the device type.
|
||||
*/
|
||||
public void evaluateDeviceType() {
|
||||
if (deviceType == null) {
|
||||
if (common.attributes.modelType.value.toLowerCase().startsWith(DEVICE_TYPE_PREFIX)) {
|
||||
String modelType = common.attributes.modelType.value.toLowerCase();
|
||||
modelType = modelType.substring(14);
|
||||
deviceType = modelType.replace(" ", "_");
|
||||
} else {
|
||||
// workaround: we have to guess the device type, valves cannot be identified if modeType is wrong
|
||||
if (mower != null) {
|
||||
deviceType = DEVICE_TYPE_MOWER;
|
||||
} else if (powerSocket != null) {
|
||||
deviceType = DEVICE_TYPE_POWER;
|
||||
} else if (sensor != null) {
|
||||
deviceType = DEVICE_TYPE_SENSOR;
|
||||
}
|
||||
}
|
||||
if (deviceType == null) {
|
||||
logger.warn("Can't identify device with id {}, wrong modelType sent from the Gardena API", id);
|
||||
active = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Assigns the dataItem to the corresponding property.
|
||||
*/
|
||||
public void setDataItem(DataItem<?> dataItem) throws GardenaException {
|
||||
if (dataItem instanceof DeviceDataItem) {
|
||||
// ignore
|
||||
} else if (dataItem instanceof LocationDataItem) {
|
||||
LocationDataItem locationDataItem = (LocationDataItem) dataItem;
|
||||
if (locationDataItem.attributes != null) {
|
||||
location = locationDataItem.attributes.name;
|
||||
}
|
||||
} else if (dataItem instanceof CommonServiceDataItem) {
|
||||
common = (CommonServiceDataItem) dataItem;
|
||||
} else if (dataItem instanceof MowerServiceDataItem) {
|
||||
mower = (MowerServiceDataItem) dataItem;
|
||||
} else if (dataItem instanceof PowerSocketServiceDataItem) {
|
||||
powerSocket = (PowerSocketServiceDataItem) dataItem;
|
||||
} else if (dataItem instanceof SensorServiceDataItem) {
|
||||
sensor = (SensorServiceDataItem) dataItem;
|
||||
} else if (dataItem instanceof ValveSetServiceDataItem) {
|
||||
valveSet = (ValveSetServiceDataItem) dataItem;
|
||||
} else if (dataItem instanceof ValveServiceDataItem) {
|
||||
String valveNumber = StringUtils.substringAfterLast(dataItem.id, ":");
|
||||
if (valveNumber != null
|
||||
&& (valveNumber.equals("") || valveNumber.equals("wc") || valveNumber.equals("0"))) {
|
||||
valve = (ValveServiceDataItem) dataItem;
|
||||
} else if ("1".equals(valveNumber)) {
|
||||
valveOne = (ValveServiceDataItem) dataItem;
|
||||
} else if ("2".equals(valveNumber)) {
|
||||
valveTwo = (ValveServiceDataItem) dataItem;
|
||||
} else if ("3".equals(valveNumber)) {
|
||||
valveThree = (ValveServiceDataItem) dataItem;
|
||||
} else if ("4".equals(valveNumber)) {
|
||||
valveFour = (ValveServiceDataItem) dataItem;
|
||||
} else if ("5".equals(valveNumber)) {
|
||||
valveFive = (ValveServiceDataItem) dataItem;
|
||||
} else if ("6".equals(valveNumber)) {
|
||||
valveSix = (ValveServiceDataItem) dataItem;
|
||||
} else {
|
||||
throw new GardenaException("Unknown valveNumber in dataItem with id: " + dataItem.id);
|
||||
}
|
||||
} else {
|
||||
throw new GardenaException("Unknown dataItem with id: " + dataItem.id);
|
||||
}
|
||||
|
||||
if (common != null && common.attributes != null) {
|
||||
common.attributes.lastUpdate.timestamp = new Date();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return id.hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (obj == null || !(obj instanceof Device)) {
|
||||
return false;
|
||||
}
|
||||
Device comp = (Device) obj;
|
||||
return comp.id.equals(id);
|
||||
}
|
||||
}
|
|
@ -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.model.dto;
|
||||
|
||||
/**
|
||||
* A local service exists only in openHAB and the state is not saved on restarts.
|
||||
*
|
||||
* @author Gerhard Riegler - Initial contribution
|
||||
*/
|
||||
|
||||
public class LocalService {
|
||||
public Integer commandDuration;
|
||||
}
|
|
@ -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.dto.api;
|
||||
|
||||
/**
|
||||
* Represents a Gardena object that is sent via the Gardena API.
|
||||
*
|
||||
* @author Gerhard Riegler - Initial contribution
|
||||
*/
|
||||
public class CommonService {
|
||||
public UserDefinedNameWrapper name;
|
||||
public TimestampedIntegerValue batteryLevel;
|
||||
public TimestampedStringValue batteryState;
|
||||
public TimestampedIntegerValue rfLinkLevel;
|
||||
public StringValue serial;
|
||||
public StringValue modelType;
|
||||
public TimestampedStringValue rfLinkState;
|
||||
public TimestampValue lastUpdate = new TimestampValue();
|
||||
}
|
|
@ -10,18 +10,13 @@
|
|||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.gardena.internal.model.command;
|
||||
package org.openhab.binding.gardena.internal.model.dto.api;
|
||||
|
||||
/**
|
||||
* Sensor command to measure the light.
|
||||
* Represents a Gardena object that is sent via the Gardena API.
|
||||
*
|
||||
* @author Gerhard Riegler - Initial contribution
|
||||
*/
|
||||
|
||||
public class SensorMeasureLightCommand extends Command {
|
||||
private static final String COMMAND = "measure_light";
|
||||
|
||||
public SensorMeasureLightCommand() {
|
||||
super(COMMAND);
|
||||
}
|
||||
public class CommonServiceDataItem extends DataItem<CommonService> {
|
||||
}
|
|
@ -10,18 +10,14 @@
|
|||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.gardena.internal.model.command;
|
||||
package org.openhab.binding.gardena.internal.model.dto.api;
|
||||
|
||||
/**
|
||||
* Command to cancel the manual watering.
|
||||
* Represents a Gardena object that is sent via the Gardena API.
|
||||
*
|
||||
* @author Gerhard Riegler - Initial contribution
|
||||
*/
|
||||
|
||||
public class WateringCancelOverrideCommand extends Command {
|
||||
private static final String COMMAND = "cancel_override";
|
||||
|
||||
public WateringCancelOverrideCommand() {
|
||||
super(COMMAND);
|
||||
}
|
||||
public class CreateWebSocket {
|
||||
public String locationId;
|
||||
}
|
|
@ -10,18 +10,13 @@
|
|||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.gardena.internal.model.command;
|
||||
package org.openhab.binding.gardena.internal.model.dto.api;
|
||||
|
||||
/**
|
||||
* Command to resume the mower scheduler.
|
||||
* Represents a Gardena object that is sent via the Gardena API.
|
||||
*
|
||||
* @author Gerhard Riegler - Initial contribution
|
||||
*/
|
||||
|
||||
public class MowerStartResumeScheduleCommand extends Command {
|
||||
private static final String COMMAND = "start_resume_schedule";
|
||||
|
||||
public MowerStartResumeScheduleCommand() {
|
||||
super(COMMAND);
|
||||
}
|
||||
public class CreateWebSocketDataItem extends DataItem<CreateWebSocket> {
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
/**
|
||||
* 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.dto.api;
|
||||
|
||||
/**
|
||||
* Represents a Gardena object that is sent via the Gardena API.
|
||||
*
|
||||
* @author Gerhard Riegler - Initial contribution
|
||||
*/
|
||||
|
||||
public class CreateWebSocketRequest {
|
||||
public CreateWebSocketDataItem data;
|
||||
|
||||
public CreateWebSocketRequest(String locationId) {
|
||||
data = new CreateWebSocketDataItem();
|
||||
data.id = "wsreq-" + locationId;
|
||||
data.type = "WEBSOCKET";
|
||||
data.attributes = new CreateWebSocket();
|
||||
data.attributes.locationId = locationId;
|
||||
}
|
||||
}
|
|
@ -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.model.dto.api;
|
||||
|
||||
import org.openhab.binding.gardena.internal.util.StringUtils;
|
||||
|
||||
/**
|
||||
* Represents a Gardena object that is sent via the Gardena API.
|
||||
*
|
||||
* @author Gerhard Riegler - Initial contribution
|
||||
*/
|
||||
|
||||
public class DataItem<T> {
|
||||
public String id;
|
||||
public String type;
|
||||
|
||||
public String getDeviceId() {
|
||||
return StringUtils.substringBeforeLast(id, ":");
|
||||
}
|
||||
|
||||
public T attributes;
|
||||
}
|
|
@ -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.dto.api;
|
||||
|
||||
/**
|
||||
* Represents a Gardena object that is sent via the Gardena API.
|
||||
*
|
||||
* @author Gerhard Riegler - Initial contribution
|
||||
*/
|
||||
|
||||
public class DeviceDataItem extends DataItem<Void> {
|
||||
}
|
|
@ -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.model.dto.api;
|
||||
|
||||
/**
|
||||
* Represents a Gardena object that is sent via the Gardena API.
|
||||
*
|
||||
* @author Gerhard Riegler - Initial contribution
|
||||
*/
|
||||
|
||||
public class IntegerValue {
|
||||
public Integer value;
|
||||
}
|
|
@ -10,13 +10,14 @@
|
|||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.gardena.internal.model;
|
||||
package org.openhab.binding.gardena.internal.model.dto.api;
|
||||
|
||||
/**
|
||||
* Empty class that represents a emtpy result from Gardena Smart Home.
|
||||
* Represents a Gardena object that is sent via the Gardena API.
|
||||
*
|
||||
* @author Gerhard Riegler - Initial contribution
|
||||
*/
|
||||
public class NoResult {
|
||||
|
||||
public class Location {
|
||||
public String name;
|
||||
}
|
|
@ -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.dto.api;
|
||||
|
||||
/**
|
||||
* Represents a Gardena object that is sent via the Gardena API.
|
||||
*
|
||||
* @author Gerhard Riegler - Initial contribution
|
||||
*/
|
||||
|
||||
public class LocationDataItem extends DataItem<Location> {
|
||||
}
|
|
@ -10,24 +10,17 @@
|
|||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.gardena.internal.model;
|
||||
package org.openhab.binding.gardena.internal.model.dto.api;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Represents a List of Gardena devices.
|
||||
* Represents a Gardena object that is sent via the Gardena API.
|
||||
*
|
||||
* @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;
|
||||
}
|
||||
public class LocationResponse {
|
||||
public LocationDataItem data;
|
||||
public List<DataItem<?>> included;
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.gardena.internal.model.dto.api;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Represents a Gardena object that is sent via the Gardena API.
|
||||
*
|
||||
* @author Gerhard Riegler - Initial contribution
|
||||
*/
|
||||
|
||||
public class LocationsResponse {
|
||||
public List<LocationDataItem> data;
|
||||
}
|
|
@ -10,18 +10,17 @@
|
|||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.gardena.internal.exception;
|
||||
package org.openhab.binding.gardena.internal.model.dto.api;
|
||||
|
||||
/**
|
||||
* Exception for invalid user and password.
|
||||
* Represents a Gardena object that is sent via the Gardena API.
|
||||
*
|
||||
* @author Gerhard Riegler - Initial contribution
|
||||
*/
|
||||
public class GardenaUnauthorizedException extends GardenaException {
|
||||
|
||||
private static final long serialVersionUID = 4343137351443555679L;
|
||||
|
||||
public GardenaUnauthorizedException(Throwable ex) {
|
||||
super(ex);
|
||||
}
|
||||
public class MowerService {
|
||||
public TimestampedStringValue state;
|
||||
public TimestampedStringValue activity;
|
||||
public TimestampedStringValue lastErrorCode;
|
||||
public IntegerValue operatingHours;
|
||||
}
|
|
@ -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.dto.api;
|
||||
|
||||
/**
|
||||
* Represents a Gardena object that is sent via the Gardena API.
|
||||
*
|
||||
* @author Gerhard Riegler - Initial contribution
|
||||
*/
|
||||
|
||||
public class MowerServiceDataItem extends DataItem<MowerService> {
|
||||
}
|
|
@ -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.model.dto.api;
|
||||
|
||||
import java.time.Instant;
|
||||
import java.time.ZoneId;
|
||||
import java.time.ZonedDateTime;
|
||||
import java.time.temporal.ChronoUnit;
|
||||
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
|
||||
/**
|
||||
* Represents a Gardena object that is sent via the Gardena API.
|
||||
*
|
||||
* @author Gerhard Riegler - Initial contribution
|
||||
*/
|
||||
public class PostOAuth2Response {
|
||||
// refresh token is valid 10 days
|
||||
private transient Instant refreshTokenValidity = Instant.now().plus(10, ChronoUnit.DAYS).minus(1,
|
||||
ChronoUnit.MINUTES);
|
||||
private transient Instant accessTokenValidity;
|
||||
|
||||
@SerializedName("access_token")
|
||||
public String accessToken;
|
||||
|
||||
// The scope of the token (what you are allowed to do)
|
||||
public String scope;
|
||||
|
||||
// The expire time in seconds for the access token
|
||||
@SerializedName("expires_in")
|
||||
public Integer expiresIn;
|
||||
|
||||
@SerializedName("refresh_token")
|
||||
public String refreshToken;
|
||||
|
||||
public String provider;
|
||||
|
||||
@SerializedName("user_id")
|
||||
public String userId;
|
||||
|
||||
@SerializedName("token_type")
|
||||
public String tokenType;
|
||||
|
||||
public void postProcess() {
|
||||
accessTokenValidity = Instant.now().plus(expiresIn - 10, ChronoUnit.SECONDS);
|
||||
}
|
||||
|
||||
public boolean isAccessTokenExpired() {
|
||||
return Instant.now().isAfter(accessTokenValidity);
|
||||
}
|
||||
|
||||
public boolean isRefreshTokenExpired() {
|
||||
return Instant.now().isAfter(refreshTokenValidity);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Token expiration: accessToken: " + ZonedDateTime.ofInstant(accessTokenValidity, ZoneId.systemDefault())
|
||||
+ ", refreshToken: " + ZonedDateTime.ofInstant(refreshTokenValidity, ZoneId.systemDefault());
|
||||
}
|
||||
}
|
|
@ -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.dto.api;
|
||||
|
||||
/**
|
||||
* Represents a Gardena object that is sent via the Gardena API.
|
||||
*
|
||||
* @author Gerhard Riegler - Initial contribution
|
||||
*/
|
||||
|
||||
public class PowerSocketService {
|
||||
public TimestampedStringValue activity;
|
||||
public TimestampedStringValue state;
|
||||
public TimestampedStringValue lastErrorCode;
|
||||
public TimestampedIntegerValue duration;
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
/**
|
||||
* 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.dto.api;
|
||||
|
||||
/**
|
||||
* Represents a Gardena object that is sent via the Gardena API.
|
||||
*
|
||||
* @author Gerhard Riegler - Initial contribution
|
||||
*/
|
||||
public class PowerSocketServiceDataItem extends DataItem<PowerSocketService> {
|
||||
}
|
|
@ -10,17 +10,16 @@
|
|||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.gardena.internal.model.command;
|
||||
package org.openhab.binding.gardena.internal.model.dto.api;
|
||||
|
||||
/**
|
||||
* Command to park a mower until further notice.
|
||||
* Represents a Gardena object that is sent via the Gardena API.
|
||||
*
|
||||
* @author Gerhard Riegler - Initial contribution
|
||||
*/
|
||||
public class MowerParkUntilFurtherNoticeCommand extends Command {
|
||||
private static final String COMMAND = "park_until_further_notice";
|
||||
|
||||
public MowerParkUntilFurtherNoticeCommand() {
|
||||
super(COMMAND);
|
||||
}
|
||||
public class SensorService {
|
||||
public TimestampedIntegerValue soilHumidity;
|
||||
public TimestampedIntegerValue soilTemperature;
|
||||
public TimestampedIntegerValue ambientTemperature;
|
||||
public TimestampedIntegerValue lightIntensity;
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
/**
|
||||
* 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.dto.api;
|
||||
|
||||
/**
|
||||
* Represents a Gardena object that is sent via the Gardena API.
|
||||
*
|
||||
* @author Gerhard Riegler - Initial contribution
|
||||
*/
|
||||
public class SensorServiceDataItem extends DataItem<SensorService> {
|
||||
}
|
|
@ -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.dto.api;
|
||||
|
||||
/**
|
||||
* Represents a Gardena object that is sent via the Gardena API.
|
||||
*
|
||||
* @author Gerhard Riegler - Initial contribution
|
||||
*/
|
||||
public class StringValue {
|
||||
public String value;
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
/**
|
||||
* 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.dto.api;
|
||||
|
||||
/**
|
||||
* Represents a Gardena object that is sent via the Gardena API.
|
||||
*
|
||||
* @author Gerhard Riegler - Initial contribution
|
||||
*/
|
||||
public class TimestampValue extends TimestampedAttribute {
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
/**
|
||||
* 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.dto.api;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* Represents a Gardena object that is sent via the Gardena API.
|
||||
*
|
||||
* @author Gerhard Riegler - Initial contribution
|
||||
*/
|
||||
public abstract class TimestampedAttribute {
|
||||
public Date timestamp;
|
||||
}
|
|
@ -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.dto.api;
|
||||
|
||||
/**
|
||||
* Represents a Gardena object that is sent via the Gardena API.
|
||||
*
|
||||
* @author Gerhard Riegler - Initial contribution
|
||||
*/
|
||||
public class TimestampedIntegerValue extends TimestampedAttribute {
|
||||
public Integer value;
|
||||
}
|
|
@ -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.dto.api;
|
||||
|
||||
/**
|
||||
* Represents a Gardena object that is sent via the Gardena API.
|
||||
*
|
||||
* @author Gerhard Riegler - Initial contribution
|
||||
*/
|
||||
public class TimestampedStringValue extends TimestampedAttribute {
|
||||
public String value;
|
||||
}
|
|
@ -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.dto.api;
|
||||
|
||||
/**
|
||||
* Represents a Gardena object that is sent via the Gardena API.
|
||||
*
|
||||
* @author Gerhard Riegler - Initial contribution
|
||||
*/
|
||||
public class UserDefinedNameWrapper {
|
||||
public String value;
|
||||
}
|
|
@ -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.dto.api;
|
||||
|
||||
/**
|
||||
* Represents a Gardena object that is sent via the Gardena API.
|
||||
*
|
||||
* @author Gerhard Riegler - Initial contribution
|
||||
*/
|
||||
public class ValveService {
|
||||
public UserDefinedNameWrapper name;
|
||||
public TimestampedStringValue activity;
|
||||
public TimestampedStringValue state;
|
||||
public TimestampedStringValue lastErrorCode;
|
||||
public TimestampedIntegerValue duration;
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
/**
|
||||
* 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.dto.api;
|
||||
|
||||
/**
|
||||
* Represents a Gardena object that is sent via the Gardena API.
|
||||
*
|
||||
* @author Gerhard Riegler - Initial contribution
|
||||
*/
|
||||
public class ValveServiceDataItem extends DataItem<ValveService> {
|
||||
}
|
|
@ -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.model.dto.api;
|
||||
|
||||
/**
|
||||
* Represents a Gardena object that is sent via the Gardena API.
|
||||
*
|
||||
* @author Gerhard Riegler - Initial contribution
|
||||
*/
|
||||
public class ValveSetService {
|
||||
public TimestampedStringValue state;
|
||||
public TimestampedStringValue lastErrorCode;
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
/**
|
||||
* 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.dto.api;
|
||||
|
||||
/**
|
||||
* Represents a Gardena object that is sent via the Gardena API.
|
||||
*
|
||||
* @author Gerhard Riegler - Initial contribution
|
||||
*/
|
||||
public class ValveSetServiceDataItem extends DataItem<ValveSetService> {
|
||||
}
|
|
@ -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.model.dto.api;
|
||||
|
||||
/**
|
||||
* Represents a Gardena object that is sent via the Gardena API.
|
||||
*
|
||||
* @author Gerhard Riegler - Initial contribution
|
||||
*/
|
||||
public class WebSocket {
|
||||
public Integer validity;
|
||||
public String url;
|
||||
}
|
|
@ -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.dto.api;
|
||||
|
||||
/**
|
||||
* Represents a Gardena object that is sent via the Gardena API.
|
||||
*
|
||||
* @author Gerhard Riegler - Initial contribution
|
||||
*/
|
||||
public class WebSocketCreatedResponse {
|
||||
public WebSocketDataItem data;
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
/**
|
||||
* 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.dto.api;
|
||||
|
||||
/**
|
||||
* Represents a Gardena object that is sent via the Gardena API.
|
||||
*
|
||||
* @author Gerhard Riegler - Initial contribution
|
||||
*/
|
||||
public class WebSocketDataItem extends DataItem<WebSocket> {
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
/**
|
||||
* 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.dto.command;
|
||||
|
||||
/**
|
||||
* Represents a Gardena command object to send to the Gardena API.
|
||||
*
|
||||
* @author Gerhard Riegler - Initial contribution
|
||||
*/
|
||||
public abstract class GardenaCommand {
|
||||
public String id;
|
||||
public String type;
|
||||
public GardenaCommandAttributes attributes;
|
||||
}
|
|
@ -10,24 +10,19 @@
|
|||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.gardena.internal.model;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
package org.openhab.binding.gardena.internal.model.dto.command;
|
||||
|
||||
/**
|
||||
* Represents a List of Gardena locations.
|
||||
* Represents a Gardena command object that is sent to the Gardena API.
|
||||
*
|
||||
* @author Gerhard Riegler - Initial contribution
|
||||
*/
|
||||
public class Locations {
|
||||
public class GardenaCommandAttributes {
|
||||
public String command;
|
||||
public Integer seconds;
|
||||
|
||||
private List<Location> locations = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* Returns a list of Gardena locations.
|
||||
*/
|
||||
public List<Location> getLocations() {
|
||||
return locations;
|
||||
public GardenaCommandAttributes(String command, Integer seconds) {
|
||||
this.command = command;
|
||||
this.seconds = seconds;
|
||||
}
|
||||
}
|
|
@ -10,18 +10,17 @@
|
|||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.gardena.internal.model.command;
|
||||
package org.openhab.binding.gardena.internal.model.dto.command;
|
||||
|
||||
/**
|
||||
* Command to park a mower until next timer.
|
||||
* Represents a Gardena command object that is sent to the Gardena API.
|
||||
*
|
||||
* @author Gerhard Riegler - Initial contribution
|
||||
*/
|
||||
public class GardenaCommandRequest {
|
||||
public GardenaCommand data;
|
||||
|
||||
public class MowerParkUntilNextTimerCommand extends Command {
|
||||
private static final String COMMAND = "park_until_next_timer";
|
||||
|
||||
public MowerParkUntilNextTimerCommand() {
|
||||
super(COMMAND);
|
||||
public GardenaCommandRequest(GardenaCommand gardenaCommand) {
|
||||
this.data = gardenaCommand;
|
||||
}
|
||||
}
|
|
@ -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.dto.command;
|
||||
|
||||
/**
|
||||
* Represents a Gardena command object that is sent to the Gardena API.
|
||||
*
|
||||
* @author Gerhard Riegler - Initial contribution
|
||||
*/
|
||||
public class MowerCommand extends GardenaCommand {
|
||||
private static final String COMMAND_TYPE = "MOWER_CONTROL";
|
||||
|
||||
public enum MowerControl {
|
||||
START_SECONDS_TO_OVERRIDE,
|
||||
START_DONT_OVERRIDE,
|
||||
PARK_UNTIL_NEXT_TASK,
|
||||
PARK_UNTIL_FURTHER_NOTICE
|
||||
}
|
||||
|
||||
public MowerCommand(MowerControl mowerControl, Integer seconds) {
|
||||
this.id = "mcid";
|
||||
this.type = COMMAND_TYPE;
|
||||
this.attributes = new GardenaCommandAttributes(mowerControl.name(), seconds);
|
||||
}
|
||||
}
|
|
@ -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.dto.command;
|
||||
|
||||
/**
|
||||
* Represents a Gardena command object that is sent to the Gardena API.
|
||||
*
|
||||
* @author Gerhard Riegler - Initial contribution
|
||||
*/
|
||||
public class PowerSocketCommand extends GardenaCommand {
|
||||
private static final String COMMAND_TYPE = "POWER_SOCKET_CONTROL";
|
||||
|
||||
public enum PowerSocketControl {
|
||||
START_SECONDS_TO_OVERRIDE,
|
||||
START_OVERRIDE,
|
||||
STOP_UNTIL_NEXT_TASK,
|
||||
PAUSE,
|
||||
UNPAUSE
|
||||
}
|
||||
|
||||
public PowerSocketCommand(PowerSocketControl powerSocketControl, Integer seconds) {
|
||||
this.id = "pscid";
|
||||
this.type = COMMAND_TYPE;
|
||||
this.attributes = new GardenaCommandAttributes(powerSocketControl.name(), seconds);
|
||||
}
|
||||
}
|
|
@ -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.dto.command;
|
||||
|
||||
/**
|
||||
* Represents a Gardena command object that is sent to the Gardena API.
|
||||
*
|
||||
* @author Gerhard Riegler - Initial contribution
|
||||
*/
|
||||
public class ValveCommand extends GardenaCommand {
|
||||
private static final String COMMAND_TYPE = "VALVE_CONTROL";
|
||||
|
||||
public static enum ValveControl {
|
||||
START_SECONDS_TO_OVERRIDE,
|
||||
STOP_UNTIL_NEXT_TASK,
|
||||
PAUSE,
|
||||
UNPAUSE
|
||||
}
|
||||
|
||||
public ValveCommand(ValveControl valveControl, Integer seconds) {
|
||||
this.id = "vcid";
|
||||
this.type = COMMAND_TYPE;
|
||||
this.attributes = new GardenaCommandAttributes(valveControl.name(), seconds);
|
||||
}
|
||||
}
|
|
@ -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.model.dto.command;
|
||||
|
||||
/**
|
||||
* Represents a Gardena command object that is sent to the Gardena API.
|
||||
*
|
||||
* @author Gerhard Riegler - Initial contribution
|
||||
*/
|
||||
public class ValveSetCommand extends GardenaCommand {
|
||||
private static final String COMMAND_TYPE = "VALVE_SET_CONTROL";
|
||||
|
||||
public enum ValveSetControl {
|
||||
STOP_UNTIL_NEXT_TASK
|
||||
}
|
||||
|
||||
public ValveSetCommand(ValveSetControl valveSetControl) {
|
||||
this.id = "vscid";
|
||||
this.type = COMMAND_TYPE;
|
||||
this.attributes = new GardenaCommandAttributes(valveSetControl.name(), null);
|
||||
}
|
||||
}
|
|
@ -1,38 +0,0 @@
|
|||
/**
|
||||
* 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();
|
||||
}
|
|
@ -1,46 +0,0 @@
|
|||
/**
|
||||
* 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;
|
||||
}
|
||||
}
|
|
@ -1,46 +0,0 @@
|
|||
/**
|
||||
* 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;
|
||||
}
|
||||
}
|
|
@ -1,35 +0,0 @@
|
|||
/**
|
||||
* 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;
|
||||
}
|
||||
}
|
|
@ -1,75 +0,0 @@
|
|||
/**
|
||||
* 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;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,66 @@
|
|||
/**
|
||||
* 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.lang.reflect.Field;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.binding.gardena.internal.exception.GardenaException;
|
||||
|
||||
/**
|
||||
* Utility class to read nested properties.
|
||||
*
|
||||
* @author Gerhard Riegler - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class PropertyUtils {
|
||||
|
||||
/**
|
||||
* Returns true if the property is null.
|
||||
*/
|
||||
public static boolean isNull(@Nullable Object instance, String propertyPath) throws GardenaException {
|
||||
return getPropertyValue(instance, propertyPath, Object.class) == null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the property value from the object instance, nested properties are possible.
|
||||
*/
|
||||
public static <T> @Nullable T getPropertyValue(@Nullable Object instance, String propertyPath, Class<T> resultClass)
|
||||
throws GardenaException {
|
||||
String[] properties = propertyPath.split("\\.");
|
||||
return getPropertyValue(instance, properties, resultClass, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Iterates through the nested properties and returns the field value.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
private static <T> @Nullable T getPropertyValue(@Nullable Object instance, String[] properties,
|
||||
Class<T> resultClass, int nestedIndex) throws GardenaException {
|
||||
if (instance == null) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
String propertyName = properties[nestedIndex];
|
||||
Field field = instance.getClass().getField(propertyName);
|
||||
Object result = field.get(instance);
|
||||
if (nestedIndex + 1 < properties.length) {
|
||||
return getPropertyValue(result, properties, resultClass, nestedIndex + 1);
|
||||
}
|
||||
return (T) result;
|
||||
} catch (NoSuchFieldException | SecurityException | IllegalArgumentException | IllegalAccessException ex) {
|
||||
throw new GardenaException(ex.getMessage(), ex);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,60 @@
|
|||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.gardena.internal.util;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* Some String operations from commons lang.
|
||||
*
|
||||
* @author Gerhard Riegler - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class StringUtils {
|
||||
/**
|
||||
* Gets the substring before the first occurrence of a separator.
|
||||
*/
|
||||
public static @Nullable String substringBefore(@Nullable String str, String separator) {
|
||||
if (str != null && !str.isEmpty()) {
|
||||
int pos = str.indexOf(separator);
|
||||
return pos == -1 ? str : str.substring(0, pos);
|
||||
} else {
|
||||
return str;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the substring before the last occurrence of a separator.
|
||||
*/
|
||||
public static @Nullable String substringBeforeLast(@Nullable String str, String separator) {
|
||||
if (str != null && !str.isEmpty()) {
|
||||
int pos = str.lastIndexOf(separator);
|
||||
return pos == -1 ? str : str.substring(0, pos);
|
||||
} else {
|
||||
return str;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the substring after the last occurrence of a separator.
|
||||
*/
|
||||
public static @Nullable String substringAfterLast(@Nullable String str, String separator) {
|
||||
if (str != null && !str.isEmpty()) {
|
||||
int pos = str.lastIndexOf(separator);
|
||||
return pos != -1 && pos != str.length() - separator.length() ? str.substring(pos + separator.length()) : "";
|
||||
} else {
|
||||
return str;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -17,8 +17,9 @@ import static org.openhab.binding.gardena.internal.GardenaBindingConstants.BINDI
|
|||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.binding.gardena.internal.handler.GardenaDeviceConfig;
|
||||
import org.openhab.binding.gardena.internal.model.Device;
|
||||
import org.openhab.binding.gardena.internal.model.dto.Device;
|
||||
import org.openhab.core.thing.Bridge;
|
||||
import org.openhab.core.thing.Thing;
|
||||
import org.openhab.core.thing.ThingTypeUID;
|
||||
|
@ -29,14 +30,15 @@ import org.openhab.core.thing.ThingUID;
|
|||
*
|
||||
* @author Gerhard Riegler - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
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());
|
||||
ThingTypeUID thingTypeUID = new ThingTypeUID(BINDING_ID, device.deviceType);
|
||||
return new ThingUID(thingTypeUID, account.getUID(), device.id);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -49,7 +51,7 @@ public class UidUtils {
|
|||
if (deviceId == null) {
|
||||
deviceId = thing.getUID().getId();
|
||||
}
|
||||
if (deviceId.equals(device.getId())) {
|
||||
if (deviceId.equals(device.id)) {
|
||||
thingUIDs.add(thing.getUID());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,6 +3,6 @@
|
|||
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>
|
||||
<name>Gardena Smart System Binding</name>
|
||||
<description>This is the binding for Gardena smart system.</description>
|
||||
</binding:binding>
|
||||
|
|
|
@ -1,462 +1,287 @@
|
|||
# binding
|
||||
binding.gardena.description=Das ist das Binding für Gardena Smart Home Produkte.
|
||||
binding.gardena.description=Das ist das Binding für Gardena Smart System.
|
||||
|
||||
# thing types
|
||||
thing-type.gardena.bridge.description=ein Gardena Smart Home Online Account
|
||||
thing-type.gardena.bridge.description=Ein Gardena Smart System 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.email.description=Email-Addresse für den Gardena Smart System Login
|
||||
thing-type.config.gardena.bridge.password.label=Passwort
|
||||
thing-type.config.gardena.bridge.password.description=Passwort für den Gardena Smart System Login
|
||||
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.config.gardena.bridge.connectionTimeout.description=Timeout des Verbindungsaufbaus zum Gardena Smart System in Sekunden
|
||||
thing-type.config.gardena.bridge.apiKey.description=Der Gardena Smart System Integrations API Schlüssel
|
||||
|
||||
thing-type.gardena.mower.label=Gardena Smart Sileno Mäher
|
||||
thing-type.gardena.mower.description=ein Gardena Smart Sileno Mäher
|
||||
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.water_control.label=Gardena Smart Bewässerungscomputer
|
||||
thing-type.gardena.water_control.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.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.pump.label=Gardena Smart Druckpumpe
|
||||
thing-type.gardena.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.power.description=Ein Gardena Smart Power Zwischenstecker
|
||||
|
||||
thing-type.gardena.ic24.label=Gardena Smart Bewässerungssteuerung
|
||||
thing-type.gardena.ic24.description=Eine Gardena Smart Bewässerungssteuerung
|
||||
thing-type.gardena.irrigation_control.label=Gardena Smart Bewässerungssteuerung
|
||||
thing-type.gardena.irrigation_control.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
|
||||
thing-type.gardena.irrigation_control.group.valveOne.label=Ventil 1 Eigenschaften
|
||||
thing-type.gardena.irrigation_control.group.valveOne_commands.label=Ventil 1 Befehle
|
||||
thing-type.gardena.irrigation_control.group.valveTwo.label=Ventil 2 Eigenschaften
|
||||
thing-type.gardena.irrigation_control.group.valveTwo_commands.label=Ventil 2 Befehle
|
||||
thing-type.gardena.irrigation_control.group.valveThree.label=Ventil 3 Eigenschaften
|
||||
thing-type.gardena.irrigation_control.group.valveThree_commands.label=Ventil 3 Befehle
|
||||
thing-type.gardena.irrigation_control.group.valveFour.label=Ventil 4 Eigenschaften
|
||||
thing-type.gardena.irrigation_control.group.valveFour_commands.label=Ventil 4 Befehle
|
||||
thing-type.gardena.irrigation_control.group.valveFive.label=Ventil 5 Eigenschaften
|
||||
thing-type.gardena.irrigation_control.group.valveFive_commands.label=Ventil 5 Befehle
|
||||
thing-type.gardena.irrigation_control.group.valveSix.label=Ventil 6 Eigenschaften
|
||||
thing-type.gardena.irrigation_control.group.valveSix_commands.label=Ventil 6 Befehle
|
||||
|
||||
# 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.valveSetProperties.label=Ventilsatz Eigenschaften
|
||||
channel-group-type.gardena.valveSetProperties.description=Eigenschaften eines Ventilsatzes
|
||||
|
||||
channel-group-type.gardena.rechargeableBattery.label=Wiederaufladbare Batterie Info
|
||||
channel-group-type.gardena.rechargeableBattery.description=Informationen über die wiederaufladbare Batterie
|
||||
channel-group-type.gardena.valveSetProperties.channel.state_timestamp.label=Status Zeitstempel
|
||||
channel-group-type.gardena.valveSetProperties.channel.lastErrorCode_timestamp.label=Letzte Fehlermeldung Zeitstempel
|
||||
|
||||
channel-group-type.gardena.radio.label=Funkverbindung
|
||||
channel-group-type.gardena.radio.description=Informationen über die Funkverbindung
|
||||
channel-group-type.gardena.valveProperties.label=Ventil Eigenschaften
|
||||
channel-group-type.gardena.valveProperties.description=Eigenschaften eines Ventils
|
||||
channel-group-type.gardena.valveProperties.channel.state_timestamp.label=Status Zeitstempel
|
||||
channel-group-type.gardena.valveProperties.channel.activity_timestamp.label=Aktivität Zeitstempel
|
||||
channel-group-type.gardena.valveProperties.channel.lastErrorCode_timestamp.label=Letzte Fehlermeldung Zeitstempel
|
||||
|
||||
channel-group-type.gardena.mower.label=Mähroboter
|
||||
channel-group-type.gardena.mower.description=Informationen über den Mähroboter
|
||||
channel-group-type.gardena.sensorProperties.label=Sensor Eigenschaften
|
||||
channel-group-type.gardena.sensorProperties.description=Eigenschaften eines Sensors
|
||||
channel-group-type.gardena.sensorProperties.channel.soilHumidity_timestamp.label=Bodenfeuchtigkeit Zeitstempel
|
||||
channel-group-type.gardena.sensorProperties.channel.soilTemperature.label=Bodentemperatur
|
||||
channel-group-type.gardena.sensorProperties.channel.soilTemperature_timestamp.label=Bodentemperatur Zeitstempel
|
||||
channel-group-type.gardena.sensorProperties.channel.ambientTemperature.label=Umgebungstemperatur
|
||||
channel-group-type.gardena.sensorProperties.channel.ambientTemperature_timestamp.label=Umgebungstemperatur Zeitstempel
|
||||
channel-group-type.gardena.sensorProperties.channel.lightIntensity_timestamp.label=Lichtintensität Zeitstempel
|
||||
|
||||
channel-group-type.gardena.internalTemperature.label=Interne Temperatur
|
||||
channel-group-type.gardena.internalTemperature.description=Die interne Temperatur des Mähroboters
|
||||
channel-group-type.gardena.powerSocketProperties.label=Zwischenstecker Eigenschaften
|
||||
channel-group-type.gardena.powerSocketProperties.description=Eigenschaften eines Zwischensteckers
|
||||
channel-group-type.gardena.powerSocketProperties.channel.state_timestamp.label=Status Zeitstempel
|
||||
channel-group-type.gardena.powerSocketProperties.channel.activity_timestamp.label=Aktivität Zeitstempel
|
||||
channel-group-type.gardena.powerSocketProperties.channel.lastErrorCode_timestamp.label=Letzte Fehlermeldung Zeitstempel
|
||||
channel-group-type.gardena.powerSocketProperties.channel.duration_timestamp.label=Dauer Zeitstempel
|
||||
|
||||
channel-group-type.gardena.battery.label=Batterieinfo
|
||||
channel-group-type.gardena.battery.description=Informationen über die Batterie
|
||||
channel-group-type.gardena.mowerProperties.label=Mäher Eigenschaften
|
||||
channel-group-type.gardena.mowerProperties.description=Eigenschaften eines Mähers
|
||||
channel-group-type.gardena.mowerProperties.channel.state_timestamp.label=Status Zeitstempel
|
||||
channel-group-type.gardena.mowerProperties.channel.activity_timestamp.label=Aktivität Zeitstempel
|
||||
channel-group-type.gardena.mowerProperties.channel.lastErrorCode_timestamp.label=Letzte Fehlermeldung Zeitstempel
|
||||
|
||||
channel-group-type.gardena.outlet.label=Wasserauslass
|
||||
channel-group-type.gardena.outlet.description=Informationen über den Wasserauslass
|
||||
channel-group-type.gardena.commonProperties.label=Gemeinsame Eigenschaften
|
||||
channel-group-type.gardena.commonProperties.description=Eigenschaften, die bei allen Geräten gleich sind
|
||||
channel-group-type.gardena.commonProperties.channel.batteryLevel_timestamp.label=Batterie Zeitstempel
|
||||
channel-group-type.gardena.commonProperties.channel.batteryState_timestamp.label=Batteriestatus Zeitstempel
|
||||
channel-group-type.gardena.commonProperties.channel.rfLinkLevel_timestamp.label=Signalstärke Zeitstempel
|
||||
channel-group-type.gardena.commonProperties.channel.rfLinkState_timestamp.label=Verbindungsstatus Zeitstempel
|
||||
channel-group-type.gardena.commonProperties.channel.lastUpdate_timestamp.label=Letzte Aktualisierung Zeitstempel
|
||||
|
||||
channel-group-type.gardena.ambientTemperature.label=Umgebungstemperatur
|
||||
channel-group-type.gardena.ambientTemperature.description=Informationen über die Umgebungstemperatur
|
||||
channel-group-type.gardena.mowerCommands.label=Mäher Befehle
|
||||
channel-group-type.gardena.mowerCommands.description=Befehle für einen Mäher
|
||||
channel-group-type.gardena.mowerCommands.channel.commandDuration.label=Mähdauer
|
||||
channel-group-type.gardena.mowerCommands.channel.start_seconds_to_override.label=Starte Mähen mit Dauer
|
||||
channel-group-type.gardena.mowerCommands.channel.start_seconds_to_override.description=Manueller Betrieb, verwendet Mähdauer um die Dauer zu definieren
|
||||
channel-group-type.gardena.mowerCommands.channel.start_dont_override.label=Zeitplan Starten
|
||||
channel-group-type.gardena.mowerCommands.channel.start_dont_override.description=Automatischer Betrieb
|
||||
channel-group-type.gardena.mowerCommands.channel.park_until_next_task.label=Parken
|
||||
channel-group-type.gardena.mowerCommands.channel.park_until_next_task.description=Abbruch der aktuellen Operation und Rückkehr zur Ladestation
|
||||
channel-group-type.gardena.mowerCommands.channel.park_until_further_notice.label=Zeitplan Pausieren
|
||||
channel-group-type.gardena.mowerCommands.channel.park_until_further_notice.description=Abbruch der aktuellen Operation, Rückkehr zur Ladestation, Zeitplan ignorieren
|
||||
|
||||
channel-group-type.gardena.soilTemperature.label=Bodentemperatur
|
||||
channel-group-type.gardena.soilTemperature.description=Die Temperatur des Bodens
|
||||
channel-group-type.gardena.valveCommands.label=Ventil Befehle
|
||||
channel-group-type.gardena.valveCommands.description=Befehle für ein Ventil
|
||||
channel-group-type.gardena.valveCommands.channel.commandDuration.label=Bewässerungsdauer
|
||||
channel-group-type.gardena.valveCommands.channel.start_seconds_to_override.label=Starte Bewässerung mit Dauer
|
||||
channel-group-type.gardena.valveCommands.channel.start_seconds_to_override.description=Manueller Betrieb, verwendet Bewässerunsdauer um die Dauer zu definieren
|
||||
channel-group-type.gardena.valveCommands.channel.stop_until_next_task.label=Ventil Schließen, Zeitplan Fortfahren
|
||||
channel-group-type.gardena.valveCommands.channel.stop_until_next_task.description=Die aktuelle Bewässerung abbrechen, mit dem Zeitplan fortfahren
|
||||
channel-group-type.gardena.valveCommands.channel.pause.label=Pause bis zur angegebenen Zeit
|
||||
channel-group-type.gardena.valveCommands.channel.pause.description=Den Automatikbetrieb bis zur angegebenen Zeit überspringen. Der derzeit aktive Vorgang kann abgebrochen werden oder auch nicht (abhängig vom Gerätemodell)
|
||||
channel-group-type.gardena.valveCommands.channel.unpause.label=Zeitplan Starten
|
||||
channel-group-type.gardena.valveCommands.channel.unpause.description=Wiederherstellen des automatischen Betriebs, wenn er angehalten wurde
|
||||
|
||||
channel-group-type.gardena.humidity.label=Feuchtigkeit
|
||||
channel-group-type.gardena.humidity.description=Die Feuchtigkeit
|
||||
channel-group-type.gardena.valveSetCommands.label=Ventilsatz Befehle
|
||||
channel-group-type.gardena.valveSetCommands.description=Befehle für einen Ventilsatz
|
||||
channel-group-type.gardena.valveSetCommands.channel.stop_until_next_task.label=Alle Ventile Schließen
|
||||
channel-group-type.gardena.valveSetCommands.channel.stop_until_next_task.description=Alle Ventile sofort schließen
|
||||
|
||||
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-group-type.gardena.powerSocketCommands.label=Zwischenstecker Befehle
|
||||
channel-group-type.gardena.powerSocketCommands.description=Befehle für einen Zwischenstecker
|
||||
channel-group-type.gardena.powerSocketCommands.channel.commandDuration.label=Einschaltdauer
|
||||
channel-group-type.gardena.powerSocketCommands.channel.start_seconds_to_override.label=Einschalten mit Dauer
|
||||
channel-group-type.gardena.powerSocketCommands.channel.start_seconds_to_override.description=Manueller Betrieb, verwendet Einschaltdauer um die Dauer zu definieren
|
||||
channel-group-type.gardena.powerSocketCommands.channel.start_override.label=Manuelles Einschalten
|
||||
channel-group-type.gardena.powerSocketCommands.channel.start_override.description=Manuelles Ein
|
||||
channel-group-type.gardena.powerSocketCommands.channel.stop_until_next_task.label=Aus, Weiter mit Zeitplan
|
||||
channel-group-type.gardena.powerSocketCommands.channel.stop_until_next_task.description=Sofort abschalten, mit dem Zeitplan fortfahren
|
||||
channel-group-type.gardena.powerSocketCommands.channel.pause.label=Pause bis zur angegebenen Zeit
|
||||
channel-group-type.gardena.powerSocketCommands.channel.pause.description=Automatischen Betrieb bis zur angegebenen Zeit überspringen. Die derzeit aktive Operation wird NICHT abgebrochen
|
||||
channel-group-type.gardena.powerSocketCommands.channel.unpause.label=Zeitplan Starten
|
||||
channel-group-type.gardena.powerSocketCommands.channel.unpause.description=Wiederherstellen des automatischen Betriebs, wenn er angehalten wurde
|
||||
|
||||
# channel types
|
||||
channel-type.gardena.mowerDurationProperty.label=Mähdauer
|
||||
channel-type.gardena.mowerDurationProperty.description=Mähdauer in Minuten
|
||||
channel-type.gardena.gardenaCommand.label=Befehl
|
||||
channel-type.gardena.gardenaCommand.description=Ein Befehl für ein Gerät
|
||||
|
||||
channel-type.gardena.parkUntilFurtherNotice.label=Parken und pausieren
|
||||
channel-type.gardena.parkUntilFurtherNotice.description=Parken und alle Zeitpläne pausieren
|
||||
channel-type.gardena.powerCommandDuration.label=Einschaltdauer
|
||||
channel-type.gardena.powerCommandDuration.description=Die Einschaltdauer in Minuten
|
||||
|
||||
channel-type.gardena.parkUntilNextTimer.label=Parken
|
||||
channel-type.gardena.parkUntilNextTimer.description=Bis zum nächsten regulären Zeitplan parken
|
||||
channel-type.gardena.valveCommandDuration.label=Einschaltdauer
|
||||
channel-type.gardena.valveCommandDuration.description=Die Einschaltdauer in Minuten
|
||||
|
||||
channel-type.gardena.startResumeSchedule.label=Zeitpläne fortsetzen
|
||||
channel-type.gardena.startResumeSchedule.description=Alle Zeitpläne werden fortgesetze
|
||||
channel-type.gardena.mowerCommandDuration.label=Einschaltdauer
|
||||
channel-type.gardena.mowerCommandDuration.description=Die Einschaltdauer in Minuten
|
||||
|
||||
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.state.label=Status
|
||||
channel-type.gardena.state.description=Der Gerätestatus
|
||||
|
||||
channel-type.gardena.lastTimeOnline.label=Zuletzt online
|
||||
channel-type.gardena.lastTimeOnline.description=Die Zeit wann das Gerät zuletzt online war
|
||||
channel-type.gardena.state.option.WARNING=Warnung
|
||||
channel-type.gardena.state.state.option.ERROR=Fehler
|
||||
channel-type.gardena.state.state.option.UNAVAILABLE=Nicht verfügbar
|
||||
|
||||
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.lastErrorCode.label=Letzte Fehlermeldung
|
||||
channel-type.gardena.lastErrorCode.description=Die letzte Fehlermeldung
|
||||
|
||||
channel-type.gardena.charging.label=Batterie wird geladen
|
||||
channel-type.gardena.charging.description=Batterie wird geladen
|
||||
channel-type.gardena.lastErrorCode.state.option.UNKNOWN=Unbekannt
|
||||
channel-type.gardena.lastErrorCode.state.option.NO_MESSAGE=Kein Fehler
|
||||
channel-type.gardena.lastErrorCode.state.option.OUTSIDE_WORKING_AREA=Außerhalb des Arbeitsbereichs
|
||||
channel-type.gardena.lastErrorCode.state.option.NO_LOOP_SIGNAL=Kein Schleifensignal
|
||||
channel-type.gardena.lastErrorCode.state.option.WRONG_LOOP_SIGNAL=Falsches Schleifensignal
|
||||
channel-type.gardena.lastErrorCode.state.option.LOOP_SENSOR_PROBLEM_FRONT=Problem Schleifensensor, vorne
|
||||
channel-type.gardena.lastErrorCode.state.option.LOOP_SENSOR_PROBLEM_REAR=Problem Schleifensensor, hinten
|
||||
channel-type.gardena.lastErrorCode.state.option.LOOP_SENSOR_PROBLEM_LEFT=Problem Schleifensensor, links
|
||||
channel-type.gardena.lastErrorCode.state.option.LOOP_SENSOR_PROBLEM_RIGHT=Problem Schleifensensor, rechts
|
||||
channel-type.gardena.lastErrorCode.state.option.WRONG_PIN_CODE=Falscher PIN Code
|
||||
channel-type.gardena.lastErrorCode.state.option.TRAPPED=Eingeschlossen
|
||||
channel-type.gardena.lastErrorCode.state.option.UPSIDE_DOWN=Steht auf dem Kopf
|
||||
channel-type.gardena.lastErrorCode.state.option.EMPTY_BATTERY=Leere Batteriestand
|
||||
channel-type.gardena.lastErrorCode.state.option.NO_DRIVE=Kein Antrieb
|
||||
channel-type.gardena.lastErrorCode.state.option.TEMPORARILY_LIFTED=Vorübergehend angehoben
|
||||
channel-type.gardena.lastErrorCode.state.option.LIFTED=Angehoben
|
||||
channel-type.gardena.lastErrorCode.state.option.STUCK_IN_CHARGING_STATION=In Ladestation eingeklemmt
|
||||
channel-type.gardena.lastErrorCode.state.option.CHARGING_STATION_BLOCKED=Ladestation blockiert
|
||||
channel-type.gardena.lastErrorCode.state.option.COLLISION_SENSOR_PROBLEM_REAR=Problem Stoßsensor hinten
|
||||
channel-type.gardena.lastErrorCode.state.option.COLLISION_SENSOR_PROBLEM_FRONT=Problem Stoßsensor vorne
|
||||
channel-type.gardena.lastErrorCode.state.option.WHEEL_MOTOR_BLOCKED_RIGHT=Radmotor rechts blockiert
|
||||
channel-type.gardena.lastErrorCode.state.option.WHEEL_MOTOR_BLOCKED_LEFT=Radmotor links blockiert
|
||||
channel-type.gardena.lastErrorCode.state.option.WHEEL_DRIVE_PROBLEM_RIGHT=Problem Antrieb, rechts
|
||||
channel-type.gardena.lastErrorCode.state.option.WHEEL_DRIVE_PROBLEM_LEFT=Problem Antrieb, links
|
||||
channel-type.gardena.lastErrorCode.state.option.CUTTING_MOTOR_DRIVE_DEFECT=Schneidmotorantrieb defekt
|
||||
channel-type.gardena.lastErrorCode.state.option.CUTTING_SYSTEM_BLOCKED=Schneidsystem blockiert
|
||||
channel-type.gardena.lastErrorCode.state.option.INVALID_SUB_DEVICE_COMBINATION=Fehlerhafte Verbindung
|
||||
channel-type.gardena.lastErrorCode.state.option.MEMORY_CIRCUIT_PROBLEM=Speicherschaltkreisproblem
|
||||
channel-type.gardena.lastErrorCode.state.option.CHARGING_SYSTEM_PROBLEM=Problem Ladesystem
|
||||
channel-type.gardena.lastErrorCode.state.option.STOP_BUTTON_PROBLEM=Stop button Problem
|
||||
channel-type.gardena.lastErrorCode.state.option.TILT_SENSOR_PROBLEM=Kippsensorproblem
|
||||
channel-type.gardena.lastErrorCode.state.option.MOWER_TILTED=Mäher gekippt
|
||||
channel-type.gardena.lastErrorCode.state.option.WHEEL_MOTOR_OVERLOADED_RIGHT=Rechter Radmotor überlastet
|
||||
channel-type.gardena.lastErrorCode.state.option.WHEEL_MOTOR_OVERLOADED_LEFT=Linker Radmotor überlastet
|
||||
channel-type.gardena.lastErrorCode.state.option.CHARGING_CURRENT_TOO_HIGH=Ladestrom zu hoch
|
||||
channel-type.gardena.lastErrorCode.state.option.ELECTRONIC_PROBLEM=Elektronisches Problem
|
||||
channel-type.gardena.lastErrorCode.state.option.CUTTING_MOTOR_PROBLEM=Schneidmotorisches Problem
|
||||
channel-type.gardena.lastErrorCode.state.option.LIMITED_CUTTING_HEIGHT_RANGE=Begrenzter Schneidhöhenbereich
|
||||
channel-type.gardena.lastErrorCode.state.option.CUTTING_HEIGHT_PROBLEM_DRIVE=Schnitthöhenproblem Antrieb
|
||||
channel-type.gardena.lastErrorCode.state.option.CUTTING_HEIGHT_PROBLEM_CURR=Schnitthöhenproblem
|
||||
channel-type.gardena.lastErrorCode.state.option.CUTTING_HEIGHT_PROBLEM_DIR=Schnitthöhenproblem Richtung
|
||||
channel-type.gardena.lastErrorCode.state.option.CUTTING_HEIGHT_BLOCKED=Schnitthöhe blockiert
|
||||
channel-type.gardena.lastErrorCode.state.option.CUTTING_HEIGHT_PROBLEM=Schnitthöhenproblem
|
||||
channel-type.gardena.lastErrorCode.state.option.BATTERY_PROBLEM=Batterieproblem
|
||||
channel-type.gardena.lastErrorCode.state.option.TOO_MANY_BATTERIES=Zu viele Batterien
|
||||
channel-type.gardena.lastErrorCode.state.option.ALARM_MOWER_SWITCHED_OFF=Alarm! Mäher ausgeschalten
|
||||
channel-type.gardena.lastErrorCode.state.option.ALARM_MOWER_STOPPED=Alarm! Mäher gestoppt
|
||||
channel-type.gardena.lastErrorCode.state.option.ALARM_MOWER_LIFTED=Alarm! Mäher angehoben
|
||||
channel-type.gardena.lastErrorCode.state.option.ALARM_MOWER_TILTED=Alarm! Mäher gekippt
|
||||
channel-type.gardena.lastErrorCode.state.option.ALARM_MOWER_IN_MOTION=Alarm! Mäher in Bewegung
|
||||
channel-type.gardena.lastErrorCode.state.option.ALARM_OUTSIDE_GEOFENCE=Alarm! Außerhalb des Geofence
|
||||
channel-type.gardena.lastErrorCode.state.option.SLIPPED=Mäher rutscht
|
||||
channel-type.gardena.lastErrorCode.state.option.INVALID_BATTERY_COMBINATION=Ungültige Batterie Kombination
|
||||
channel-type.gardena.lastErrorCode.state.option.UNINITIALISED=Unbekannter Status des Mähers
|
||||
channel-type.gardena.lastErrorCode.state.option.WAIT_UPDATING=Wird aktualisiert ...
|
||||
channel-type.gardena.lastErrorCode.state.option.WAIT_POWER_UP=Wird eingeschaltet ...
|
||||
channel-type.gardena.lastErrorCode.state.option.OFF_DISABLED=Der Mäher ist ausgeschaltet
|
||||
channel-type.gardena.lastErrorCode.state.option.OFF_HATCH_OPEN=Deaktiviert. Abdeckung ist offen oder PIN-Code erforderlich
|
||||
channel-type.gardena.lastErrorCode.state.option.OFF_HATCH_CLOSED=Deaktiviert. Manueller Start erforderlich
|
||||
channel-type.gardena.lastErrorCode.state.option.PARKED_DAILY_LIMIT_REACHED=Mähwerk hat den Mähvorgang aufgrund der erreichten Tagesgrenze abgeschlossen
|
||||
channel-type.gardena.lastErrorCode.state.option.TIMER_CANCELLED=Timer abgebrochen
|
||||
channel-type.gardena.lastErrorCode.state.option.CONCURRENT_LIMIT_REACHED=Ventil kann nicht geöffnet werden, weil höchstens 2 Ventile gleichzeitig geöffnet sein können
|
||||
channel-type.gardena.lastErrorCode.state.option.NOT_CONNECTED=Es wurde kein Ventil angeschlossen
|
||||
channel-type.gardena.lastErrorCode.state.option.VALVE_CURRENT_MAX_EXCEEDED=Das Ventil wurde geschlossen, weil das Ventil mehr Strom als erlaubt abzieht
|
||||
channel-type.gardena.lastErrorCode.state.option.TOTAL_CURRENT_MAX_EXCEEDED=Das Ventil wurde geschlossen, weil der verwendete Gesamtstrom über dem zulässigen Maximum lag.
|
||||
channel-type.gardena.lastErrorCode.state.option.WATERING_CANCELED=Bewässerung wurde abgebrochen
|
||||
channel-type.gardena.lastErrorCode.state.option.MASTER_VALVE=Hauptventil ist nicht angeschlossen
|
||||
channel-type.gardena.lastErrorCode.state.option.WATERING_DURATION_TOO_SHORT=Bewässerungsdauer zu kurz
|
||||
channel-type.gardena.lastErrorCode.state.option.VALVE_BROKEN=Die elektrische Verbindung zum Ventil ist unterbrochen, oder der Induktor ist beschädigt
|
||||
channel-type.gardena.lastErrorCode.state.option.FROST_PREVENTS_STARTING=Wegen Frost bleibt das Ventil geschlossen
|
||||
channel-type.gardena.lastErrorCode.state.option.LOW_BATTERY_PREVENTS_STARTING=Wegen niedriger Batterie bleibt das Ventil geschlossen
|
||||
channel-type.gardena.lastErrorCode.state.option.VALVE_POWER_SUPPLY_FAILED=Stromversorgung ausgefallen
|
||||
channel-type.gardena.lastErrorCode.state.option.VOLTAGE_DROP=Es wurde ein Spannungsabfall an der Stromversorgung festgestellt
|
||||
channel-type.gardena.lastErrorCode.state.option.WRONG_POWER_SUPPLY=Falsches Netzteil angeschlossen
|
||||
channel-type.gardena.lastErrorCode.state.option.NO_MCU_CONNECTION=Kommunikation mit sekundärer MCU nicht möglich
|
||||
|
||||
channel-type.gardena.radioQuality.label=Verbindungsqualität
|
||||
channel-type.gardena.radioQuality.description=Die Qualität der Funk Verbindung
|
||||
channel-type.gardena.timestamp.label=Zeitstempel
|
||||
channel-type.gardena.timestamp.description=Zeitstempel
|
||||
channel-type.gardena.timestampRefresh.label=Zeitstempel
|
||||
channel-type.gardena.timestampRefresh.description=Zeitstempel
|
||||
|
||||
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.name.label=Name
|
||||
channel-type.gardena.name.description=Der Name des Gerätes
|
||||
|
||||
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.activity.label=Aktivität
|
||||
channel-type.gardena.activity.description=Die Aktivität des Gerätes
|
||||
channel-type.gardena.activity.state.option.OFF=Aus
|
||||
channel-type.gardena.activity.state.option.FOREVER_ON=Einschalten durch eine manuelle Aktion, kein Ausschalten geplant
|
||||
channel-type.gardena.activity.state.option.TIME_LIMITED_ON=Einschalten durch eine manuelle Aktion, das Ausschalten ist geplant
|
||||
channel-type.gardena.activity.state.option.SCHEDULED_ON=Betrieb nach Zeitplan, aktueller Stand ist 'ein'
|
||||
channel-type.gardena.activity.state.option.CLOSED=Ventil geschlossen
|
||||
channel-type.gardena.activity.state.option.MANUAL_WATERING=Bewässerung aktiv
|
||||
channel-type.gardena.activity.state.option.SCHEDULED_WATERING=Bewässerung aktiv
|
||||
channel-type.gardena.activity.state.option.PAUSED=In einem Wartezustand mit geschlossener Luke
|
||||
channel-type.gardena.activity.state.option.OK_CUTTING=Mähen
|
||||
channel-type.gardena.activity.state.option.OK_CUTTING_TIMER_OVERRIDDEN=Mähen
|
||||
channel-type.gardena.activity.state.option.OK_SEARCHING=Suche Ladestation
|
||||
channel-type.gardena.activity.state.option.OK_LEAVING=Verlasse Ladestation
|
||||
channel-type.gardena.activity.state.option.OK_CHARGING=Lädt
|
||||
channel-type.gardena.activity.state.option.PARKED_TIMER=Nach Timer geparkt
|
||||
channel-type.gardena.activity.state.option.PARKED_PARK_SELECTED=Bis auf weiteres geparkt
|
||||
channel-type.gardena.activity.state.option.PARKED_AUTOTIMER=Wegen zu geringer Grashöhe geparkt
|
||||
channel-type.gardena.activity.state.option.NONE=Keine
|
||||
|
||||
channel-type.gardena.manualOperation.label=Manuelle Steuerung
|
||||
channel-type.gardena.manualOperation.description=Der Mäher wird manuell gesteuert
|
||||
channel-type.gardena.duration.label=Dauer
|
||||
channel-type.gardena.duration.description=Die Dauer in Minuten
|
||||
|
||||
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.soilHumidity.label=Bodenfeuchtigkeit
|
||||
channel-type.gardena.soilHumidity.description=Die Bodenfeuchtigkeit in Prozent
|
||||
|
||||
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.lightIntensity.label=Lichtintensität
|
||||
channel-type.gardena.lightIntensity.description=Die Lichtintensität in Lux
|
||||
|
||||
channel-type.gardena.temperature.label=Temperatur
|
||||
channel-type.gardena.temperature.description=Die Temperatur
|
||||
channel-type.gardena.temperature.description=Die Temperatur in Grad Celsius
|
||||
|
||||
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.operatingHours.label=Betriebsstunden
|
||||
channel-type.gardena.operatingHours.description=Die Betriebsstunden
|
||||
|
||||
channel-type.gardena.valveOpen.label=Ventil geöffnet
|
||||
channel-type.gardena.valveOpen.description=Ventil geöffnet
|
||||
channel-type.gardena.batteryState.label=Batteriestatus
|
||||
channel-type.gardena.batteryState.description=Der Batteriestatus
|
||||
channel-type.gardena.batteryState.state.option.OK=OK
|
||||
channel-type.gardena.batteryState.state.option.LOW=Niedrig
|
||||
channel-type.gardena.batteryState.state.option.REPLACE_NOW=Jetzt ersetzen
|
||||
channel-type.gardena.batteryState.state.option.OUT_OF_OPERATION=Außer Betrieb
|
||||
channel-type.gardena.batteryState.state.option.CHARGING=Laden
|
||||
channel-type.gardena.batteryState.state.option.NO_BATTERY=Keine Batterie
|
||||
channel-type.gardena.batteryState.state.option.UNKNOWN=Unbekannt
|
||||
|
||||
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
|
||||
channel-type.gardena.rfLinkState.label=Verbinungsstatus
|
||||
channel-type.gardena.rfLinkState.description=Der Verbinungsstatus
|
||||
channel-type.gardena.rfLinkState.state.option.ONLINE=Online
|
||||
channel-type.gardena.rfLinkState.state.option.OFFLINE=Offline
|
||||
channel-type.gardena.rfLinkState.state.option.UNKNOWN=Unbekannt
|
||||
|
|
|
@ -4,39 +4,31 @@
|
|||
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 -->
|
||||
<!-- Gardena smart system Account -->
|
||||
<bridge-type id="account">
|
||||
<label>Gardena Smart Home Account</label>
|
||||
<description>The Gardena Smart Home Account</description>
|
||||
<label>Gardena Smart System Account</label>
|
||||
<description>The Gardena smart system 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>
|
||||
<description>Email address for logging in to Gardena smart system</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>
|
||||
<description>Password for logging in to Gardena smart system</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 name="apiKey" type="text" required="true">
|
||||
<label>API Key</label>
|
||||
<description>The Gardena smart system integration API key</description>
|
||||
</parameter>
|
||||
<parameter name="connectionTimeout" type="integer">
|
||||
<parameter name="connectionTimeout" type="integer" min="0" unit="s">
|
||||
<label>Connection Timeout</label>
|
||||
<description>The timeout in seconds for connections to Gardena Smart Home</description>
|
||||
<advanced>true</advanced>
|
||||
<description>The timeout in seconds for connections to Gardena smart system integration API</description>
|
||||
<unitLabel>seconds</unitLabel>
|
||||
<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>
|
||||
|
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue