]> git.basschouten.com Git - openhab-addons.git/commitdiff
[boschindego] Add channels for last/next cutting time (#12989)
authorJacob Laursen <jacob-github@vindvejr.dk>
Sat, 2 Jul 2022 08:48:33 +0000 (10:48 +0200)
committerGitHub <noreply@github.com>
Sat, 2 Jul 2022 08:48:33 +0000 (10:48 +0200)
* Add channels for last/next cutting time
* Let handleCommand() work synchronously

Signed-off-by: Jacob Laursen <jacob-github@vindvejr.dk>
bundles/org.openhab.binding.boschindego/README.md
bundles/org.openhab.binding.boschindego/src/main/java/org/openhab/binding/boschindego/internal/BoschIndegoBindingConstants.java
bundles/org.openhab.binding.boschindego/src/main/java/org/openhab/binding/boschindego/internal/BoschIndegoHandlerFactory.java
bundles/org.openhab.binding.boschindego/src/main/java/org/openhab/binding/boschindego/internal/IndegoController.java
bundles/org.openhab.binding.boschindego/src/main/java/org/openhab/binding/boschindego/internal/config/BoschIndegoConfiguration.java
bundles/org.openhab.binding.boschindego/src/main/java/org/openhab/binding/boschindego/internal/dto/response/PredictiveCuttingTimeResponse.java [deleted file]
bundles/org.openhab.binding.boschindego/src/main/java/org/openhab/binding/boschindego/internal/dto/response/PredictiveLastCuttingResponse.java [new file with mode: 0644]
bundles/org.openhab.binding.boschindego/src/main/java/org/openhab/binding/boschindego/internal/dto/response/PredictiveNextCuttingResponse.java [new file with mode: 0644]
bundles/org.openhab.binding.boschindego/src/main/java/org/openhab/binding/boschindego/internal/handler/BoschIndegoHandler.java
bundles/org.openhab.binding.boschindego/src/main/resources/OH-INF/i18n/boschindego.properties
bundles/org.openhab.binding.boschindego/src/main/resources/OH-INF/thing/thing-types.xml

index e4df403b8687c40128acc0458c2a0f567c2ca656..5dee2a5982348ff28e4caddee6ee1e98f73346ae 100644 (file)
@@ -8,11 +8,12 @@ His [Java Library](https://github.com/zazaz-de/iot-device-bosch-indego-controlle
 
 Currently the binding supports  ***indego***  mowers as a thing type with these configuration parameters:
 
-| Parameter | Description                                                          |
-|-----------|----------------------------------------------------------------------|
-| username  | Username for the Bosch Indego account                                |
-| password  | Password for the Bosch Indego account                                |
-| refresh   | Specifies the refresh interval in seconds (default 180, minimum: 60) |
+| Parameter          | Description                                                     | Default |
+|--------------------|-----------------------------------------------------------------|---------|
+| username           | Username for the Bosch Indego account                           |         |
+| password           | Password for the Bosch Indego account                           |         |
+| refresh            | The number of seconds between refreshing device state           | 180     |
+| cuttingTimeRefresh | The number of minutes between refreshing last/next cutting time | 60      |
 
 ## Channels
 
@@ -24,6 +25,8 @@ Currently the binding supports  ***indego***  mowers as a thing type with these
 | textualstate | String      | State as a text. (readonly)                                                                                                         |
 | ready        | Number      | Shows if the mower is ready to mow (1=ready, 0=not ready, readonly)                                                                 |
 | mowed        | Dimmer      | Cut grass in percent (readonly)                                                                                                     |
+| lastCutting  | DateTime    | Last cutting time (readonly)                                                                                                        |
+| nextCutting  | DateTime    | Next scheduled cutting time (readonly)                                                                                              |
 
 ### State Codes
 
@@ -76,6 +79,8 @@ Number Indego_StateCode { channel="boschindego:indego:lawnmower:statecode" }
 String Indego_TextualState { channel="boschindego:indego:lawnmower:textualstate" }
 Number Indego_Ready { channel="boschindego:indego:lawnmower:ready" }
 Dimmer Indego_Mowed { channel="boschindego:indego:lawnmower:mowed" }
+DateTime Indego_LastCutting { channel="boschindego:indego:lawnmower:lastCutting" }
+DateTime Indego_NextCutting { channel="boschindego:indego:lawnmower:nextCutting" }
 ```
 
 ### `indego.sitemap` File
index 5469157253717ac57dccb83f6c43ff0991b444e3..e1c6ff3d58b63a9a6045b3a15435f5169398e7f3 100644 (file)
@@ -38,6 +38,8 @@ public class BoschIndegoBindingConstants {
     public static final String ERRORCODE = "errorcode";
     public static final String STATECODE = "statecode";
     public static final String READY = "ready";
+    public static final String LAST_CUTTING = "lastCutting";
+    public static final String NEXT_CUTTING = "nextCutting";
 
     public static final Set<ThingTypeUID> SUPPORTED_THING_TYPES_UIDS = Set.of(THING_TYPE_INDEGO);
 }
index 4cb385d89235976229e0e963977a52b2214bbf70..0c70446a0ecb19a29da3233eb5c99f5a5eb8d99d 100644 (file)
@@ -19,6 +19,7 @@ import org.eclipse.jdt.annotation.Nullable;
 import org.eclipse.jetty.client.HttpClient;
 import org.openhab.binding.boschindego.internal.handler.BoschIndegoHandler;
 import org.openhab.core.i18n.LocaleProvider;
+import org.openhab.core.i18n.TimeZoneProvider;
 import org.openhab.core.i18n.TranslationProvider;
 import org.openhab.core.io.net.http.HttpClientFactory;
 import org.openhab.core.thing.Thing;
@@ -43,14 +44,16 @@ public class BoschIndegoHandlerFactory extends BaseThingHandlerFactory {
 
     private final HttpClient httpClient;
     private final BoschIndegoTranslationProvider translationProvider;
+    private final TimeZoneProvider timeZoneProvider;
 
     @Activate
     public BoschIndegoHandlerFactory(@Reference HttpClientFactory httpClientFactory,
             final @Reference TranslationProvider i18nProvider, final @Reference LocaleProvider localeProvider,
-            ComponentContext componentContext) {
+            final @Reference TimeZoneProvider timeZoneProvider, ComponentContext componentContext) {
         super.activate(componentContext);
         this.httpClient = httpClientFactory.getCommonHttpClient();
         this.translationProvider = new BoschIndegoTranslationProvider(i18nProvider, localeProvider);
+        this.timeZoneProvider = timeZoneProvider;
     }
 
     @Override
@@ -63,7 +66,7 @@ public class BoschIndegoHandlerFactory extends BaseThingHandlerFactory {
         ThingTypeUID thingTypeUID = thing.getThingTypeUID();
 
         if (THING_TYPE_INDEGO.equals(thingTypeUID)) {
-            return new BoschIndegoHandler(thing, httpClient, translationProvider);
+            return new BoschIndegoHandler(thing, httpClient, translationProvider, timeZoneProvider);
         }
 
         return null;
index b10a09a0e01e74f5e5a1ab6a72c94b8a9eeba1dc..dd50c8e7cf7fa09feb4df4d82c43f38c6f30f883 100644 (file)
@@ -38,7 +38,8 @@ import org.openhab.binding.boschindego.internal.dto.response.AuthenticationRespo
 import org.openhab.binding.boschindego.internal.dto.response.DeviceCalendarResponse;
 import org.openhab.binding.boschindego.internal.dto.response.DeviceStateResponse;
 import org.openhab.binding.boschindego.internal.dto.response.LocationWeatherResponse;
-import org.openhab.binding.boschindego.internal.dto.response.PredictiveCuttingTimeResponse;
+import org.openhab.binding.boschindego.internal.dto.response.PredictiveLastCuttingResponse;
+import org.openhab.binding.boschindego.internal.dto.response.PredictiveNextCuttingResponse;
 import org.openhab.binding.boschindego.internal.exceptions.IndegoAuthenticationException;
 import org.openhab.binding.boschindego.internal.exceptions.IndegoException;
 import org.openhab.binding.boschindego.internal.exceptions.IndegoInvalidCommandException;
@@ -455,9 +456,8 @@ public class IndegoController {
      * @throws IndegoException if any communication or parsing error occurred
      */
     public boolean getPredictiveMoving() throws IndegoAuthenticationException, IndegoException {
-        final PredictiveStatus status = getRequestWithAuthentication(
-                SERIAL_NUMBER_SUBPATH + this.getSerialNumber() + "/predictive", PredictiveStatus.class);
-        return status.enabled;
+        return getRequestWithAuthentication(SERIAL_NUMBER_SUBPATH + this.getSerialNumber() + "/predictive",
+                PredictiveStatus.class).enabled;
     }
 
     /**
@@ -473,6 +473,18 @@ public class IndegoController {
         putRequestWithAuthentication(SERIAL_NUMBER_SUBPATH + this.getSerialNumber() + "/predictive", status);
     }
 
+    /**
+     * Queries predictive last cutting as {@link Instant}.
+     * 
+     * @return predictive last cutting
+     * @throws IndegoAuthenticationException if request was rejected as unauthorized
+     * @throws IndegoException if any communication or parsing error occurred
+     */
+    public @Nullable Instant getPredictiveLastCutting() throws IndegoAuthenticationException, IndegoException {
+        return getRequestWithAuthentication(SERIAL_NUMBER_SUBPATH + this.getSerialNumber() + "/predictive/lastcutting",
+                PredictiveLastCuttingResponse.class).getLastCutting();
+    }
+
     /**
      * Queries predictive next cutting as {@link Instant}.
      * 
@@ -480,11 +492,9 @@ public class IndegoController {
      * @throws IndegoAuthenticationException if request was rejected as unauthorized
      * @throws IndegoException if any communication or parsing error occurred
      */
-    public Instant getPredictiveNextCutting() throws IndegoAuthenticationException, IndegoException {
-        final PredictiveCuttingTimeResponse nextCutting = getRequestWithAuthentication(
-                SERIAL_NUMBER_SUBPATH + this.getSerialNumber() + "/predictive/nextcutting",
-                PredictiveCuttingTimeResponse.class);
-        return nextCutting.getNextCutting();
+    public @Nullable Instant getPredictiveNextCutting() throws IndegoAuthenticationException, IndegoException {
+        return getRequestWithAuthentication(SERIAL_NUMBER_SUBPATH + this.getSerialNumber() + "/predictive/nextcutting",
+                PredictiveNextCuttingResponse.class).getNextCutting();
     }
 
     /**
@@ -495,9 +505,8 @@ public class IndegoController {
      * @throws IndegoException if any communication or parsing error occurred
      */
     public DeviceCalendarResponse getPredictiveExclusionTime() throws IndegoAuthenticationException, IndegoException {
-        final DeviceCalendarResponse calendar = getRequestWithAuthentication(
-                SERIAL_NUMBER_SUBPATH + this.getSerialNumber() + "/predictive/calendar", DeviceCalendarResponse.class);
-        return calendar;
+        return getRequestWithAuthentication(SERIAL_NUMBER_SUBPATH + this.getSerialNumber() + "/predictive/calendar",
+                DeviceCalendarResponse.class);
     }
 
     /**
index 9512d5d4b5834b6d243591f302def25b138bf87b..03148db98a933567031aa5a2119be3d4192badb6 100644 (file)
@@ -25,4 +25,5 @@ public class BoschIndegoConfiguration {
     public @Nullable String username;
     public @Nullable String password;
     public long refresh = 180;
+    public long cuttingTimeRefresh = 60;
 }
diff --git a/bundles/org.openhab.binding.boschindego/src/main/java/org/openhab/binding/boschindego/internal/dto/response/PredictiveCuttingTimeResponse.java b/bundles/org.openhab.binding.boschindego/src/main/java/org/openhab/binding/boschindego/internal/dto/response/PredictiveCuttingTimeResponse.java
deleted file mode 100644 (file)
index 27d78e4..0000000
+++ /dev/null
@@ -1,38 +0,0 @@
-/**
- * Copyright (c) 2010-2022 Contributors to the openHAB project
- *
- * See the NOTICE file(s) distributed with this work for additional
- * information.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License 2.0 which is available at
- * http://www.eclipse.org/legal/epl-2.0
- *
- * SPDX-License-Identifier: EPL-2.0
- */
-package org.openhab.binding.boschindego.internal.dto.response;
-
-import java.time.Instant;
-import java.time.ZonedDateTime;
-import java.time.format.DateTimeParseException;
-
-import com.google.gson.annotations.SerializedName;
-
-/**
- * Response for next cutting time.
- * 
- * @author Jacob Laursen - Initial contribution
- */
-public class PredictiveCuttingTimeResponse {
-    @SerializedName("mow_next")
-    public String nextCutting;
-
-    public Instant getNextCutting() {
-        try {
-            return ZonedDateTime.parse(nextCutting).toInstant();
-        } catch (final DateTimeParseException e) {
-            // Ignored
-        }
-        return null;
-    }
-}
diff --git a/bundles/org.openhab.binding.boschindego/src/main/java/org/openhab/binding/boschindego/internal/dto/response/PredictiveLastCuttingResponse.java b/bundles/org.openhab.binding.boschindego/src/main/java/org/openhab/binding/boschindego/internal/dto/response/PredictiveLastCuttingResponse.java
new file mode 100644 (file)
index 0000000..ddcebef
--- /dev/null
@@ -0,0 +1,40 @@
+/**
+ * Copyright (c) 2010-2022 Contributors to the openHAB project
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ */
+package org.openhab.binding.boschindego.internal.dto.response;
+
+import java.time.Instant;
+import java.time.ZonedDateTime;
+import java.time.format.DateTimeParseException;
+
+import org.eclipse.jdt.annotation.Nullable;
+
+import com.google.gson.annotations.SerializedName;
+
+/**
+ * Response for last cutting time.
+ * 
+ * @author Jacob Laursen - Initial contribution
+ */
+public class PredictiveLastCuttingResponse {
+    @SerializedName("last_mowed")
+    public String lastCutting;
+
+    public @Nullable Instant getLastCutting() {
+        try {
+            return ZonedDateTime.parse(lastCutting).toInstant();
+        } catch (final DateTimeParseException e) {
+            // Ignored
+        }
+        return null;
+    }
+}
diff --git a/bundles/org.openhab.binding.boschindego/src/main/java/org/openhab/binding/boschindego/internal/dto/response/PredictiveNextCuttingResponse.java b/bundles/org.openhab.binding.boschindego/src/main/java/org/openhab/binding/boschindego/internal/dto/response/PredictiveNextCuttingResponse.java
new file mode 100644 (file)
index 0000000..4ffa7c3
--- /dev/null
@@ -0,0 +1,40 @@
+/**
+ * Copyright (c) 2010-2022 Contributors to the openHAB project
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ */
+package org.openhab.binding.boschindego.internal.dto.response;
+
+import java.time.Instant;
+import java.time.ZonedDateTime;
+import java.time.format.DateTimeParseException;
+
+import org.eclipse.jdt.annotation.Nullable;
+
+import com.google.gson.annotations.SerializedName;
+
+/**
+ * Response for next cutting time.
+ * 
+ * @author Jacob Laursen - Initial contribution
+ */
+public class PredictiveNextCuttingResponse {
+    @SerializedName("mow_next")
+    public String nextCutting;
+
+    public @Nullable Instant getNextCutting() {
+        try {
+            return ZonedDateTime.parse(nextCutting).toInstant();
+        } catch (final DateTimeParseException e) {
+            // Ignored
+        }
+        return null;
+    }
+}
index c3d9afa3268167c61deb221814a64231e0a16d7f..da247be3399eb59e216d2cf6f14a807c69f4e7e8 100644 (file)
@@ -14,6 +14,8 @@ package org.openhab.binding.boschindego.internal.handler;
 
 import static org.openhab.binding.boschindego.internal.BoschIndegoBindingConstants.*;
 
+import java.time.Instant;
+import java.time.ZonedDateTime;
 import java.util.concurrent.ScheduledFuture;
 import java.util.concurrent.TimeUnit;
 
@@ -28,6 +30,8 @@ import org.openhab.binding.boschindego.internal.dto.DeviceCommand;
 import org.openhab.binding.boschindego.internal.dto.response.DeviceStateResponse;
 import org.openhab.binding.boschindego.internal.exceptions.IndegoAuthenticationException;
 import org.openhab.binding.boschindego.internal.exceptions.IndegoException;
+import org.openhab.core.i18n.TimeZoneProvider;
+import org.openhab.core.library.types.DateTimeType;
 import org.openhab.core.library.types.DecimalType;
 import org.openhab.core.library.types.PercentType;
 import org.openhab.core.library.types.StringType;
@@ -55,16 +59,20 @@ public class BoschIndegoHandler extends BaseThingHandler {
     private final Logger logger = LoggerFactory.getLogger(BoschIndegoHandler.class);
     private final HttpClient httpClient;
     private final BoschIndegoTranslationProvider translationProvider;
+    private final TimeZoneProvider timeZoneProvider;
 
     private @NonNullByDefault({}) IndegoController controller;
-    private @Nullable ScheduledFuture<?> pollFuture;
-    private long refreshRate;
+    private @Nullable ScheduledFuture<?> statePollFuture;
+    private @Nullable ScheduledFuture<?> cuttingTimePollFuture;
     private boolean propertiesInitialized;
+    private int previousStateCode;
 
-    public BoschIndegoHandler(Thing thing, HttpClient httpClient, BoschIndegoTranslationProvider translationProvider) {
+    public BoschIndegoHandler(Thing thing, HttpClient httpClient, BoschIndegoTranslationProvider translationProvider,
+            TimeZoneProvider timeZoneProvider) {
         super(thing);
         this.httpClient = httpClient;
         this.translationProvider = translationProvider;
+        this.timeZoneProvider = timeZoneProvider;
     }
 
     @Override
@@ -86,29 +94,37 @@ public class BoschIndegoHandler extends BaseThingHandler {
         }
 
         controller = new IndegoController(httpClient, username, password);
-        refreshRate = config.refresh;
 
         updateStatus(ThingStatus.UNKNOWN);
-        this.pollFuture = scheduler.scheduleWithFixedDelay(this::refreshState, 0, refreshRate, TimeUnit.SECONDS);
+        this.statePollFuture = scheduler.scheduleWithFixedDelay(this::refreshStateWithExceptionHandling, 0,
+                config.refresh, TimeUnit.SECONDS);
+        this.cuttingTimePollFuture = scheduler.scheduleWithFixedDelay(this::refreshCuttingTimesWithExceptionHandling, 0,
+                config.cuttingTimeRefresh, TimeUnit.MINUTES);
     }
 
     @Override
     public void dispose() {
         logger.debug("Disposing Indego handler");
-        ScheduledFuture<?> pollFuture = this.pollFuture;
+        ScheduledFuture<?> pollFuture = this.statePollFuture;
         if (pollFuture != null) {
             pollFuture.cancel(true);
         }
-        this.pollFuture = null;
+        this.statePollFuture = null;
+        pollFuture = this.cuttingTimePollFuture;
+        if (pollFuture != null) {
+            pollFuture.cancel(true);
+        }
+        this.cuttingTimePollFuture = null;
     }
 
     @Override
     public void handleCommand(ChannelUID channelUID, Command command) {
-        if (command == RefreshType.REFRESH) {
-            scheduler.submit(() -> this.refreshState());
-            return;
-        }
         try {
+            if (command == RefreshType.REFRESH) {
+                handleRefreshCommand(channelUID.getId());
+                return;
+            }
+
             if (command instanceof DecimalType && channelUID.getId().equals(STATE)) {
                 sendCommand(((DecimalType) command).intValue());
             }
@@ -120,6 +136,23 @@ public class BoschIndegoHandler extends BaseThingHandler {
         }
     }
 
+    private void handleRefreshCommand(String channelId) throws IndegoAuthenticationException, IndegoException {
+        switch (channelId) {
+            case STATE:
+            case TEXTUAL_STATE:
+            case MOWED:
+            case ERRORCODE:
+            case STATECODE:
+            case READY:
+                this.refreshState();
+                break;
+            case LAST_CUTTING:
+            case NEXT_CUTTING:
+                this.refreshCuttingTimes();
+                break;
+        }
+    }
+
     private void sendCommand(int commandInt) throws IndegoException {
         DeviceCommand command;
         switch (commandInt) {
@@ -150,16 +183,37 @@ public class BoschIndegoHandler extends BaseThingHandler {
         updateState(state);
     }
 
-    private void refreshState() {
+    private void refreshStateWithExceptionHandling() {
         try {
-            if (!propertiesInitialized) {
-                getThing().setProperty(Thing.PROPERTY_SERIAL_NUMBER, controller.getSerialNumber());
-                propertiesInitialized = true;
-            }
+            refreshState();
+        } catch (IndegoAuthenticationException e) {
+            updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
+                    "@text/offline.comm-error.authentication-failure");
+        } catch (IndegoException e) {
+            updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, e.getMessage());
+        }
+    }
+
+    private void refreshState() throws IndegoAuthenticationException, IndegoException {
+        if (!propertiesInitialized) {
+            getThing().setProperty(Thing.PROPERTY_SERIAL_NUMBER, controller.getSerialNumber());
+            propertiesInitialized = true;
+        }
+
+        DeviceStateResponse state = controller.getState();
+        updateStatus(ThingStatus.ONLINE);
+        updateState(state);
 
-            DeviceStateResponse state = controller.getState();
-            updateStatus(ThingStatus.ONLINE);
-            updateState(state);
+        // When state code changed, refresh cutting times immediately.
+        if (state.state != previousStateCode) {
+            refreshCuttingTimes();
+            previousStateCode = state.state;
+        }
+    }
+
+    private void refreshCuttingTimesWithExceptionHandling() {
+        try {
+            refreshCuttingTimes();
         } catch (IndegoAuthenticationException e) {
             updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
                     "@text/offline.comm-error.authentication-failure");
@@ -168,6 +222,28 @@ public class BoschIndegoHandler extends BaseThingHandler {
         }
     }
 
+    private void refreshCuttingTimes() throws IndegoAuthenticationException, IndegoException {
+        if (isLinked(LAST_CUTTING)) {
+            Instant lastCutting = controller.getPredictiveLastCutting();
+            if (lastCutting != null) {
+                updateState(LAST_CUTTING,
+                        new DateTimeType(ZonedDateTime.ofInstant(lastCutting, timeZoneProvider.getTimeZone())));
+            } else {
+                updateState(LAST_CUTTING, UnDefType.UNDEF);
+            }
+        }
+
+        if (isLinked(NEXT_CUTTING)) {
+            Instant nextCutting = controller.getPredictiveNextCutting();
+            if (nextCutting != null) {
+                updateState(NEXT_CUTTING,
+                        new DateTimeType(ZonedDateTime.ofInstant(nextCutting, timeZoneProvider.getTimeZone())));
+            } else {
+                updateState(NEXT_CUTTING, UnDefType.UNDEF);
+            }
+        }
+    }
+
     private void updateState(DeviceStateResponse state) {
         DeviceStatus deviceStatus = DeviceStatus.fromCode(state.state);
         int status = getStatusFromCommand(deviceStatus.getAssociatedCommand());
@@ -200,7 +276,7 @@ public class BoschIndegoHandler extends BaseThingHandler {
             logger.debug("Command is equal to state");
             return false;
         }
-        // Cant pause while the mower is docked
+        // Can't pause while the mower is docked
         if (command == DeviceCommand.PAUSE && deviceStatus.getAssociatedCommand() == DeviceCommand.RETURN) {
             logger.debug("Can't pause the mower while it's docked or docking");
             return false;
index ee095e6a690fc675f5e9528dbe5b4460958bfbcd..158fba4601d12c4fa38a951885f2172ee64c81e7 100644 (file)
@@ -10,10 +10,12 @@ thing-type.boschindego.indego.description = Indego which supports the connect fe
 
 # thing types config
 
+thing-type.config.boschindego.indego.cuttingTimeRefresh.label = Cutting Time Refresh Interval
+thing-type.config.boschindego.indego.cuttingTimeRefresh.description = The number of minutes between refreshing last/next cutting time.
 thing-type.config.boschindego.indego.password.label = Password
 thing-type.config.boschindego.indego.password.description = Password for the Bosch Indego account.
 thing-type.config.boschindego.indego.refresh.label = Refresh Interval
-thing-type.config.boschindego.indego.refresh.description = Specifies the refresh interval in seconds.
+thing-type.config.boschindego.indego.refresh.description = The number of seconds between refreshing device state.
 thing-type.config.boschindego.indego.username.label = Username
 thing-type.config.boschindego.indego.username.description = Username for the Bosch Indego account.
 
@@ -21,7 +23,12 @@ thing-type.config.boschindego.indego.username.description = Username for the Bos
 
 channel-type.boschindego.errorcode.label = Error Code
 channel-type.boschindego.errorcode.description = 0 = no error
+channel-type.boschindego.lastCutting.label = Last Cutting
+channel-type.boschindego.lastCutting.description = Last cutting time
 channel-type.boschindego.mowed.label = Cut Grass
+channel-type.boschindego.mowed.description = Cut grass in percent
+channel-type.boschindego.nextCutting.label = Next Cutting
+channel-type.boschindego.nextCutting.description = Next scheduled cutting time
 channel-type.boschindego.ready.label = Ready
 channel-type.boschindego.ready.description = Indicates if mower is ready to mow
 channel-type.boschindego.ready.state.option.0 = not ready
index 192792b4c21d3024912852bcd6adda6b3abee9c2..03d63cca45f1bb56172dd921242f8491b0ede7c6 100644 (file)
@@ -14,6 +14,8 @@
                        <channel id="statecode" typeId="statecode"/>
                        <channel id="mowed" typeId="mowed"/>
                        <channel id="ready" typeId="ready"/>
+                       <channel id="lastCutting" typeId="lastCutting"/>
+                       <channel id="nextCutting" typeId="nextCutting"/>
                </channels>
                <config-description>
                        <parameter name="username" type="text" required="true">
                        </parameter>
                        <parameter name="refresh" type="integer" min="60">
                                <label>Refresh Interval</label>
-                               <description>Specifies the refresh interval in seconds.</description>
+                               <description>The number of seconds between refreshing device state.</description>
                                <default>180</default>
                        </parameter>
+                       <parameter name="cuttingTimeRefresh" type="integer" min="1">
+                               <label>Cutting Time Refresh Interval</label>
+                               <description>The number of minutes between refreshing last/next cutting time.</description>
+                               <advanced>true</advanced>
+                               <default>60</default>
+                       </parameter>
                </config-description>
        </thing-type>
 
        <channel-type id="mowed">
                <item-type>Dimmer</item-type>
                <label>Cut Grass</label>
+               <description>Cut grass in percent</description>
                <state readOnly="true" pattern="%d %%"></state>
        </channel-type>
        <channel-type id="ready">
                        </options>
                </state>
        </channel-type>
+       <channel-type id="lastCutting">
+               <item-type>DateTime</item-type>
+               <label>Last Cutting</label>
+               <description>Last cutting time</description>
+               <category>Time</category>
+               <state readOnly="true"/>
+       </channel-type>
+       <channel-type id="nextCutting">
+               <item-type>DateTime</item-type>
+               <label>Next Cutting</label>
+               <description>Next scheduled cutting time</description>
+               <category>Time</category>
+               <state readOnly="true"/>
+       </channel-type>
 
 </thing:thing-descriptions>