added migrated 2.x add-ons
Signed-off-by: Kai Kreuzer <kai@openhab.org>
This commit is contained in:
@@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<features name="org.openhab.binding.gardena-${project.version}" xmlns="http://karaf.apache.org/xmlns/features/v1.4.0">
|
||||
<repository>mvn:org.openhab.core.features.karaf/org.openhab.core.features.karaf.openhab-core/${ohc.version}/xml/features</repository>
|
||||
|
||||
<feature name="openhab-binding-gardena" description="Gardena Binding" version="${project.version}">
|
||||
<feature>openhab-runtime-base</feature>
|
||||
<bundle start-level="80">mvn:org.openhab.addons.bundles/org.openhab.binding.gardena/${project.version}</bundle>
|
||||
</feature>
|
||||
</features>
|
||||
@@ -0,0 +1,47 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.gardena.internal;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.core.thing.ThingTypeUID;
|
||||
|
||||
/**
|
||||
* The {@link GardenaBinding} class defines common constants, which are used across the whole binding.
|
||||
*
|
||||
* @author Gerhard Riegler - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class GardenaBindingConstants {
|
||||
|
||||
public static final String BINDING_ID = "gardena";
|
||||
|
||||
public static final ThingTypeUID THING_TYPE_ACCOUNT = new ThingTypeUID(BINDING_ID, "account");
|
||||
|
||||
public static final String PROPERTY_MANUFACTURER = "manufacturer";
|
||||
public static final String PROPERTY_PRODUCT = "product";
|
||||
public static final String PROPERTY_SERIALNUMBER = "serial_number";
|
||||
public static final String PROPERTY_SGTIN = "sgtin";
|
||||
public static final String PROPERTY_VERSION = "version";
|
||||
public static final String PROPERTY_CATEGORY = "category";
|
||||
|
||||
public static final String PROPERTY_CONNECTION_STATUS = "connection_status";
|
||||
public static final String PROPERTY_CONNECTION_STATUS_UNREACH_VALUE = "status_device_unreachable";
|
||||
public static final String PROPERTY_STATE = "state";
|
||||
|
||||
public static final String ABILITY_DEVICE_INFO = "device_info";
|
||||
public static final String ABILITY_RADIO = "radio";
|
||||
|
||||
public static final String SETTING_LEAKAGE_DETECTION = "leakage_detection";
|
||||
public static final String SETTING_OPERATION_MODE = "operating_mode";
|
||||
public static final String SETTING_TURN_ON_PRESSURE = "turn_on_pressure";
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.gardena.internal;
|
||||
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
|
||||
import org.openhab.binding.gardena.internal.config.GardenaConfig;
|
||||
import org.openhab.binding.gardena.internal.exception.GardenaException;
|
||||
import org.openhab.binding.gardena.internal.model.Device;
|
||||
import org.openhab.binding.gardena.internal.model.Location;
|
||||
import org.openhab.binding.gardena.internal.model.Setting;
|
||||
|
||||
/**
|
||||
* Describes the methods required for the communication with Gardens Smart Home.
|
||||
*
|
||||
* @author Gerhard Riegler - Initial contribution
|
||||
*/
|
||||
public interface GardenaSmart {
|
||||
|
||||
/**
|
||||
* Initializes Gardena Smart Home and loads all devices from all locations.
|
||||
*/
|
||||
public void init(String id, GardenaConfig config, GardenaSmartEventListener eventListener,
|
||||
ScheduledExecutorService scheduler) throws GardenaException;
|
||||
|
||||
/**
|
||||
* Disposes Gardena Smart Home.
|
||||
*/
|
||||
public void dispose();
|
||||
|
||||
/**
|
||||
* Loads all devices from all locations.
|
||||
*/
|
||||
public void loadAllDevices() throws GardenaException;
|
||||
|
||||
/**
|
||||
* Returns all locations.
|
||||
*/
|
||||
public Set<Location> getLocations();
|
||||
|
||||
/**
|
||||
* Returns a device with the given id.
|
||||
*/
|
||||
public Device getDevice(String deviceId) throws GardenaException;
|
||||
|
||||
/**
|
||||
* Sends a command to Gardena Smart Home.
|
||||
*/
|
||||
public void sendCommand(Device device, GardenaSmartCommandName commandName, Object value) throws GardenaException;
|
||||
|
||||
/**
|
||||
* Sends a setting to Gardena Smart Home.
|
||||
*/
|
||||
public void sendSetting(Setting setting, Object value) throws GardenaException;
|
||||
|
||||
/**
|
||||
* Returns the id.
|
||||
*/
|
||||
public String getId();
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.gardena.internal;
|
||||
|
||||
/**
|
||||
* A names of all GardenaSmart commands.
|
||||
*
|
||||
* @author Gerhard Riegler - Initial contribution
|
||||
*/
|
||||
public enum GardenaSmartCommandName {
|
||||
// mower
|
||||
PARK_UNTIL_FURTHER_NOTICE,
|
||||
PARK_UNTIL_NEXT_TIMER,
|
||||
START_OVERRIDE_TIMER,
|
||||
START_RESUME_SCHEDULE,
|
||||
DURATION_PROPERTY,
|
||||
|
||||
// sensor
|
||||
MEASURE_AMBIENT_TEMPERATURE,
|
||||
MEASURE_LIGHT,
|
||||
MEASURE_SOIL_HUMIDITY,
|
||||
MEASURE_SOIL_TEMPERATURE,
|
||||
|
||||
// outlet
|
||||
OUTLET_MANUAL_OVERRIDE_TIME,
|
||||
OUTLET_VALVE,
|
||||
|
||||
// power
|
||||
POWER_TIMER,
|
||||
|
||||
// irrigation control
|
||||
WATERING_TIMER_VALVE_1,
|
||||
WATERING_TIMER_VALVE_2,
|
||||
WATERING_TIMER_VALVE_3,
|
||||
WATERING_TIMER_VALVE_4,
|
||||
WATERING_TIMER_VALVE_5,
|
||||
WATERING_TIMER_VALVE_6,
|
||||
|
||||
// pump
|
||||
PUMP_MANUAL_WATERING_TIMER
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.gardena.internal;
|
||||
|
||||
import org.openhab.binding.gardena.internal.model.Device;
|
||||
|
||||
/**
|
||||
* Listener with methods called from events within the {@link GardenaSmart} class.
|
||||
*
|
||||
* @author Gerhard Riegler - Initial contribution
|
||||
*/
|
||||
public interface GardenaSmartEventListener {
|
||||
|
||||
/**
|
||||
* Called when a device has been updated.
|
||||
*/
|
||||
public void onDeviceUpdated(Device device);
|
||||
|
||||
/**
|
||||
* Called when a new device has been detected.
|
||||
*/
|
||||
public void onNewDevice(Device device);
|
||||
|
||||
/**
|
||||
* Called when a device has been deleted.
|
||||
*/
|
||||
public void onDeviceDeleted(Device device);
|
||||
|
||||
/**
|
||||
* Called when the connection is lost to Gardena Smart Home.
|
||||
*/
|
||||
public void onConnectionLost();
|
||||
|
||||
/**
|
||||
* Called when the connection is resumed to Gardena Smart Home.
|
||||
*/
|
||||
public void onConnectionResumed();
|
||||
}
|
||||
@@ -0,0 +1,573 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.gardena.internal;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.ScheduledFuture;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.apache.commons.lang.ObjectUtils;
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.eclipse.jetty.client.HttpClient;
|
||||
import org.eclipse.jetty.client.HttpResponseException;
|
||||
import org.eclipse.jetty.client.api.ContentResponse;
|
||||
import org.eclipse.jetty.client.api.Request;
|
||||
import org.eclipse.jetty.client.util.StringContentProvider;
|
||||
import org.eclipse.jetty.http.HttpHeader;
|
||||
import org.eclipse.jetty.http.HttpMethod;
|
||||
import org.eclipse.jetty.util.ssl.SslContextFactory;
|
||||
import org.openhab.binding.gardena.internal.config.GardenaConfig;
|
||||
import org.openhab.binding.gardena.internal.config.GardenaConfigWrapper;
|
||||
import org.openhab.binding.gardena.internal.exception.GardenaDeviceNotFoundException;
|
||||
import org.openhab.binding.gardena.internal.exception.GardenaException;
|
||||
import org.openhab.binding.gardena.internal.exception.GardenaUnauthorizedException;
|
||||
import org.openhab.binding.gardena.internal.model.Ability;
|
||||
import org.openhab.binding.gardena.internal.model.Device;
|
||||
import org.openhab.binding.gardena.internal.model.Devices;
|
||||
import org.openhab.binding.gardena.internal.model.Errors;
|
||||
import org.openhab.binding.gardena.internal.model.Location;
|
||||
import org.openhab.binding.gardena.internal.model.Locations;
|
||||
import org.openhab.binding.gardena.internal.model.NoResult;
|
||||
import org.openhab.binding.gardena.internal.model.Property;
|
||||
import org.openhab.binding.gardena.internal.model.PropertyValue;
|
||||
import org.openhab.binding.gardena.internal.model.Session;
|
||||
import org.openhab.binding.gardena.internal.model.SessionWrapper;
|
||||
import org.openhab.binding.gardena.internal.model.Setting;
|
||||
import org.openhab.binding.gardena.internal.model.command.Command;
|
||||
import org.openhab.binding.gardena.internal.model.command.MowerParkUntilFurtherNoticeCommand;
|
||||
import org.openhab.binding.gardena.internal.model.command.MowerParkUntilNextTimerCommand;
|
||||
import org.openhab.binding.gardena.internal.model.command.MowerStartOverrideTimerCommand;
|
||||
import org.openhab.binding.gardena.internal.model.command.MowerStartResumeScheduleCommand;
|
||||
import org.openhab.binding.gardena.internal.model.command.SensorMeasureAmbientTemperatureCommand;
|
||||
import org.openhab.binding.gardena.internal.model.command.SensorMeasureLightCommand;
|
||||
import org.openhab.binding.gardena.internal.model.command.SensorMeasureSoilHumidityCommand;
|
||||
import org.openhab.binding.gardena.internal.model.command.SensorMeasureSoilTemperatureCommand;
|
||||
import org.openhab.binding.gardena.internal.model.command.SettingCommand;
|
||||
import org.openhab.binding.gardena.internal.model.command.SettingCommandWrapper;
|
||||
import org.openhab.binding.gardena.internal.model.command.WateringCancelOverrideCommand;
|
||||
import org.openhab.binding.gardena.internal.model.command.WateringManualOverrideCommand;
|
||||
import org.openhab.binding.gardena.internal.model.deser.DateDeserializer;
|
||||
import org.openhab.binding.gardena.internal.model.deser.PropertyValueDeserializer;
|
||||
import org.openhab.binding.gardena.internal.model.property.BaseProperty;
|
||||
import org.openhab.binding.gardena.internal.model.property.IrrigationControlWateringProperty;
|
||||
import org.openhab.binding.gardena.internal.model.property.PropertyWrapper;
|
||||
import org.openhab.binding.gardena.internal.model.property.StringProperty;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
|
||||
/**
|
||||
* {@link GardenaSmart} implementation to access Gardena Smart Home.
|
||||
*
|
||||
* @author Gerhard Riegler - Initial contribution
|
||||
*/
|
||||
public class GardenaSmartImpl implements GardenaSmart {
|
||||
private final Logger logger = LoggerFactory.getLogger(GardenaSmartImpl.class);
|
||||
|
||||
public static final String DEVICE_CATEGORY_PUMP = "electronic_pressure_pump";
|
||||
private static final String ABILITY_MOWER = "mower";
|
||||
private static final String ABILITY_OUTLET = "outlet";
|
||||
private static final String ABILITY_HUMIDITY = "humidity";
|
||||
private static final String ABILITY_LIGHT = "light";
|
||||
private static final String ABILITY_AMBIENT_TEMPERATURE = "ambient_temperature";
|
||||
private static final String ABILITY_SOIL_TEMPERATURE = "soil_temperature";
|
||||
private static final String ABILITY_POWER = "power";
|
||||
private static final String ABILITY_WATERING = "watering";
|
||||
private static final String ABILITY_MANUAL_WATERING = "manual_watering";
|
||||
|
||||
private static final String PROPERTY_BUTTON_MANUAL_OVERRIDE_TIME = "button_manual_override_time";
|
||||
private static final String PROPERTY_POWER_TIMER = "power_timer";
|
||||
private static final String PROPERTY_WATERING_TIMER = "watering_timer_";
|
||||
private static final String PROPERTY_MANUAL_WATERING_TIMER = "manual_watering_timer";
|
||||
|
||||
private static final String DEVICE_CATEGORY_MOWER = "mower";
|
||||
private static final String DEVICE_CATEGORY_GATEWAY = "gateway";
|
||||
|
||||
private static final String DEFAULT_MOWER_DURATION = "180";
|
||||
|
||||
private static final String URL = "https://smart.gardena.com";
|
||||
private static final String URL_LOGIN = URL + "/v1/auth/token";
|
||||
private static final String URL_LOCATIONS = URL + "/v1/locations/?user_id=";
|
||||
private static final String URL_DEVICES = URL + "/v1/devices/?locationId=";
|
||||
private static final String URL_COMMAND = URL + "/v1/devices/%s/abilities/%s/command?locationId=%s";
|
||||
private static final String URL_PROPERTY = URL + "/v1/devices/%s/abilities/%s/properties/%s?locationId=%s";
|
||||
private static final String URL_SETTING = URL + "/v1/devices/%s/settings/%s?locationId=%s";
|
||||
|
||||
private Gson gson = new GsonBuilder().registerTypeAdapter(Date.class, new DateDeserializer())
|
||||
.registerTypeAdapter(PropertyValue.class, new PropertyValueDeserializer()).create();
|
||||
private HttpClient httpClient;
|
||||
|
||||
private String mowerDuration = DEFAULT_MOWER_DURATION;
|
||||
private Session session;
|
||||
private GardenaConfig config;
|
||||
private String id;
|
||||
|
||||
private ScheduledExecutorService scheduler;
|
||||
private ScheduledFuture<?> refreshThreadFuture;
|
||||
private RefreshDevicesThread refreshDevicesThread = new RefreshDevicesThread();
|
||||
|
||||
private GardenaSmartEventListener eventListener;
|
||||
|
||||
private Map<String, Device> allDevicesById = new HashMap<>();
|
||||
private Set<Location> allLocations = new HashSet<>();
|
||||
|
||||
@Override
|
||||
public void init(String id, GardenaConfig config, GardenaSmartEventListener eventListener,
|
||||
ScheduledExecutorService scheduler) throws GardenaException {
|
||||
this.id = id;
|
||||
this.config = config;
|
||||
this.eventListener = eventListener;
|
||||
this.scheduler = scheduler;
|
||||
|
||||
if (!config.isValid()) {
|
||||
throw new GardenaException("Invalid config, no email or password specified");
|
||||
}
|
||||
|
||||
httpClient = new HttpClient(new SslContextFactory(true));
|
||||
httpClient.setConnectTimeout(config.getConnectionTimeout() * 1000L);
|
||||
|
||||
try {
|
||||
httpClient.start();
|
||||
} catch (Exception ex) {
|
||||
throw new GardenaException(ex.getMessage(), ex);
|
||||
}
|
||||
|
||||
loadAllDevices();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
stopRefreshThread(true);
|
||||
if (httpClient != null) {
|
||||
try {
|
||||
httpClient.stop();
|
||||
} catch (Exception e) {
|
||||
// ignore
|
||||
}
|
||||
httpClient.destroy();
|
||||
}
|
||||
allLocations.clear();
|
||||
allDevicesById.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* Schedules the device refresh thread.
|
||||
*/
|
||||
private void startRefreshThread() {
|
||||
refreshThreadFuture = scheduler.scheduleWithFixedDelay(refreshDevicesThread, 6, config.getRefresh(),
|
||||
TimeUnit.SECONDS);
|
||||
}
|
||||
|
||||
/**
|
||||
* Stops the device refresh thread.
|
||||
*/
|
||||
private void stopRefreshThread(boolean force) {
|
||||
if (refreshThreadFuture != null) {
|
||||
refreshThreadFuture.cancel(force);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<Location> getLocations() {
|
||||
return allLocations;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Device getDevice(String deviceId) throws GardenaException {
|
||||
Device device = allDevicesById.get(deviceId);
|
||||
if (device == null) {
|
||||
throw new GardenaDeviceNotFoundException(
|
||||
String.format("Device with id '%s' not found on gateway '%s'", deviceId, id));
|
||||
}
|
||||
return device;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadAllDevices() throws GardenaException {
|
||||
stopRefreshThread(false);
|
||||
try {
|
||||
allLocations.clear();
|
||||
allDevicesById.clear();
|
||||
|
||||
verifySession();
|
||||
Locations locations = executeRequest(HttpMethod.GET,
|
||||
URL_LOCATIONS + session.getSessionAttributes().getUserId(), null, Locations.class);
|
||||
|
||||
for (Location location : locations.getLocations()) {
|
||||
allLocations.add(location);
|
||||
Devices devices = loadDevices(location);
|
||||
for (Device device : devices.getDevices()) {
|
||||
if (DEVICE_CATEGORY_GATEWAY.equals(device.getCategory())) {
|
||||
location.getDeviceIds().remove(device.getId());
|
||||
} else {
|
||||
allDevicesById.put(device.getId(), device);
|
||||
}
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
startRefreshThread();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads all devices for the location, adds virtual properties for commands.
|
||||
*/
|
||||
private Devices loadDevices(Location location) throws GardenaException {
|
||||
Devices devices = executeRequest(HttpMethod.GET, URL_DEVICES + location.getId(), null, Devices.class);
|
||||
for (Device device : devices.getDevices()) {
|
||||
device.setLocation(location);
|
||||
for (Ability ability : device.getAbilities()) {
|
||||
ability.setDevice(device);
|
||||
for (Property property : ability.getProperties()) {
|
||||
property.setAbility(ability);
|
||||
|
||||
if (device.getCategory().equals(DEVICE_CATEGORY_PUMP)) {
|
||||
if (property.getName().equals(PROPERTY_MANUAL_WATERING_TIMER)) {
|
||||
Integer duration = getIntegerValue(property.getValueAsString());
|
||||
if (duration == null) {
|
||||
duration = 0;
|
||||
}
|
||||
property.setValue(new PropertyValue(String.valueOf(duration / 60)));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
for (Setting setting : device.getSettings()) {
|
||||
setting.setDevice(device);
|
||||
}
|
||||
|
||||
if (DEVICE_CATEGORY_MOWER.equals(device.getCategory())) {
|
||||
Ability mower = device.getAbility(ABILITY_MOWER);
|
||||
mower.addProperty(new Property(GardenaSmartCommandName.PARK_UNTIL_NEXT_TIMER, "false"));
|
||||
mower.addProperty(new Property(GardenaSmartCommandName.PARK_UNTIL_FURTHER_NOTICE, "false"));
|
||||
mower.addProperty(new Property(GardenaSmartCommandName.START_RESUME_SCHEDULE, "false"));
|
||||
mower.addProperty(new Property(GardenaSmartCommandName.START_OVERRIDE_TIMER, "false"));
|
||||
|
||||
mower.addProperty(new Property(GardenaSmartCommandName.DURATION_PROPERTY, mowerDuration));
|
||||
}
|
||||
}
|
||||
return devices;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendCommand(Device device, GardenaSmartCommandName commandName, Object value) throws GardenaException {
|
||||
Ability ability = null;
|
||||
Command command = null;
|
||||
|
||||
switch (commandName) {
|
||||
case PARK_UNTIL_NEXT_TIMER:
|
||||
ability = device.getAbility(ABILITY_MOWER);
|
||||
command = new MowerParkUntilNextTimerCommand();
|
||||
break;
|
||||
case PARK_UNTIL_FURTHER_NOTICE:
|
||||
ability = device.getAbility(ABILITY_MOWER);
|
||||
command = new MowerParkUntilFurtherNoticeCommand();
|
||||
break;
|
||||
case START_RESUME_SCHEDULE:
|
||||
ability = device.getAbility(ABILITY_MOWER);
|
||||
command = new MowerStartResumeScheduleCommand();
|
||||
break;
|
||||
case START_OVERRIDE_TIMER:
|
||||
ability = device.getAbility(ABILITY_MOWER);
|
||||
command = new MowerStartOverrideTimerCommand(mowerDuration);
|
||||
break;
|
||||
case DURATION_PROPERTY:
|
||||
if (value == null) {
|
||||
throw new GardenaException("Command '" + commandName + "' requires a value");
|
||||
}
|
||||
mowerDuration = ObjectUtils.toString(value);
|
||||
return;
|
||||
case MEASURE_AMBIENT_TEMPERATURE:
|
||||
ability = device.getAbility(ABILITY_AMBIENT_TEMPERATURE);
|
||||
command = new SensorMeasureAmbientTemperatureCommand();
|
||||
break;
|
||||
case MEASURE_LIGHT:
|
||||
ability = device.getAbility(ABILITY_LIGHT);
|
||||
command = new SensorMeasureLightCommand();
|
||||
break;
|
||||
case MEASURE_SOIL_HUMIDITY:
|
||||
ability = device.getAbility(ABILITY_HUMIDITY);
|
||||
command = new SensorMeasureSoilHumidityCommand();
|
||||
break;
|
||||
case MEASURE_SOIL_TEMPERATURE:
|
||||
ability = device.getAbility(ABILITY_SOIL_TEMPERATURE);
|
||||
command = new SensorMeasureSoilTemperatureCommand();
|
||||
break;
|
||||
case OUTLET_MANUAL_OVERRIDE_TIME:
|
||||
if (value == null) {
|
||||
throw new GardenaException("Command '" + commandName + "' requires a value");
|
||||
}
|
||||
StringProperty prop = new StringProperty(PROPERTY_BUTTON_MANUAL_OVERRIDE_TIME,
|
||||
ObjectUtils.toString(value));
|
||||
|
||||
executeSetProperty(device, ABILITY_OUTLET, PROPERTY_BUTTON_MANUAL_OVERRIDE_TIME, prop);
|
||||
break;
|
||||
case OUTLET_VALVE:
|
||||
ability = device.getAbility(ABILITY_OUTLET);
|
||||
if (value != null && value == Boolean.TRUE) {
|
||||
String wateringDuration = device.getAbility(ABILITY_OUTLET)
|
||||
.getProperty(PROPERTY_BUTTON_MANUAL_OVERRIDE_TIME).getValueAsString();
|
||||
command = new WateringManualOverrideCommand(wateringDuration);
|
||||
} else {
|
||||
command = new WateringCancelOverrideCommand();
|
||||
}
|
||||
break;
|
||||
case POWER_TIMER:
|
||||
if (value == null) {
|
||||
throw new GardenaException("Command '" + commandName + "' requires a value");
|
||||
}
|
||||
prop = new StringProperty(PROPERTY_POWER_TIMER, ObjectUtils.toString(value));
|
||||
executeSetProperty(device, ABILITY_POWER, PROPERTY_POWER_TIMER, prop);
|
||||
break;
|
||||
case WATERING_TIMER_VALVE_1:
|
||||
case WATERING_TIMER_VALVE_2:
|
||||
case WATERING_TIMER_VALVE_3:
|
||||
case WATERING_TIMER_VALVE_4:
|
||||
case WATERING_TIMER_VALVE_5:
|
||||
case WATERING_TIMER_VALVE_6:
|
||||
if (value == null) {
|
||||
throw new GardenaException("Command '" + commandName + "' requires a value");
|
||||
} else if (!(value instanceof Integer)) {
|
||||
throw new GardenaException("Watering duration value '" + value + "' not a number");
|
||||
}
|
||||
int valveId = Integer.parseInt(StringUtils.right(commandName.toString(), 1));
|
||||
String wateringTimerProperty = PROPERTY_WATERING_TIMER + valveId;
|
||||
IrrigationControlWateringProperty irrigationProp = new IrrigationControlWateringProperty(
|
||||
wateringTimerProperty, (Integer) value, valveId);
|
||||
executeSetProperty(device, ABILITY_WATERING, wateringTimerProperty, irrigationProp);
|
||||
break;
|
||||
case PUMP_MANUAL_WATERING_TIMER:
|
||||
Integer duration = getIntegerValue(value);
|
||||
if (duration == null) {
|
||||
throw new GardenaException("Command '" + commandName + "' requires a number value");
|
||||
}
|
||||
prop = new StringProperty(PROPERTY_MANUAL_WATERING_TIMER, String.valueOf(duration * 60));
|
||||
|
||||
executeSetProperty(device, ABILITY_MANUAL_WATERING, PROPERTY_MANUAL_WATERING_TIMER, prop);
|
||||
break;
|
||||
default:
|
||||
throw new GardenaException("Unknown command " + commandName);
|
||||
}
|
||||
|
||||
if (command != null) {
|
||||
stopRefreshThread(false);
|
||||
executeRequest(HttpMethod.POST, getCommandUrl(device, ability), command, NoResult.class);
|
||||
startRefreshThread();
|
||||
}
|
||||
}
|
||||
|
||||
private Integer getIntegerValue(Object value) {
|
||||
try {
|
||||
return Integer.valueOf(ObjectUtils.toString(value));
|
||||
} catch (NumberFormatException ex) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends the new property value for the ability.
|
||||
*/
|
||||
private void executeSetProperty(Device device, String ability, String property, BaseProperty value)
|
||||
throws GardenaException {
|
||||
String propertyUrl = String.format(URL_PROPERTY, device.getId(), ability, property,
|
||||
device.getLocation().getId());
|
||||
stopRefreshThread(false);
|
||||
executeRequest(HttpMethod.PUT, propertyUrl, new PropertyWrapper(value), NoResult.class);
|
||||
device.getAbility(ability).getProperty(property).setValue(new PropertyValue(value.getValue()));
|
||||
startRefreshThread();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendSetting(Setting setting, Object value) throws GardenaException {
|
||||
SettingCommand settingCommand = new SettingCommand(setting.getName());
|
||||
settingCommand.setDeviceId(setting.getDevice().getId());
|
||||
settingCommand.setValue(value);
|
||||
|
||||
stopRefreshThread(false);
|
||||
executeRequest(HttpMethod.PUT, getSettingUrl(setting), new SettingCommandWrapper(settingCommand),
|
||||
NoResult.class);
|
||||
startRefreshThread();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the command url.
|
||||
*/
|
||||
private String getCommandUrl(Device device, Ability ability) throws GardenaException {
|
||||
return String.format(URL_COMMAND, device.getId(), ability.getName(), device.getLocation().getId());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the settings url.
|
||||
*/
|
||||
private String getSettingUrl(Setting setting) {
|
||||
Device device = setting.getDevice();
|
||||
return String.format(URL_SETTING, device.getId(), setting.getId(), device.getLocation().getId());
|
||||
}
|
||||
|
||||
/**
|
||||
* Communicates with Gardena Smart Home and parses the result.
|
||||
*/
|
||||
private synchronized <T> T executeRequest(HttpMethod method, String url, Object contentObject, Class<T> result)
|
||||
throws GardenaException {
|
||||
try {
|
||||
if (logger.isTraceEnabled()) {
|
||||
logger.trace("{} request: {}", method, url);
|
||||
if (contentObject != null) {
|
||||
logger.trace("{} data : {}", method, gson.toJson(contentObject));
|
||||
}
|
||||
}
|
||||
|
||||
Request request = httpClient.newRequest(url).method(method)
|
||||
.timeout(config.getConnectionTimeout(), TimeUnit.SECONDS)
|
||||
.idleTimeout(config.getConnectionTimeout(), TimeUnit.SECONDS)
|
||||
.header(HttpHeader.CONTENT_TYPE, "application/json").header(HttpHeader.ACCEPT, "application/json")
|
||||
.header(HttpHeader.ACCEPT_ENCODING, "gzip");
|
||||
|
||||
if (contentObject != null) {
|
||||
StringContentProvider content = new StringContentProvider(gson.toJson(contentObject));
|
||||
request.content(content);
|
||||
}
|
||||
|
||||
if (!result.equals(SessionWrapper.class)) {
|
||||
verifySession();
|
||||
request.header("authorization", "Bearer " + session.getToken());
|
||||
request.header("authorization-provider", session.getSessionAttributes().getProvider());
|
||||
}
|
||||
|
||||
ContentResponse contentResponse = request.send();
|
||||
int status = contentResponse.getStatus();
|
||||
if (logger.isTraceEnabled()) {
|
||||
logger.trace("Status : {}", status);
|
||||
logger.trace("Response: {}", contentResponse.getContentAsString());
|
||||
}
|
||||
|
||||
if (status == 500) {
|
||||
throw new GardenaException(
|
||||
gson.fromJson(contentResponse.getContentAsString(), Errors.class).toString());
|
||||
} else if (status != 200 && status != 204 && status != 201) {
|
||||
throw new GardenaException(String.format("Error %s %s", status, contentResponse.getReason()));
|
||||
}
|
||||
|
||||
if (result == NoResult.class) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return gson.fromJson(contentResponse.getContentAsString(), result);
|
||||
} catch (ExecutionException ex) {
|
||||
Throwable cause = ex.getCause();
|
||||
if (cause instanceof HttpResponseException) {
|
||||
HttpResponseException responseException = (HttpResponseException) ex.getCause();
|
||||
int status = responseException.getResponse().getStatus();
|
||||
if (status == 401) {
|
||||
throw new GardenaUnauthorizedException(ex.getCause());
|
||||
}
|
||||
}
|
||||
throw new GardenaException(ex.getMessage(), ex);
|
||||
} catch (Exception ex) {
|
||||
throw new GardenaException(ex.getMessage(), ex);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies the Gardena Smart Home session and reconnects if necessary.
|
||||
*/
|
||||
private void verifySession() throws GardenaException {
|
||||
if (session == null
|
||||
|| session.getCreated() + (config.getSessionTimeout() * 60000) <= System.currentTimeMillis()) {
|
||||
logger.trace("(Re)logging in to Gardena Smart Home");
|
||||
session = executeRequest(HttpMethod.POST, URL_LOGIN, new GardenaConfigWrapper(config), SessionWrapper.class)
|
||||
.getSession();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Thread which refreshes the data from Gardena Smart Home.
|
||||
*/
|
||||
private class RefreshDevicesThread implements Runnable {
|
||||
private boolean connectionLost = false;
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
logger.debug("Refreshing gardena device data");
|
||||
final Map<String, Device> newDevicesById = new HashMap<>();
|
||||
|
||||
for (Location location : allLocations) {
|
||||
Devices devices = loadDevices(location);
|
||||
for (Device device : devices.getDevices()) {
|
||||
if (DEVICE_CATEGORY_GATEWAY.equals(device.getCategory())) {
|
||||
location.getDeviceIds().remove(device.getId());
|
||||
} else {
|
||||
newDevicesById.put(device.getId(), device);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (connectionLost) {
|
||||
connectionLost = false;
|
||||
logger.info("Connection resumed to Gardena Smart Home with id '{}'", id);
|
||||
eventListener.onConnectionResumed();
|
||||
}
|
||||
|
||||
// determine deleted devices
|
||||
Collection<Device> deletedDevices = allDevicesById.values().stream()
|
||||
.filter(d -> !newDevicesById.values().contains(d)).collect(Collectors.toSet());
|
||||
|
||||
// determine new devices
|
||||
Collection<Device> newDevices = newDevicesById.values().stream()
|
||||
.filter(d -> !allDevicesById.values().contains(d)).collect(Collectors.toSet());
|
||||
|
||||
// determine updated devices
|
||||
Collection<Device> updatedDevices = allDevicesById.values().stream().distinct()
|
||||
.filter(newDevicesById.values()::contains).collect(Collectors.toSet());
|
||||
|
||||
allDevicesById = newDevicesById;
|
||||
|
||||
for (Device deletedDevice : deletedDevices) {
|
||||
eventListener.onDeviceDeleted(deletedDevice);
|
||||
}
|
||||
|
||||
for (Device newDevice : newDevices) {
|
||||
eventListener.onNewDevice(newDevice);
|
||||
}
|
||||
|
||||
for (Device updatedDevice : updatedDevices) {
|
||||
eventListener.onDeviceUpdated(updatedDevice);
|
||||
}
|
||||
|
||||
} catch (GardenaException ex) {
|
||||
if (!connectionLost) {
|
||||
connectionLost = true;
|
||||
logger.warn("Connection lost to Gardena Smart Home with id '{}'", id);
|
||||
logger.trace("{}", ex.getMessage(), ex);
|
||||
eventListener.onConnectionLost();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,132 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.gardena.internal.config;
|
||||
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.apache.commons.lang.builder.ToStringBuilder;
|
||||
import org.apache.commons.lang.builder.ToStringStyle;
|
||||
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
|
||||
/**
|
||||
* The main Gardena config class.
|
||||
*
|
||||
* @author Gerhard Riegler - Initial contribution
|
||||
*/
|
||||
public class GardenaConfig {
|
||||
|
||||
private static final Integer DEFAULT_SESSION_TIMEOUT = 30;
|
||||
private static final Integer DEFAULT_CONNECTION_TIMEOUT = 10;
|
||||
private static final Integer DEFAULT_REFRESH = 60;
|
||||
|
||||
@SerializedName("username")
|
||||
private String email;
|
||||
private String password;
|
||||
|
||||
private transient Integer sessionTimeout = DEFAULT_SESSION_TIMEOUT;
|
||||
private transient Integer connectionTimeout = DEFAULT_CONNECTION_TIMEOUT;
|
||||
private transient Integer refresh = DEFAULT_REFRESH;
|
||||
|
||||
public GardenaConfig() {
|
||||
}
|
||||
|
||||
public GardenaConfig(String email, String password) {
|
||||
this.email = email;
|
||||
this.password = password;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the email to connect to Gardena Smart Home.
|
||||
*/
|
||||
public String getEmail() {
|
||||
return email;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the email to connect to Gardena Smart Home.
|
||||
*/
|
||||
public void setEmail(String email) {
|
||||
this.email = email;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the password to connect to Gardena Smart Home.
|
||||
*/
|
||||
public String getPassword() {
|
||||
return password;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the password to connect to Gardena Smart Home.
|
||||
*/
|
||||
public void setPassword(String password) {
|
||||
this.password = password;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the session timeout to Gardena Smart Home.
|
||||
*/
|
||||
public int getSessionTimeout() {
|
||||
return sessionTimeout;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the session timeout to Gardena Smart Home.
|
||||
*/
|
||||
public void setSessionTimeout(int sessionTimeout) {
|
||||
this.sessionTimeout = sessionTimeout;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the connection timeout to Gardena Smart Home.
|
||||
*/
|
||||
public Integer getConnectionTimeout() {
|
||||
return connectionTimeout;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the connection timeout to Gardena Smart Home.
|
||||
*/
|
||||
public void setConnectionTimeout(Integer connectionTimeout) {
|
||||
this.connectionTimeout = connectionTimeout;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the refresh interval to fetch new data from Gardena Smart Home.
|
||||
*/
|
||||
public Integer getRefresh() {
|
||||
return refresh;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the refresh interval to fetch new data from Gardena Smart Home.
|
||||
*/
|
||||
public void setRefresh(Integer refresh) {
|
||||
this.refresh = refresh;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate the config, if at least email and password is specified.
|
||||
*/
|
||||
public boolean isValid() {
|
||||
return StringUtils.isNotBlank(email) && StringUtils.isNotBlank(password);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE).append("email", email)
|
||||
.append("password", StringUtils.isBlank(password) ? "" : StringUtils.repeat("*", password.length()))
|
||||
.append("sessionTimeout", sessionTimeout).append("connectionTimeout", connectionTimeout)
|
||||
.append("refresh", refresh).toString();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.gardena.internal.config;
|
||||
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
|
||||
/**
|
||||
* GardenaConfgData wrapper for valid Gardena JSON serialization.
|
||||
*
|
||||
* @author Gerhard Riegler - Initial contribution
|
||||
*/
|
||||
|
||||
public class GardenaConfigDataWrapper {
|
||||
@SerializedName("attributes")
|
||||
private GardenaConfig config;
|
||||
|
||||
@SerializedName("type")
|
||||
private String typeToken = "token";
|
||||
|
||||
public GardenaConfigDataWrapper() {
|
||||
}
|
||||
|
||||
public GardenaConfigDataWrapper(GardenaConfig config) {
|
||||
this.config = config;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.gardena.internal.config;
|
||||
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
|
||||
/**
|
||||
* GardenaConfg wrapper for valid Gardena JSON serialization.
|
||||
*
|
||||
* @author Gerhard Riegler - Initial contribution
|
||||
*/
|
||||
public class GardenaConfigWrapper {
|
||||
@SerializedName("data")
|
||||
private GardenaConfigDataWrapper dataWrapper;
|
||||
|
||||
public GardenaConfigWrapper() {
|
||||
}
|
||||
|
||||
public GardenaConfigWrapper(GardenaConfig config) {
|
||||
this.dataWrapper = new GardenaConfigDataWrapper(config);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,176 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.gardena.internal.discovery;
|
||||
|
||||
import static org.openhab.binding.gardena.internal.GardenaBindingConstants.BINDING_ID;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.concurrent.CancellationException;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.binding.gardena.internal.GardenaSmart;
|
||||
import org.openhab.binding.gardena.internal.exception.GardenaException;
|
||||
import org.openhab.binding.gardena.internal.handler.GardenaAccountHandler;
|
||||
import org.openhab.binding.gardena.internal.model.Device;
|
||||
import org.openhab.binding.gardena.internal.model.Location;
|
||||
import org.openhab.binding.gardena.internal.util.UidUtils;
|
||||
import org.openhab.core.config.discovery.AbstractDiscoveryService;
|
||||
import org.openhab.core.config.discovery.DiscoveryResult;
|
||||
import org.openhab.core.config.discovery.DiscoveryResultBuilder;
|
||||
import org.openhab.core.config.discovery.DiscoveryService;
|
||||
import org.openhab.core.thing.Thing;
|
||||
import org.openhab.core.thing.ThingTypeUID;
|
||||
import org.openhab.core.thing.ThingUID;
|
||||
import org.openhab.core.thing.binding.ThingHandler;
|
||||
import org.openhab.core.thing.binding.ThingHandlerService;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* The {@link GardenaDeviceDiscoveryService} is used to discover devices that are connected to Gardena Smart Home.
|
||||
*
|
||||
* @author Gerhard Riegler - Initial contribution
|
||||
*/
|
||||
public class GardenaDeviceDiscoveryService extends AbstractDiscoveryService
|
||||
implements DiscoveryService, ThingHandlerService {
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(GardenaDeviceDiscoveryService.class);
|
||||
private static final int DISCOVER_TIMEOUT_SECONDS = 30;
|
||||
|
||||
private @NonNullByDefault({}) GardenaAccountHandler accountHandler;
|
||||
private Future<?> scanFuture;
|
||||
|
||||
public GardenaDeviceDiscoveryService() {
|
||||
super(Collections.unmodifiableSet(Stream.of(new ThingTypeUID(BINDING_ID, "-")).collect(Collectors.toSet())),
|
||||
DISCOVER_TIMEOUT_SECONDS, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setThingHandler(@Nullable ThingHandler handler) {
|
||||
if (handler instanceof GardenaAccountHandler) {
|
||||
this.accountHandler = (GardenaAccountHandler) handler;
|
||||
this.accountHandler.setDiscoveryService(this);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable ThingHandler getThingHandler() {
|
||||
return accountHandler;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called on component activation.
|
||||
*/
|
||||
@Override
|
||||
public void activate() {
|
||||
super.activate(null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deactivate() {
|
||||
super.deactivate();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void startScan() {
|
||||
logger.debug("Starting Gardena discovery scan");
|
||||
loadDevices();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stopScan() {
|
||||
logger.debug("Stopping Gardena discovery scan");
|
||||
if (scanFuture != null) {
|
||||
scanFuture.cancel(true);
|
||||
}
|
||||
super.stopScan();
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts a thread which loads all Gardena devices registered in the account
|
||||
*/
|
||||
public void loadDevices() {
|
||||
if (scanFuture == null) {
|
||||
scanFuture = scheduler.submit(() -> {
|
||||
try {
|
||||
GardenaSmart gardena = accountHandler.getGardenaSmart();
|
||||
gardena.loadAllDevices();
|
||||
for (Location location : gardena.getLocations()) {
|
||||
for (String deviceId : location.getDeviceIds()) {
|
||||
deviceDiscovered(gardena.getDevice(deviceId));
|
||||
}
|
||||
}
|
||||
|
||||
for (Thing thing : accountHandler.getThing().getThings()) {
|
||||
try {
|
||||
gardena.getDevice(UidUtils.getGardenaDeviceId(thing));
|
||||
} catch (GardenaException ex) {
|
||||
thingRemoved(thing.getUID());
|
||||
}
|
||||
}
|
||||
|
||||
logger.debug("Finished Gardena device discovery scan on gateway '{}'",
|
||||
accountHandler.getGardenaSmart().getId());
|
||||
} catch (GardenaException ex) {
|
||||
logger.error("{}", ex.getMessage(), ex);
|
||||
} finally {
|
||||
scanFuture = null;
|
||||
removeOlderResults(getTimestampOfLastScan());
|
||||
}
|
||||
});
|
||||
} else {
|
||||
logger.debug("Gardena device discovery scan in progress");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Waits for the discovery scan to finish and then returns.
|
||||
*/
|
||||
public void waitForScanFinishing() {
|
||||
if (scanFuture != null) {
|
||||
logger.debug("Waiting for finishing Gardena device discovery scan");
|
||||
try {
|
||||
scanFuture.get();
|
||||
logger.debug("Gardena device discovery scan finished");
|
||||
} catch (CancellationException ex) {
|
||||
// ignore
|
||||
} catch (Exception ex) {
|
||||
logger.error("Error waiting for device discovery scan: {}", ex.getMessage(), ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates the DiscoveryResult from a Gardena device.
|
||||
*/
|
||||
public void deviceDiscovered(Device device) {
|
||||
ThingUID accountUID = accountHandler.getThing().getUID();
|
||||
ThingUID thingUID = UidUtils.generateThingUID(device, accountHandler.getThing());
|
||||
|
||||
DiscoveryResult discoveryResult = DiscoveryResultBuilder.create(thingUID).withBridge(accountUID)
|
||||
.withLabel(device.getName()).build();
|
||||
thingDiscovered(discoveryResult);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the Gardena device.
|
||||
*/
|
||||
public void deviceRemoved(Device device) {
|
||||
ThingUID thingUID = UidUtils.generateThingUID(device, accountHandler.getThing());
|
||||
thingRemoved(thingUID);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.gardena.internal.exception;
|
||||
|
||||
/**
|
||||
* Exception if a device is not found, this happens if a device is requested and the data from Gardena Smart Home has
|
||||
* not been loaded.
|
||||
*
|
||||
* @author Gerhard Riegler - Initial contribution
|
||||
*/
|
||||
public class GardenaDeviceNotFoundException extends GardenaException {
|
||||
|
||||
private static final long serialVersionUID = 2704767320916725490L;
|
||||
|
||||
public GardenaDeviceNotFoundException(String message) {
|
||||
super(message);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.gardena.internal.exception;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* Exception if something happens in the communication to Gardena Smart Home.
|
||||
*
|
||||
* @author Gerhard Riegler - Initial contribution
|
||||
*/
|
||||
public class GardenaException extends IOException {
|
||||
|
||||
private static final long serialVersionUID = 8568935118878542270L;
|
||||
|
||||
public GardenaException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public GardenaException(Throwable ex) {
|
||||
super(ex);
|
||||
}
|
||||
|
||||
public GardenaException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.gardena.internal.exception;
|
||||
|
||||
/**
|
||||
* Exception for invalid user and password.
|
||||
*
|
||||
* @author Gerhard Riegler - Initial contribution
|
||||
*/
|
||||
public class GardenaUnauthorizedException extends GardenaException {
|
||||
|
||||
private static final long serialVersionUID = 4343137351443555679L;
|
||||
|
||||
public GardenaUnauthorizedException(Throwable ex) {
|
||||
super(ex);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.gardena.internal.handler;
|
||||
|
||||
/**
|
||||
* Exception if the AccountHandler is not available.
|
||||
*
|
||||
* @author Gerhard Riegler - Initial contribution
|
||||
*/
|
||||
public class AccountHandlerNotAvailableException extends Exception {
|
||||
|
||||
private static final long serialVersionUID = -1895774551653276530L;
|
||||
|
||||
public AccountHandlerNotAvailableException(String message) {
|
||||
super(message);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,188 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.gardena.internal.handler;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.openhab.binding.gardena.internal.GardenaSmart;
|
||||
import org.openhab.binding.gardena.internal.GardenaSmartEventListener;
|
||||
import org.openhab.binding.gardena.internal.GardenaSmartImpl;
|
||||
import org.openhab.binding.gardena.internal.config.GardenaConfig;
|
||||
import org.openhab.binding.gardena.internal.discovery.GardenaDeviceDiscoveryService;
|
||||
import org.openhab.binding.gardena.internal.exception.GardenaException;
|
||||
import org.openhab.binding.gardena.internal.model.Device;
|
||||
import org.openhab.binding.gardena.internal.util.UidUtils;
|
||||
import org.openhab.core.thing.Bridge;
|
||||
import org.openhab.core.thing.Channel;
|
||||
import org.openhab.core.thing.ChannelUID;
|
||||
import org.openhab.core.thing.Thing;
|
||||
import org.openhab.core.thing.ThingStatus;
|
||||
import org.openhab.core.thing.ThingStatusDetail;
|
||||
import org.openhab.core.thing.ThingUID;
|
||||
import org.openhab.core.thing.binding.BaseBridgeHandler;
|
||||
import org.openhab.core.thing.binding.ThingHandlerService;
|
||||
import org.openhab.core.types.Command;
|
||||
import org.openhab.core.types.RefreshType;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* The {@link GardenaAccountHandler} is the handler for a Gardena Smart Home access and connects it to the framework.
|
||||
*
|
||||
* @author Gerhard Riegler - Initial contribution
|
||||
*/
|
||||
public class GardenaAccountHandler extends BaseBridgeHandler implements GardenaSmartEventListener {
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(GardenaAccountHandler.class);
|
||||
private static final long REINITIALIZE_DELAY_SECONDS = 10;
|
||||
|
||||
private GardenaDeviceDiscoveryService discoveryService;
|
||||
|
||||
private GardenaSmart gardenaSmart = new GardenaSmartImpl();
|
||||
private GardenaConfig gardenaConfig;
|
||||
|
||||
public GardenaAccountHandler(Bridge bridge) {
|
||||
super(bridge);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initialize() {
|
||||
logger.debug("Initializing Gardena account '{}'", getThing().getUID().getId());
|
||||
|
||||
gardenaConfig = getThing().getConfiguration().as(GardenaConfig.class);
|
||||
logger.debug("{}", gardenaConfig);
|
||||
|
||||
initializeGardena();
|
||||
}
|
||||
|
||||
public void setDiscoveryService(GardenaDeviceDiscoveryService discoveryService) {
|
||||
this.discoveryService = discoveryService;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the GardenaSmart account.
|
||||
*/
|
||||
private void initializeGardena() {
|
||||
final GardenaAccountHandler instance = this;
|
||||
scheduler.execute(() -> {
|
||||
try {
|
||||
String id = getThing().getUID().getId();
|
||||
gardenaSmart.init(id, gardenaConfig, instance, scheduler);
|
||||
discoveryService.startScan(null);
|
||||
discoveryService.waitForScanFinishing();
|
||||
updateStatus(ThingStatus.ONLINE);
|
||||
} catch (GardenaException ex) {
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, ex.getMessage());
|
||||
disposeGardena();
|
||||
scheduleReinitialize();
|
||||
logger.debug("{}", ex.getMessage(), ex);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Schedules a reinitialization, if Gardea Smart Home account is not reachable at startup.
|
||||
*/
|
||||
private void scheduleReinitialize() {
|
||||
scheduler.schedule(() -> {
|
||||
initializeGardena();
|
||||
}, REINITIALIZE_DELAY_SECONDS, TimeUnit.SECONDS);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
super.dispose();
|
||||
disposeGardena();
|
||||
}
|
||||
|
||||
/**
|
||||
* Disposes the GardenaSmart account.
|
||||
*/
|
||||
private void disposeGardena() {
|
||||
logger.debug("Disposing Gardena account '{}'", getThing().getUID().getId());
|
||||
|
||||
discoveryService.stopScan();
|
||||
|
||||
gardenaSmart.dispose();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the Gardena Smart Home implementation.
|
||||
*/
|
||||
public GardenaSmart getGardenaSmart() {
|
||||
return gardenaSmart;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<Class<? extends ThingHandlerService>> getServices() {
|
||||
return Collections.singleton(GardenaDeviceDiscoveryService.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleCommand(ChannelUID channelUID, Command command) {
|
||||
if (RefreshType.REFRESH == command) {
|
||||
logger.debug("Refreshing Gardena account '{}'", getThing().getUID().getId());
|
||||
disposeGardena();
|
||||
initializeGardena();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDeviceUpdated(Device device) {
|
||||
for (ThingUID thingUID : UidUtils.getThingUIDs(device, getThing())) {
|
||||
Thing gardenaThing = getThing().getThing(thingUID);
|
||||
try {
|
||||
GardenaThingHandler gardenaThingHandler = (GardenaThingHandler) gardenaThing.getHandler();
|
||||
gardenaThingHandler.updateProperties(device);
|
||||
for (Channel channel : gardenaThing.getChannels()) {
|
||||
gardenaThingHandler.updateChannel(channel.getUID());
|
||||
}
|
||||
gardenaThingHandler.updateSettings(device);
|
||||
gardenaThingHandler.updateStatus(device);
|
||||
} catch (GardenaException ex) {
|
||||
logger.error("There is something wrong with your thing '{}', please check or recreate it: {}",
|
||||
gardenaThing.getUID(), ex.getMessage());
|
||||
logger.debug("Gardena exception caught on device update.", ex);
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, ex.getMessage());
|
||||
} catch (AccountHandlerNotAvailableException ignore) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNewDevice(Device device) {
|
||||
if (discoveryService != null) {
|
||||
discoveryService.deviceDiscovered(device);
|
||||
}
|
||||
onDeviceUpdated(device);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDeviceDeleted(Device device) {
|
||||
if (discoveryService != null) {
|
||||
discoveryService.deviceRemoved(device);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onConnectionLost() {
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, "Connection lost");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onConnectionResumed() {
|
||||
updateStatus(ThingStatus.ONLINE);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.gardena.internal.handler;
|
||||
|
||||
/**
|
||||
* The {@link GardenaDeviceConfig} class represents the configuration for a device connected to an Gardena account.
|
||||
*
|
||||
* @author Gerhard Riegler - Initial contribution
|
||||
*/
|
||||
|
||||
public class GardenaDeviceConfig {
|
||||
public String deviceId;
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.gardena.internal.handler;
|
||||
|
||||
import static org.openhab.binding.gardena.internal.GardenaBindingConstants.*;
|
||||
|
||||
import org.openhab.core.thing.Bridge;
|
||||
import org.openhab.core.thing.Thing;
|
||||
import org.openhab.core.thing.ThingTypeUID;
|
||||
import org.openhab.core.thing.binding.BaseThingHandlerFactory;
|
||||
import org.openhab.core.thing.binding.ThingHandler;
|
||||
import org.openhab.core.thing.binding.ThingHandlerFactory;
|
||||
import org.osgi.service.component.annotations.Component;
|
||||
|
||||
/**
|
||||
* The {@link GardenaHandlerFactory} is responsible for creating Gardena things and thing handlers.
|
||||
*
|
||||
* @author Gerhard Riegler - Initial contribution
|
||||
*/
|
||||
@Component(service = ThingHandlerFactory.class, configurationPid = "binding.gardena")
|
||||
public class GardenaHandlerFactory extends BaseThingHandlerFactory {
|
||||
|
||||
@Override
|
||||
public boolean supportsThingType(ThingTypeUID thingTypeUID) {
|
||||
return BINDING_ID.equals(thingTypeUID.getBindingId());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ThingHandler createHandler(Thing thing) {
|
||||
if (THING_TYPE_ACCOUNT.equals(thing.getThingTypeUID())) {
|
||||
return new GardenaAccountHandler((Bridge) thing);
|
||||
} else {
|
||||
return new GardenaThingHandler(thing);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,372 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.gardena.internal.handler;
|
||||
|
||||
import static org.openhab.binding.gardena.internal.GardenaBindingConstants.*;
|
||||
import static org.openhab.binding.gardena.internal.GardenaSmartCommandName.*;
|
||||
|
||||
import java.time.ZoneId;
|
||||
import java.time.ZonedDateTime;
|
||||
import java.util.Calendar;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import org.apache.commons.lang.ObjectUtils;
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.openhab.binding.gardena.internal.GardenaSmart;
|
||||
import org.openhab.binding.gardena.internal.GardenaSmartCommandName;
|
||||
import org.openhab.binding.gardena.internal.GardenaSmartImpl;
|
||||
import org.openhab.binding.gardena.internal.exception.GardenaDeviceNotFoundException;
|
||||
import org.openhab.binding.gardena.internal.exception.GardenaException;
|
||||
import org.openhab.binding.gardena.internal.model.Ability;
|
||||
import org.openhab.binding.gardena.internal.model.Device;
|
||||
import org.openhab.binding.gardena.internal.model.Setting;
|
||||
import org.openhab.binding.gardena.internal.util.DateUtils;
|
||||
import org.openhab.binding.gardena.internal.util.UidUtils;
|
||||
import org.openhab.core.config.core.Configuration;
|
||||
import org.openhab.core.config.core.validation.ConfigValidationException;
|
||||
import org.openhab.core.library.types.DateTimeType;
|
||||
import org.openhab.core.library.types.DecimalType;
|
||||
import org.openhab.core.library.types.OnOffType;
|
||||
import org.openhab.core.library.types.StringType;
|
||||
import org.openhab.core.thing.ChannelUID;
|
||||
import org.openhab.core.thing.Thing;
|
||||
import org.openhab.core.thing.ThingStatus;
|
||||
import org.openhab.core.thing.ThingStatusDetail;
|
||||
import org.openhab.core.thing.binding.BaseThingHandler;
|
||||
import org.openhab.core.types.Command;
|
||||
import org.openhab.core.types.RefreshType;
|
||||
import org.openhab.core.types.State;
|
||||
import org.openhab.core.types.Type;
|
||||
import org.openhab.core.types.UnDefType;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* The {@link GardenaThingHandler} is responsible for handling commands, which are sent to one of the channels.
|
||||
*
|
||||
* @author Gerhard Riegler - Initial contribution
|
||||
*/
|
||||
public class GardenaThingHandler extends BaseThingHandler {
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(GardenaThingHandler.class);
|
||||
private final Calendar VALID_DATE_START = DateUtils.parseToCalendar("1970-01-02T00:00Z");
|
||||
|
||||
public GardenaThingHandler(Thing thing) {
|
||||
super(thing);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initialize() {
|
||||
try {
|
||||
Device device = getDevice();
|
||||
updateProperties(device);
|
||||
updateSettings(device);
|
||||
updateStatus(device);
|
||||
} catch (GardenaException ex) {
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, ex.getMessage());
|
||||
} catch (AccountHandlerNotAvailableException ex) {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the thing configuration from the Gardena device.
|
||||
*/
|
||||
protected void updateSettings(Device device) throws GardenaException {
|
||||
if (GardenaSmartImpl.DEVICE_CATEGORY_PUMP.equals(device.getCategory())) {
|
||||
Configuration config = editConfiguration();
|
||||
|
||||
if (!equalsSetting(config, device, SETTING_LEAKAGE_DETECTION)
|
||||
|| !equalsSetting(config, device, SETTING_OPERATION_MODE)
|
||||
|| !equalsSetting(config, device, SETTING_TURN_ON_PRESSURE)) {
|
||||
config.put(SETTING_LEAKAGE_DETECTION, device.getSetting(SETTING_LEAKAGE_DETECTION).getValue());
|
||||
config.put(SETTING_OPERATION_MODE, device.getSetting(SETTING_OPERATION_MODE).getValue());
|
||||
config.put(SETTING_TURN_ON_PRESSURE,
|
||||
ObjectUtils.toString(device.getSetting(SETTING_TURN_ON_PRESSURE).getValue()));
|
||||
updateConfiguration(config);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private boolean equalsSetting(Configuration config, Device device, String key) throws GardenaException {
|
||||
return config.get(key) != null
|
||||
&& config.get(key).equals(ObjectUtils.toString(device.getSetting(key).getValue()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the thing properties from the Gardena device.
|
||||
*/
|
||||
protected void updateProperties(Device device) throws GardenaException {
|
||||
Map<String, String> properties = editProperties();
|
||||
Ability deviceInfo = device.getAbility(ABILITY_DEVICE_INFO);
|
||||
setProperty(properties, deviceInfo, PROPERTY_MANUFACTURER);
|
||||
setProperty(properties, deviceInfo, PROPERTY_PRODUCT);
|
||||
setProperty(properties, deviceInfo, PROPERTY_SERIALNUMBER);
|
||||
setProperty(properties, deviceInfo, PROPERTY_SGTIN);
|
||||
setProperty(properties, deviceInfo, PROPERTY_VERSION);
|
||||
setProperty(properties, deviceInfo, PROPERTY_CATEGORY);
|
||||
updateProperties(properties);
|
||||
}
|
||||
|
||||
private void setProperty(Map<String, String> properties, Ability deviceInfo, String propertyName) {
|
||||
try {
|
||||
properties.put(propertyName, deviceInfo.getProperty(propertyName).getValueAsString());
|
||||
} catch (GardenaException ex) {
|
||||
logger.debug("Ignoring missing device property {}", propertyName);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void channelLinked(ChannelUID channelUID) {
|
||||
try {
|
||||
updateChannel(channelUID);
|
||||
} catch (GardenaDeviceNotFoundException | AccountHandlerNotAvailableException ex) {
|
||||
logger.debug("{}", ex.getMessage(), ex);
|
||||
} catch (GardenaException ex) {
|
||||
logger.error("{}", ex.getMessage(), ex);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the channel from the Gardena device.
|
||||
*/
|
||||
protected void updateChannel(ChannelUID channelUID) throws GardenaException, AccountHandlerNotAvailableException {
|
||||
Device device = getDevice();
|
||||
State state = convertToState(device, channelUID);
|
||||
if (state != null) {
|
||||
updateState(channelUID, state);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a Gardena property value to a openHAB state.
|
||||
*/
|
||||
private State convertToState(Device device, ChannelUID channelUID) throws GardenaException {
|
||||
String abilityName = channelUID.getGroupId();
|
||||
String propertyName = channelUID.getIdWithoutGroup();
|
||||
|
||||
try {
|
||||
String value = device.getAbility(abilityName).getProperty(propertyName).getValueAsString();
|
||||
|
||||
if (StringUtils.trimToNull(value) == null || StringUtils.equals(value, "N/A")) {
|
||||
return UnDefType.NULL;
|
||||
}
|
||||
|
||||
switch (getThing().getChannel(channelUID.getId()).getAcceptedItemType()) {
|
||||
case "String":
|
||||
return new StringType(value);
|
||||
case "Number":
|
||||
if (ABILITY_RADIO.equals(abilityName) && PROPERTY_STATE.equals(propertyName)) {
|
||||
switch (value) {
|
||||
case "poor":
|
||||
return new DecimalType(1);
|
||||
case "good":
|
||||
return new DecimalType(2);
|
||||
case "excellent":
|
||||
return new DecimalType(4);
|
||||
default:
|
||||
return UnDefType.NULL;
|
||||
}
|
||||
}
|
||||
return new DecimalType(value);
|
||||
case "Switch":
|
||||
return Boolean.TRUE.toString().equalsIgnoreCase(value) || "on".equalsIgnoreCase(value)
|
||||
? OnOffType.ON
|
||||
: OnOffType.OFF;
|
||||
case "DateTime":
|
||||
Calendar cal = DateUtils.parseToCalendar(value);
|
||||
if (cal != null && !cal.before(VALID_DATE_START)) {
|
||||
return new DateTimeType(ZonedDateTime.ofInstant(cal.toInstant(), ZoneId.systemDefault()));
|
||||
} else {
|
||||
return UnDefType.NULL;
|
||||
}
|
||||
}
|
||||
} catch (GardenaException e) {
|
||||
logger.warn("Channel '{}' cannot be updated as device does not contain property '{}:{}'", channelUID,
|
||||
abilityName, propertyName);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts an openHAB type to a Gardena command property.
|
||||
*/
|
||||
private Object convertFromType(Type type) {
|
||||
if (type instanceof OnOffType) {
|
||||
return type == OnOffType.ON ? Boolean.TRUE : Boolean.FALSE;
|
||||
} else if (type instanceof DecimalType) {
|
||||
return ((DecimalType) type).intValue();
|
||||
} else if (type instanceof StringType) {
|
||||
return ((StringType) type).toFullString();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleCommand(ChannelUID channelUID, Command command) {
|
||||
try {
|
||||
GardenaSmartCommandName commandName = getCommandName(channelUID);
|
||||
logger.debug("Received Gardena command: {}", commandName);
|
||||
|
||||
if (RefreshType.REFRESH == command) {
|
||||
logger.debug("Refreshing channel '{}'", channelUID);
|
||||
if (commandName != null && commandName.toString().startsWith("MEASURE_")) {
|
||||
getGardenaSmart().sendCommand(getDevice(), commandName, null);
|
||||
} else {
|
||||
updateChannel(channelUID);
|
||||
}
|
||||
} else if (commandName != null) {
|
||||
getGardenaSmart().sendCommand(getDevice(), commandName, convertFromType(command));
|
||||
}
|
||||
} catch (AccountHandlerNotAvailableException | GardenaDeviceNotFoundException ex) {
|
||||
// ignore
|
||||
} catch (Exception ex) {
|
||||
logger.warn("{}", ex.getMessage(), ex);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the Gardena command from the channel.
|
||||
*/
|
||||
private GardenaSmartCommandName getCommandName(ChannelUID channelUID) {
|
||||
switch (channelUID.getId()) {
|
||||
case "mower#park_until_further_notice":
|
||||
return PARK_UNTIL_FURTHER_NOTICE;
|
||||
case "mower#park_until_next_timer":
|
||||
return PARK_UNTIL_NEXT_TIMER;
|
||||
case "mower#start_override_timer":
|
||||
return START_OVERRIDE_TIMER;
|
||||
case "mower#start_resume_schedule":
|
||||
return START_RESUME_SCHEDULE;
|
||||
case "mower#duration_property":
|
||||
return DURATION_PROPERTY;
|
||||
|
||||
case "ambient_temperature#temperature":
|
||||
return MEASURE_AMBIENT_TEMPERATURE;
|
||||
case "soil_temperature#temperature":
|
||||
return MEASURE_SOIL_TEMPERATURE;
|
||||
case "humidity#humidity":
|
||||
return MEASURE_SOIL_HUMIDITY;
|
||||
case "light#light":
|
||||
return MEASURE_LIGHT;
|
||||
|
||||
case "outlet#button_manual_override_time":
|
||||
return OUTLET_MANUAL_OVERRIDE_TIME;
|
||||
case "outlet#valve_open":
|
||||
return OUTLET_VALVE;
|
||||
|
||||
case "power#power_timer":
|
||||
return POWER_TIMER;
|
||||
case "watering#watering_timer_1":
|
||||
return WATERING_TIMER_VALVE_1;
|
||||
case "watering#watering_timer_2":
|
||||
return WATERING_TIMER_VALVE_2;
|
||||
case "watering#watering_timer_3":
|
||||
return WATERING_TIMER_VALVE_3;
|
||||
case "watering#watering_timer_4":
|
||||
return WATERING_TIMER_VALVE_4;
|
||||
case "watering#watering_timer_5":
|
||||
return WATERING_TIMER_VALVE_5;
|
||||
case "watering#watering_timer_6":
|
||||
return WATERING_TIMER_VALVE_6;
|
||||
|
||||
case "manual_watering#manual_watering_timer":
|
||||
return PUMP_MANUAL_WATERING_TIMER;
|
||||
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the thing status based on the Gardena device status.
|
||||
*/
|
||||
protected void updateStatus(Device device) {
|
||||
String connectionStatus = "";
|
||||
try {
|
||||
connectionStatus = device.getAbility(ABILITY_RADIO).getProperty(PROPERTY_CONNECTION_STATUS)
|
||||
.getValueAsString();
|
||||
} catch (GardenaException ex) {
|
||||
// ignore, device has no connection status property
|
||||
}
|
||||
|
||||
boolean isUnreach = PROPERTY_CONNECTION_STATUS_UNREACH_VALUE.equals(connectionStatus);
|
||||
|
||||
ThingStatus oldStatus = thing.getStatus();
|
||||
ThingStatus newStatus = ThingStatus.ONLINE;
|
||||
ThingStatusDetail newDetail = ThingStatusDetail.NONE;
|
||||
|
||||
if (isUnreach) {
|
||||
newStatus = ThingStatus.OFFLINE;
|
||||
newDetail = ThingStatusDetail.COMMUNICATION_ERROR;
|
||||
} else if (!device.isConfigurationSynchronized()) {
|
||||
newStatus = thing.getStatus();
|
||||
newDetail = ThingStatusDetail.CONFIGURATION_PENDING;
|
||||
}
|
||||
|
||||
if (oldStatus != newStatus || thing.getStatusInfo().getStatusDetail() != newDetail) {
|
||||
updateStatus(newStatus, newDetail);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleConfigurationUpdate(Map<String, Object> configurationParameters)
|
||||
throws ConfigValidationException {
|
||||
validateConfigurationParameters(configurationParameters);
|
||||
|
||||
try {
|
||||
GardenaSmart gardena = getGardenaSmart();
|
||||
Device device = gardena.getDevice(UidUtils.getGardenaDeviceId(getThing()));
|
||||
|
||||
for (Entry<String, Object> configurationParmeter : configurationParameters.entrySet()) {
|
||||
String key = configurationParmeter.getKey();
|
||||
Object newValue = configurationParmeter.getValue();
|
||||
if (newValue != null && SETTING_TURN_ON_PRESSURE.equals(key)) {
|
||||
newValue = new Double((String) newValue);
|
||||
}
|
||||
|
||||
Setting setting = device.getSetting(key);
|
||||
if (ObjectUtils.notEqual(setting.getValue(), newValue)) {
|
||||
gardena.sendSetting(setting, newValue);
|
||||
setting.setValue(newValue);
|
||||
}
|
||||
}
|
||||
updateSettings(device);
|
||||
} catch (GardenaException | AccountHandlerNotAvailableException ex) {
|
||||
logger.warn("Error setting thing properties: {}", ex.getMessage(), ex);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the Gardena device for this ThingHandler.
|
||||
*/
|
||||
private Device getDevice() throws GardenaException, AccountHandlerNotAvailableException {
|
||||
return getGardenaSmart().getDevice(UidUtils.getGardenaDeviceId(getThing()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the Gardena Smart Home implementation if the bridge is available.
|
||||
*/
|
||||
private GardenaSmart getGardenaSmart() throws AccountHandlerNotAvailableException {
|
||||
if (getBridge() == null || getBridge().getHandler() == null
|
||||
|| ((GardenaAccountHandler) getBridge().getHandler()).getGardenaSmart() == null) {
|
||||
if (thing.getStatus() != ThingStatus.INITIALIZING) {
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.HANDLER_MISSING_ERROR);
|
||||
}
|
||||
throw new AccountHandlerNotAvailableException("Gardena AccountHandler not yet available!");
|
||||
}
|
||||
|
||||
return ((GardenaAccountHandler) getBridge().getHandler()).getGardenaSmart();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.gardena.internal.model;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.openhab.binding.gardena.internal.exception.GardenaException;
|
||||
|
||||
/**
|
||||
* Represents a Gardena ability.
|
||||
*
|
||||
* @author Gerhard Riegler - Initial contribution
|
||||
*/
|
||||
public class Ability {
|
||||
|
||||
private String name;
|
||||
private String type;
|
||||
private transient Device device;
|
||||
|
||||
private List<Property> properties = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* Returns the name of the ability.
|
||||
*/
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the type of the ability.
|
||||
*/
|
||||
public String getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of properties of the ability.
|
||||
*/
|
||||
public List<Property> getProperties() {
|
||||
return properties;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a property to this ability.
|
||||
*/
|
||||
public void addProperty(Property property) {
|
||||
property.setAbility(this);
|
||||
properties.add(property);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the property with the specified name.
|
||||
*/
|
||||
public Property getProperty(String name) throws GardenaException {
|
||||
for (Property property : properties) {
|
||||
if (property.getName().equals(name)) {
|
||||
return property;
|
||||
}
|
||||
}
|
||||
throw new GardenaException("Property '" + name + "' not found in ability '" + this.name + "'");
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the device of the ability.
|
||||
*/
|
||||
public Device getDevice() {
|
||||
return device;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the name of the ability.
|
||||
*/
|
||||
public void setDevice(Device device) {
|
||||
this.device = device;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,147 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.gardena.internal.model;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.commons.lang.builder.EqualsBuilder;
|
||||
import org.apache.commons.lang.builder.HashCodeBuilder;
|
||||
import org.openhab.binding.gardena.internal.exception.GardenaException;
|
||||
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
|
||||
/**
|
||||
* Represents a Gardena device.
|
||||
*
|
||||
* @author Gerhard Riegler - Initial contribution
|
||||
*/
|
||||
public class Device {
|
||||
|
||||
private String id;
|
||||
private String name;
|
||||
private String description;
|
||||
private String category;
|
||||
@SerializedName("configuration_synchronized")
|
||||
private boolean configurationSynchronized;
|
||||
private List<Ability> abilities = new ArrayList<>();
|
||||
@SerializedName("scheduled_events")
|
||||
private List<ScheduledEvent> scheduledEvents = new ArrayList<>();
|
||||
private transient Location location;
|
||||
private List<Setting> settings = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* Returns the id of the device.
|
||||
*/
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name of the device.
|
||||
*/
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the description of the device.
|
||||
*/
|
||||
public String getDescription() {
|
||||
return description;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the category of the device.
|
||||
*/
|
||||
public String getCategory() {
|
||||
return category;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true, if all configurations are synchronized.
|
||||
*/
|
||||
public boolean isConfigurationSynchronized() {
|
||||
return configurationSynchronized;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of abilities of the device.
|
||||
*/
|
||||
public List<Ability> getAbilities() {
|
||||
return abilities;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of scheduled events of the device.
|
||||
*/
|
||||
public List<ScheduledEvent> getScheduledEvents() {
|
||||
return scheduledEvents;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the location of the device.
|
||||
*/
|
||||
public Location getLocation() {
|
||||
return location;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the location of the device.
|
||||
*/
|
||||
public void setLocation(Location location) {
|
||||
this.location = location;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the ability with the specified name.
|
||||
*/
|
||||
public Ability getAbility(String name) throws GardenaException {
|
||||
for (Ability ability : abilities) {
|
||||
if (ability.getName().equals(name)) {
|
||||
return ability;
|
||||
}
|
||||
}
|
||||
throw new GardenaException("Ability '" + name + "' not found in device '" + this.name + "'");
|
||||
}
|
||||
|
||||
public List<Setting> getSettings() {
|
||||
return settings;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the setting with the specified name.
|
||||
*/
|
||||
public Setting getSetting(String name) throws GardenaException {
|
||||
for (Setting setting : settings) {
|
||||
if (setting.getName().equals(name)) {
|
||||
return setting;
|
||||
}
|
||||
}
|
||||
throw new GardenaException("Setting '" + name + "' not found in device '" + this.name + "'");
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return new HashCodeBuilder().append(id).toHashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (obj == null || !(obj instanceof Device)) {
|
||||
return false;
|
||||
}
|
||||
Device comp = (Device) obj;
|
||||
return new EqualsBuilder().append(comp.getId(), id).isEquals();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.gardena.internal.model;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Represents a List of Gardena devices.
|
||||
*
|
||||
* @author Gerhard Riegler - Initial contribution
|
||||
*/
|
||||
public class Devices {
|
||||
|
||||
private List<Device> devices = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* Returns a list of Gardena devices.
|
||||
*/
|
||||
public List<Device> getDevices() {
|
||||
return devices;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.gardena.internal.model;
|
||||
|
||||
import org.apache.commons.lang.builder.ToStringBuilder;
|
||||
import org.apache.commons.lang.builder.ToStringStyle;
|
||||
|
||||
/**
|
||||
* Represents a Gardena error.
|
||||
*
|
||||
* @author Gerhard Riegler - Initial contribution
|
||||
*/
|
||||
public class Error {
|
||||
|
||||
private String id;
|
||||
private String status;
|
||||
private String title;
|
||||
private String detail;
|
||||
|
||||
/**
|
||||
* Returns the id of the error.
|
||||
*/
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the status of the error.
|
||||
*/
|
||||
public String getStatus() {
|
||||
return status;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the title of the error.
|
||||
*/
|
||||
public String getTitle() {
|
||||
return title;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the detail of the error.
|
||||
*/
|
||||
public String getDetail() {
|
||||
return detail;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE).append("id", id).append("status", status)
|
||||
.append("title", title).append("detail", detail).toString();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.gardena.internal.model;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.commons.lang.builder.ToStringBuilder;
|
||||
import org.apache.commons.lang.builder.ToStringStyle;
|
||||
|
||||
/**
|
||||
* Represents a List of Gardena errors.
|
||||
*
|
||||
* @author Gerhard Riegler - Initial contribution
|
||||
*/
|
||||
public class Errors {
|
||||
|
||||
private List<Error> errors = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* Returns a list of Gardena errors.
|
||||
*/
|
||||
public List<Error> getErrors() {
|
||||
return errors;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
ToStringBuilder tsb = new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE);
|
||||
for (Error error : errors) {
|
||||
tsb.append(error);
|
||||
}
|
||||
return tsb.toString();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.gardena.internal.model;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.commons.lang.builder.EqualsBuilder;
|
||||
import org.apache.commons.lang.builder.HashCodeBuilder;
|
||||
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
|
||||
/**
|
||||
* Represents a Gardena location.
|
||||
*
|
||||
* @author Gerhard Riegler - Initial contribution
|
||||
*/
|
||||
public class Location {
|
||||
|
||||
private String id;
|
||||
private String name;
|
||||
@SerializedName("devices")
|
||||
public List<String> deviceIds = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* Returns the id of the location.
|
||||
*/
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name of the location.
|
||||
*/
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the device ids of the location.
|
||||
*/
|
||||
public List<String> getDeviceIds() {
|
||||
return deviceIds;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return new HashCodeBuilder().append(id).toHashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (obj == null || !(obj instanceof Location)) {
|
||||
return false;
|
||||
}
|
||||
Location comp = (Location) obj;
|
||||
return new EqualsBuilder().append(comp.getId(), id).isEquals();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.gardena.internal.model;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Represents a List of Gardena locations.
|
||||
*
|
||||
* @author Gerhard Riegler - Initial contribution
|
||||
*/
|
||||
public class Locations {
|
||||
|
||||
private List<Location> locations = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* Returns a list of Gardena locations.
|
||||
*/
|
||||
public List<Location> getLocations() {
|
||||
return locations;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.gardena.internal.model;
|
||||
|
||||
/**
|
||||
* Empty class that represents a emtpy result from Gardena Smart Home.
|
||||
*
|
||||
* @author Gerhard Riegler - Initial contribution
|
||||
*/
|
||||
public class NoResult {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,117 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.gardena.internal.model;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
import org.openhab.binding.gardena.internal.GardenaSmartCommandName;
|
||||
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
|
||||
/**
|
||||
* Represents a Gardena property.
|
||||
*
|
||||
* @author Gerhard Riegler - Initial contribution
|
||||
*/
|
||||
public class Property {
|
||||
|
||||
private String name;
|
||||
private PropertyValue value;
|
||||
private Date timestamp;
|
||||
private String unit;
|
||||
private boolean writeable;
|
||||
|
||||
@SerializedName("supported_values")
|
||||
private List<String> supportedValues;
|
||||
private transient Ability ability;
|
||||
|
||||
public Property() {
|
||||
}
|
||||
|
||||
public Property(GardenaSmartCommandName commandName, String value) {
|
||||
this.name = commandName.toString().toLowerCase();
|
||||
this.value = new PropertyValue(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name of the property.
|
||||
*/
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value of the property.
|
||||
*/
|
||||
public String getValueAsString() {
|
||||
return value != null ? value.getValue() : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value of the property.
|
||||
*/
|
||||
public PropertyValue getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the value of the property.
|
||||
*/
|
||||
public void setValue(PropertyValue value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the timestamp of the property.
|
||||
*/
|
||||
public Date getTimestamp() {
|
||||
return timestamp;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the unit of the property.
|
||||
*/
|
||||
public String getUnit() {
|
||||
return unit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true, if the property is writeable.
|
||||
*/
|
||||
public boolean isWriteable() {
|
||||
return writeable;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of supported values.
|
||||
*/
|
||||
public List<String> getSupportedValues() {
|
||||
return supportedValues;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the ability of the property.
|
||||
*/
|
||||
|
||||
public Ability getAbility() {
|
||||
return ability;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the ability of the property.
|
||||
*/
|
||||
public void setAbility(Ability ability) {
|
||||
this.ability = ability;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.gardena.internal.model;
|
||||
|
||||
/**
|
||||
* Represents a Gardena property value.
|
||||
*
|
||||
* @author Gerhard Riegler - Initial contribution
|
||||
*/
|
||||
public class PropertyValue {
|
||||
private String value;
|
||||
|
||||
public PropertyValue() {
|
||||
}
|
||||
|
||||
public PropertyValue(String value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value of the property.
|
||||
*/
|
||||
public String getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the value of the property.
|
||||
*/
|
||||
public void setValue(String value) {
|
||||
this.value = value;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.gardena.internal.model;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Represents a Gardena recurrence.
|
||||
*
|
||||
* @author Gerhard Riegler - Initial contribution
|
||||
*/
|
||||
public class Recurrence {
|
||||
|
||||
private String type;
|
||||
private List<String> weekdays;
|
||||
|
||||
/**
|
||||
* Returns the type of the recurrence.
|
||||
*/
|
||||
public String getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of weekdays.
|
||||
*/
|
||||
public List<String> getWeekdays() {
|
||||
return weekdays;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.gardena.internal.model;
|
||||
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
|
||||
/**
|
||||
* Represents a Gardena scheduled event.
|
||||
*
|
||||
* @author Gerhard Riegler - Initial contribution
|
||||
*/
|
||||
public class ScheduledEvent {
|
||||
|
||||
private String id;
|
||||
private String type;
|
||||
@SerializedName("start_at")
|
||||
private String start;
|
||||
@SerializedName("end_at")
|
||||
private String end;
|
||||
private String weekday;
|
||||
|
||||
private Recurrence recurrence = new Recurrence();
|
||||
|
||||
/**
|
||||
* Returns the id of the scheduled event.
|
||||
*/
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the type of the scheduled event.
|
||||
*/
|
||||
public String getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the start of the scheduled event.
|
||||
*/
|
||||
public String getStart() {
|
||||
return start;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the end of the scheduled event.
|
||||
*/
|
||||
public String getEnd() {
|
||||
return end;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the weekday of the scheduled event.
|
||||
*/
|
||||
public String getWeekday() {
|
||||
return weekday;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the recurrence of the scheduled event.
|
||||
*/
|
||||
public Recurrence getRecurrence() {
|
||||
return recurrence;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.gardena.internal.model;
|
||||
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
|
||||
/**
|
||||
* Represents a Gardena session.
|
||||
*
|
||||
* @author Gerhard Riegler - Initial contribution
|
||||
*/
|
||||
public class Session {
|
||||
@SerializedName("id")
|
||||
private String token;
|
||||
private long created;
|
||||
|
||||
@SerializedName("attributes")
|
||||
private SessionAttributes sessionAttributes = new SessionAttributes();
|
||||
|
||||
public Session() {
|
||||
this.created = System.currentTimeMillis();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the token of the session.
|
||||
*/
|
||||
public String getToken() {
|
||||
return token;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the creation timestamp of the session.
|
||||
*/
|
||||
public long getCreated() {
|
||||
return created;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the session attributes.
|
||||
*/
|
||||
public SessionAttributes getSessionAttributes() {
|
||||
return sessionAttributes;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.gardena.internal.model;
|
||||
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
|
||||
/**
|
||||
* Session attributes for valid Gardena JSON serialization.
|
||||
*
|
||||
* @author Gerhard Riegler - Initial contribution
|
||||
*/
|
||||
public class SessionAttributes {
|
||||
@SerializedName("user_id")
|
||||
private String userId;
|
||||
|
||||
@SerializedName("provider")
|
||||
private String provider;
|
||||
|
||||
/**
|
||||
* Returns the user id.
|
||||
*/
|
||||
public String getUserId() {
|
||||
return userId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the user id.
|
||||
*/
|
||||
public void setUserId(String userId) {
|
||||
this.userId = userId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the provider.
|
||||
*/
|
||||
public String getProvider() {
|
||||
return provider;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the provider.
|
||||
*/
|
||||
public void setProvider(String provider) {
|
||||
this.provider = provider;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.gardena.internal.model;
|
||||
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
|
||||
/**
|
||||
* Session wrapper for valid Gardena JSON serialization.
|
||||
*
|
||||
* @author Gerhard Riegler - Initial contribution
|
||||
*/
|
||||
public class SessionWrapper {
|
||||
@SerializedName("data")
|
||||
private Session session;
|
||||
|
||||
public SessionWrapper() {
|
||||
}
|
||||
|
||||
public SessionWrapper(Session session) {
|
||||
this.session = session;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the session.
|
||||
*/
|
||||
public Session getSession() {
|
||||
return session;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the session.
|
||||
*/
|
||||
public void setSession(Session session) {
|
||||
this.session = session;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.gardena.internal.model;
|
||||
|
||||
/**
|
||||
* Represents a Gardena setting.
|
||||
*
|
||||
* @author Gerhard Riegler - Initial contribution
|
||||
*/
|
||||
|
||||
public class Setting {
|
||||
private String name;
|
||||
private String id;
|
||||
private Object value;
|
||||
private transient Device device;
|
||||
|
||||
/**
|
||||
* Returns the name of the setting.
|
||||
*/
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the id of the setting.
|
||||
*/
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value of the setting.
|
||||
*/
|
||||
public Object getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the name of the setting.
|
||||
*/
|
||||
public void setValue(Object value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the device of the setting.
|
||||
*/
|
||||
public Device getDevice() {
|
||||
return device;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the name of the setting.
|
||||
*/
|
||||
public void setDevice(Device device) {
|
||||
this.device = device;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,94 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.gardena.internal.model.command;
|
||||
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
|
||||
/**
|
||||
* Base class for a Gardena command with parameters.
|
||||
*
|
||||
* @author Gerhard Riegler - Initial contribution
|
||||
*/
|
||||
public abstract class Command {
|
||||
|
||||
@SerializedName(value = "name")
|
||||
protected String command;
|
||||
protected CommandParameters parameters;
|
||||
|
||||
/**
|
||||
* Creates a command with the given name.
|
||||
*/
|
||||
public Command(String command) {
|
||||
this.command = command;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the command name.
|
||||
*/
|
||||
public String getCommand() {
|
||||
return command;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the parameters of the command.
|
||||
*/
|
||||
public CommandParameters getParameters() {
|
||||
return parameters;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the parameters of the command.
|
||||
*/
|
||||
public void setParameters(CommandParameters parameters) {
|
||||
this.parameters = parameters;
|
||||
}
|
||||
|
||||
/**
|
||||
* Class to hold the command parameters.
|
||||
*
|
||||
* @author Gerhard Riegler - Initial contribution
|
||||
*/
|
||||
public class CommandParameters {
|
||||
private String duration;
|
||||
@SerializedName("manual_override")
|
||||
private String manualOverride;
|
||||
|
||||
/**
|
||||
* Returns the duration parameter.
|
||||
*/
|
||||
public String getDuration() {
|
||||
return duration;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the duration parameter.
|
||||
*/
|
||||
public void setDuration(String duration) {
|
||||
this.duration = duration;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the manual override parameter.
|
||||
*/
|
||||
public String getManualOverride() {
|
||||
return manualOverride;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the manual override parameter.
|
||||
*/
|
||||
public void setManualOverride(String manualOverride) {
|
||||
this.manualOverride = manualOverride;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.gardena.internal.model.command;
|
||||
|
||||
/**
|
||||
* Command to park a mower until further notice.
|
||||
*
|
||||
* @author Gerhard Riegler - Initial contribution
|
||||
*/
|
||||
public class MowerParkUntilFurtherNoticeCommand extends Command {
|
||||
private static final String COMMAND = "park_until_further_notice";
|
||||
|
||||
public MowerParkUntilFurtherNoticeCommand() {
|
||||
super(COMMAND);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.gardena.internal.model.command;
|
||||
|
||||
/**
|
||||
* Command to park a mower until next timer.
|
||||
*
|
||||
* @author Gerhard Riegler - Initial contribution
|
||||
*/
|
||||
|
||||
public class MowerParkUntilNextTimerCommand extends Command {
|
||||
private static final String COMMAND = "park_until_next_timer";
|
||||
|
||||
public MowerParkUntilNextTimerCommand() {
|
||||
super(COMMAND);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.gardena.internal.model.command;
|
||||
|
||||
/**
|
||||
* Command to manually override the mower timer.
|
||||
*
|
||||
* @author Gerhard Riegler - Initial contribution
|
||||
*/
|
||||
|
||||
public class MowerStartOverrideTimerCommand extends Command {
|
||||
private static final String COMMAND = "start_override_timer";
|
||||
|
||||
public MowerStartOverrideTimerCommand(String durationInMinutes) {
|
||||
super(COMMAND);
|
||||
parameters = new CommandParameters();
|
||||
parameters.setDuration(durationInMinutes);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.gardena.internal.model.command;
|
||||
|
||||
/**
|
||||
* Command to resume the mower scheduler.
|
||||
*
|
||||
* @author Gerhard Riegler - Initial contribution
|
||||
*/
|
||||
|
||||
public class MowerStartResumeScheduleCommand extends Command {
|
||||
private static final String COMMAND = "start_resume_schedule";
|
||||
|
||||
public MowerStartResumeScheduleCommand() {
|
||||
super(COMMAND);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.gardena.internal.model.command;
|
||||
|
||||
/**
|
||||
* Sensor command to measure the ambient temperatur.
|
||||
*
|
||||
* @author Gerhard Riegler - Initial contribution
|
||||
*/
|
||||
|
||||
public class SensorMeasureAmbientTemperatureCommand extends Command {
|
||||
private static final String COMMAND = "measure_ambient_temperature";
|
||||
|
||||
public SensorMeasureAmbientTemperatureCommand() {
|
||||
super(COMMAND);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.gardena.internal.model.command;
|
||||
|
||||
/**
|
||||
* Sensor command to measure the light.
|
||||
*
|
||||
* @author Gerhard Riegler - Initial contribution
|
||||
*/
|
||||
|
||||
public class SensorMeasureLightCommand extends Command {
|
||||
private static final String COMMAND = "measure_light";
|
||||
|
||||
public SensorMeasureLightCommand() {
|
||||
super(COMMAND);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.gardena.internal.model.command;
|
||||
|
||||
/**
|
||||
* Sensor command to measure the soil humidity.
|
||||
*
|
||||
* @author Gerhard Riegler - Initial contribution
|
||||
*/
|
||||
|
||||
public class SensorMeasureSoilHumidityCommand extends Command {
|
||||
private static final String COMMAND = "measure_soil_humidity";
|
||||
|
||||
public SensorMeasureSoilHumidityCommand() {
|
||||
super(COMMAND);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.gardena.internal.model.command;
|
||||
|
||||
/**
|
||||
* Sensor command to measure the soil temperature.
|
||||
*
|
||||
* @author Gerhard Riegler - Initial contribution
|
||||
*/
|
||||
|
||||
public class SensorMeasureSoilTemperatureCommand extends Command {
|
||||
private static final String COMMAND = "measure_soil_temperature";
|
||||
|
||||
public SensorMeasureSoilTemperatureCommand() {
|
||||
super(COMMAND);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.gardena.internal.model.command;
|
||||
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
|
||||
/**
|
||||
* Common command to set a device setting.
|
||||
*
|
||||
* @author Gerhard Riegler - Initial contribution
|
||||
*/
|
||||
public class SettingCommand extends Command {
|
||||
private Object value;
|
||||
@SerializedName("device")
|
||||
private String deviceId;
|
||||
|
||||
public SettingCommand(String name) {
|
||||
super(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value of the setting command.
|
||||
*/
|
||||
public Object getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the value of the setting command.
|
||||
*/
|
||||
public void setValue(Object value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the device id of the setting command.
|
||||
*/
|
||||
public String getDeviceId() {
|
||||
return deviceId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the device id of the setting command.
|
||||
*/
|
||||
public void setDeviceId(String deviceId) {
|
||||
this.deviceId = deviceId;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.gardena.internal.model.command;
|
||||
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
|
||||
/**
|
||||
* SettingComand wrapper for valid Gardena JSON serialization.
|
||||
*
|
||||
* @author Gerhard Riegler - Initial contribution
|
||||
*/
|
||||
public class SettingCommandWrapper {
|
||||
@SerializedName("settings")
|
||||
private SettingCommand command;
|
||||
|
||||
public SettingCommandWrapper(SettingCommand command) {
|
||||
this.command = command;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the setting command.
|
||||
*/
|
||||
public SettingCommand getCommand() {
|
||||
return command;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.gardena.internal.model.command;
|
||||
|
||||
/**
|
||||
* Command to cancel the manual watering.
|
||||
*
|
||||
* @author Gerhard Riegler - Initial contribution
|
||||
*/
|
||||
|
||||
public class WateringCancelOverrideCommand extends Command {
|
||||
private static final String COMMAND = "cancel_override";
|
||||
|
||||
public WateringCancelOverrideCommand() {
|
||||
super(COMMAND);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.gardena.internal.model.command;
|
||||
|
||||
/**
|
||||
* Command to start the manual watering.
|
||||
*
|
||||
* @author Gerhard Riegler - Initial contribution
|
||||
*/
|
||||
|
||||
public class WateringManualOverrideCommand extends Command {
|
||||
private static final String COMMAND = "manual_override";
|
||||
|
||||
public WateringManualOverrideCommand(String durationInMinutes) {
|
||||
super(COMMAND);
|
||||
parameters = new CommandParameters();
|
||||
parameters.setDuration(durationInMinutes);
|
||||
parameters.setManualOverride("open");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.gardena.internal.model.deser;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.Date;
|
||||
|
||||
import org.openhab.binding.gardena.internal.util.DateUtils;
|
||||
|
||||
import com.google.gson.JsonDeserializationContext;
|
||||
import com.google.gson.JsonDeserializer;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonParseException;
|
||||
|
||||
/**
|
||||
* Custom deserializer for date types.
|
||||
*
|
||||
* @author Gerhard Riegler - Initial contribution
|
||||
*/
|
||||
public class DateDeserializer implements JsonDeserializer<Date> {
|
||||
|
||||
@Override
|
||||
public Date deserialize(JsonElement element, Type type, JsonDeserializationContext ctx) throws JsonParseException {
|
||||
return DateUtils.parseToDate(element.getAsString());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.gardena.internal.model.deser;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.openhab.binding.gardena.internal.model.PropertyValue;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.google.gson.JsonArray;
|
||||
import com.google.gson.JsonDeserializationContext;
|
||||
import com.google.gson.JsonDeserializer;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonParseException;
|
||||
|
||||
/**
|
||||
* Custom deserializer for Gardena complex property value type.
|
||||
*
|
||||
* @author Gerhard Riegler - Initial contribution
|
||||
*/
|
||||
public class PropertyValueDeserializer implements JsonDeserializer<PropertyValue> {
|
||||
private final Logger logger = LoggerFactory.getLogger(PropertyValueDeserializer.class);
|
||||
|
||||
private static final String PROPERTY_DURATION = "duration";
|
||||
private static final String PROPERTY_TYPE = "type";
|
||||
private static final String PROPERTY_MAC = "mac";
|
||||
private static final String PROPERTY_ISCONNECTED = "isconnected";
|
||||
|
||||
@Override
|
||||
public PropertyValue deserialize(JsonElement element, Type type, JsonDeserializationContext ctx)
|
||||
throws JsonParseException {
|
||||
if (element.isJsonObject()) {
|
||||
JsonObject jsonObj = element.getAsJsonObject();
|
||||
if (jsonObj.has(PROPERTY_DURATION)) {
|
||||
long duration = jsonObj.get(PROPERTY_DURATION).getAsLong();
|
||||
if (duration != 0) {
|
||||
duration = Math.round(duration / 60.0);
|
||||
}
|
||||
return new PropertyValue(String.valueOf(duration));
|
||||
} else if (jsonObj.has(PROPERTY_TYPE)) {
|
||||
return new PropertyValue(jsonObj.get(PROPERTY_TYPE).getAsString());
|
||||
} else if (jsonObj.has(PROPERTY_MAC) && jsonObj.has(PROPERTY_ISCONNECTED)) {
|
||||
// ignore known gateway properties
|
||||
return new PropertyValue();
|
||||
} else {
|
||||
logger.warn("Unsupported json value object, returning empty value");
|
||||
return new PropertyValue();
|
||||
}
|
||||
|
||||
} else if (element.isJsonArray()) {
|
||||
JsonArray jsonArray = element.getAsJsonArray();
|
||||
return new PropertyValue(StringUtils.join(jsonArray.iterator(), ","));
|
||||
} else {
|
||||
return new PropertyValue(element.getAsString());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.gardena.internal.model.property;
|
||||
|
||||
/**
|
||||
* Base class to send properties to Gardena.
|
||||
*
|
||||
* @author Gerhard Riegler - Initial contribution
|
||||
*/
|
||||
public abstract class BaseProperty {
|
||||
private String name;
|
||||
|
||||
public BaseProperty(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the property name.
|
||||
*/
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value of the property.
|
||||
*/
|
||||
public abstract String getValue();
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.gardena.internal.model.property;
|
||||
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
|
||||
/**
|
||||
* Represents a Gardena complex property value for the irrigation control.
|
||||
*
|
||||
* @author Gerhard Riegler - Initial contribution
|
||||
*/
|
||||
|
||||
public class IrrigationControlWateringProperty extends BaseProperty {
|
||||
private IrrigationControlWateringValue value = new IrrigationControlWateringValue();
|
||||
|
||||
public IrrigationControlWateringProperty(String name, int duration, int valveId) {
|
||||
super(name);
|
||||
|
||||
value.state = duration == 0 ? "idle" : "manual";
|
||||
value.duration = duration;
|
||||
value.valveId = valveId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getValue() {
|
||||
return String.valueOf(value.duration);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private class IrrigationControlWateringValue {
|
||||
public String state;
|
||||
public int duration;
|
||||
@SerializedName("valve_id")
|
||||
public int valveId;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.gardena.internal.model.property;
|
||||
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
|
||||
/**
|
||||
* Property wrapper for valid Gardena JSON serialization.
|
||||
*
|
||||
* @author Gerhard Riegler - Initial contribution
|
||||
*/
|
||||
public class PropertyWrapper {
|
||||
@SerializedName("properties")
|
||||
private BaseProperty property;
|
||||
|
||||
public PropertyWrapper() {
|
||||
}
|
||||
|
||||
public PropertyWrapper(BaseProperty property) {
|
||||
this.property = property;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the property.
|
||||
*/
|
||||
public BaseProperty getProperty() {
|
||||
return property;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the property.
|
||||
*/
|
||||
public void setProperties(BaseProperty property) {
|
||||
this.property = property;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.gardena.internal.model.property;
|
||||
|
||||
/**
|
||||
* Represents a String Gardena property.
|
||||
*
|
||||
* @author Gerhard Riegler - Initial contribution
|
||||
*/
|
||||
public class StringProperty extends BaseProperty {
|
||||
private String value;
|
||||
|
||||
public StringProperty(String name, String value) {
|
||||
super(name);
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the property value.
|
||||
*/
|
||||
@Override
|
||||
public String getValue() {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.gardena.internal.util;
|
||||
|
||||
import java.text.ParseException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.ZoneId;
|
||||
import java.time.ZoneOffset;
|
||||
import java.time.ZonedDateTime;
|
||||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* Utility class to convert a String to a date or calendar.
|
||||
*
|
||||
* @author Gerhard Riegler - Initial contribution
|
||||
*/
|
||||
public class DateUtils {
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(DateUtils.class);
|
||||
private static final String[] DATE_FORMATS = new String[] { "yyyy-MM-dd'T'HH:mm:ss'Z'",
|
||||
"yyyy-MM-dd'T'HH:mm:ss.SSS'Z'", "yyyy-MM-dd'T'HH:mm'Z'" };
|
||||
|
||||
/**
|
||||
* Converts a string to a Date, trying different date formats used by Gardena.
|
||||
*/
|
||||
public static Date parseToDate(String text) {
|
||||
if (StringUtils.isNotBlank(text)) {
|
||||
Date parsedDate = null;
|
||||
for (String dateFormat : DATE_FORMATS) {
|
||||
try {
|
||||
parsedDate = new SimpleDateFormat(dateFormat).parse(text);
|
||||
ZonedDateTime gmt = ZonedDateTime.ofInstant(parsedDate.toInstant(), ZoneOffset.UTC);
|
||||
LocalDateTime here = gmt.withZoneSameInstant(ZoneId.systemDefault()).toLocalDateTime();
|
||||
parsedDate = Date.from(here.toInstant(ZoneOffset.UTC));
|
||||
break;
|
||||
} catch (ParseException ex) {
|
||||
}
|
||||
}
|
||||
if (parsedDate == null) {
|
||||
LOGGER.error("Can't parse date {}", text);
|
||||
}
|
||||
return parsedDate;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a string to a Calendar, trying different date formats used by Gardena.
|
||||
*/
|
||||
public static Calendar parseToCalendar(String text) {
|
||||
Date parsedDate = parseToDate(text);
|
||||
if (parsedDate != null) {
|
||||
Calendar cal = Calendar.getInstance();
|
||||
cal.setTime(parsedDate);
|
||||
return cal;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.gardena.internal.util;
|
||||
|
||||
import static org.openhab.binding.gardena.internal.GardenaBindingConstants.BINDING_ID;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.openhab.binding.gardena.internal.handler.GardenaDeviceConfig;
|
||||
import org.openhab.binding.gardena.internal.model.Device;
|
||||
import org.openhab.core.thing.Bridge;
|
||||
import org.openhab.core.thing.Thing;
|
||||
import org.openhab.core.thing.ThingTypeUID;
|
||||
import org.openhab.core.thing.ThingUID;
|
||||
|
||||
/**
|
||||
* Utility class for converting between a Thing and a Gardena device.
|
||||
*
|
||||
* @author Gerhard Riegler - Initial contribution
|
||||
*/
|
||||
public class UidUtils {
|
||||
|
||||
/**
|
||||
* Generates the ThingUID for the given device in the given account.
|
||||
*/
|
||||
public static ThingUID generateThingUID(Device device, Bridge account) {
|
||||
ThingTypeUID thingTypeUID = new ThingTypeUID(BINDING_ID, device.getCategory());
|
||||
return new ThingUID(thingTypeUID, account.getUID(), device.getId());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all ThingUIDs for a given device.
|
||||
*/
|
||||
public static List<ThingUID> getThingUIDs(Device device, Bridge account) {
|
||||
List<ThingUID> thingUIDs = new ArrayList<>();
|
||||
for (Thing thing : account.getThings()) {
|
||||
String deviceId = thing.getConfiguration().as(GardenaDeviceConfig.class).deviceId;
|
||||
if (deviceId == null) {
|
||||
deviceId = thing.getUID().getId();
|
||||
}
|
||||
if (deviceId.equals(device.getId())) {
|
||||
thingUIDs.add(thing.getUID());
|
||||
}
|
||||
}
|
||||
return thingUIDs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the device id of the Gardena device from the given thing.
|
||||
*/
|
||||
public static String getGardenaDeviceId(Thing thing) {
|
||||
String deviceId = thing.getConfiguration().as(GardenaDeviceConfig.class).deviceId;
|
||||
if (deviceId != null) {
|
||||
return deviceId;
|
||||
}
|
||||
|
||||
return thing.getUID().getId();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<binding:binding id="gardena" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:binding="https://openhab.org/schemas/binding/v1.0.0"
|
||||
xsi:schemaLocation="https://openhab.org/schemas/binding/v1.0.0 https://openhab.org/schemas/binding-1.0.0.xsd">
|
||||
|
||||
<name>Gardena Smart Home Binding</name>
|
||||
<description>This is the binding for Gardena Smart Home.</description>
|
||||
<author>Gerhard Riegler</author>
|
||||
</binding:binding>
|
||||
@@ -0,0 +1,462 @@
|
||||
# binding
|
||||
binding.gardena.description=Das ist das Binding für Gardena Smart Home Produkte.
|
||||
|
||||
# thing types
|
||||
thing-type.gardena.bridge.description=ein Gardena Smart Home Online Account
|
||||
|
||||
thing-type.config.gardena.bridge.email.description=Email Addresse für den Gardena Smart Home Login
|
||||
thing-type.config.gardena.bridge.password.label=Passwort
|
||||
thing-type.config.gardena.bridge.password.description=Passwort für den Gardena Smart Home Login
|
||||
thing-type.config.gardena.bridge.sessionTimeout.description=Timeout der Gardena Smart Home Session in Minuten
|
||||
thing-type.config.gardena.bridge.connectionTimeout.label=Verbindungstimeout
|
||||
thing-type.config.gardena.bridge.connectionTimeout.description=Timeout des Verbindungsaufbaus zu Gardena Smart Home in Sekunden
|
||||
thing-type.config.gardena.bridge.refresh.label=Refreshintervall
|
||||
thing-type.config.gardena.bridge.refresh.description=Der Intervall für die Datenabholung von Gardena Smart Home in Sekunden
|
||||
|
||||
thing-type.gardena.mower.label=Gardena Smart Sileno Mäher
|
||||
thing-type.gardena.mower.description=ein Gardena Smart Sileno Mäher
|
||||
|
||||
thing-type.gardena.watering_computer.label=Gardena Smart Bewässerungscomputer
|
||||
thing-type.gardena.watering_computer.description=ein Gardena Smart Bewässerungscomputer
|
||||
|
||||
thing-type.gardena.sensor.label=Gardena Smart Sensor
|
||||
thing-type.gardena.sensor.description=ein Gardena Smart Sensor
|
||||
|
||||
thing-type.gardena.electronic_pressure_pump.label=Gardena Smart Druckpumpe
|
||||
thing-type.gardena.electronic_pressure_pump.description=Eine Gardena Smart Druckpumpe
|
||||
|
||||
thing-type.gardena.power.label=Gardena Smart Power Zwischenstecker
|
||||
thing-type.gardena.power.description=Eine Gardena Smart Power Zwischenstecker
|
||||
|
||||
thing-type.gardena.ic24.label=Gardena Smart Bewässerungssteuerung
|
||||
thing-type.gardena.ic24.description=Eine Gardena Smart Bewässerungssteuerung
|
||||
|
||||
# config
|
||||
thing-type.config.gardena.electronic_pressure_pump.leakage_detection.label=Leckage-Erkennung
|
||||
thing-type.config.gardena.electronic_pressure_pump.leakage_detection.state.option.watering=Bewässerung
|
||||
thing-type.config.gardena.electronic_pressure_pump.leakage_detection.state.option.washing_machine=Waschmaschine
|
||||
thing-type.config.gardena.electronic_pressure_pump.leakage_detection.state.option.domestic_water_supply=Häusliche Wasserversorgung
|
||||
thing-type.config.gardena.electronic_pressure_pump.leakage_detection.state.option.off=Aus
|
||||
|
||||
thing-type.config.gardena.electronic_pressure_pump.operating_mode.label=Betriebsmodus
|
||||
thing-type.config.gardena.electronic_pressure_pump.operating_mode.state.option.automatic=Automatisch
|
||||
thing-type.config.gardena.electronic_pressure_pump.operating_mode.state.option.scheduled=Zeitgesteuert
|
||||
|
||||
thing-type.config.gardena.electronic_pressure_pump.turn_on_pressure.label=Einschaltdruck
|
||||
|
||||
# channel group
|
||||
channel-group-type.gardena.deviceInfo.label=Geräteinfo
|
||||
channel-group-type.gardena.deviceInfo.description=Informationen über das Gerät
|
||||
|
||||
channel-group-type.gardena.rechargeableBattery.label=Wiederaufladbare Batterie Info
|
||||
channel-group-type.gardena.rechargeableBattery.description=Informationen über die wiederaufladbare Batterie
|
||||
|
||||
channel-group-type.gardena.radio.label=Funkverbindung
|
||||
channel-group-type.gardena.radio.description=Informationen über die Funkverbindung
|
||||
|
||||
channel-group-type.gardena.mower.label=Mähroboter
|
||||
channel-group-type.gardena.mower.description=Informationen über den Mähroboter
|
||||
|
||||
channel-group-type.gardena.internalTemperature.label=Interne Temperatur
|
||||
channel-group-type.gardena.internalTemperature.description=Die interne Temperatur des Mähroboters
|
||||
|
||||
channel-group-type.gardena.battery.label=Batterieinfo
|
||||
channel-group-type.gardena.battery.description=Informationen über die Batterie
|
||||
|
||||
channel-group-type.gardena.outlet.label=Wasserauslass
|
||||
channel-group-type.gardena.outlet.description=Informationen über den Wasserauslass
|
||||
|
||||
channel-group-type.gardena.ambientTemperature.label=Umgebungstemperatur
|
||||
channel-group-type.gardena.ambientTemperature.description=Informationen über die Umgebungstemperatur
|
||||
|
||||
channel-group-type.gardena.soilTemperature.label=Bodentemperatur
|
||||
channel-group-type.gardena.soilTemperature.description=Die Temperatur des Bodens
|
||||
|
||||
channel-group-type.gardena.humidity.label=Feuchtigkeit
|
||||
channel-group-type.gardena.humidity.description=Die Feuchtigkeit
|
||||
|
||||
channel-group-type.gardena.light.label=Helligkeit
|
||||
channel-group-type.gardena.light.description=Die Helligkeit
|
||||
|
||||
channel-group-type.gardena.firmware.label=Firmware
|
||||
channel-group-type.gardena.firmware.description=Informationen über die Firmware
|
||||
|
||||
channel-group-type.gardena.outletTemperature.label=Auslauftemperatur
|
||||
channel-group-type.gardena.outletTemperature.description=Die Auslauftemperatur
|
||||
|
||||
channel-group-type.gardena.pump.label=Pumpe
|
||||
channel-group-type.gardena.pump.description=Die Pumpe
|
||||
|
||||
channel-group-type.gardena.outletPressure.label=Auslassdruck
|
||||
channel-group-type.gardena.outletPressure.description=Der Auslassdruck
|
||||
|
||||
channel-group-type.gardena.outletPressureMax.label=Maximum Auslassdruck
|
||||
channel-group-type.gardena.outletPressureMax.description=Der maximale Auslassdruck
|
||||
|
||||
channel-group-type.gardena.flow.label=Förderung
|
||||
channel-group-type.gardena.flow.description=Die Förderung
|
||||
|
||||
channel-group-type.gardena.manualWatering.label=Manuelle Bewässerung
|
||||
channel-group-type.gardena.manualWatering.description=Die manuelle Bewässerung
|
||||
|
||||
channel-group-type.gardena.scheduling.label=Zeitplan
|
||||
channel-group-type.gardena.scheduling.description=Der Zeitplan
|
||||
|
||||
channel-group-type.gardena.mowerStats.label=Mähroboter Statistiken
|
||||
channel-group-type.gardena.mowerStats.description=Statistiken über den Mähroboter
|
||||
|
||||
channel-group-type.gardena.power.label=Energie
|
||||
channel-group-type.gardena.power.description=Energie
|
||||
|
||||
channel-group-type.gardena.watering.label=Bewässerung
|
||||
channel-group-type.gardena.watering.description=Die Bewässerung
|
||||
|
||||
channel-group-type.gardena.ic24.label=Bewässerungssteuerung
|
||||
channel-group-type.gardena.ic24.description=Die Bewässerungssteuerung
|
||||
|
||||
channel-group-type.gardena.ic24scheduling.label=Zeitplanung
|
||||
channel-group-type.gardena.ic24scheduling.description=Die Zeitplanung
|
||||
|
||||
# channel types
|
||||
channel-type.gardena.mowerDurationProperty.label=Mähdauer
|
||||
channel-type.gardena.mowerDurationProperty.description=Mähdauer in Minuten
|
||||
|
||||
channel-type.gardena.parkUntilFurtherNotice.label=Parken und pausieren
|
||||
channel-type.gardena.parkUntilFurtherNotice.description=Parken und alle Zeitpläne pausieren
|
||||
|
||||
channel-type.gardena.parkUntilNextTimer.label=Parken
|
||||
channel-type.gardena.parkUntilNextTimer.description=Bis zum nächsten regulären Zeitplan parken
|
||||
|
||||
channel-type.gardena.startResumeSchedule.label=Zeitpläne fortsetzen
|
||||
channel-type.gardena.startResumeSchedule.description=Alle Zeitpläne werden fortgesetze
|
||||
|
||||
channel-type.gardena.startOverrideTimer.label=Manuelles mähen
|
||||
channel-type.gardena.startOverrideTimer.description=Sofort mähen für die eingestellte Mähdauer
|
||||
|
||||
channel-type.gardena.lastTimeOnline.label=Zuletzt online
|
||||
channel-type.gardena.lastTimeOnline.description=Die Zeit wann das Gerät zuletzt online war
|
||||
|
||||
channel-type.gardena.rechargeableBatteryStatus.label=Akkuzustand
|
||||
channel-type.gardena.rechargeableBatteryStatus.description=Der Zustand des Akkus
|
||||
channel-type.gardena.rechargeableBatteryStatus.state.option.weak=Schwach
|
||||
channel-type.gardena.rechargeableBatteryStatus.state.option.undefined=Undefiniert
|
||||
|
||||
channel-type.gardena.charging.label=Batterie wird geladen
|
||||
channel-type.gardena.charging.description=Batterie wird geladen
|
||||
|
||||
channel-type.gardena.radioQuality.label=Verbindungsqualität
|
||||
channel-type.gardena.radioQuality.description=Die Qualität der Funk Verbindung
|
||||
|
||||
channel-type.gardena.connectionStatus.label=Verbindungsstatus
|
||||
channel-type.gardena.connectionStatus.description=Der Status der Verbindung
|
||||
channel-type.gardena.connectionStatus.state.option.status_device_unreachable=Nicht erreichbar
|
||||
channel-type.gardena.connectionStatus.state.option.status_device_alive=Erreichbar
|
||||
channel-type.gardena.connectionStatus.state.option.unknown=Unbekannt
|
||||
|
||||
channel-type.gardena.radioState.label=Verbindungszustand
|
||||
channel-type.gardena.radioState.description=Der Zustand der Funk Verbindung
|
||||
channel-type.gardena.radioState.state.option.poor=Schlecht
|
||||
channel-type.gardena.radioState.state.option.good=Gut
|
||||
channel-type.gardena.radioState.state.option.excellent=Exzellent
|
||||
channel-type.gardena.radioState.state.option.undefined=Undefiniert
|
||||
|
||||
channel-type.gardena.manualOperation.label=Manuelle Steuerung
|
||||
channel-type.gardena.manualOperation.description=Der Mäher wird manuell gesteuert
|
||||
|
||||
channel-type.gardena.status.label=Mäherstatus
|
||||
channel-type.gardena.status.description=Der Status des Mähers
|
||||
channel-type.gardena.status.state.option.uninitialised=Nicht initialisiert
|
||||
channel-type.gardena.status.state.option.paused=Pausiert
|
||||
channel-type.gardena.status.state.option.ok_cutting=Mähen
|
||||
channel-type.gardena.status.state.option.ok_searching=Suche Ladestation
|
||||
channel-type.gardena.status.state.option.ok_charging=Lädt
|
||||
channel-type.gardena.status.state.option.ok_leaving=Mähen
|
||||
channel-type.gardena.status.state.option.wait_updating=Wird aktualisiert ...
|
||||
channel-type.gardena.status.state.option.wait_power_up=Wird eingeschaltet ...
|
||||
channel-type.gardena.status.state.option.parked_timer=Geparkt nach Zeitplan
|
||||
channel-type.gardena.status.state.option.parked_park_selected=Geparkt
|
||||
channel-type.gardena.status.state.option.off_disabled=Der Mäher ist ausgeschaltet
|
||||
channel-type.gardena.status.state.option.off_hatch_open=Deaktiviert. Abdeckung ist offen oder PIN-Code erforderlich
|
||||
channel-type.gardena.status.state.option.unknown=Unbekannter Status
|
||||
channel-type.gardena.status.state.option.error=Fehler
|
||||
channel-type.gardena.status.state.option.error_at_power_up=Neustart ...
|
||||
channel-type.gardena.status.state.option.off_hatch_closed=Deaktiviert. Manueller Start erforderlich
|
||||
channel-type.gardena.status.state.option.ok_cutting_timer_overridden=Manuelles Mähen
|
||||
channel-type.gardena.status.state.option.parked_autotimer=Geparkt durch SensorControl
|
||||
channel-type.gardena.status.state.option.parked_daily_limit_reached=Abgeschlossen
|
||||
channel-type.gardena.status.state.option.undefined=Undefiniert
|
||||
|
||||
channel-type.gardena.error.label=Mäherfehler
|
||||
channel-type.gardena.error.description=Der Fehler des Mähers
|
||||
channel-type.gardena.error.state.option.no_message=Kein Fehler
|
||||
channel-type.gardena.error.state.option.outside_working_area=Außerhalb des Arbeitsbereichs
|
||||
channel-type.gardena.error.state.option.no_loop_signal=Kein Schleifensignal
|
||||
channel-type.gardena.error.state.option.wrong_loop_signal=Falsches Schleifensignal
|
||||
channel-type.gardena.error.state.option.loop_sensor_problem_front=Problem Schleifensensor, vorne
|
||||
channel-type.gardena.error.state.option.loop_sensor_problem_rear=Problem Schleifensensor, hinten
|
||||
channel-type.gardena.error.state.option.loop_sensor_problem_left=Problem Schleifensensor, links
|
||||
channel-type.gardena.error.state.option.loop_sensor_problem_right=Problem Schleifensensor, rechts
|
||||
channel-type.gardena.error.state.option.wrong_pin_code=Falscher PIN Code
|
||||
channel-type.gardena.error.state.option.trapped=Eingeschlossen
|
||||
channel-type.gardena.error.state.option.upside_down=Steht auf dem Kopf
|
||||
channel-type.gardena.error.state.option.low_battery=Niedriger Batteriestand
|
||||
channel-type.gardena.error.state.option.empty_battery=empty_battery
|
||||
channel-type.gardena.error.state.option.no_drive=no_drive
|
||||
channel-type.gardena.error.state.option.temporarily_lifted=Vorübergehend angehoben
|
||||
channel-type.gardena.error.state.option.lifted=Angehoben
|
||||
channel-type.gardena.error.state.option.stuck_in_charging_station=Eingeklemmt in Ladestation
|
||||
channel-type.gardena.error.state.option.charging_station_blocked=Ladestation blockiert
|
||||
channel-type.gardena.error.state.option.collision_sensor_problem_rear=Problem Stoßsensor hinten
|
||||
channel-type.gardena.error.state.option.collision_sensor_problem_front=Problem Stoßsensor vorne
|
||||
channel-type.gardena.error.state.option.wheel_motor_blocked_right=Radmotor rechts blockiert
|
||||
channel-type.gardena.error.state.option.wheel_motor_blocked_left=Radmotor links blockiert
|
||||
channel-type.gardena.error.state.option.wheel_drive_problem_right=Problem Antrieb, rechts
|
||||
channel-type.gardena.error.state.option.wheel_drive_problem_left=Problem Antrieb, links
|
||||
channel-type.gardena.error.state.option.cutting_motor_drive_defect=Schneidmotorantrieb defekt
|
||||
channel-type.gardena.error.state.option.cutting_system_blocked=Schneidsystem blockiert
|
||||
channel-type.gardena.error.state.option.invalid_sub_device_combination=Fehlerhafte Verbindung
|
||||
channel-type.gardena.error.state.option.settings_restored=Standardeinstellungen
|
||||
channel-type.gardena.error.state.option.memory_circuit_problem=Speicherschaltkreisproblem
|
||||
channel-type.gardena.error.state.option.slope_too_steep=Steigung zu steil
|
||||
channel-type.gardena.error.state.option.charging_system_problem=Problem Ladesystem
|
||||
channel-type.gardena.error.state.option.stop_button_problem=Stop button Problem
|
||||
channel-type.gardena.error.state.option.tilt_sensor_problem=Kippsensorproblem
|
||||
channel-type.gardena.error.state.option.mower_tilted=Mäher gekippt
|
||||
channel-type.gardena.error.state.option.wheel_motor_overloaded_right=Rechter Radmotor überlastet
|
||||
channel-type.gardena.error.state.option.wheel_motor_overloaded_left=Linker Radmotor überlastet
|
||||
channel-type.gardena.error.state.option.charging_current_too_high=Ladestrom zu hoch
|
||||
channel-type.gardena.error.state.option.electronic_problem=Elektronisches Problem
|
||||
channel-type.gardena.error.state.option.cutting_motor_problem=Schneidmotorisches Problem
|
||||
channel-type.gardena.error.state.option.limited_cutting_height_range=Begrenzter Schneidhöhenbereich
|
||||
channel-type.gardena.error.state.option.unexpected_cutting_height_adj=Unerwartete Schnitthöhe
|
||||
channel-type.gardena.error.state.option.cutting_height_problem_drive=Schnitthöhenproblem Antrieb
|
||||
channel-type.gardena.error.state.option.cutting_height_problem_curr=Schnitthöhenproblem
|
||||
channel-type.gardena.error.state.option.cutting_height_problem_dir=Schnitthöhenproblem
|
||||
channel-type.gardena.error.state.option.cutting_height_blocked=Schnitthöhe blockiert
|
||||
channel-type.gardena.error.state.option.cutting_height_problem=Schnitthöhenproblem
|
||||
channel-type.gardena.error.state.option.no_response_from_charger=Keine Antwort vom Ladegerät
|
||||
channel-type.gardena.error.state.option.ultrasonic_problem=Ultraschallproblem
|
||||
channel-type.gardena.error.state.option.temporary_problem=Vorübergehendes Problem
|
||||
channel-type.gardena.error.state.option.guide_1_not_found=SK 1 nicht gefunden
|
||||
channel-type.gardena.error.state.option.guide_2_not_found=SK 2 nicht gefunden
|
||||
channel-type.gardena.error.state.option.guide_3_not_found=SK 3 nicht gefunden
|
||||
channel-type.gardena.error.state.option.gps_tracker_module_error=GPS tracker Modul Fehler
|
||||
channel-type.gardena.error.state.option.weak_gps_signal=Schwaches GPS Signal
|
||||
channel-type.gardena.error.state.option.difficult_finding_home=Problem die Ladestation zu finden
|
||||
channel-type.gardena.error.state.option.guide_calibration_accomplished=Kalibration des Suchkabels beendet
|
||||
channel-type.gardena.error.state.option.guide_calibration_failed=Kalibration des Suchkabels fehlgeschlagen
|
||||
channel-type.gardena.error.state.option.temporary_battery_problem=Kurzzeitiges Batterieproblem
|
||||
channel-type.gardena.error.state.option.battery_problem=Batterieproblem
|
||||
channel-type.gardena.error.state.option.too_many_batteries=Zu viele Batterien
|
||||
channel-type.gardena.error.state.option.alarm_mower_switched_off=Alarm! Mäher ausgeschalten
|
||||
channel-type.gardena.error.state.option.alarm_mower_stopped=Alarm! Mäher gestoppt
|
||||
channel-type.gardena.error.state.option.alarm_mower_lifted=Alarm! Mäher angehoben
|
||||
channel-type.gardena.error.state.option.alarm_mower_tilted=Alarm! Mäher gekippt
|
||||
channel-type.gardena.error.state.option.alarm_mower_in_motion=Alarm! Mäher in Bewegung
|
||||
channel-type.gardena.error.state.option.alarm_outside_geofence=Alarm! Außerhalb des Geofence
|
||||
channel-type.gardena.error.state.option.connection_changed=Verbindung geändert
|
||||
channel-type.gardena.error.state.option.connection_not_changed=Verbindung nicht geändert
|
||||
channel-type.gardena.error.state.option.com_board_not_available=COM board nicht verfügbar
|
||||
channel-type.gardena.error.state.option.slipped=Rutscht
|
||||
channel-type.gardena.error.state.option.invalid_battery_combination=Ungültige Batterie Kombination
|
||||
channel-type.gardena.error.state.option.imbalanced_cutting_disc=Unwuchte Schneidscheibe
|
||||
channel-type.gardena.error.state.option.safety_function_faulty=Sicherheitsfunktion fehlerhaft
|
||||
|
||||
channel-type.gardena.sourceForNextStart.label=Quelle für den nächsten Start
|
||||
channel-type.gardena.sourceForNextStart.description=Die Quelle für den nächsten Start
|
||||
channel-type.gardena.sourceForNextStart.state.option.no_source=Keine Quelle
|
||||
channel-type.gardena.sourceForNextStart.state.option.completed_cutting_daily_limit=Tägliches Mählimit erreicht
|
||||
channel-type.gardena.sourceForNextStart.state.option.week_timer=Wochen timer
|
||||
channel-type.gardena.sourceForNextStart.state.option.countdown_timer=Countdown timer
|
||||
channel-type.gardena.sourceForNextStart.state.option.mower_charging=Mäher lädt
|
||||
channel-type.gardena.sourceForNextStart.state.option.completed_cutting_autotimer=Fertig gemäht
|
||||
channel-type.gardena.sourceForNextStart.state.option.undefined=Undefiniert
|
||||
|
||||
channel-type.gardena.timestampNextStart.label=Nächster Startzeitpunkt
|
||||
channel-type.gardena.timestampNextStart.description=Zeitpunkt des nächsten Starts
|
||||
|
||||
channel-type.gardena.overrideEndTime.label=Überschreiben der Endzeit
|
||||
channel-type.gardena.overrideEndTime.description=Überschreiben der Endzeit
|
||||
|
||||
channel-type.gardena.temperature.label=Temperatur
|
||||
channel-type.gardena.temperature.description=Die Temperatur
|
||||
|
||||
channel-type.gardena.disposableBatteryStatus.label=Einweg Batterie Status
|
||||
channel-type.gardena.disposableBatteryStatus.description=Der Status der Einweg Batterie
|
||||
channel-type.gardena.disposableBatteryStatus.state.option.out_of_operation=Ausser Betrieb
|
||||
channel-type.gardena.disposableBatteryStatus.state.option.replace_now=Kritischer Batteriestand, wechseln Sie jetzt
|
||||
channel-type.gardena.disposableBatteryStatus.state.option.low=Niedrig
|
||||
channel-type.gardena.disposableBatteryStatus.state.option.ok=OK
|
||||
channel-type.gardena.disposableBatteryStatus.state.option.undefined=Undefiniert
|
||||
|
||||
channel-type.gardena.valveOpen.label=Ventil geöffnet
|
||||
channel-type.gardena.valveOpen.description=Ventil geöffnet
|
||||
|
||||
channel-type.gardena.manualOverride.label=Manuelle Steuerung
|
||||
channel-type.gardena.manualOverride.description=Manuelle Steuerung
|
||||
channel-type.gardena.manualOverride.state.option.inactive=Inaktiv
|
||||
channel-type.gardena.manualOverride.state.option.open=Offen
|
||||
channel-type.gardena.manualOverride.state.option.undefined=Undefiniert
|
||||
|
||||
channel-type.gardena.buttonManualOverrideTime.label=Zeit manuelle Steuerung
|
||||
channel-type.gardena.buttonManualOverrideTime.description=Die Zeit die das Ventil geöffnet ist, wenn der Knopf am Gerät gedrückt wird
|
||||
|
||||
channel-type.gardena.outletCommand.label=Ventil
|
||||
channel-type.gardena.outletCommand.description=Öffnen und Schließen des Ventils
|
||||
|
||||
channel-type.gardena.frostWarning.label=Frostwarnung
|
||||
channel-type.gardena.frostWarning.description=Frostwarnung
|
||||
channel-type.gardena.frostWarning.state.option.no_frost=Kein Frost
|
||||
channel-type.gardena.frostWarning.state.option.frost=Frost
|
||||
channel-type.gardena.frostWarning.state.option.undefined=Undefiniert
|
||||
|
||||
channel-type.gardena.humidity.label=Feuchtigkeit
|
||||
channel-type.gardena.humidity.description=Die Feuchtigkeit
|
||||
|
||||
channel-type.gardena.light.label=Helligkeit
|
||||
channel-type.gardena.light.description=Die Helligkeit
|
||||
|
||||
channel-type.gardena.firmwareStatus.label=Status
|
||||
channel-type.gardena.firmwareStatus.description=Der Firmware Status
|
||||
|
||||
channel-type.gardena.firmwareUploadProgress.label=Upload Fortschritt
|
||||
channel-type.gardena.firmwareUploadProgress.description=Der Firmware upload Fortschritt
|
||||
|
||||
channel-type.gardena.firmwareAvailableVersion.label=Verfügbare Version
|
||||
channel-type.gardena.firmwareAvailableVersion.description=Verfügbare Firmware Version
|
||||
|
||||
channel-type.gardena.pumpMode.label=Modus
|
||||
channel-type.gardena.pumpMode.description=Der Modus
|
||||
channel-type.gardena.pumpMode.state.option.off=Aus
|
||||
channel-type.gardena.pumpMode.state.option.auto=Automatik
|
||||
|
||||
channel-type.gardena.pumpOnOff.label=Pumpe
|
||||
channel-type.gardena.pumpOnOff.description=Die Pumpe
|
||||
channel-type.gardena.pumpOnOff.state.option.off=Aus
|
||||
channel-type.gardena.pumpOnOff.state.option.on=Ein
|
||||
|
||||
channel-type.gardena.turnOnPressure.label=Einschaltdruck
|
||||
channel-type.gardena.turnOnPressure.description=Der Einschaltdruck
|
||||
|
||||
channel-type.gardena.operatingMode.label=Betriebsmodus
|
||||
channel-type.gardena.operatingMode.description=Der Betriebsmodus
|
||||
channel-type.gardena.operatingMode.state.option.scheduled=Zeitgesteuert
|
||||
channel-type.gardena.operatingMode.state.option.automatic=Automatisch
|
||||
|
||||
channel-type.gardena.counter.label=Zähler
|
||||
channel-type.gardena.counter.description=Der Zähler
|
||||
|
||||
channel-type.gardena.outletPressure.label=Auslassdruck
|
||||
channel-type.gardena.outletPressure.description=Der Auslassdruck
|
||||
|
||||
channel-type.gardena.flowRate.label=Fördermenge
|
||||
channel-type.gardena.flowRate.description=Die Fördermenge
|
||||
|
||||
channel-type.gardena.flowSinceLastReset.label=Durchfluss seit letztem Reset
|
||||
channel-type.gardena.flowSinceLastReset.description=Der Durchfluss seit letztem Reset
|
||||
|
||||
channel-type.gardena.flowTotal.label=Gesamtdurchfluss
|
||||
channel-type.gardena.flowTotal.description=Der Gesamtdurchfluss
|
||||
|
||||
channel-type.gardena.drippingAlert.label=Leckage-Erkennung
|
||||
channel-type.gardena.drippingAlert.description=Die Leckage-Erkennung
|
||||
channel-type.gardena.drippingAlert.state.option.sixty=Sechzig
|
||||
channel-type.gardena.drippingAlert.state.option.two=Zwei
|
||||
channel-type.gardena.drippingAlert.state.option.off=Aus
|
||||
|
||||
channel-type.gardena.manualWatering.label=Manuelle Bewässerung
|
||||
channel-type.gardena.manualWatering.description=Die manuelle Bewässerung
|
||||
|
||||
channel-type.gardena.manualWateringTimer.label=Manueller Bewässerungs-Timer
|
||||
channel-type.gardena.manualWateringTimer.description=Der manuelle Bewässerungs-Timer
|
||||
channel-type.gardena.manualWateringTimer.state.option.0=Aus
|
||||
|
||||
|
||||
channel-type.gardena.lastManualOverrideTime.label=Letzte manuelle Betätigung
|
||||
channel-type.gardena.lastManualOverrideTime.description=Die letzte manuelle Betätigung
|
||||
|
||||
channel-type.gardena.adaptiveSchedulingLastDecision.label=Intelligente Zeitplanung
|
||||
channel-type.gardena.adaptiveSchedulingLastDecision.description=Die letzte Entscheidung der intelligenten Zeitplanung
|
||||
channel-type.gardena.adaptiveSchedulingLastDecision.state.option.undefined=Undefiniert
|
||||
channel-type.gardena.adaptiveSchedulingLastDecision.state.option.watered_sensor_timeout=Keine Sensordaten
|
||||
channel-type.gardena.adaptiveSchedulingLastDecision.state.option.skipped=Zeiplan ausgesetzt
|
||||
channel-type.gardena.adaptiveSchedulingLastDecision.state.option.watered=Nach Zeitplan
|
||||
|
||||
channel-type.gardena.temperatureMin.label=Minimum Temperatur
|
||||
channel-type.gardena.temperatureMin.description=Die minimale Temperatur
|
||||
channel-type.gardena.temperatureMax.label=Maximum Temperatur
|
||||
channel-type.gardena.temperatureMax.description=Die maximale Temperatur
|
||||
|
||||
channel-type.gardena.errorCounter.label=Fehlerzähler
|
||||
channel-type.gardena.errorCounter.description=Der Fehlerzähler
|
||||
|
||||
channel-type.gardena.errorCounterOne.label=Fehlerzähler 1
|
||||
channel-type.gardena.errorCounterOne.description=Der 1 Fehlerzähler
|
||||
|
||||
channel-type.gardena.errorCounterTwo.label=Fehlerzähler 2
|
||||
channel-type.gardena.errorCounterTwo.description=Der 2 Fehlerzähler
|
||||
|
||||
channel-type.gardena.errorCounterThree.label=Fehlerzähler 3
|
||||
channel-type.gardena.errorCounterThree.description=Der 3 Fehlerzähler
|
||||
|
||||
channel-type.gardena.errorCounterFour.label=Fehlerzähler 4
|
||||
channel-type.gardena.errorCounterFour.description=Der vierte Fehlerzähler
|
||||
|
||||
channel-type.gardena.operatingDays.label=Betriebstage
|
||||
channel-type.gardena.operatingDays.description=Die Betriebstage
|
||||
|
||||
channel-type.gardena.scheduledWateringEnd.label=Geplantes Bewässerungsende
|
||||
channel-type.gardena.scheduledWateringEnd.description=Das geplante Bewässerungsende
|
||||
|
||||
channel-type.gardena.scheduledWateringNextStart.label=Nächste geplante Bewässerung
|
||||
channel-type.gardena.scheduledWateringNextStart.description=Die nächste geplante Bewässerung
|
||||
|
||||
channel-type.gardena.cuttingTime.label=Mähdauer
|
||||
channel-type.gardena.cuttingTime.description=Die gesamte Mähdauer
|
||||
|
||||
channel-type.gardena.chargingCycles.label=Ladezyklen
|
||||
channel-type.gardena.chargingCycles.description=Die Anzahl der Ladezyklen
|
||||
|
||||
channel-type.gardena.collisions.label=Kollisionen
|
||||
channel-type.gardena.collisions.description=Die Anzahl der Kollisionen
|
||||
|
||||
channel-type.gardena.runningTime.label=Laufzeit
|
||||
channel-type.gardena.runningTime.description=Die gesamte Laufzeit
|
||||
|
||||
channel-type.gardena.powerTimer.label=Einschaltzeit
|
||||
channel-type.gardena.powerTimer.description=Die Einschaltzeit
|
||||
channel-type.gardena.powerTimer.state.option.on=Ein
|
||||
channel-type.gardena.powerTimer.state.option.off=Aus
|
||||
channel-type.gardena.powerTimer.state.option.60=1 Minute
|
||||
channel-type.gardena.powerTimer.state.option.300=5 Minuten
|
||||
channel-type.gardena.powerTimer.state.option.900=15 Minuten
|
||||
channel-type.gardena.powerTimer.state.option.3600=1 Stunde
|
||||
channel-type.gardena.powerTimer.state.option.7200=2 Stunden
|
||||
channel-type.gardena.powerTimer.state.option.18000=5 Stunden
|
||||
channel-type.gardena.powerTimer.state.option.43200=12 Stunden
|
||||
channel-type.gardena.powerTimer.state.option.86400=1 Tag
|
||||
channel-type.gardena.powerTimer.state.option.259200=3 Tage
|
||||
channel-type.gardena.powerTimer.state.option.604800=1 Woche
|
||||
channel-type.gardena.powerTimer.state.option.1209600=2 Wochen
|
||||
|
||||
channel-type.gardena.powerError.label=Fehler
|
||||
channel-type.gardena.powerError.description=Fehler
|
||||
channel-type.gardena.powerError.state.option.ok=OK
|
||||
channel-type.gardena.powerError.state.option.timer_cancelled=Timer abgebrochen
|
||||
channel-type.gardena.powerError.state.option.unknown=Unbekannt
|
||||
|
||||
channel-type.gardena.wateringTimer.label=Bewässerungstimer
|
||||
channel-type.gardena.wateringTimer.description=Der Bewässerungstimer
|
||||
|
||||
channel-type.gardena.valvesConnected.label=Angeschlossenen Ventile
|
||||
channel-type.gardena.valvesConnected.description=Die angeschlossenen Ventile
|
||||
|
||||
channel-type.gardena.valvesMasterConfig.label=Ventile Hauptkonfiguration
|
||||
channel-type.gardena.valvesMasterConfig.description=Die Hauptkonfiguration der Ventile
|
||||
|
||||
channel-type.gardena.ic24error.label=Bewässerungssteuerung Fehler
|
||||
channel-type.gardena.ic24error.description=Der Fehler der Bewässerungssteuerung
|
||||
channel-type.gardena.ic24error.state.option.voltage_drop=Spannungsabfall
|
||||
channel-type.gardena.ic24error.state.option.wrong_power_supply=Falsche Stromversorgung
|
||||
channel-type.gardena.ic24error.state.option.no_mcu_connection=Keine MCU verbunden
|
||||
channel-type.gardena.ic24error.state.option.unknown=Unbekannt
|
||||
@@ -0,0 +1,42 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<thing:thing-descriptions bindingId="gardena"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:thing="https://openhab.org/schemas/thing-description/v1.0.0"
|
||||
xsi:schemaLocation="https://openhab.org/schemas/thing-description/v1.0.0 https://openhab.org/schemas/thing-description-1.0.0.xsd">
|
||||
|
||||
<!-- Gardena Smart Home Account -->
|
||||
<bridge-type id="account">
|
||||
<label>Gardena Smart Home Account</label>
|
||||
<description>The Gardena Smart Home Account</description>
|
||||
|
||||
<config-description>
|
||||
<parameter name="email" type="text" required="true">
|
||||
<label>Email</label>
|
||||
<description>Email address for logging in to Gardena Smart Home</description>
|
||||
</parameter>
|
||||
<parameter name="password" type="text" required="true">
|
||||
<label>Password</label>
|
||||
<context>password</context>
|
||||
<description>Password for logging in to Gardena Smart Home</description>
|
||||
</parameter>
|
||||
<parameter name="sessionTimeout" type="integer">
|
||||
<label>Session Timeout</label>
|
||||
<description>The timeout in minutes for a session to Gardena Smart Home</description>
|
||||
<advanced>true</advanced>
|
||||
<default>30</default>
|
||||
</parameter>
|
||||
<parameter name="connectionTimeout" type="integer">
|
||||
<label>Connection Timeout</label>
|
||||
<description>The timeout in seconds for connections to Gardena Smart Home</description>
|
||||
<advanced>true</advanced>
|
||||
<default>10</default>
|
||||
</parameter>
|
||||
<parameter name="refresh" type="integer">
|
||||
<label>Refresh Interval</label>
|
||||
<description>The interval in seconds for refreshing the data from Gardena Smart Home</description>
|
||||
<advanced>true</advanced>
|
||||
<default>60</default>
|
||||
</parameter>
|
||||
</config-description>
|
||||
</bridge-type>
|
||||
</thing:thing-descriptions>
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user