[automower] Implementation of complete automower API (#17545)

* started implementation of complete automower API

Signed-off-by: Michael Weger <weger.michael@gmx.net>
This commit is contained in:
MikeTheTux
2025-02-20 21:37:41 +01:00
committed by GitHub
parent 1b90467bd4
commit 4ce97d55ed
45 changed files with 4003 additions and 345 deletions
+184 -117
View File
@@ -1,141 +1,200 @@
# Automower Binding
This is the binding for [Husqvarna Automower a robotic lawn mowers](https://www.husqvarna.com/uk/products/robotic-lawn-mowers/).
This binding allows you to integrate, view and control Automower lawn mowers in the openHAB environment.
This is the binding for [Husqvarna Automower® robotic lawn mowers](https://www.husqvarna.com/uk/products/robotic-lawn-mowers/).
This binding allows you to integrate, view and control Automower® lawn mowers in the openHAB environment.
## Supported Things
`bridge:` The bridge needs to be configured with credentials and an application key that allows communicating with the Automower Connect API
`bridge:` The bridge needs to be configured with credentials and an application key that allows communicating with the Automower® Connect API
`automower:` A single Husqvarna Automower robot
`automower:` A single Husqvarna Automower® robot
All Husqvarna Automower models with "Automower Connect" should be supported. It was tested only with a Husqvarna Automower 430X and 450X.
All Husqvarna Automower® models with "Automower® Connect" should be supported. It was tested with a Husqvarna Automower® 430X, 450X and 430X NERA.
## Discovery
Once the bridge is created and configured, openHAB will automatically discover all Automowers registered on your account.
Once the bridge is created and configured, openHAB will automatically discover all Automower® registered on your account.
## Thing Configuration
`bridge:`
- appKey (mandatory): The Application Key is required to communicate with the Automower Connect API. It can be obtained by registering an Application on [the Husqvarna Website](https://developer.husqvarnagroup.cloud/). This application also needs to be connected to the ["Authentication API" and the "Automower Connect API"](https://developer.husqvarnagroup.cloud/docs/getting-started)
- appSecret (mandatory): The Application Secret is required to communicate with the Automower Connect API. It can be obtained by registering an Application on [the Husqvarna Website](https://developer.husqvarnagroup.cloud/).
- appKey (mandatory): The Application Key is required to communicate with the Automower® Connect API. It can be obtained by registering an Application on [the Husqvarna Website](https://developer.husqvarnagroup.cloud/). This application also needs to be connected to the ["Authentication API" and the "Automower® Connect API"](https://developer.husqvarnagroup.cloud/docs/getting-started)
- appSecret (mandatory): The Application Secret is required to communicate with the Automower® Connect API. It can be obtained by registering an Application on [the Husqvarna Website](https://developer.husqvarnagroup.cloud/).
- pollingInterval (optional): How often the bridge state should be queried in seconds. Default is 1h (3600s)
Keep in mind that the status of the bridge should not be queried too often.
According to the Husqvarna documentation not more than 10000 requests per month and application key are allowed.
According to the Husqvarna documentation not more than 10000 requests per month / 1 request per second and application key are allowed.
With the default value of 1h this would mean ~720 requests per month for the bridge state
`automower:`
- mowerId (mandatory): The Id of an automower as used by the Automower Connect Api to identify a mower. This is automatically filled when the thing is discovered
- pollingInterval (optional): How often the current automower state should be polled in seconds. Default is 10min (600s)
- mowerId (mandatory): The Id of an Automower® as used by the Automower® Connect Api to identify a mower. This is automatically filled when the thing is discovered
- pollingInterval (optional): How often the current Automower® state should be polled in seconds. Default is 10min (600s)
Keep in mind that the status of the Automowers should not be queried too often.
According to the Husqvarna documentation, no more than 10000 requests per month and application key are allowed.
With the default value of 10min this would mean ~4300 requests per month per single Automower
Keep in mind that the status of the Automower® should not be queried too often.
According to the Husqvarna documentation not more than 10000 requests per month / 1 request per second and application key are allowed.
With the default value of 10min this would mean ~4300 requests per month per single Automower®
## Channels
### Status Channels
| channel | type | access mode | description |
|-------------------------|----------|-------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| mode | String | R | The current mode (MAIN_AREA, SECONDARY_AREA, HOME, DEMO, UNKNOWN) |
| activity | String | R | The current activity (UNKNOWN, NOT_APPLICABLE, MOWING, GOING_HOME, CHARGING, LEAVING, PARKED_IN_CS, STOPPED_IN_GARDEN) |
| state | String | R | The current state (UNKNOWN, NOT_APPLICABLE, PAUSED, IN_OPERATION, WAIT_UPDATING, WAIT_POWER_UP, RESTRICTED_NONE, RESTRICTED_WEEK_SCHEDULE, RESTRICTED_PARK_OVERRIDE, RESTRICTED_SENSOR, RESTRICTED_DAILY_LIMIT, OFF, STOPPED, ERROR, FATAL_ERROR, ERROR_AT_POWER_UP) |
| last-update | DateTime | R | The time when the automower updated its states |
| battery | Number | R | The battery state of charge in percent |
| error-code | Number | R | The current error code |
| error-timestamp | DateTime | R | The timestamp when the current error occurred |
| planner-next-start | DateTime | R | The time for the next auto start. If the mower is charging then the value is the estimated time when it will be leaving the charging station. If the mower is about to start now, the value is NULL. |
| planner-override-action | String | R | The action that overrides current planner operation. |
| calendar-tasks | String | R | The JSON with the information about Automower planner. |
| channel | type | access mode | description | advanced |
|---------------------------------------|----------------------|-----|----------------------------------------------------------------------------------------------------------------|-------|
| status#name | String | R | The name of the Automower® | false |
| status#mode | String | R | The current mode (MAIN_AREA, SECONDARY_AREA, HOME, DEMO, UNKNOWN) | false |
| status#activity | String | R | The current activity (UNKNOWN, NOT_APPLICABLE, MOWING, GOING_HOME, CHARGING, LEAVING, PARKED_IN_CS, STOPPED_IN_GARDEN) | false |
| status#inactive-reason | String | R | The current reason for being inactive (NONE, PLANNING, SEARCHING_FOR_SATELLITES) | false |
| status#state | String | R | The current state (UNKNOWN, NOT_APPLICABLE, PAUSED, IN_OPERATION, WAIT_UPDATING, WAIT_POWER_UP, RESTRICTED_NONE, RESTRICTED_WEEK_SCHEDULE, RESTRICTED_PARK_OVERRIDE, RESTRICTED_SENSOR, RESTRICTED_DAILY_LIMIT, RESTRICTED_FOTA, RESTRICTED_FROST, RESTRICTED_ALL_WORK_AREAS_COMPLETED, RESTRICTED_EXTERNAL, OFF, STOPPED, ERROR, FATAL_ERROR, ERROR_AT_POWER_UP) | false |
| status#work-area-id<sup id="a1">[1](#f1)</sup> | Number | R | Id of the active work area | true |
| status#work-area<sup id="a1">[1](#f1)</sup> | String | R | Name of the active work area | false |
| status#last-update | DateTime | R | The time when the Automower® updated its states | false |
| status#last-poll-update | DateTime | R | The time when the binding polled the last update from the cloud | true |
| status#poll-update | Switch | R | Poll Automower® status update from the cloud | true |
| status#battery | Number:Dimensionless | R | The battery state of charge in percent | false |
| status#error-code | Number | R/W | The current error code. `sendCommand(0)` to confirm current non fatal error | true |
| status#error-message | String | R | The current error message | false |
| status#error-timestamp | DateTime | R | The timestamp when the current error occurred | false |
| status#error-confirmable<sup id="a1">[1](#f1)</sup> | Switch | R | If the mower has an Error Code this attribute states if the error is confirmable | true |
| status#next-start | DateTime | R | The time for the next auto start. If the mower is charging then the value is the estimated time when it will be leaving the charging station. If the mower is about to start now, the value is NULL | false |
| status#override-action | String | R | The action that overrides current planner operation | true |
| status#restricted-reason | String | R | A reason that restrics current planner operation (NONE, WEEK_SCHEDULE, PARK_OVERRIDE, SENSOR, DAILY_LIMIT, FOTA, FROST, ALL_WORK_AREAS_COMPLETED, EXTERNAL) | false |
| status#external-reason | String | R | An external reason set by i.e. IFTTT, Google Assistant or Amazon Alexa that restrics current planner operation | true |
### Command Channels
| channel | type | access mode | description |
|-----------------------------|----------|-------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| start | Number | W | Starts the automower for a duration |
| resume_schedule | Switch | W | Resumes the Automower schedule |
| pause | Switch | W | Pause the Automower |
| park | Number | W | Park the Automower for a duration |
| park_until_next_schedule | Switch | W | Park the Automower until next schedule |
| park_until_further_notice | Switch | W | Park the Automower until further notice. |
### Settings Channels
| channel | type | access mode | description | advanced |
|---------------------------------------------------|--------|-------------|-------------------------------------------------------------------------|----------|
| setting#cutting-height | Number | R/W | Prescaled cutting height, Range: 1-9 | false |
| setting#headlight-mode<sup id="a1">[1](#f1)</sup> | String | R/W | Headlight Mode (ALWAYS_ON, ALWAYS_OFF, EVENING_ONLY, EVENING_AND_NIGHT) | false |
### Statistics Channels
| channel | type | access mode | description | advanced |
|-------------------------------------|----------------------|-------------|---------------------------------------------------------------------------------------------|----------|
| statistic#cutting-blade-usage-time | Number:Time | R/W | The time since the last reset of the cutting blade usage counter. `sendCommand(0)` to reset | false |
| statistic#down-time | Number:Time | R | The time the mower has been disconnected from the cloud | true |
| statistic#number-of-charging-cycles | Number | R | Number of charging cycles | false |
| statistic#number-of-collisions | Number | R | The total number of collisions | false |
| statistic#total-charging-time | Number:Time | R | Total charging time | false |
| statistic#total-cutting-time | Number:Time | R | Total Cutting Time | false |
| statistic#total-cutting-percent | Number:Dimensionless | R | Total cutting time in percent | false |
| statistic#total-drive-distance | Number:Length | R | Total driven distance | false |
| statistic#total-running-time | Number:Time | R | The total running time (the wheel motors have been running) | false |
| statistic#total-searching-time | Number:Length | R | The total searching time | false |
| statistic#total-searching-percent | Number:Dimensionless | R | The total searching time in percent | false |
| statistic#up-time | Number:Time | R | The time the mower has been connected to the cloud | true |
### Calendar Tasks Channels
These channels hold the different Calendar Task configurations.
| channel | type | access mode | description | advanced |
|---------------------------------------------------------------|-------------|-------------|-----------------------------------------------|----------|
| calendartask#\<x\>-task-start | Number:Time | R/W | Start time relative to midnight | true |
| calendartask#\<x\>-task-duration | Number:Time | R/W | Duration time | true |
| calendartask#\<x\>-task-monday | Switch | R/W | Enabled on Mondays | true |
| calendartask#\<x\>-task-tuesday | Switch | R/W | Enabled on Tuesdays | true |
| calendartask#\<x\>-task-wednesday | Switch | R/W | Enabled on Wednesdays | true |
| calendartask#\<x\>-task-thursday | Switch | R/W | Enabled on Thursdays | true |
| calendartask#\<x\>-task-friday | Switch | R/W | Enabled on Fridays | true |
| calendartask#\<x\>-task-saturday | Switch | R/W | Enabled on Saturdays | true |
| calendartask#\<x\>-task-sunday | Switch | R/W | Enabled on Sundays | true |
| calendartask#\<x\>-task-workAreaId<sup id="a1">[1](#f1)</sup> | Number | R | Work Area Id mapped to this calendar | true |
| calendartask#\<x\>-task-workArea<sup id="a1">[1](#f1)</sup> | String | R | Name of the Work Area mapped to this calendar | true |
\<x\> ... 01-#calendartasks
### Position Channels
These channels hold the last 50 GPS positions recorded by the Automower, thus describing the path it followed.
These channels hold the last 50 GPS positions recorded by the Automower®, thus describing the path it followed.
Position 01 is the latest recorded position, the other positions are pushed back, thus removing the previous position 50 from the list because it is replaced by the previous position 49.
Channel `last-position` is always identical with channel `position01` and thus provides more convenient access if only the latest GPS information is required by the user.
| channel | type | access mode | description |
|------------|----------|-------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| position01 | Location | R | GPS Position 01 |
| position02 | Location | R | GPS Position 02 |
| position03 | Location | R | GPS Position 03 |
| position04 | Location | R | GPS Position 04 |
| position05 | Location | R | GPS Position 05 |
| position06 | Location | R | GPS Position 06 |
| position07 | Location | R | GPS Position 07 |
| position08 | Location | R | GPS Position 08 |
| position09 | Location | R | GPS Position 09 |
| position10 | Location | R | GPS Position 10 |
| position11 | Location | R | GPS Position 11 |
| position12 | Location | R | GPS Position 12 |
| position13 | Location | R | GPS Position 13 |
| position14 | Location | R | GPS Position 14 |
| position15 | Location | R | GPS Position 15 |
| position16 | Location | R | GPS Position 16 |
| position17 | Location | R | GPS Position 17 |
| position18 | Location | R | GPS Position 18 |
| position19 | Location | R | GPS Position 19 |
| position20 | Location | R | GPS Position 20 |
| position21 | Location | R | GPS Position 21 |
| position22 | Location | R | GPS Position 22 |
| position23 | Location | R | GPS Position 23 |
| position24 | Location | R | GPS Position 24 |
| position25 | Location | R | GPS Position 25 |
| position26 | Location | R | GPS Position 26 |
| position27 | Location | R | GPS Position 27 |
| position28 | Location | R | GPS Position 28 |
| position29 | Location | R | GPS Position 29 |
| position30 | Location | R | GPS Position 30 |
| position31 | Location | R | GPS Position 31 |
| position32 | Location | R | GPS Position 32 |
| position33 | Location | R | GPS Position 33 |
| position34 | Location | R | GPS Position 34 |
| position35 | Location | R | GPS Position 35 |
| position36 | Location | R | GPS Position 36 |
| position37 | Location | R | GPS Position 37 |
| position38 | Location | R | GPS Position 38 |
| position39 | Location | R | GPS Position 39 |
| position40 | Location | R | GPS Position 40 |
| position41 | Location | R | GPS Position 41 |
| position42 | Location | R | GPS Position 42 |
| position43 | Location | R | GPS Position 43 |
| position44 | Location | R | GPS Position 44 |
| position45 | Location | R | GPS Position 45 |
| position46 | Location | R | GPS Position 46 |
| position47 | Location | R | GPS Position 47 |
| position48 | Location | R | GPS Position 48 |
| position49 | Location | R | GPS Position 49 |
| position50 | Location | R | GPS Position 50 |
| last-position | Location | R | Last GPS Position (identical with positions#position01) |
| channel | type | access mode | description | advanced |
|-----------------------------------------------|----------|-------------|---------------------------------------------------------|----------|
| position#last<sup id="a1">[1](#f1)</sup> | Location | R | Last GPS Position (identical with positions#position01) | false |
| position#\<x\>-pos<sup id="a1">[1](#f1)</sup> | Location | R | GPS Position \<x\> | true |
\<x\> ... 01-50
### Stayout Zones Channels
These channels hold the different Stayout Zone configurations.
| channel | type | access mode | description | advanced |
|-----------------------------------------------------------|--------|-------------|------------------------------------------------------------------------------------------------------------------------------------|----------|
| stayoutzone#dirty<sup id="a1">[1](#f1)</sup> | Switch | R | If the stay-out zones are synchronized with the Husqvarna cloud. If the map is dirty you can not enable or disable a stay-out zone | true |
| stayoutzone#\<x\>-zone-id<sup id="a1">[1](#f1)</sup> | String | R | Id of the Stayout zone | true |
| stayoutzone#\<x\>-zone-name<sup id="a1">[1](#f1)</sup> | String | R | The name of the Stayout zone | true |
| stayoutzone#\<x\>-zone-enabled<sup id="a1">[1](#f1)</sup> | Switch | R/W | If the Stayout zone is enabled, the Automower® will not access the zone | true |
\<x\> ... 01-#stayoutzones
### Work Area Channels
These channels hold the different Work Area configurations.
| channel | type | access mode | description | advanced |
|-----------------------------------------------------------------------------------------------------------|-----------------------|-------------|-----------------------------------------------------|----------|
| workarea#\<x\>-area-id<sup id="a1">[1](#f1)</sup> | Number | R | Id of the Work Area | false |
| workarea#\<x\>-area-name<sup id="a1">[1](#f1)</sup> | String | R | Name of the work area | false |
| workarea#\<x\>-area-cutting-height<sup id="a1">[1](#f1)</sup> | Number:Dimensionless | R/W | Cutting height in percent. 0-100 | false |
| workarea#\<x\>-area-enabled<sup id="a1">[1](#f1)</sup> | Switch | R/W | If the work area is enabled or disabled | false |
| workarea#\<x\>-area-progress<sup id="a1">[1](#f1)</sup><sup>,</sup><sup id="a2">[2](#f2)</sup> | Number | R | The progress on a work area | true |
| workarea#\<x\>-area-last-time-completed<sup id="a1">[1](#f1)</sup><sup>,</sup><sup id="a2">[2](#f2)</sup> | DateTime | R | Timestamp when the work area was last completed | true |
\<x\> ... 01-#workareas
### Messages
These channels hold the last 50 messages recorded by the Automower®.
Message 01 is the latest recorded message, the other messages are pushed back, thus removing the previous message 50 from the list because it is replaced by the previous message 49.
| channel | type | access mode | description | advanced |
|-------------------------|----------|-------------|------------------------------------------|----------|
| message#\<x\>-time | DateTime | R | Timestamp when the event occurred | true |
| message#\<x\>-code | Number | R | (Error) code of the event | true |
| message#\<x\>-text | String | R | The message | true |
| message#\<x\>-severity | String | R | The severity of the event | true |
| message#\<x\>-position | Location | R | GPS Position of the event (if available) | true |
\<x\> ... 01-50
### Command Channels
Command channels that trigger actions.
| channel | type | access mode | description | advanced |
|-----------------------------------|----------|-------------|------------------------------------------|----------|
| command#start | Number | W | Start the Automower® for a duration | false |
| command#resume_schedule | Switch | W | Resume the Automower® schedule | false |
| command#pause | Switch | W | Pause the Automower® | false |
| command#park | Number | W | Park the Automower® for a duration | false |
| command#park_until_next_schedule | Switch | W | Park the Automower® until next schedule | false |
| command#park_until_further_notice | Switch | W | Park the Automower® until further notice | false |
## Actions
The following actions are available for `automower`things:
The following actions are available for `automower` things:
| action name | arguments | description |
|------------------------|----------------|------------------------------------------------------------------------------------------------|
| start | duration (int) | Starts the automower for the given duration (minutes), overriding the schedule |
| pause | - | Pauses the automower wherever it is currently located |
| parkUntilNextSchedule | - | Parks the automower, fully charges it and starts afterwards according to the schedule |
| parkUntilFurtherNotice | - | Parks the automower until it is started again by the start action or the schedule gets resumed |
| park | duration (int) | Parks the automower for the given duration (minutes), overriding the schedule |
| resumeSchedule | - | Resumes the schedule for the automower |
| action name | arguments | description |
|----------------------------|------------------|------------------------------------------------------------------------------------------------|
| start | `duration (int)` | Start the Automower® for the given duration (minutes), overriding the schedule |
| pause | - | Pause the Automower® wherever it is currently located |
| parkUntilNextSchedule | - | Park the Automower®, fully charges it and starts afterwards according to the schedule |
| parkUntilFurtherNotice | - | Park the Automower® until it is started again by the start action or the schedule gets resumed |
| park | `duration (int)` | Park the Automower® for the given duration (minutes), overriding the schedule |
| resumeSchedule | - | Resume the schedule for the Automower® |
| confirmError | - | Confirm current non fatal error |
| resetCuttingBladeUsageTime | - | Reset the cutting blade usage time |
| setSettings | `byte cuttingHeight`<br/>`String headlightMode` | Update Automower® settings |
| setWorkArea | `long workAreaId`<br/>`boolean enable`<br/>`byte cuttingHeight` | Update work area settings |
| setStayOutZone | `String zoneId`<br/>`boolean enable` | Enable or disable stay-out zone |
| setCalendarTask | `Long workAreaId` (optional, set to `null` if the mower doesn't support work areas)<br/>`short[] start`<br/>`short[] duration`<br/>`boolean[] monday`<br/>`boolean[] tuesday`<br/>`boolean[] wednesday`<br/>`boolean[] thursday`<br/>`boolean[] friday`<br/>`boolean[] saturday`<br/>`boolean[] sunday` | Update calendar task settings. Parameter are an array for all calendar tasks (per work area) |
| poll | - | Poll Automower® status update from the cloud |
## Full Example
@@ -143,7 +202,7 @@ The following actions are available for `automower`things:
```java
Bridge automower:bridge:mybridge [ appKey="<your_private_application_key>", userName="<your_username>", password="<your_password>" ] {
Thing automower myAutomower [ mowerId="<your_id_received_from_discovery>", pollingInterval=3600] {
Thing automower myAutomower [ mowerId="<your_id_received_from_discovery>", pollingInterval=3600 ] {
}
}
```
@@ -151,25 +210,24 @@ Bridge automower:bridge:mybridge [ appKey="<your_private_application_key>", user
### automower.items
```java
String Automower_Mode "Mode [%s]" { channel="automower:automower:mybridge:myAutomower:mode" }
String Automower_Activity "Activity [%s]" { channel="automower:automower:mybridge:myAutomower:activity" }
String Automower_State "State [%s]" { channel="automower:automower:mybridge:myAutomower:state" }
DateTime Automower_Last_Update "Last Update" { channel="automower:automower:mybridge:myAutomower:last-update" }
Number Automower_Battery "Battery [%d %%]" { channel="automower:automower:mybridge:myAutomower:battery" }
Number Automower_Error_Code "Error Code [%d]" { channel="automower:automower:mybridge:myAutomower:error-code" }
DateTime Automower_Error_Time "Error Time" { channel="automower:automower:mybridge:myAutomower:error-timestamp" }
String Automower_Override_Action "Override Action [%s]" { channel="automower:automower:mybridge:myAutomower:planner-override-action" }
DateTime Automower_Next_Start_Time "Next Start Time" { channel="automower:automower:mybridge:myAutomower:planner-next-start" }
String Automower_Calendar_Tasks "Planned Tasks [%s]" { channel="automower:automower:mybridge:myAutomower:calendar-tasks" }
String Automower_Mode "Mode [%s]" { channel="automower:automower:mybridge:myAutomower:status#mode" }
String Automower_Activity "Activity [%s]" { channel="automower:automower:mybridge:myAutomower:status#activity" }
String Automower_State "State [%s]" { channel="automower:automower:mybridge:myAutomower:status#state" }
DateTime Automower_Last_Update "Last Update" { channel="automower:automower:mybridge:myAutomower:status#last-update" }
Number Automower_Battery "Battery [%d %%]" { channel="automower:automower:mybridge:myAutomower:status#battery" }
Number Automower_Error_Code "Error Code [%d]" { channel="automower:automower:mybridge:myAutomower:status#error-code" }
DateTime Automower_Error_Time "Error Time" { channel="automower:automower:mybridge:myAutomower:status#error-timestamp" }
String Automower_Override_Action "Override Action [%s]" { channel="automower:automower:mybridge:myAutomower:status#override-action" }
DateTime Automower_Next_Start_Time "Next Start Time" { channel="automower:automower:mybridge:myAutomower:status#next-start" }
Number Automower_Command_Start "Start mowing for duration [%d min]" { channel="automower:automower:mybridge:myAutomower:start" }
Switch Automower_Command_Resume "Resume the schedule" { channel="automower:automower:mybridge:myAutomower:resume_schedule" }
Switch Automower_Command_Pause "Pause the automower" { channel="automower:automower:mybridge:myAutomower:pause" }
Number Automower_Command_Park "Park for duration [%d min]" { channel="automower:automower:mybridge:myAutomower:park" }
Switch Automower_Command_Park_Next_Schedule "Park until next schedule" { channel="automower:automower:mybridge:myAutomower:park_until_next_schedule" }
Switch Automower_Command_Park_Notice "Park until further notice" { channel="automower:automower:mybridge:myAutomower:park_until_further_notice" }
Number Automower_Command_Start "Start mowing for duration [%d min]" { channel="automower:automower:mybridge:myAutomower:command#start" }
Switch Automower_Command_Resume "Resume the schedule" { channel="automower:automower:mybridge:myAutomower:command#resume_schedule" }
Switch Automower_Command_Pause "Pause the automower" { channel="automower:automower:mybridge:myAutomower:command#pause" }
Number Automower_Command_Park "Park for duration [%d min]" { channel="automower:automower:mybridge:myAutomower:command#park" }
Switch Automower_Command_Park_Next_Schedule "Park until next schedule" { channel="automower:automower:mybridge:myAutomower:command#park_until_next_schedule" }
Switch Automower_Command_Park_Notice "Park until further notice" { channel="automower:automower:mybridge:myAutomower:command#park_until_further_notice" }
Location Automower_Last_Position "Last Position" { channel="automower:automower:mybridge:myAutomower:last-position" }
Location Automower_Last_Position "Last Position" { channel="automower:automower:mybridge:myAutomower:position#last-position" }
```
### automower.sitemap
@@ -194,14 +252,23 @@ sitemap demo label="Automower"
### automower.rule
Example rule that triggers an automower action
Example rule that triggers an Automower® action
```java
rule "AutomowerParkUntilFurtherNotice"
when
Item Some_Item changed to ON
then
// via command item
Automower_Command_Park_Notice.sendCommand(ON)
// alternative via actions
val mowerActions = getActions("automower", "automower:automower:mybridge:myAutomower")
mowerActions.parkUntilFurtherNotice()
end
```
## Footnotes
- <b id="f1">1)</b> ... Channel availability depends on Automower® capabilities [](#a1)
- <b id="f2">2)</b> ... Channel available for EPOS Automower® and systematic mowing work areas only [](#a2)
@@ -13,10 +13,13 @@
package org.openhab.binding.automower.internal;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.core.thing.ThingTypeUID;
import org.openhab.core.thing.type.ChannelTypeUID;
/**
* The {@link AutomowerBindingConstants} class defines common constants, which are
@@ -35,57 +38,328 @@ public class AutomowerBindingConstants {
public static final ThingTypeUID THING_TYPE_AUTOMOWER = new ThingTypeUID(BINDING_ID, "automower");
// List of all status Channel ids
public static final String GROUP_STATUS = ""; // no channel group in use at the moment, we'll possibly introduce
// this in a future release
public static final String GROUP_STATUS = "status#";
public static final String CHANNEL_STATUS_NAME = GROUP_STATUS + "name";
public static final String CHANNEL_STATUS_MODE = GROUP_STATUS + "mode";
public static final String CHANNEL_STATUS_ACTIVITY = GROUP_STATUS + "activity";
public static final String CHANNEL_STATUS_INACTIVE_REASON = GROUP_STATUS + "inactive-reason";
public static final String CHANNEL_STATUS_STATE = GROUP_STATUS + "state";
public static final String CHANNEL_STATUS_LAST_UPDATE = GROUP_STATUS + "last-update";
public static final String CHANNEL_STATUS_LAST_POLL_UPDATE = GROUP_STATUS + "last-poll-update";
public static final String CHANNEL_STATUS_POLL_UPDATE = GROUP_STATUS + "poll-update";
public static final String CHANNEL_STATUS_WORK_AREA_ID = GROUP_STATUS + "work-area-id";
public static final String CHANNEL_STATUS_WORK_AREA = GROUP_STATUS + "work-area";
public static final String CHANNEL_STATUS_BATTERY = GROUP_STATUS + "battery";
public static final String CHANNEL_STATUS_ERROR_CODE = GROUP_STATUS + "error-code";
public static final String CHANNEL_STATUS_ERROR_MESSAGE = GROUP_STATUS + "error-message";
public static final String CHANNEL_STATUS_ERROR_TIMESTAMP = GROUP_STATUS + "error-timestamp";
public static final String CHANNEL_PLANNER_NEXT_START = GROUP_STATUS + "planner-next-start";
public static final String CHANNEL_PLANNER_OVERRIDE_ACTION = GROUP_STATUS + "planner-override-action";
public static final String CHANNEL_CALENDAR_TASKS = GROUP_STATUS + "calendar-tasks";
public static final String CHANNEL_STATUS_ERROR_CONFIRMABLE = GROUP_STATUS + "error-confirmable";
public static final String CHANNEL_STATUS_NEXT_START = GROUP_STATUS + "next-start";
public static final String CHANNEL_STATUS_OVERRIDE_ACTION = GROUP_STATUS + "override-action";
public static final String CHANNEL_STATUS_RESTRICTED_REASON = GROUP_STATUS + "restricted-reason";
public static final String CHANNEL_STATUS_EXTERNAL_REASON = GROUP_STATUS + "external-reason";
// Position Channels ids
public static final String GROUP_POSITIONS = ""; // no channel group in use at the moment, we'll possibly
// introduce
// this in a future release
public static final String LAST_POSITION = GROUP_POSITIONS + "last-position";
public static final ArrayList<String> CHANNEL_POSITIONS = new ArrayList<>(
List.of(GROUP_POSITIONS + "position01", GROUP_POSITIONS + "position02", GROUP_POSITIONS + "position03",
GROUP_POSITIONS + "position04", GROUP_POSITIONS + "position05", GROUP_POSITIONS + "position06",
GROUP_POSITIONS + "position07", GROUP_POSITIONS + "position08", GROUP_POSITIONS + "position09",
GROUP_POSITIONS + "position10", GROUP_POSITIONS + "position11", GROUP_POSITIONS + "position12",
GROUP_POSITIONS + "position13", GROUP_POSITIONS + "position14", GROUP_POSITIONS + "position15",
GROUP_POSITIONS + "position16", GROUP_POSITIONS + "position17", GROUP_POSITIONS + "position18",
GROUP_POSITIONS + "position19", GROUP_POSITIONS + "position20", GROUP_POSITIONS + "position21",
GROUP_POSITIONS + "position22", GROUP_POSITIONS + "position23", GROUP_POSITIONS + "position24",
GROUP_POSITIONS + "position25", GROUP_POSITIONS + "position26", GROUP_POSITIONS + "position27",
GROUP_POSITIONS + "position28", GROUP_POSITIONS + "position29", GROUP_POSITIONS + "position30",
GROUP_POSITIONS + "position31", GROUP_POSITIONS + "position32", GROUP_POSITIONS + "position33",
GROUP_POSITIONS + "position34", GROUP_POSITIONS + "position35", GROUP_POSITIONS + "position36",
GROUP_POSITIONS + "position37", GROUP_POSITIONS + "position38", GROUP_POSITIONS + "position39",
GROUP_POSITIONS + "position40", GROUP_POSITIONS + "position41", GROUP_POSITIONS + "position42",
GROUP_POSITIONS + "position43", GROUP_POSITIONS + "position44", GROUP_POSITIONS + "position45",
GROUP_POSITIONS + "position46", GROUP_POSITIONS + "position47", GROUP_POSITIONS + "position48",
GROUP_POSITIONS + "position49", GROUP_POSITIONS + "position50"));
// List of all setting Channel ids
public static final String GROUP_SETTING = "setting#";
public static final String CHANNEL_SETTING_CUTTING_HEIGHT = GROUP_SETTING + "cutting-height";
public static final String CHANNEL_SETTING_HEADLIGHT_MODE = GROUP_SETTING + "headlight-mode";
// List of all setting Channel ids
public static final String GROUP_STATISTIC = "statistic#";
public static final String CHANNEL_STATISTIC_CUTTING_BLADE_USAGE_TIME = GROUP_STATISTIC
+ "cutting-blade-usage-time";
public static final String CHANNEL_STATISTIC_DOWN_TIME = GROUP_STATISTIC + "down-time";
public static final String CHANNEL_STATISTIC_NUMBER_OF_CHARGING_CYCLES = GROUP_STATISTIC
+ "number-of-charging-cycles";
public static final String CHANNEL_STATISTIC_NUMBER_OF_COLLISIONS = GROUP_STATISTIC + "number-of-collisions";
public static final String CHANNEL_STATISTIC_TOTAL_CHARGING_TIME = GROUP_STATISTIC + "total-charging-time";
public static final String CHANNEL_STATISTIC_TOTAL_CUTTING_TIME = GROUP_STATISTIC + "total-cutting-time";
public static final String CHANNEL_STATISTIC_TOTAL_CUTTING_PERCENT = GROUP_STATISTIC + "total-cutting-percent";
public static final String CHANNEL_STATISTIC_TOTAL_DRIVE_DISTANCE = GROUP_STATISTIC + "total-drive-distance";
public static final String CHANNEL_STATISTIC_TOTAL_RUNNING_TIME = GROUP_STATISTIC + "total-running-time";
public static final String CHANNEL_STATISTIC_TOTAL_SEARCHING_TIME = GROUP_STATISTIC + "total-searching-time";
public static final String CHANNEL_STATISTIC_TOTAL_SEARCHING_PERCENT = GROUP_STATISTIC + "total-searching-percent";
public static final String CHANNEL_STATISTIC_UP_TIME = GROUP_STATISTIC + "up-time";
// Calendar Task Channel ids
public static final String GROUP_CALENDARTASK = "calendartask#";
public static final String CHANNEL_CALENDARTASK_START = "task-start";
public static final String CHANNEL_CALENDARTASK_DURATION = "task-duration";
public static final String CHANNEL_CALENDARTASK_MONDAY = "task-monday";
public static final String CHANNEL_CALENDARTASK_TUEDAY = "task-tuesday";
public static final String CHANNEL_CALENDARTASK_WEDNESDAY = "task-wednesday";
public static final String CHANNEL_CALENDARTASK_THURSRAY = "task-thursday";
public static final String CHANNEL_CALENDARTASK_FRIDAY = "task-friday";
public static final String CHANNEL_CALENDARTASK_SATURDAY = "task-saturday";
public static final String CHANNEL_CALENDARTASK_SUNDAY = "task-sunday";
public static final String CHANNEL_CALENDARTASK_WORKAREAID = "task-workareaid";
public static final String CHANNEL_CALENDARTASK_WORKAREA = "task-workarea";
public static final ArrayList<String> CHANNEL_CALENDARTASK = new ArrayList<>(
List.of(CHANNEL_CALENDARTASK_START, CHANNEL_CALENDARTASK_DURATION, CHANNEL_CALENDARTASK_MONDAY,
CHANNEL_CALENDARTASK_TUEDAY, CHANNEL_CALENDARTASK_WEDNESDAY, CHANNEL_CALENDARTASK_THURSRAY,
CHANNEL_CALENDARTASK_FRIDAY, CHANNEL_CALENDARTASK_SATURDAY, CHANNEL_CALENDARTASK_SUNDAY,
CHANNEL_CALENDARTASK_WORKAREAID, CHANNEL_CALENDARTASK_WORKAREA));
public static final ArrayList<ChannelTypeUID> CHANNEL_TYPE_CALENDARTASK = new ArrayList<>(
List.of(new ChannelTypeUID(BINDING_ID, "calendarTaskStartType"),
new ChannelTypeUID(BINDING_ID, "calendarTaskDurationType"),
new ChannelTypeUID(BINDING_ID, "calendarTaskMondayType"),
new ChannelTypeUID(BINDING_ID, "calendarTaskTuesdayType"),
new ChannelTypeUID(BINDING_ID, "calendarTaskWednesdayType"),
new ChannelTypeUID(BINDING_ID, "calendarTaskThursdayType"),
new ChannelTypeUID(BINDING_ID, "calendarTaskFridayType"),
new ChannelTypeUID(BINDING_ID, "calendarTaskSaturdayType"),
new ChannelTypeUID(BINDING_ID, "calendarTaskSundayType"),
new ChannelTypeUID(BINDING_ID, "calendarTaskWorkAreaIdType"),
new ChannelTypeUID(BINDING_ID, "workareaNameType")));
// Position Channel ids
public static final String GROUP_POSITION = "position#";
public static final String CHANNEL_POSITION_LAST = GROUP_POSITION + "last";
public static final String CHANNEL_POSITION = "pos";
// Stayout Zones Channel ids
public static final String GROUP_STAYOUTZONE = "stayoutzone#";
public static final String CHANNEL_STAYOUTZONE_DIRTY = GROUP_STAYOUTZONE + "dirty";
public static final String CHANNEL_STAYOUTZONE_ENABLED = "zone-enabled";
public static final ArrayList<String> CHANNEL_STAYOUTZONE = new ArrayList<>(
List.of("zone-id", "zone-name", CHANNEL_STAYOUTZONE_ENABLED));
public static final ArrayList<ChannelTypeUID> CHANNEL_TYPE_STAYOUTZONE = new ArrayList<>(
List.of(new ChannelTypeUID(BINDING_ID, "zoneIdType"), new ChannelTypeUID(BINDING_ID, "zoneNameType"),
new ChannelTypeUID(BINDING_ID, "zoneEnabledType")));
// Work Areas Channel ids
public static final String GROUP_WORKAREA = "workarea#";
public static final String CHANNEL_WORKAREA_CUTTING_HEIGHT = "area-cutting-height";
public static final String CHANNEL_WORKAREA_ENABLED = "area-enabled";
public static final ArrayList<String> CHANNEL_WORKAREA = new ArrayList<>(List.of("area-id", "area-name",
CHANNEL_WORKAREA_CUTTING_HEIGHT, CHANNEL_WORKAREA_ENABLED, "area-progress", "area-last-time-completed"));
public static final ArrayList<ChannelTypeUID> CHANNEL_TYPE_WORKAREA = new ArrayList<>(List.of(
new ChannelTypeUID(BINDING_ID, "workareaIdType"), new ChannelTypeUID(BINDING_ID, "workareaNameType"),
new ChannelTypeUID(BINDING_ID, "workareaCuttingHeightType"),
new ChannelTypeUID(BINDING_ID, "workareaEnabledType"),
new ChannelTypeUID(BINDING_ID, "workareaProgressType"),
new ChannelTypeUID(BINDING_ID, "workareaLastTimeCompletedType")));
// Messages Channel ids
public static final String GROUP_MESSAGE = "message#";
public static final ArrayList<String> CHANNEL_MESSAGE = new ArrayList<>(
List.of("msg-timestamp", "msg-code", "msg-text", "msg-severity", "msg-gps-position"));
public static final ArrayList<ChannelTypeUID> CHANNEL_TYPE_MESSAGE = new ArrayList<>(List.of(
new ChannelTypeUID(BINDING_ID, "messageTimeType"), new ChannelTypeUID(BINDING_ID, "messageCodeType"),
new ChannelTypeUID(BINDING_ID, "messageType"), new ChannelTypeUID(BINDING_ID, "messageSeverityType"),
new ChannelTypeUID(BINDING_ID, "messagePositionType")));
// Command Channel ids
public static final String GROUP_COMMANDS = ""; // no channel group in use at the moment, we'll possibly introduce
// this in a future release
public static final String CHANNEL_COMMAND_START = GROUP_COMMANDS + "start";
public static final String CHANNEL_COMMAND_RESUME_SCHEDULE = GROUP_COMMANDS + "resume_schedule";
public static final String CHANNEL_COMMAND_PAUSE = GROUP_COMMANDS + "pause";
public static final String CHANNEL_COMMAND_PARK = GROUP_COMMANDS + "park";
public static final String CHANNEL_COMMAND_PARK_UNTIL_NEXT_SCHEDULE = GROUP_COMMANDS + "park_until_next_schedule";
public static final String CHANNEL_COMMAND_PARK_UNTIL_NOTICE = GROUP_COMMANDS + "park_until_further_notice";
public static final String GROUP_COMMAND = "command#";
public static final String CHANNEL_COMMAND_START = GROUP_COMMAND + "start";
public static final String CHANNEL_COMMAND_RESUME_SCHEDULE = GROUP_COMMAND + "resume_schedule";
public static final String CHANNEL_COMMAND_PAUSE = GROUP_COMMAND + "pause";
public static final String CHANNEL_COMMAND_PARK = GROUP_COMMAND + "park";
public static final String CHANNEL_COMMAND_PARK_UNTIL_NEXT_SCHEDULE = GROUP_COMMAND + "park_until_next_schedule";
public static final String CHANNEL_COMMAND_PARK_UNTIL_NOTICE = GROUP_COMMAND + "park_until_further_notice";
// Automower properties
public static final String AUTOMOWER_ID = "mowerId";
public static final String AUTOMOWER_NAME = "mowerName";
public static final String AUTOMOWER_MODEL = "mowerModel";
public static final String AUTOMOWER_SERIAL_NUMBER = "mowerSerialNumber";
public static final String AUTOMOWER_CAN_CONFIRM_ERROR = "mowerCanConfirmError";
public static final String AUTOMOWER_HAS_HEADLIGHTS = "mowerHasHeadlights";
public static final String AUTOMOWER_HAS_POSITION = "mowerHasPosition";
public static final String AUTOMOWER_HAS_STAY_OUT_ZONES = "mowerHasStayOutZones";
public static final String AUTOMOWER_HAS_WORK_AREAS = "mowerHasWorkAreas";
// Channel Types of dynamic channels
public static final ChannelTypeUID CHANNEL_TYPE_STATUS_WORK_AREA_ID = new ChannelTypeUID(BINDING_ID,
"workAreaIdType");
public static final ChannelTypeUID CHANNEL_TYPE_STATUS_WORK_AREA = new ChannelTypeUID(BINDING_ID, "workAreaType");
public static final ChannelTypeUID CHANNEL_TYPE_STATUS_ERROR_CONFIRMABLE = new ChannelTypeUID(BINDING_ID,
"errorConfirmableType");
public static final ChannelTypeUID CHANNEL_TYPE_SETTING_HEADLIGHT_MODE = new ChannelTypeUID(BINDING_ID,
"settingHeadlightModeType");
public static final ChannelTypeUID CHANNEL_TYPE_POSITION_LAST = new ChannelTypeUID(BINDING_ID, "lastPositionType");
public static final ChannelTypeUID CHANNEL_TYPE_POSITION = new ChannelTypeUID(BINDING_ID, "positionType");
public static final ChannelTypeUID CHANNEL_TYPE_STAYOUTZONES_DIRTY = new ChannelTypeUID(BINDING_ID,
"zoneDirtyType");
public static final Map<Integer, String> ERROR = new HashMap<>() {
{
put(0, "No message");
put(1, "Outside working area");
put(2, "No loop signal");
put(3, "Wrong loop signal");
put(4, "Loop sensor problem, front");
put(5, "Loop sensor problem, rear");
put(6, "Loop sensor problem, left");
put(7, "Loop sensor problem, right");
put(8, "Wrong PIN code");
put(9, "Trapped");
put(10, "Upside down");
put(11, "Low battery");
put(12, "Empty battery");
put(13, "No drive");
put(14, "Mower lifted");
put(15, "Lifted");
put(16, "Stuck in charging station");
put(17, "Charging station blocked");
put(18, "Collision sensor problem, rear");
put(19, "Collision sensor problem, front");
put(20, "Wheel motor blocked, right");
put(21, "Wheel motor blocked, left");
put(22, "Wheel drive problem, right");
put(23, "Wheel drive problem, left");
put(24, "Cutting system blocked");
put(25, "Cutting system blocked");
put(26, "Invalid sub-device combination");
put(27, "Settings restored");
put(28, "Memory circuit problem");
put(29, "Slope too steep");
put(30, "Charging system problem");
put(31, "STOP button problem");
put(32, "Tilt sensor problem");
put(33, "Mower tilted");
put(34, "Cutting stopped - slope too steep");
put(35, "Wheel motor overloaded, right");
put(36, "Wheel motor overloaded, left");
put(37, "Charging current too high");
put(38, "Electronic problem");
put(39, "Cutting motor problem");
put(40, "Limited cutting height range");
put(41, "Unexpected cutting height adj");
put(42, "Limited cutting height range");
put(43, "Cutting height problem, drive");
put(44, "Cutting height problem, curr");
put(45, "Cutting height problem, dir");
put(46, "Cutting height blocked");
put(47, "Cutting height problem");
put(48, "No response from charger");
put(49, "Ultrasonic problem");
put(50, "Guide 1 not found");
put(51, "Guide 2 not found");
put(52, "Guide 3 not found");
put(53, "GPS navigation problem");
put(54, "Weak GPS signal");
put(55, "Difficult finding home");
put(56, "Guide calibration accomplished");
put(57, "Guide calibration failed");
put(58, "Temporary battery problem");
put(59, "Temporary battery problem");
put(60, "Temporary battery problem");
put(61, "Temporary battery problem");
put(62, "Temporary battery problem");
put(63, "Temporary battery problem");
put(64, "Temporary battery problem");
put(65, "Temporary battery problem");
put(66, "Battery problem");
put(67, "Battery problem");
put(68, "Temporary battery problem");
put(69, "Alarm! Mower switched off");
put(70, "Alarm! Mower stopped");
put(71, "Alarm! Mower lifted");
put(72, "Alarm! Mower tilted");
put(73, "Alarm! Mower in motion");
put(74, "Alarm! Outside geofence");
put(75, "Connection changed");
put(76, "Connection NOT changed");
put(77, "Com board not available");
put(78, "Slipped - Mower has Slipped. Situation not solved with moving pattern");
put(79, "Invalid battery combination - Invalid combination of different battery types.");
put(80, "Cutting system imbalance Warning");
put(81, "Safety function faulty");
put(82, "Wheel motor blocked, rear right");
put(83, "Wheel motor blocked, rear left");
put(84, "Wheel drive problem, rear right");
put(85, "Wheel drive problem, rear left");
put(86, "Wheel motor overloaded, rear right");
put(87, "Wheel motor overloaded, rear left");
put(88, "Angular sensor problem");
put(89, "Invalid system configuration");
put(90, "No power in charging station");
put(91, "Switch cord problem");
put(92, "Work area not valid");
put(93, "No accurate position from satellites");
put(94, "Reference station communication problem");
put(95, "Folding sensor activated");
put(96, "Right brush motor overloaded");
put(97, "Left brush motor overloaded");
put(98, "Ultrasonic Sensor 1 defect");
put(99, "Ultrasonic Sensor 2 defect");
put(100, "Ultrasonic Sensor 3 defect");
put(101, "Ultrasonic Sensor 4 defect");
put(102, "Cutting drive motor 1 defect");
put(103, "Cutting drive motor 2 defect");
put(104, "Cutting drive motor 3 defect");
put(105, "Lift Sensor defect");
put(106, "Collision sensor defect");
put(107, "Docking sensor defect");
put(108, "Folding cutting deck sensor defect");
put(109, "Loop sensor defect");
put(110, "Collision sensor error");
put(111, "No confirmed position");
put(112, "Cutting system major imbalance");
put(113, "Complex working area");
put(114, "Too high discharge current");
put(115, "Too high internal current");
put(116, "High charging power loss");
put(117, "High internal power loss");
put(118, "Charging system problem");
put(119, "Zone generator problem");
put(120, "Internal voltage error");
put(121, "High internal temerature");
put(122, "CAN error");
put(123, "Destination not reachable");
put(124, "Destination blocked");
put(125, "Battery needs replacement");
put(126, "Battery near end of life");
put(127, "Battery problem");
put(128, "Multiple reference stations detected");
put(129, "Auxiliary cutting means blocked");
put(130, "Imbalanced auxiliary cutting disc detected");
put(131, "Lifted in link arm");
put(132, "EPOS accessory missing");
put(133, "Bluetooth com with CS failed");
put(134, "Invalid SW configuration");
put(135, "Radar problem");
put(136, "Work area tampered");
put(137, "High temperature in cutting motor, right");
put(138, "High temperature in cutting motor, center");
put(139, "High temperature in cutting motor, left");
put(141, "Wheel brush motor problem");
put(143, "Accessory power problem");
put(144, "Boundary wire problem");
put(701, "Connectivity problem");
put(702, "Connectivity settings restored");
put(703, "Connectivity problem");
put(704, "Connectivity problem");
put(705, "Connectivity problem");
put(706, "Poor signal quality");
put(707, "SIM card requires PIN");
put(708, "SIM card locked");
put(709, "SIM card not found");
put(710, "SIM card locked");
put(711, "SIM card locked");
put(712, "SIM card locked");
put(713, "Geofence problem");
put(714, "Geofence problem");
put(715, "Connectivity problem");
put(716, "Connectivity problem");
put(717, "SMS could not be sent");
put(724, "Communication circuit board SW must be updated");
}
};
}
@@ -27,6 +27,7 @@ import org.openhab.binding.automower.internal.discovery.AutomowerDiscoveryServic
import org.openhab.binding.automower.internal.things.AutomowerHandler;
import org.openhab.core.auth.client.oauth2.OAuthFactory;
import org.openhab.core.config.discovery.DiscoveryService;
import org.openhab.core.i18n.TimeZoneProvider;
import org.openhab.core.io.net.http.HttpClientFactory;
import org.openhab.core.thing.Bridge;
import org.openhab.core.thing.Thing;
@@ -55,12 +56,14 @@ public class AutomowerHandlerFactory extends BaseThingHandlerFactory {
private final OAuthFactory oAuthFactory;
protected final @NonNullByDefault({}) HttpClient httpClient;
private @Nullable ServiceRegistration<?> automowerDiscoveryServiceRegistration;
private final TimeZoneProvider timeZoneProvider;
@Activate
public AutomowerHandlerFactory(@Reference OAuthFactory oAuthFactory,
@Reference HttpClientFactory httpClientFactory) {
public AutomowerHandlerFactory(@Reference OAuthFactory oAuthFactory, @Reference HttpClientFactory httpClientFactory,
@Reference TimeZoneProvider timeZoneProvider) {
this.oAuthFactory = oAuthFactory;
this.httpClient = httpClientFactory.getCommonHttpClient();
this.timeZoneProvider = timeZoneProvider;
}
@Override
@@ -77,7 +80,7 @@ public class AutomowerHandlerFactory extends BaseThingHandlerFactory {
}
if (AutomowerHandler.SUPPORTED_THING_TYPES.contains(thing.getThingTypeUID())) {
return new AutomowerHandler(thing);
return new AutomowerHandler(thing, timeZoneProvider);
}
return null;
@@ -14,6 +14,7 @@ package org.openhab.binding.automower.internal.actions;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.binding.automower.internal.rest.api.automowerconnect.dto.HeadlightMode;
import org.openhab.binding.automower.internal.things.AutomowerCommand;
import org.openhab.binding.automower.internal.things.AutomowerHandler;
import org.openhab.core.automation.annotation.ActionInput;
@@ -131,4 +132,131 @@ public class AutomowerActions implements ThingActions {
public static void resumeSchedule(ThingActions actions) {
((AutomowerActions) actions).resumeSchedule();
}
@RuleAction(label = "@text/action-confirm-error-label", description = "@text/action-confirm-error-desc")
public void confirmError() {
AutomowerHandler automowerHandler = handler;
if (automowerHandler == null) {
logger.warn("Automower Action service ThingHandler is null!");
} else {
automowerHandler.sendAutomowerConfirmError();
}
}
public static void confirmError(ThingActions actions) {
((AutomowerActions) actions).confirmError();
}
@RuleAction(label = "@text/action-reset-cutting-blade-usage-time-label", description = "@text/action-reset-cutting-blade-usage-time-desc")
public void resetCuttingBladeUsageTime() {
AutomowerHandler automowerHandler = handler;
if (automowerHandler == null) {
logger.warn("Automower Action service ThingHandler is null!");
} else {
automowerHandler.sendAutomowerResetCuttingBladeUsageTime();
}
}
public static void resetCuttingBladeUsageTime(ThingActions actions) {
((AutomowerActions) actions).resetCuttingBladeUsageTime();
}
@RuleAction(label = "@text/action-set-settings-label", description = "@text/action-set-settings-desc")
public void setSettings(
@ActionInput(name = "cutting-height", label = "@text/action-input-cutting-height-label", description = "@text/action-input-cutting-height-desc") @Nullable Byte cuttingHeight,
@ActionInput(name = "headlight-mode", label = "@text/action-input-headlight-mode-label", description = "@text/action-input-headlight-mode-desc") @Nullable String headlightMode) {
AutomowerHandler automowerHandler = handler;
if (automowerHandler == null) {
logger.warn("Automower Action service ThingHandler is null!");
} else {
try {
if (headlightMode != null) {
automowerHandler.sendAutomowerSettings(cuttingHeight, HeadlightMode.valueOf(headlightMode));
} else {
automowerHandler.sendAutomowerSettings(cuttingHeight, null);
}
} catch (IllegalArgumentException e) {
logger.warn("Invalid HeadlightMode: {}, Error: {}", headlightMode, e.getMessage());
}
}
}
public static void setSettings(ThingActions actions, @Nullable Byte cuttingHeight, @Nullable String headlightMode) {
((AutomowerActions) actions).setSettings(cuttingHeight, headlightMode);
}
@RuleAction(label = "@text/action-set-work-area-label", description = "@text/action-set-work-area-desc")
public void setWorkArea(
@ActionInput(name = "workarea-id", label = "@text/action-input-workarea-id-label", description = "@text/action-input-workarea-id-desc") long workAreaId,
@ActionInput(name = "enable", label = "@text/action-input-enable-label", description = "@text/action-input-enable-desc") boolean enable,
@ActionInput(name = "cutting-height", label = "@text/action-input-cutting-height-label", description = "@text/action-input-cutting-height-desc") byte cuttingHeight) {
AutomowerHandler automowerHandler = handler;
if (automowerHandler == null) {
logger.warn("Automower Action service ThingHandler is null!");
} else {
automowerHandler.sendAutomowerWorkArea(workAreaId, enable, cuttingHeight);
}
}
public static void setWorkArea(ThingActions actions, long workAreaId, boolean enable, byte cuttingHeight) {
((AutomowerActions) actions).setWorkArea(workAreaId, enable, cuttingHeight);
}
@RuleAction(label = "@text/action-set-stayoutzone-label", description = "@text/action-set-stayoutzone-desc")
public void setStayOutZone(
@ActionInput(name = "zone-id", label = "@text/action-input-zone-id-label", description = "@text/action-input-zone-id-desc") String zoneId,
@ActionInput(name = "enable", label = "@text/action-input-enable-label", description = "@text/action-input-enable-desc") boolean enable) {
AutomowerHandler automowerHandler = handler;
if (automowerHandler == null) {
logger.warn("Automower Action service ThingHandler is null!");
} else {
automowerHandler.sendAutomowerStayOutZone(zoneId, enable);
}
}
public static void setStayOutZone(ThingActions actions, String zoneId, boolean enable) {
((AutomowerActions) actions).setStayOutZone(zoneId, enable);
}
@RuleAction(label = "@text/action-set-calendartask-label", description = "@text/action-set-calendartask-desc")
public void setCalendarTask(
@ActionInput(name = "workarea-id", label = "@text/action-input-workarea-id-label", description = "@text/action-input-workarea-id-desc") @Nullable Long workAreaId,
@ActionInput(name = "start", label = "@text/action-input-start-label", description = "@text/action-input-start-desc") short[] start,
@ActionInput(name = "duration", label = "@text/action-input-duration-label", description = "@text/action-input-duration-desc") short[] duration,
@ActionInput(name = "monday", label = "@text/action-input-monday-label", description = "@text/action-input-monday-desc") boolean[] monday,
@ActionInput(name = "tuesday", label = "@text/action-input-tuesday-label", description = "@text/action-input-tuesday-desc") boolean[] tuesday,
@ActionInput(name = "wednesday", label = "@text/action-input-wednesday-label", description = "@text/action-input-wednesday-desc") boolean[] wednesday,
@ActionInput(name = "thursday", label = "@text/action-input-thursday-label", description = "@text/action-input-thursday-desc") boolean[] thursday,
@ActionInput(name = "friday", label = "@text/action-input-friday-label", description = "@text/action-input-friday-desc") boolean[] friday,
@ActionInput(name = "saturday", label = "@text/action-input-saturday-label", description = "@text/action-input-saturday-desc") boolean[] saturday,
@ActionInput(name = "sunday", label = "@text/action-input-sunday-label", description = "@text/action-input-sunday-desc") boolean[] sunday) {
AutomowerHandler automowerHandler = handler;
if (automowerHandler == null) {
logger.warn("Automower Action service ThingHandler is null!");
} else {
automowerHandler.sendAutomowerCalendarTask(workAreaId, start, duration, monday, tuesday, wednesday,
thursday, friday, saturday, sunday);
}
}
public static void setCalendarTask(ThingActions actions, @Nullable Long workAreaId, short[] start, short[] duration,
boolean[] monday, boolean[] tuesday, boolean[] wednesday, boolean[] thursday, boolean[] friday,
boolean[] saturday, boolean[] sunday) {
((AutomowerActions) actions).setCalendarTask(workAreaId, start, duration, monday, tuesday, wednesday, thursday,
friday, saturday, sunday);
}
@RuleAction(label = "@text/action-poll-label", description = "@text/action-poll-desc")
public void poll() {
AutomowerHandler automowerHandler = handler;
if (automowerHandler == null) {
logger.warn("Automower Action service ThingHandler is null!");
} else {
automowerHandler.poll();
}
}
public static void poll(ThingActions actions) {
((AutomowerActions) actions).poll();
}
}
@@ -14,16 +14,32 @@ package org.openhab.binding.automower.internal.bridge;
import java.io.IOException;
import java.time.Instant;
import java.util.List;
import java.util.concurrent.ScheduledExecutorService;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.eclipse.jetty.client.HttpClient;
import org.openhab.binding.automower.internal.rest.api.automowerconnect.AutomowerConnectApi;
import org.openhab.binding.automower.internal.rest.api.automowerconnect.dto.Calendar;
import org.openhab.binding.automower.internal.rest.api.automowerconnect.dto.CalendarTask;
import org.openhab.binding.automower.internal.rest.api.automowerconnect.dto.Mower;
import org.openhab.binding.automower.internal.rest.api.automowerconnect.dto.MowerCalendar;
import org.openhab.binding.automower.internal.rest.api.automowerconnect.dto.MowerCalendardRequest;
import org.openhab.binding.automower.internal.rest.api.automowerconnect.dto.MowerCommand;
import org.openhab.binding.automower.internal.rest.api.automowerconnect.dto.MowerCommandAttributes;
import org.openhab.binding.automower.internal.rest.api.automowerconnect.dto.MowerCommandRequest;
import org.openhab.binding.automower.internal.rest.api.automowerconnect.dto.MowerListResult;
import org.openhab.binding.automower.internal.rest.api.automowerconnect.dto.MowerMessages;
import org.openhab.binding.automower.internal.rest.api.automowerconnect.dto.MowerSettings;
import org.openhab.binding.automower.internal.rest.api.automowerconnect.dto.MowerSettingsRequest;
import org.openhab.binding.automower.internal.rest.api.automowerconnect.dto.MowerStayOutZone;
import org.openhab.binding.automower.internal.rest.api.automowerconnect.dto.MowerStayOutZoneAttributes;
import org.openhab.binding.automower.internal.rest.api.automowerconnect.dto.MowerStayOutZoneRequest;
import org.openhab.binding.automower.internal.rest.api.automowerconnect.dto.MowerWorkArea;
import org.openhab.binding.automower.internal.rest.api.automowerconnect.dto.MowerWorkAreaAttributes;
import org.openhab.binding.automower.internal.rest.api.automowerconnect.dto.MowerWorkAreaRequest;
import org.openhab.binding.automower.internal.rest.api.automowerconnect.dto.Settings;
import org.openhab.binding.automower.internal.rest.exceptions.AutomowerCommunicationException;
import org.openhab.binding.automower.internal.things.AutomowerCommand;
import org.openhab.core.auth.client.oauth2.AccessTokenResponse;
@@ -81,6 +97,15 @@ public class AutomowerBridge {
return automowerApi.getMower(appKey, authenticate().getAccessToken(), id).getData();
}
/**
* @param id The id of the mower to query
* @return A detailed status of the mower with the specified id
* @throws AutomowerCommunicationException In case the query cannot be executed successfully
*/
public MowerMessages getAutomowerMessages(String id) throws AutomowerCommunicationException {
return automowerApi.getMowerMessages(appKey, authenticate().getAccessToken(), id).getData();
}
/**
* Sends a command to the automower with the specified id
*
@@ -103,4 +128,109 @@ public class AutomowerBridge {
request.setData(mowerCommand);
automowerApi.sendCommand(appKey, authenticate().getAccessToken(), id, request);
}
/**
* Sends a calendarTask to the automower
*
* @param id The id of the mower
* @param hasWorkAreas Work area capability of the mower
* @param workAreaId The Id of the work area this calendar belongs to (or null, if there is no work area support)
* @param calendarTasks The calendar that should be sent. It is using the same json structure (start, duration, ...)
* as provided when reading the channel
* @throws AutomowerCommunicationException In case the query cannot be executed successfully
*/
public void sendAutomowerCalendarTask(String id, boolean hasWorkAreas, @Nullable Long workAreaId,
List<CalendarTask> calendarTasks) throws AutomowerCommunicationException {
Calendar calendar = new Calendar();
calendar.setTasks(calendarTasks);
MowerCalendar mowerCalendar = new MowerCalendar();
mowerCalendar.setType("calendar");
mowerCalendar.setAttributes(calendar);
MowerCalendardRequest calendarRequest = new MowerCalendardRequest();
calendarRequest.setData(mowerCalendar);
automowerApi.sendCalendar(appKey, authenticate().getAccessToken(), id, hasWorkAreas, workAreaId,
calendarRequest);
}
/**
* Sends Settings to the automower
*
* @param id The id of the mower
* @param settings The Settings that should be sent. It is using the same json structure
* as provided when reading the channel
* @throws AutomowerCommunicationException In case the query cannot be executed successfully
*/
public void sendAutomowerSettings(String id, Settings settings) throws AutomowerCommunicationException {
MowerSettings mowerSettings = new MowerSettings();
mowerSettings.setType("settings");
mowerSettings.setAttributes(settings);
MowerSettingsRequest settingsRequest = new MowerSettingsRequest();
settingsRequest.setData(mowerSettings);
automowerApi.sendSettings(appKey, authenticate().getAccessToken(), id, settingsRequest);
}
/**
* Confirm current non fatal error on the mower
*
* @param id The id of the mower
* @throws AutomowerCommunicationException In case the query cannot be executed successfully
*/
public void sendAutomowerConfirmError(String id) throws AutomowerCommunicationException {
automowerApi.sendConfirmError(appKey, authenticate().getAccessToken(), id);
}
/**
* Reset the cutting blade usage time
*
* @param id The id of the mower
* @throws AutomowerCommunicationException In case the query cannot be executed successfully
*/
public void sendAutomowerResetCuttingBladeUsageTime(String id) throws AutomowerCommunicationException {
automowerApi.sendResetCuttingBladeUsageTime(appKey, authenticate().getAccessToken(), id);
}
/**
* Enable or disable stay out zone
*
* @param id The id of the mower
* @param zoneId The id of the stay out zone
* @param zoneAttributes The new zone status
* @throws AutomowerCommunicationException In case the query cannot be executed successfully
*/
public void sendAutomowerStayOutZone(String id, String zoneId, MowerStayOutZoneAttributes zoneAttributes)
throws AutomowerCommunicationException {
MowerStayOutZone zoneData = new MowerStayOutZone();
zoneData.setType("stayOutZone");
zoneData.setId(zoneId);
zoneData.setAttributes(zoneAttributes);
MowerStayOutZoneRequest zoneRequest = new MowerStayOutZoneRequest();
zoneRequest.setData(zoneData);
automowerApi.sendStayOutZone(appKey, authenticate().getAccessToken(), id, zoneId, zoneRequest);
}
/**
* Update a work area setting
*
* @param id The id of the mower
* @param workAreaId The id of the work area
* @param workAreaAttributes The new work area status
* @throws AutomowerCommunicationException In case the query cannot be executed successfully
*/
public void sendAutomowerWorkArea(String id, long workAreaId, MowerWorkAreaAttributes workAreaAttributes)
throws AutomowerCommunicationException {
MowerWorkArea workAreaData = new MowerWorkArea();
workAreaData.setType("workArea");
workAreaData.setId(workAreaId);
workAreaData.setAttributes(workAreaAttributes);
MowerWorkAreaRequest workAreaRequest = new MowerWorkAreaRequest();
workAreaRequest.setData(workAreaData);
automowerApi.sendWorkArea(appKey, authenticate().getAccessToken(), id, workAreaId, workAreaRequest);
}
}
@@ -63,6 +63,17 @@ public class AutomowerDiscoveryService extends AbstractDiscoveryService {
properties.put(AutomowerBindingConstants.AUTOMOWER_MODEL, mower.getAttributes().getSystem().getModel());
properties.put(AutomowerBindingConstants.AUTOMOWER_NAME, mower.getAttributes().getSystem().getName());
properties.put(AutomowerBindingConstants.AUTOMOWER_CAN_CONFIRM_ERROR,
(mower.getAttributes().getCapabilities().canConfirmError() ? "yes" : "no"));
properties.put(AutomowerBindingConstants.AUTOMOWER_HAS_HEADLIGHTS,
(mower.getAttributes().getCapabilities().hasHeadlights() ? "yes" : "no"));
properties.put(AutomowerBindingConstants.AUTOMOWER_HAS_POSITION,
(mower.getAttributes().getCapabilities().hasPosition() ? "yes" : "no"));
properties.put(AutomowerBindingConstants.AUTOMOWER_HAS_STAY_OUT_ZONES,
(mower.getAttributes().getCapabilities().hasStayOutZones() ? "yes" : "no"));
properties.put(AutomowerBindingConstants.AUTOMOWER_HAS_WORK_AREAS,
(mower.getAttributes().getCapabilities().hasWorkAreas() ? "yes" : "no"));
DiscoveryResult discoveryResult = DiscoveryResultBuilder.create(mowerThingUid)
.withThingType(thingTypeUID).withProperties(properties).withBridge(bridgeUID)
.withRepresentationProperty(AutomowerBindingConstants.AUTOMOWER_ID)
@@ -17,6 +17,7 @@ import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.eclipse.jetty.client.HttpClient;
import org.eclipse.jetty.client.api.ContentResponse;
import org.eclipse.jetty.client.api.Request;
@@ -24,11 +25,18 @@ import org.eclipse.jetty.client.util.StringContentProvider;
import org.eclipse.jetty.http.HttpMethod;
import org.eclipse.jetty.http.HttpStatus;
import org.openhab.binding.automower.internal.rest.api.HusqvarnaApi;
import org.openhab.binding.automower.internal.rest.api.automowerconnect.dto.MowerCalendardRequest;
import org.openhab.binding.automower.internal.rest.api.automowerconnect.dto.MowerCommandRequest;
import org.openhab.binding.automower.internal.rest.api.automowerconnect.dto.MowerListResult;
import org.openhab.binding.automower.internal.rest.api.automowerconnect.dto.MowerMessagesResult;
import org.openhab.binding.automower.internal.rest.api.automowerconnect.dto.MowerResult;
import org.openhab.binding.automower.internal.rest.api.automowerconnect.dto.MowerSettingsRequest;
import org.openhab.binding.automower.internal.rest.api.automowerconnect.dto.MowerStayOutZoneRequest;
import org.openhab.binding.automower.internal.rest.api.automowerconnect.dto.MowerWorkAreaRequest;
import org.openhab.binding.automower.internal.rest.exceptions.AutomowerCommunicationException;
import org.openhab.binding.automower.internal.rest.exceptions.UnauthorizedException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.gson.JsonSyntaxException;
@@ -39,6 +47,9 @@ import com.google.gson.JsonSyntaxException;
*/
@NonNullByDefault
public class AutomowerConnectApi extends HusqvarnaApi {
private final Logger logger = LoggerFactory.getLogger(AutomowerConnectApi.class);
public AutomowerConnectApi(HttpClient httpClient) {
super(httpClient);
}
@@ -62,15 +73,26 @@ public class AutomowerConnectApi extends HusqvarnaApi {
request.method(HttpMethod.GET);
ContentResponse response = executeRequest(appKey, token, request);
logger.trace("getMower: {}", response.getContentAsString());
return parseResponse(response, MowerResult.class);
}
public MowerMessagesResult getMowerMessages(String appKey, String token, String mowerId)
throws AutomowerCommunicationException {
final Request request = getHttpClient().newRequest(getBaseUrl() + "/mowers/" + mowerId + "/messages");
request.method(HttpMethod.GET);
ContentResponse response = executeRequest(appKey, token, request);
logger.trace("getMowerMessages: {}", response.getContentAsString());
return parseResponse(response, MowerMessagesResult.class);
}
public void sendCommand(String appKey, String token, String id, MowerCommandRequest command)
throws AutomowerCommunicationException {
final Request request = getHttpClient().newRequest(getBaseUrl() + "/mowers/" + id + "/actions");
request.method(HttpMethod.POST);
logger.trace("sendCommand: {}", gson.toJson(command));
request.content(new StringContentProvider(gson.toJson(command)));
ContentResponse response = executeRequest(appKey, token, request);
@@ -78,6 +100,93 @@ public class AutomowerConnectApi extends HusqvarnaApi {
checkForError(response, response.getStatus());
}
public void sendCalendar(String appKey, String token, String id, boolean hasWorkAreas, @Nullable Long workAreaId,
MowerCalendardRequest calendar) throws AutomowerCommunicationException {
String url;
if (hasWorkAreas && (workAreaId != null)) {
url = getBaseUrl() + "/mowers/" + id + "/workAreas/" + workAreaId + "/calendar";
} else {
url = getBaseUrl() + "/mowers/" + id + "/calendar";
}
final Request request = getHttpClient().newRequest(url);
request.method(HttpMethod.POST);
logger.trace("sendCalendar: {}", gson.toJson(calendar));
request.content(new StringContentProvider(gson.toJson(calendar)));
ContentResponse response = executeRequest(appKey, token, request);
checkForError(response, response.getStatus());
}
public void sendSettings(String appKey, String token, String id, MowerSettingsRequest settings)
throws AutomowerCommunicationException {
String url;
url = getBaseUrl() + "/mowers/" + id + "/settings";
final Request request = getHttpClient().newRequest(url);
request.method(HttpMethod.POST);
logger.trace("sendSettings: {}", gson.toJson(settings));
request.content(new StringContentProvider(gson.toJson(settings)));
ContentResponse response = executeRequest(appKey, token, request);
checkForError(response, response.getStatus());
}
public void sendConfirmError(String appKey, String token, String id) throws AutomowerCommunicationException {
String url;
url = getBaseUrl() + "/mowers/" + id + "/errors/confirm";
final Request request = getHttpClient().newRequest(url);
request.method(HttpMethod.POST);
ContentResponse response = executeRequest(appKey, token, request);
checkForError(response, response.getStatus());
}
public void sendResetCuttingBladeUsageTime(String appKey, String token, String id)
throws AutomowerCommunicationException {
String url;
url = getBaseUrl() + "/mowers/" + id + "/statistics/resetCuttingBladeUsageTime";
final Request request = getHttpClient().newRequest(url);
request.method(HttpMethod.POST);
ContentResponse response = executeRequest(appKey, token, request);
checkForError(response, response.getStatus());
}
public void sendStayOutZone(String appKey, String token, String id, String zoneId,
MowerStayOutZoneRequest zoneRequest) throws AutomowerCommunicationException {
String url;
url = getBaseUrl() + "/mowers/" + id + "/stayOutZones/" + zoneId;
final Request request = getHttpClient().newRequest(url);
request.method(HttpMethod.PATCH);
logger.trace("sendStayOutZone: {}", gson.toJson(zoneRequest));
request.content(new StringContentProvider(gson.toJson(zoneRequest)));
ContentResponse response = executeRequest(appKey, token, request);
checkForError(response, response.getStatus());
}
public void sendWorkArea(String appKey, String token, String id, long workAreaId,
MowerWorkAreaRequest workAreaRequest) throws AutomowerCommunicationException {
String url;
url = getBaseUrl() + "/mowers/" + id + "/workAreas/" + workAreaId;
final Request request = getHttpClient().newRequest(url);
request.method(HttpMethod.PATCH);
logger.trace("sendWorkArea: {}", gson.toJson(workAreaRequest));
request.content(new StringContentProvider(gson.toJson(workAreaRequest)));
ContentResponse response = executeRequest(appKey, token, request);
checkForError(response, response.getStatus());
}
private ContentResponse executeRequest(String appKey, String token, final Request request)
throws AutomowerCommunicationException {
request.timeout(10, TimeUnit.SECONDS);
@@ -103,7 +212,6 @@ public class AutomowerConnectApi extends HusqvarnaApi {
int statusCode = response.getStatus();
checkForError(response, statusCode);
try {
return gson.fromJson(response.getContentAsString(), type);
} catch (JsonSyntaxException e) {
@@ -0,0 +1,22 @@
/*
* Copyright (c) 2010-2025 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.automower.internal.rest.api.automowerconnect.dto;
/**
* @author MikeTheTux - Initial contribution
*/
public enum Action {
NOT_ACTIVE,
FORCE_PARK,
FORCE_MOW
}
@@ -16,13 +16,13 @@ package org.openhab.binding.automower.internal.rest.api.automowerconnect.dto;
* @author Markus Pfleger - Initial contribution
*/
public class Battery {
private int batteryPercent;
private byte batteryPercent;
public int getBatteryPercent() {
public byte getBatteryPercent() {
return batteryPercent;
}
public void setBatteryPercent(int batteryPercent) {
public void setBatteryPercent(byte batteryPercent) {
this.batteryPercent = batteryPercent;
}
}
@@ -25,4 +25,8 @@ public class Calendar {
public List<CalendarTask> getTasks() {
return tasks;
}
public void setTasks(List<CalendarTask> tasks) {
this.tasks = tasks;
}
}
@@ -19,53 +19,98 @@ public class CalendarTask {
/**
* Start time expressed in minutes after midnight.
*/
private Integer start;
private short start;
/**
* Duration time expressed in minutes
*/
private Integer duration;
private Boolean monday;
private Boolean tuesday;
private Boolean wednesday;
private Boolean thursday;
private Boolean friday;
private Boolean saturday;
private Boolean sunday;
private short duration;
private boolean monday;
private boolean tuesday;
private boolean wednesday;
private boolean thursday;
private boolean friday;
private boolean saturday;
private boolean sunday;
private Long workAreaId;
public Integer getStart() {
public short getStart() {
return start;
}
public Integer getDuration() {
public short getDuration() {
return duration;
}
public Boolean getMonday() {
public boolean getMonday() {
return monday;
}
public Boolean getTuesday() {
public boolean getTuesday() {
return tuesday;
}
public Boolean getWednesday() {
public boolean getWednesday() {
return wednesday;
}
public Boolean getThursday() {
public boolean getThursday() {
return thursday;
}
public Boolean getFriday() {
public boolean getFriday() {
return friday;
}
public Boolean getSaturday() {
public boolean getSaturday() {
return saturday;
}
public Boolean getSunday() {
public boolean getSunday() {
return sunday;
}
public Long getWorkAreaId() {
return workAreaId;
}
public void setStart(short start) {
this.start = start;
}
public void setDuration(short duration) {
this.duration = duration;
}
public void setMonday(boolean monday) {
this.monday = monday;
}
public void setTuesday(boolean tuesday) {
this.tuesday = tuesday;
}
public void setWednesday(boolean wednesday) {
this.wednesday = wednesday;
}
public void setThursday(boolean thursday) {
this.thursday = thursday;
}
public void setFriday(boolean friday) {
this.friday = friday;
}
public void setSaturday(boolean saturday) {
this.saturday = saturday;
}
public void setSunday(boolean sunday) {
this.sunday = sunday;
}
public void setWorkAreaId(Long workAreaId) {
this.workAreaId = workAreaId;
}
}
@@ -0,0 +1,44 @@
/*
* Copyright (c) 2010-2025 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.automower.internal.rest.api.automowerconnect.dto;
/**
* @author MikeTheTux - Initial contribution
*/
public class Capabilities {
private boolean canConfirmError;
private boolean headlights;
private boolean position;
private boolean stayOutZones;
private boolean workAreas;
public boolean canConfirmError() {
return canConfirmError;
}
public boolean hasHeadlights() {
return headlights;
}
public boolean hasPosition() {
return position;
}
public boolean hasStayOutZones() {
return stayOutZones;
}
public boolean hasWorkAreas() {
return workAreas;
}
}
@@ -0,0 +1,28 @@
/*
* Copyright (c) 2010-2025 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.automower.internal.rest.api.automowerconnect.dto;
/**
* @author MikeTheTux - Initial contribution
*/
public class Headlight {
private HeadlightMode mode;
public HeadlightMode getHeadlightMode() {
return mode;
}
public void setHeadlightMode(HeadlightMode mode) {
this.mode = mode;
}
}
@@ -0,0 +1,23 @@
/*
* Copyright (c) 2010-2025 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.automower.internal.rest.api.automowerconnect.dto;
/**
* @author MikeTheTux - Initial contribution
*/
public enum HeadlightMode {
ALWAYS_ON,
ALWAYS_OFF,
EVENING_ONLY,
EVENING_AND_NIGHT
}
@@ -0,0 +1,22 @@
/*
* Copyright (c) 2010-2025 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.automower.internal.rest.api.automowerconnect.dto;
/**
* @author MikeTheTux - Initial contribution
*/
public enum InactiveReason {
NONE,
PLANNING,
SEARCHING_FOR_SATELLITES
}
@@ -0,0 +1,64 @@
/*
* Copyright (c) 2010-2025 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.automower.internal.rest.api.automowerconnect.dto;
/**
* @author MikeTheTux - Initial contribution
*/
public class Message {
private long time;
private int code;
private String severity;
private Double latitude;
private Double longitude;
public long getTime() {
return time;
}
public void setTime(long time) {
this.time = time;
}
public int getCode() {
return code;
}
public void setCode(int code) {
this.code = code;
}
public String getSeverity() {
return severity;
}
public void setSeverity(String severity) {
this.severity = severity;
}
public Double getLatitude() {
return latitude;
}
public void setLatitude(Double latitude) {
this.latitude = latitude;
}
public Double getLongitude() {
return longitude;
}
public void setLongitude(Double longitude) {
this.longitude = longitude;
}
}
@@ -0,0 +1,27 @@
/*
* Copyright (c) 2010-2025 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.automower.internal.rest.api.automowerconnect.dto;
import java.util.ArrayList;
import java.util.List;
/**
* @author MikeTheTux - Initial contribution
*/
public class MessageAttributes {
List<Message> messages = new ArrayList<>();
public List<Message> getMessages() {
return this.messages;
}
}
@@ -18,10 +18,12 @@ package org.openhab.binding.automower.internal.rest.api.automowerconnect.dto;
public class MowerApp {
private Mode mode;
private Activity activity;
private InactiveReason inactiveReason;
private State state;
private Long workAreaId;
private int errorCode;
private long errorCodeTimestamp;
private Boolean isErrorConfirmable;
public Mode getMode() {
return mode;
@@ -39,6 +41,14 @@ public class MowerApp {
this.activity = activity;
}
public InactiveReason getInactiveReason() {
return inactiveReason;
}
public void setInactiveReason(InactiveReason inactiveReason) {
this.inactiveReason = inactiveReason;
}
public State getState() {
return state;
}
@@ -47,6 +57,14 @@ public class MowerApp {
this.state = state;
}
public Long getWorkAreaId() {
return workAreaId;
}
public void setWorkAreaId(Long workAreaId) {
this.workAreaId = workAreaId;
}
public int getErrorCode() {
return errorCode;
}
@@ -62,4 +80,12 @@ public class MowerApp {
public void setErrorCodeTimestamp(long errorCodeTimestamp) {
this.errorCodeTimestamp = errorCodeTimestamp;
}
public Boolean getIsErrorConfirmable() {
return isErrorConfirmable;
}
public void setIsErrorConfirmable(Boolean isErrorConfirmable) {
this.isErrorConfirmable = isErrorConfirmable;
}
}
@@ -0,0 +1,37 @@
/*
* Copyright (c) 2010-2025 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.automower.internal.rest.api.automowerconnect.dto;
/**
* @author MikeTheTux - Initial contribution
*/
public class MowerCalendar {
private String type;
private Calendar attributes;
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public Calendar getAttributes() {
return attributes;
}
public void setAttributes(Calendar attributes) {
this.attributes = attributes;
}
}
@@ -0,0 +1,28 @@
/*
* Copyright (c) 2010-2025 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.automower.internal.rest.api.automowerconnect.dto;
/**
* @author MikeTheTux - Initial contribution
*/
public class MowerCalendardRequest {
private MowerCalendar data;
public MowerCalendar getData() {
return data;
}
public void setData(MowerCalendar data) {
this.data = data;
}
}
@@ -13,6 +13,7 @@
package org.openhab.binding.automower.internal.rest.api.automowerconnect.dto;
import java.util.ArrayList;
import java.util.List;
/**
* @author Markus Pfleger - Initial contribution
@@ -20,11 +21,16 @@ import java.util.ArrayList;
public class MowerData {
private System system;
private Battery battery;
private Capabilities capabilities;
private MowerApp mower;
private Calendar calendar;
private Planner planner;
private Metadata metadata;
private ArrayList<Position> positions = new ArrayList<>();
private List<Position> positions = new ArrayList<>();
private Settings settings;
private Statistics statistics;
private StayOutZones stayOutZones;
private List<WorkArea> workAreas = new ArrayList<>();
public System getSystem() {
return system;
@@ -42,6 +48,14 @@ public class MowerData {
this.battery = battery;
}
public Capabilities getCapabilities() {
return capabilities;
}
public void setCapabilities(Capabilities capabilities) {
this.capabilities = capabilities;
}
public MowerApp getMower() {
return mower;
}
@@ -78,11 +92,43 @@ public class MowerData {
this.positions.add(position);
}
public ArrayList<Position> getPositions() {
public List<Position> getPositions() {
return this.positions;
}
public Position getLastPosition() {
return !this.positions.isEmpty() ? this.positions.get(0) : null;
}
public Settings getSettings() {
return settings;
}
public void setSettings(Settings settings) {
this.settings = settings;
}
public Statistics getStatistics() {
return statistics;
}
public void setStatistics(Statistics statistics) {
this.statistics = statistics;
}
public StayOutZones getStayOutZones() {
return stayOutZones;
}
public void setStayOutZones(StayOutZones stayOutZones) {
this.stayOutZones = stayOutZones;
}
public List<WorkArea> getWorkAreas() {
return workAreas;
}
public void setWorkAreas(List<WorkArea> workAreas) {
this.workAreas = workAreas;
}
}
@@ -0,0 +1,46 @@
/*
* Copyright (c) 2010-2025 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.automower.internal.rest.api.automowerconnect.dto;
/**
* @author MikeTheTux - Initial contribution
*/
public class MowerMessages {
private String type;
private String id;
private MessageAttributes attributes;
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public MessageAttributes getAttributes() {
return attributes;
}
public void setAttributes(MessageAttributes attributes) {
this.attributes = attributes;
}
}
@@ -0,0 +1,28 @@
/*
* Copyright (c) 2010-2025 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.automower.internal.rest.api.automowerconnect.dto;
/**
* @author MikeTheTux - Initial contribution
*/
public class MowerMessagesResult {
private MowerMessages data;
public MowerMessages getData() {
return data;
}
public void setData(MowerMessages data) {
this.data = data;
}
}
@@ -0,0 +1,37 @@
/*
* Copyright (c) 2010-2025 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.automower.internal.rest.api.automowerconnect.dto;
/**
* @author MikeTheTux - Initial contribution
*/
public class MowerSettings {
private String type;
private Settings attributes;
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public Settings getAttributes() {
return attributes;
}
public void setAttributes(Settings attributes) {
this.attributes = attributes;
}
}
@@ -0,0 +1,28 @@
/*
* Copyright (c) 2010-2025 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.automower.internal.rest.api.automowerconnect.dto;
/**
* @author MikeTheTux - Initial contribution
*/
public class MowerSettingsRequest {
private MowerSettings data;
public MowerSettings getData() {
return data;
}
public void setData(MowerSettings data) {
this.data = data;
}
}
@@ -0,0 +1,46 @@
/*
* Copyright (c) 2010-2025 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.automower.internal.rest.api.automowerconnect.dto;
/**
* @author MikeTheTux - Initial contribution
*/
public class MowerStayOutZone {
private String type;
private String id;
private MowerStayOutZoneAttributes attributes;
public String getType() {
return type;
}
public void setId(String id) {
this.id = id;
}
public String getId() {
return id;
}
public void setType(String type) {
this.type = type;
}
public MowerStayOutZoneAttributes getAttributes() {
return attributes;
}
public void setAttributes(MowerStayOutZoneAttributes attributes) {
this.attributes = attributes;
}
}
@@ -0,0 +1,28 @@
/*
* Copyright (c) 2010-2025 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.automower.internal.rest.api.automowerconnect.dto;
/**
* @author MikeTheTux - Initial contribution
*/
public class MowerStayOutZoneAttributes {
private boolean enable;
public boolean getEnable() {
return enable;
}
public void setEnable(boolean enable) {
this.enable = enable;
}
}
@@ -0,0 +1,28 @@
/*
* Copyright (c) 2010-2025 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.automower.internal.rest.api.automowerconnect.dto;
/**
* @author MikeTheTux - Initial contribution
*/
public class MowerStayOutZoneRequest {
private MowerStayOutZone data;
public MowerStayOutZone getData() {
return data;
}
public void setData(MowerStayOutZone data) {
this.data = data;
}
}
@@ -0,0 +1,46 @@
/*
* Copyright (c) 2010-2025 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.automower.internal.rest.api.automowerconnect.dto;
/**
* @author MikeTheTux - Initial contribution
*/
public class MowerWorkArea {
private String type;
private long id;
private MowerWorkAreaAttributes attributes;
public String getType() {
return type;
}
public void setId(long id) {
this.id = id;
}
public long getId() {
return id;
}
public void setType(String type) {
this.type = type;
}
public MowerWorkAreaAttributes getAttributes() {
return attributes;
}
public void setAttributes(MowerWorkAreaAttributes attributes) {
this.attributes = attributes;
}
}
@@ -0,0 +1,37 @@
/*
* Copyright (c) 2010-2025 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.automower.internal.rest.api.automowerconnect.dto;
/**
* @author MikeTheTux - Initial contribution
*/
public class MowerWorkAreaAttributes {
private byte cuttingHeight;
private boolean enable;
public byte getCuttingHeight() {
return cuttingHeight;
}
public void setCuttingHeight(byte cuttingHeight) {
this.cuttingHeight = cuttingHeight;
}
public boolean getEnable() {
return enable;
}
public void setEnable(boolean enable) {
this.enable = enable;
}
}
@@ -0,0 +1,28 @@
/*
* Copyright (c) 2010-2025 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.automower.internal.rest.api.automowerconnect.dto;
/**
* @author MikeTheTux - Initial contribution
*/
public class MowerWorkAreaRequest {
private MowerWorkArea data;
public MowerWorkArea getData() {
return data;
}
public void setData(MowerWorkArea data) {
this.data = data;
}
}
@@ -20,31 +20,37 @@ public class Planner {
private long nextStartTimestamp;
private RestrictedReason restrictedReason;
private PlannerOverride override;
private int externalReason;
public long getNextStartTimestamp() {
return nextStartTimestamp;
}
public Planner setNextStartTimestamp(long nextStartTimestamp) {
public void setNextStartTimestamp(long nextStartTimestamp) {
this.nextStartTimestamp = nextStartTimestamp;
return this;
}
public RestrictedReason getRestrictedReason() {
return restrictedReason;
}
public Planner setRestrictedReason(RestrictedReason restrictedReason) {
public void setRestrictedReason(RestrictedReason restrictedReason) {
this.restrictedReason = restrictedReason;
return this;
}
public PlannerOverride getOverride() {
return override;
}
public Planner setOverride(PlannerOverride override) {
public void setOverride(PlannerOverride override) {
this.override = override;
return this;
}
public int getExternalReason() {
return externalReason;
}
public void setExternalReason(int externalReason) {
this.externalReason = externalReason;
}
}
@@ -16,14 +16,13 @@ package org.openhab.binding.automower.internal.rest.api.automowerconnect.dto;
* @author Marcin Czeczko - Initial contribution
*/
public class PlannerOverride {
private String action;
private Action action;
public String getAction() {
public Action getAction() {
return action;
}
public PlannerOverride setAction(String action) {
public void setAction(Action action) {
this.action = action;
return this;
}
}
@@ -21,5 +21,8 @@ public enum RestrictedReason {
PARK_OVERRIDE,
SENSOR,
DAILY_LIMIT,
NOT_APPLICABLE
FOTA,
FROST,
ALL_WORK_AREAS_COMPLETED,
EXTERNAL
}
@@ -0,0 +1,37 @@
/*
* Copyright (c) 2010-2025 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.automower.internal.rest.api.automowerconnect.dto;
/**
* @author MikeTheTux - Initial contribution
*/
public class Settings {
private byte cuttingHeight;
private Headlight headlight;
public byte getCuttingHeight() {
return cuttingHeight;
}
public void setCuttingHeight(byte cuttingHeight) {
this.cuttingHeight = cuttingHeight;
}
public Headlight getHeadlight() {
return headlight;
}
public void setHeadlight(Headlight headlight) {
this.headlight = headlight;
}
}
@@ -0,0 +1,109 @@
/*
* Copyright (c) 2010-2025 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.automower.internal.rest.api.automowerconnect.dto;
/**
* @author MikeTheTux - Initial contribution
*/
public class Statistics {
private long cuttingBladeUsageTime;
private long downTime;
private int numberOfChargingCycles;
private int numberOfCollisions;
private long totalChargingTime;
private long totalCuttingTime;
private long totalDriveDistance; // docu states totalDrivenDistance which does not work
private long totalRunningTime;
private long totalSearchingTime;
private long upTime;
public long getCuttingBladeUsageTime() {
return cuttingBladeUsageTime;
}
public void setCuttingBladeUsageTime(long cuttingBladeUsageTime) {
this.cuttingBladeUsageTime = cuttingBladeUsageTime;
}
public long getDownTime() {
return downTime;
}
public void setDownTime(long downTime) {
this.downTime = downTime;
}
public int getNumberOfChargingCycles() {
return numberOfChargingCycles;
}
public void setNumberOfChargingCycles(int numberOfChargingCycles) {
this.numberOfChargingCycles = numberOfChargingCycles;
}
public int getNumberOfCollisions() {
return numberOfCollisions;
}
public void setNumberOfCollisions(int numberOfCollisions) {
this.numberOfCollisions = numberOfCollisions;
}
public long getTotalChargingTime() {
return totalChargingTime;
}
public void setTotalChargingTime(long totalChargingTime) {
this.totalChargingTime = totalChargingTime;
}
public long getTotalCuttingTime() {
return totalCuttingTime;
}
public void setTotalCuttingTime(long totalCuttingTime) {
this.totalCuttingTime = totalCuttingTime;
}
public long getTotalDriveDistance() {
return totalDriveDistance;
}
public void setTotalDriveDistance(long totalDriveDistance) {
this.totalDriveDistance = totalDriveDistance;
}
public long getTotalRunningTime() {
return totalRunningTime;
}
public void setTotalRunningTime(long totalRunningTime) {
this.totalRunningTime = totalRunningTime;
}
public long getTotalSearchingTime() {
return totalSearchingTime;
}
public void setTotalSearchingTime(long totalSearchingTime) {
this.totalSearchingTime = totalSearchingTime;
}
public long getUpTime() {
return upTime;
}
public void setUpTime(long upTime) {
this.upTime = upTime;
}
}
@@ -0,0 +1,46 @@
/*
* Copyright (c) 2010-2025 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.automower.internal.rest.api.automowerconnect.dto;
/**
* @author MikeTheTux - Initial contribution
*/
public class StayOutZone {
private String id;
private String name;
private Boolean enabled;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Boolean isEnabled() {
return enabled;
}
public void setEnabed(Boolean enabled) {
this.enabled = enabled;
}
}
@@ -0,0 +1,40 @@
/*
* Copyright (c) 2010-2025 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.automower.internal.rest.api.automowerconnect.dto;
import java.util.ArrayList;
import java.util.List;
/**
* @author MikeTheTux - Initial contribution
*/
public class StayOutZones {
private Boolean dirty;
private List<StayOutZone> zones = new ArrayList<>();
public Boolean isDirty() {
return dirty;
}
public void setDirty(Boolean dirty) {
this.dirty = dirty;
}
public List<StayOutZone> getZones() {
return zones;
}
public void setZones(List<StayOutZone> zones) {
this.zones = zones;
}
}
@@ -0,0 +1,73 @@
/*
* Copyright (c) 2010-2025 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.automower.internal.rest.api.automowerconnect.dto;
/**
* @author MikeTheTux - Initial contribution
*/
public class WorkArea {
private long workAreaId;
private String name;
private byte cuttingHeight;
private boolean enabled;
private Byte progress; // Only available for EPOS mowers and systematic mowing work areas.
private Long lastTimeCompleted; // Only available for EPOS mowers and systematic mowing work areas.
public long getWorkAreaId() {
return workAreaId;
}
public void setWorkAreaId(long workAreaId) {
this.workAreaId = workAreaId;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public byte getCuttingHeight() {
return cuttingHeight;
}
public void setCuttingHeight(byte cuttingHeight) {
this.cuttingHeight = cuttingHeight;
}
public boolean isEnabled() {
return enabled;
}
public void setEnabled(boolean enabled) {
this.enabled = enabled;
}
public Byte getProgress() {
return progress;
}
public void setProgress(Byte progress) {
this.progress = progress;
}
public Long getLastTimeCompleted() {
return lastTimeCompleted;
}
public void setLastTimeCompleted(Long lastTimeCompleted) {
this.lastTimeCompleted = lastTimeCompleted;
}
}
@@ -18,6 +18,7 @@ import java.util.Map;
import java.util.Optional;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.binding.automower.internal.AutomowerBindingConstants;
import org.openhab.core.thing.ChannelUID;
/**
@@ -25,12 +26,13 @@ import org.openhab.core.thing.ChannelUID;
*/
@NonNullByDefault
public enum AutomowerCommand {
START("Start", "start"),
RESUME_SCHEDULE("ResumeSchedule", "resume_schedule"),
PAUSE("Pause", "pause"),
PARK("Park", "park"),
PARK_UNTIL_NEXT_SCHEDULE("ParkUntilNextSchedule", "park_until_next_schedule"),
PARK_UNTIL_FURTHER_NOTICE("ParkUntilFurtherNotice", "park_until_further_notice");
START("Start", AutomowerBindingConstants.CHANNEL_COMMAND_START),
RESUME_SCHEDULE("ResumeSchedule", AutomowerBindingConstants.CHANNEL_COMMAND_RESUME_SCHEDULE),
PAUSE("Pause", AutomowerBindingConstants.CHANNEL_COMMAND_PAUSE),
PARK("Park", AutomowerBindingConstants.CHANNEL_COMMAND_PARK),
PARK_UNTIL_NEXT_SCHEDULE("ParkUntilNextSchedule",
AutomowerBindingConstants.CHANNEL_COMMAND_PARK_UNTIL_NEXT_SCHEDULE),
PARK_UNTIL_FURTHER_NOTICE("ParkUntilFurtherNotice", AutomowerBindingConstants.CHANNEL_COMMAND_PARK_UNTIL_NOTICE);
private static final Map<String, AutomowerCommand> CHANNEL_TO_CMD_MAP = new HashMap<>();
@@ -24,6 +24,7 @@ import org.eclipse.jdt.annotation.Nullable;
public class AutomowerConfiguration {
public @Nullable String mowerId;
public @Nullable Integer pollingInterval;
public @Nullable String mowerZoneId;
@Nullable
public String getMowerId() {
@@ -41,4 +42,9 @@ public class AutomowerConfiguration {
public void setPollingInterval(Integer pollingInterval) {
this.pollingInterval = pollingInterval;
}
@Nullable
public String getMowerZoneId() {
return mowerZoneId;
}
}
@@ -7,7 +7,6 @@ addon.automower.description = Binding to interact with Husquvarna Automower robo
thing-type.automower.automower.label = Automower
thing-type.automower.automower.description = An automatic lawn mower
thing-type.automower.automower.channel.last-position.description = Last Position
thing-type.automower.bridge.label = Automower Connect Bridge
thing-type.automower.bridge.description = The bridge to communicate with the Automower Connect API
@@ -15,6 +14,8 @@ thing-type.automower.bridge.description = The bridge to communicate with the Aut
thing-type.config.automower.automower.mowerId.label = Automower Id
thing-type.config.automower.automower.mowerId.description = The Id of an automower as used by the Automower Connect Api to identify a mower
thing-type.config.automower.automower.mowerZoneId.label = TimeZone
thing-type.config.automower.automower.mowerZoneId.description = Time zone of the mower (e.g. Europe/Berlin)
thing-type.config.automower.automower.pollingInterval.label = Polling Interval
thing-type.config.automower.automower.pollingInterval.description = How often the current automower state should be polled in seconds
thing-type.config.automower.bridge.appKey.label = Application Key
@@ -24,12 +25,24 @@ thing-type.config.automower.bridge.appSecret.description = The Application Secre
thing-type.config.automower.bridge.pollingInterval.label = Polling Interval
thing-type.config.automower.bridge.pollingInterval.description = How often the available automowers should be queried in seconds
# channel group types
channel-group-type.automower.calendarTasksType.label = Calendar Tasks
channel-group-type.automower.commandsType.label = Commands
channel-group-type.automower.messagesType.label = Messages
channel-group-type.automower.positionsType.label = Positions
channel-group-type.automower.settingsType.label = Settings
channel-group-type.automower.statisticsType.label = Statistics
channel-group-type.automower.statusType.label = Status
channel-group-type.automower.stayoutZonesType.label = Stayout Zones
channel-group-type.automower.workAreasType.label = Work Areas
# channel types
channel-type.automower.activityType.label = Activity
channel-type.automower.activityType.description = The current activity
channel-type.automower.activityType.state.option.UNKNOWN = Unknown
channel-type.automower.activityType.state.option.NOT_APPLICABLE = N/A
channel-type.automower.activityType.state.option.NOT_APPLICABLE = Not Applicable
channel-type.automower.activityType.state.option.MOWING = Mowing
channel-type.automower.activityType.state.option.GOING_HOME = Returning to charging station
channel-type.automower.activityType.state.option.CHARGING = Charging
@@ -38,14 +51,59 @@ channel-type.automower.activityType.state.option.PARKED_IN_CS = Parked in chargi
channel-type.automower.activityType.state.option.STOPPED_IN_GARDEN = Stopped in garden
channel-type.automower.batteryType.label = Battery
channel-type.automower.batteryType.description = The battery level of the mower at the time of last update
channel-type.automower.calendarTasksType.label = Planner Info JSON
channel-type.automower.calendarTasksType.description = The channel providing a JSON with the information about the planner tasks.
channel-type.automower.calendarTaskDurationType.label = Duration
channel-type.automower.calendarTaskDurationType.description = Duration time
channel-type.automower.calendarTaskDurationType.state.pattern = %1$tHh:%1$tMm
channel-type.automower.calendarTaskFridayType.label = Enabled on Fridays
channel-type.automower.calendarTaskFridayType.description = Enabled on Fridays
channel-type.automower.calendarTaskMondayType.label = Enabled on Mondays
channel-type.automower.calendarTaskMondayType.description = Enabled on Mondays
channel-type.automower.calendarTaskSaturdayType.label = Enabled on Saturdays
channel-type.automower.calendarTaskSaturdayType.description = Enabled on Saturdays
channel-type.automower.calendarTaskStartType.label = Start Time
channel-type.automower.calendarTaskStartType.description = Start time relative to midnight
channel-type.automower.calendarTaskStartType.state.pattern = %1$tHh:%1$tMm
channel-type.automower.calendarTaskSundayType.label = Enabled on Sundays
channel-type.automower.calendarTaskSundayType.description = Enabled on Sundays
channel-type.automower.calendarTaskThursdayType.label = Enabled on Thursdays
channel-type.automower.calendarTaskThursdayType.description = Enabled on Thursdays
channel-type.automower.calendarTaskTuesdayType.label = Enabled on Tuesdays
channel-type.automower.calendarTaskTuesdayType.description = Enabled on Tuesdays
channel-type.automower.calendarTaskWednesdayType.label = Enabled on Wednesdays
channel-type.automower.calendarTaskWednesdayType.description = Enabled on Wednesdays
channel-type.automower.calendarTaskWorkAreaIdType.label = Work Area Id of Calendar
channel-type.automower.calendarTaskWorkAreaIdType.description = Work Area Id mapped to this calendar
channel-type.automower.errorCodeType.label = Error Code
channel-type.automower.errorCodeType.description = The error code at the time of last update
channel-type.automower.errorConfirmableType.label = Error Confirmable
channel-type.automower.errorConfirmableType.description = If the mower has an Error Code this attribute states if the error is confirmable
channel-type.automower.errorMessageType.label = Error Message
channel-type.automower.errorMessageType.description = The error message at the time of last update
channel-type.automower.errorTimestampType.label = Error Time
channel-type.automower.errorTimestampType.description = The time when the error occurred
channel-type.automower.externalReasonType.label = External Reason
channel-type.automower.externalReasonType.description = The channel providing an external reason that restrics current planner operation.
channel-type.automower.inactiveReasonType.label = Inactive Reason
channel-type.automower.inactiveReasonType.description = The current reason for being inactive
channel-type.automower.inactiveReasonType.state.option.NONE = No inactive reason
channel-type.automower.inactiveReasonType.state.option.PLANNING = The mower is planning a path or a work area
channel-type.automower.inactiveReasonType.state.option.SEARCHING_FOR_SATELLITES = Waiting for fix when using EPOS
channel-type.automower.lastPollUpdateType.label = Last Poll Update
channel-type.automower.lastPollUpdateType.description = The time when the binding polled the last update from the cloud
channel-type.automower.lastPositionType.label = Last GPS Position
channel-type.automower.lastPositionType.description = Last GPS position of the mower
channel-type.automower.lastUpdateType.label = Last Update
channel-type.automower.lastUpdateType.description = The time when the mower sent the last update
channel-type.automower.messageCodeType.label = Code
channel-type.automower.messageCodeType.description = (Error) code of the event
channel-type.automower.messagePositionType.label = GPS Position
channel-type.automower.messagePositionType.description = GPS Position of the event (if available)
channel-type.automower.messageSeverityType.label = Severity
channel-type.automower.messageSeverityType.description = The severity of the event
channel-type.automower.messageTimeType.label = Timestamp
channel-type.automower.messageTimeType.description = Timestamp when the event occurred
channel-type.automower.messageType.label = Message
channel-type.automower.messageType.description = The Message
channel-type.automower.modeType.label = Mode
channel-type.automower.modeType.description = The current mode
channel-type.automower.modeType.state.option.MAIN_AREA = Main Area
@@ -55,6 +113,10 @@ channel-type.automower.modeType.state.option.DEMO = Demo
channel-type.automower.modeType.state.option.UNKNOWN = Unknown
channel-type.automower.nameType.label = Automower Name
channel-type.automower.nameType.description = The channel providing the automower name
channel-type.automower.nextStartType.label = Next Auto Start
channel-type.automower.nextStartType.description = The channel providing the time for the next auto start. If the mower is charging then the value is the estimated time when it will be leaving the charging station. If the mower is about to start now, the value is NULL.
channel-type.automower.overrideActionType.label = Override Action
channel-type.automower.overrideActionType.description = The channel providing an action that overrides current planner operation.
channel-type.automower.park.label = Park with Duration
channel-type.automower.park.description = Park for a duration in minutes
channel-type.automower.parkUntilFurtherNotice.label = Park and Pause the Schedule
@@ -63,16 +125,55 @@ channel-type.automower.parkUntilNextSchedule.label = Park Until Next Schedule
channel-type.automower.parkUntilNextSchedule.description = Park until next schedule
channel-type.automower.pause.label = Pause
channel-type.automower.pause.description = Pause the mower now until manual resume
channel-type.automower.plannerNextStartTimestampType.label = Next Auto Start
channel-type.automower.plannerNextStartTimestampType.description = The channel providing the time for the next auto start. If the mower is charging then the value is the estimated time when it will be leaving the charging station. If the mower is about to start now, the value is NULL.
channel-type.automower.plannerOverrideActionType.label = Override Action
channel-type.automower.plannerOverrideActionType.description = The channel providing an action that overrides current planner operation.
channel-type.automower.pollUpdateType.label = Poll Update
channel-type.automower.pollUpdateType.description = Poll mower status update from the cloud
channel-type.automower.positionType.label = GPS Position
channel-type.automower.positionType.description = The channel providing a waypoint of the mower's activity.
channel-type.automower.positionType.description = A waypoint of the mower's activity
channel-type.automower.restrictedReasonType.label = Restricted Reason
channel-type.automower.restrictedReasonType.description = The channel providing a reason that restrics current planner operation.
channel-type.automower.restrictedReasonType.state.option.NONE = No restricted reason
channel-type.automower.restrictedReasonType.state.option.WEEK_SCHEDULE = Restricted by week schedule
channel-type.automower.restrictedReasonType.state.option.PARK_OVERRIDE = Forced to park
channel-type.automower.restrictedReasonType.state.option.SENSOR = Restricted by sensor
channel-type.automower.restrictedReasonType.state.option.DAILY_LIMIT = Restricted by daily limit
channel-type.automower.restrictedReasonType.state.option.FOTA = Restricted by FOTA transfer
channel-type.automower.restrictedReasonType.state.option.FROST = Restricted by frost sensor
channel-type.automower.restrictedReasonType.state.option.ALL_WORK_AREAS_COMPLETED = Restricted: All work areas completed
channel-type.automower.restrictedReasonType.state.option.EXTERNAL = Restricted by external reason
channel-type.automower.resumeSchedule.label = Resume Schedule
channel-type.automower.resumeSchedule.description = Resume schedule
channel-type.automower.settingCuttingHeightType.label = Cutting Height
channel-type.automower.settingCuttingHeightType.description = Prescaled cutting height, range: 1-9
channel-type.automower.settingHeadlightModeType.label = Headlight Mode
channel-type.automower.settingHeadlightModeType.description = Information about headlights
channel-type.automower.start.label = Start with Duration
channel-type.automower.start.description = Start for a duration in minutes
channel-type.automower.statCuttingBladeUsageTimeType.label = Cutting Blade Usage Time
channel-type.automower.statCuttingBladeUsageTimeType.description = The time since the last reset of the cutting blade usage counter
channel-type.automower.statDownTimeType.label = Down Time
channel-type.automower.statDownTimeType.description = The time the mower has been disconnected from the cloud
channel-type.automower.statDownTimeType.state.pattern = %1$tHh:%1$tMm:%1$tSs
channel-type.automower.statNumberOfChargingCyclesType.label = Number of Charging Cycles
channel-type.automower.statNumberOfChargingCyclesType.description = Number of charging cycles
channel-type.automower.statNumberOfCollisionsType.label = Number of Collisions
channel-type.automower.statNumberOfCollisionsType.description = The total number of collisions
channel-type.automower.statTotalChargingTimeType.label = Total Charging Time
channel-type.automower.statTotalChargingTimeType.description = Total charging time
channel-type.automower.statTotalCuttingPercentType.label = Relative Total Cutting Time
channel-type.automower.statTotalCuttingPercentType.description = Total cutting time in percent
channel-type.automower.statTotalCuttingTimeType.label = Total Cutting Time
channel-type.automower.statTotalCuttingTimeType.description = Total cutting time
channel-type.automower.statTotalDriveDistanceType.label = Total Drive Distance
channel-type.automower.statTotalDriveDistanceType.description = Total driven distance
channel-type.automower.statTotalRunningTimeType.label = Total Running Time
channel-type.automower.statTotalRunningTimeType.description = The total running time (the wheel motors have been running)
channel-type.automower.statTotalSearchingPercentType.label = Relative Total Searching Time
channel-type.automower.statTotalSearchingPercentType.description = The total searching time in percent
channel-type.automower.statTotalSearchingTimeType.label = Total Searching Time
channel-type.automower.statTotalSearchingTimeType.description = The total searching time
channel-type.automower.statUpTimeType.label = Up Time
channel-type.automower.statUpTimeType.description = The time the mower has been connected to the cloud
channel-type.automower.statUpTimeType.state.pattern = %1$tHh:%1$tMm:%1$tSs
channel-type.automower.stateType.label = State
channel-type.automower.stateType.description = The current state
channel-type.automower.stateType.state.option.UNKNOWN = Unknown
@@ -81,20 +182,102 @@ channel-type.automower.stateType.state.option.PAUSED = Paused by user
channel-type.automower.stateType.state.option.IN_OPERATION = Working
channel-type.automower.stateType.state.option.WAIT_UPDATING = Downloading new firmware
channel-type.automower.stateType.state.option.WAIT_POWER_UP = Booting mower
channel-type.automower.stateType.state.option.RESTRICTED_NONE = Waiting
channel-type.automower.stateType.state.option.RESTRICTED_NONE = No restricted reason
channel-type.automower.stateType.state.option.RESTRICTED_WEEK_SCHEDULE = Restricted by week schedule
channel-type.automower.stateType.state.option.RESTRICTED_PARK_OVERRIDE = Forced to park
channel-type.automower.stateType.state.option.RESTRICTED_SENSOR = Restricted by sensor
channel-type.automower.stateType.state.option.RESTRICTED_DAILY_LIMIT = Restricted by daily limit
channel-type.automower.stateType.state.option.RESTRICTED_FOTA = Restricted by FOTA transfer
channel-type.automower.stateType.state.option.RESTRICTED_FROST = Restricted by frost sensor
channel-type.automower.stateType.state.option.RESTRICTED_ALL_WORK_AREAS_COMPLETED = Restricted: All work areas completed
channel-type.automower.stateType.state.option.RESTRICTED_EXTERNAL = Restricted by external reason
channel-type.automower.stateType.state.option.OFF = Off
channel-type.automower.stateType.state.option.STOPPED = Stopped- Manual intervention required
channel-type.automower.stateType.state.option.STOPPED = Stopped: Manual intervention required
channel-type.automower.stateType.state.option.ERROR = Error
channel-type.automower.stateType.state.option.FATAL_ERROR = Fatal error
channel-type.automower.stateType.state.option.ERROR_AT_POWER_UP = Boot error
channel-type.automower.workAreaIdType.label = Work Area Id
channel-type.automower.workAreaIdType.description = Id of the active work area
channel-type.automower.workAreaType.label = Work Area Name
channel-type.automower.workAreaType.description = Name of the active work area
channel-type.automower.workareaCuttingHeightType.label = Cutting Height
channel-type.automower.workareaCuttingHeightType.description = Cutting height of the work area, range: 0-100
channel-type.automower.workareaEnabledType.label = Work Area Enabled
channel-type.automower.workareaEnabledType.description = If the work area is enabled or disabled
channel-type.automower.workareaIdType.label = Work Area Id
channel-type.automower.workareaIdType.description = Id of the Work Area
channel-type.automower.workareaLastTimeCompletedType.label = Last Time Completed
channel-type.automower.workareaLastTimeCompletedType.description = Timestamp when the work area was last completed. EPOS mowers and systematic mowing work areas only.
channel-type.automower.workareaNameType.label = Work Area Name
channel-type.automower.workareaNameType.description = Name of the work area
channel-type.automower.workareaProgressType.label = Work Area Progress
channel-type.automower.workareaProgressType.description = The progress on a work area. EPOS mowers and systematic mowing work areas only.
channel-type.automower.zoneDirtyType.label = Stayout Zones Dirty Flag
channel-type.automower.zoneDirtyType.description = If the stay-out zones are synchronized with the Husqvarna cloud. If the map is dirty you can not enable or disable a stay-out zone.
channel-type.automower.zoneEnabledType.label = Stayout Zone Enabled
channel-type.automower.zoneEnabledType.description = If the Stayout zone is enabled, the Automower® will not access the zone
channel-type.automower.zoneIdType.label = Stayout Zone Id
channel-type.automower.zoneIdType.description = Id of the Stayout zone
channel-type.automower.zoneNameType.label = Stayout Zone Name
channel-type.automower.zoneNameType.description = The name of the Stayout zone
# channel types
channel-type.automower.plannerExternalReasonType.label = External Reason
channel-type.automower.plannerExternalReasonType.description = The channel providing an external reason that restrics current planner operation.
channel-type.automower.plannerNextStartTimestampType.label = Next Auto Start
channel-type.automower.plannerNextStartTimestampType.description = The channel providing the time for the next auto start. If the mower is charging then the value is the estimated time when it will be leaving the charging station. If the mower is about to start now, the value is NULL.
channel-type.automower.plannerOverrideActionType.label = Override Action
channel-type.automower.plannerOverrideActionType.description = The channel providing an action that overrides current planner operation.
channel-type.automower.plannerRestrictedReasonType.label = Restricted Reason
channel-type.automower.plannerRestrictedReasonType.description = The channel providing a reason that restrics current planner operation.
channel-type.automower.plannerRestrictedReasonType.state.option.NONE = No restricted reason
channel-type.automower.plannerRestrictedReasonType.state.option.WEEK_SCHEDULE = Restricted by week schedule
channel-type.automower.plannerRestrictedReasonType.state.option.PARK_OVERRIDE = Forced to park
channel-type.automower.plannerRestrictedReasonType.state.option.SENSOR = Restricted by sensor
channel-type.automower.plannerRestrictedReasonType.state.option.DAILY_LIMIT = Restricted by daily limit
channel-type.automower.plannerRestrictedReasonType.state.option.FOTA = Restricted by FOTA transfer
channel-type.automower.plannerRestrictedReasonType.state.option.FROST = Restricted by frost sensor
channel-type.automower.plannerRestrictedReasonType.state.option.ALL_WORK_AREAS_COMPLETED = Restricted: All work areas completed
channel-type.automower.plannerRestrictedReasonType.state.option.EXTERNAL = Restricted by external reason
# channel types
channel-type.automower.calendarTasksDurationType.label = Duration
channel-type.automower.calendarTasksDurationType.description = Duration time
channel-type.automower.calendarTasksDurationType.state.pattern = %1$tHh:%1$tMm
channel-type.automower.calendarTasksFridayType.label = Enabled on Fridays
channel-type.automower.calendarTasksFridayType.description = Enabled on Fridays
channel-type.automower.calendarTasksMondayType.label = Enabled on Mondays
channel-type.automower.calendarTasksMondayType.description = Enabled on Mondays
channel-type.automower.calendarTasksSaturdayType.label = Enabled on Saturdays
channel-type.automower.calendarTasksSaturdayType.description = Enabled on Saturdays
channel-type.automower.calendarTasksStartType.label = Start Time
channel-type.automower.calendarTasksStartType.description = Start time relative to midnight
channel-type.automower.calendarTasksStartType.state.pattern = %1$tHh:%1$tMm
channel-type.automower.calendarTasksSundayType.label = Enabled on Sundays
channel-type.automower.calendarTasksSundayType.description = Enabled on Sundays
channel-type.automower.calendarTasksThursdayType.label = Enabled on Thursdays
channel-type.automower.calendarTasksThursdayType.description = Enabled on Thursdays
channel-type.automower.calendarTasksTuesdayType.label = Enabled on Tuesdays
channel-type.automower.calendarTasksTuesdayType.description = Enabled on Tuesdays
channel-type.automower.calendarTasksWednesdayType.label = Enabled on Wednesdays
channel-type.automower.calendarTasksWednesdayType.description = Enabled on Wednesdays
channel-type.automower.calendarTasksWorkAreaIdType.label = Work Area Id of Calendar
channel-type.automower.calendarTasksWorkAreaIdType.description = Work Area Id mapped to this calendar
# thing types
thing-type.automower.automower.channel.last-position.description = Last Position
# channel types
channel-type.automower.calendarTasksType.label = Planner Info JSON
channel-type.automower.calendarTasksType.description = The channel providing a JSON with the information about the planner tasks.
# actions
action-input-duration-label = Duration
action-input-duration-label = duration
action-input-duration-desc = The duration of the automower command in minutes
action-park-label = park the automower
action-park-desc = Parks the automower for a defined amount of time, overriding its schedule.
@@ -108,6 +291,54 @@ action-resumeschedule-label = resume the schedule
action-resumeschedule-desc = Resumes the schedule for the automower.
action-start-label = start the automower
action-start-desc = Starts the automower for a defined amount of time, overriding its schedule.
action-confirm-error-label = confirm error
action-confirm-error-desc = Confirm current non fatal error.
action-reset-cutting-blade-usage-time-label = reset cutting blade usage time
action-reset-cutting-blade-usage-time-desc = Reset the cutting blade usage time.
action-set-settings-label = update automower settings
action-set-settings-desc = Sends a set of Settings to the automower.
action-input-cutting-height-label = cutting height
action-input-cutting-height-desc = Prescaled cutting height, Range: 1-9.
action-input-headlight-mode-label = headlight mode
action-input-headlight-mode-desc = Headlight Mode (ALWAYS_ON, ALWAYS_OFF, EVENING_ONLY, EVENING_AND_NIGHT).
action-set-work-area-label = update work area configuration
action-set-work-area-desc = Update the work area configuration of the specified area.
action-input-workarea-id-label = work area id
action-input-workarea-id-desc = Id of WorkArea to be updated.
action-input-enable-label = enable
action-input-enable-desc = Enable or disable WorkArea.
action-input-cutting-height-label = cutting height
action-input-cutting-height-desc = Cutting height of the WorkArea.
action-set-stayoutzone-label = update stayout zone configuration
action-set-stayoutzone-desc = Update the stayout zone configuration of the specified zone.
action-input-zone-id-label = zone id
action-input-zone-id-desc = Id of the stayout zone to be updated.
action-input-enable-label = enable
action-input-enable-desc = Enable or disable stayout zone.
action-set-calendartask-label = update calendar task configuration
action-set-calendartask-desc = Update the calendar task configuration of the mower or specified work area.
action-input-workarea-id-label = work area id
action-input-workarea-id-desc = Id of WorkArea where the calendar task configuration shall be updated (null if mower doesn't support work areas).
action-input-start-label = start
action-input-start-desc = Start time relative to midnight (minutes).
action-input-duration-label = duration
action-input-duration-desc = Duration time (minutes).
action-input-monday-label = monday[]
action-input-monday-desc = Enabled on Mondays (array with the number of calendar tasks).
action-input-tuesday-label = tuesday[]
action-input-tuesday-desc = Enabled on Tuesdays (array with the number of calendar tasks).
action-input-wednesday-label = wednesday[]
action-input-wednesday-desc = Enabled on Wednesdays (array with the number of calendar tasks).
action-input-thursday-label = thursday[]
action-input-thursday-desc = Enabled on Thursdays (array with the number of calendar tasks).
action-input-friday-label = friday[]
action-input-friday-desc = Enabled on Fridays (array with the number of calendar tasks).
action-input-saturday-label = saturday
action-input-saturday-desc = Enabled on Saturdays (array with the number of calendar tasks).
action-input-sunday-label = sunday
action-input-sunday-desc = Enabled on Sunday (array with the number of calendar tasks).
action-poll-label = poll
action-poll-desc = Poll mower status update from the cloud
# status messages
@@ -42,88 +42,29 @@
<label>Automower</label>
<description>An automatic lawn mower</description>
<channels>
<!-- Status -->
<channel id="name" typeId="nameType"/>
<channel id="mode" typeId="modeType"/>
<channel id="activity" typeId="activityType"/>
<channel id="state" typeId="stateType"/>
<channel id="last-update" typeId="lastUpdateType"/>
<channel id="battery" typeId="system.battery-level"/>
<channel id="error-code" typeId="errorCodeType"/>
<channel id="error-timestamp" typeId="errorTimestampType"/>
<channel id="planner-next-start" typeId="plannerNextStartTimestampType"/>
<channel id="planner-override-action" typeId="plannerOverrideActionType"/>
<channel id="calendar-tasks" typeId="calendarTasksType"/>
<!-- Commands -->
<channel id="start" typeId="start"/>
<channel id="resume_schedule" typeId="resumeSchedule"/>
<channel id="pause" typeId="pause"/>
<channel id="park" typeId="park"/>
<channel id="park_until_next_schedule" typeId="parkUntilNextSchedule"/>
<channel id="park_until_further_notice" typeId="parkUntilFurtherNotice"/>
<!-- Positions -->
<channel id="last-position" typeId="positionType">
<description>Last Position</description>
</channel>
<channel id="position01" typeId="positionType"/>
<channel id="position02" typeId="positionType"/>
<channel id="position03" typeId="positionType"/>
<channel id="position04" typeId="positionType"/>
<channel id="position05" typeId="positionType"/>
<channel id="position06" typeId="positionType"/>
<channel id="position07" typeId="positionType"/>
<channel id="position08" typeId="positionType"/>
<channel id="position09" typeId="positionType"/>
<channel id="position10" typeId="positionType"/>
<channel id="position11" typeId="positionType"/>
<channel id="position12" typeId="positionType"/>
<channel id="position13" typeId="positionType"/>
<channel id="position14" typeId="positionType"/>
<channel id="position15" typeId="positionType"/>
<channel id="position16" typeId="positionType"/>
<channel id="position17" typeId="positionType"/>
<channel id="position18" typeId="positionType"/>
<channel id="position19" typeId="positionType"/>
<channel id="position20" typeId="positionType"/>
<channel id="position21" typeId="positionType"/>
<channel id="position22" typeId="positionType"/>
<channel id="position23" typeId="positionType"/>
<channel id="position24" typeId="positionType"/>
<channel id="position25" typeId="positionType"/>
<channel id="position26" typeId="positionType"/>
<channel id="position27" typeId="positionType"/>
<channel id="position28" typeId="positionType"/>
<channel id="position29" typeId="positionType"/>
<channel id="position30" typeId="positionType"/>
<channel id="position31" typeId="positionType"/>
<channel id="position32" typeId="positionType"/>
<channel id="position33" typeId="positionType"/>
<channel id="position34" typeId="positionType"/>
<channel id="position35" typeId="positionType"/>
<channel id="position36" typeId="positionType"/>
<channel id="position37" typeId="positionType"/>
<channel id="position38" typeId="positionType"/>
<channel id="position39" typeId="positionType"/>
<channel id="position40" typeId="positionType"/>
<channel id="position41" typeId="positionType"/>
<channel id="position42" typeId="positionType"/>
<channel id="position43" typeId="positionType"/>
<channel id="position44" typeId="positionType"/>
<channel id="position45" typeId="positionType"/>
<channel id="position46" typeId="positionType"/>
<channel id="position47" typeId="positionType"/>
<channel id="position48" typeId="positionType"/>
<channel id="position49" typeId="positionType"/>
<channel id="position50" typeId="positionType"/>
</channels>
<channel-groups>
<channel-group id="status" typeId="statusType"/>
<channel-group id="setting" typeId="settingsType"/>
<channel-group id="statistic" typeId="statisticsType"/>
<channel-group id="calendartask" typeId="calendarTasksType"/>
<channel-group id="position" typeId="positionsType"/>
<channel-group id="stayoutzone" typeId="stayoutZonesType"/>
<channel-group id="workarea" typeId="workAreasType"/>
<channel-group id="command" typeId="commandsType"/>
<channel-group id="message" typeId="messagesType"/>
</channel-groups>
<properties>
<property name="mowerId">N/A</property>
<property name="mowerName">N/A</property>
<property name="mowerModel">N/A</property>
<property name="mowerSerialNumber">N/A</property>
<property name="mowerCanConfirmError">N/A</property>
<property name="mowerHasHeadlights">N/A</property>
<property name="mowerHasPosition">N/A</property>
<property name="mowerHasStayOutZones">N/A</property>
<property name="mowerHasWorkAreas">N/A</property>
<property name="thingTypeVersion">1</property>
</properties>
<config-description>
@@ -136,10 +77,163 @@
<default>600</default>
<description>How often the current automower state should be polled in seconds</description>
</parameter>
<parameter name="mowerZoneId" type="text" required="false">
<label>TimeZone</label>
<description>Time zone of the mower (e.g. Europe/Berlin)</description>
</parameter>
</config-description>
</thing-type>
<channel-group-type id="statusType">
<label>Status</label>
<channels>
<!-- Status -->
<channel id="name" typeId="nameType"/>
<channel id="mode" typeId="modeType"/>
<channel id="activity" typeId="activityType"/>
<channel id="inactive-reason" typeId="inactiveReasonType"/>
<channel id="state" typeId="stateType"/>
<!-- channels created on demand
<channel id="work-area-id" typeId="workAreaIdType"/>
<channel id="work-area" typeId="workAreaType"/>
-->
<channel id="last-update" typeId="lastUpdateType"/>
<channel id="last-poll-update" typeId="lastPollUpdateType"/>
<channel id="poll-update" typeId="pollUpdateType"/>
<channel id="battery" typeId="system.battery-level"/>
<channel id="error-code" typeId="errorCodeType"/>
<channel id="error-message" typeId="errorMessageType"/>
<channel id="error-timestamp" typeId="errorTimestampType"/>
<!-- channel created on demand
<channel id="error-confirmable" typeId="errorConfirmableType"/>
-->
<channel id="next-start" typeId="nextStartType"/>
<channel id="override-action" typeId="overrideActionType"/>
<channel id="restricted-reason" typeId="restrictedReasonType"/>
<channel id="external-reason" typeId="externalReasonType"/>
</channels>
</channel-group-type>
<!-- Settings -->
<channel-group-type id="settingsType">
<label>Settings</label>
<channels>
<channel id="cutting-height" typeId="settingCuttingHeightType"/>
<!-- channel created on demand
<channel id="headlight-mode" typeId="settingHeadlightModeType"/>
-->
</channels>
</channel-group-type>
<!-- Statistics -->
<channel-group-type id="statisticsType">
<label>Statistics</label>
<channels>
<channel id="cutting-blade-usage-time" typeId="statCuttingBladeUsageTimeType"/>
<channel id="down-time" typeId="statDownTimeType"/>
<channel id="number-of-charging-cycles" typeId="statNumberOfChargingCyclesType"/>
<channel id="number-of-collisions" typeId="statNumberOfCollisionsType"/>
<channel id="total-charging-time" typeId="statTotalChargingTimeType"/>
<channel id="total-cutting-time" typeId="statTotalCuttingTimeType"/>
<channel id="total-cutting-percent" typeId="statTotalCuttingPercentType"/>
<channel id="total-drive-distance" typeId="statTotalDriveDistanceType"/>
<channel id="total-running-time" typeId="statTotalRunningTimeType"/>
<channel id="total-searching-time" typeId="statTotalSearchingTimeType"/>
<channel id="total-searching-percent" typeId="statTotalSearchingPercentType"/>
<channel id="up-time" typeId="statUpTimeType"/>
</channels>
</channel-group-type>
<!-- Calendar Tasks -->
<channel-group-type id="calendarTasksType">
<label>Calendar Tasks</label>
<!-- channels created on demand
<channels>
<channel id="<xx>-start" typeId="calendarTaskStartType"/>
<channel id="<xx>-duration" typeId="calendarTaskDurationType"/>
<channel id="<xx>-monday" typeId="calendarTaskMondayType"/>
<channel id="<xx>-tuesday" typeId="calendarTaskTuesdayType"/>
<channel id="<xx>-wednesday" typeId="calendarTaskWednesdayType"/>
<channel id="<xx>-thursday" typeId="calendarTaskThursdayType"/>
<channel id="<xx>-friday" typeId="calendarTaskFridayType"/>
<channel id="<xx>-saturday" typeId="calendarTaskSaturdayType"/>
<channel id="<xx>-sunday" typeId="calendarTaskSundayType"/>
<channel id="<xx>-workAreaId" typeId="calendarTaskWorkAreaIdType"/>
<channel id="<xx>-workArea" typeId="workareaNameType"/>
...
</channels>
-->
</channel-group-type>
<!-- Positions -->
<channel-group-type id="positionsType">
<label>Positions</label>
<!-- channels created on demand
<channels>
<channel id="last" typeId="lastPositionType"/>
<channel id="<xx>" typeId="positionType"/>
...
</channels>
-->
</channel-group-type>
<!-- Stayout Zones -->
<channel-group-type id="stayoutZonesType">
<label>Stayout Zones</label>
<!-- channels created on demand
<channels>
<channel id="dirty" typeId="zoneDirtyType"/>
<channel id="<xx>-id" typeId="zoneIdType"/>
<channel id="<xx>-name" typeId="zoneNameType"/>
<channel id="<xx>-enabled" typeId="zoneEnabledType"/>
...
</channels>
-->
</channel-group-type>
<!-- Work Areas -->
<channel-group-type id="workAreasType">
<label>Work Areas</label>
<!-- channels created on demand
<channels>
<channel id="<xx>-id" typeId="workareaIdType"/>
<channel id="<xx>-name" typeId="workareaNameType"/>
<channel id="<xx>-cutting-height" typeId="workareaCuttingHeightType"/>
<channel id="<xx>-enabled" typeId="workareaEnabledType"/>
<channel id="<xx>-progress" typeId="workareaProgressType"/>
<channel id="<xx>-last-time-completed" typeId="workareaLastTimeCompletedType"/>
...
</channels>
-->
</channel-group-type>
<!-- Messages -->
<channel-group-type id="messagesType">
<label>Messages</label>
<!-- channels created dynamically (1...50)
<channels>
<channel id="<xx>-time" typeId="messageTimeType"/>
<channel id="<xx>-code" typeId="messageCodeType"/>
<channel id="<xx>-text" typeId="messageType"/>
<channel id="<xx>-severity" typeId="messageSeverityType"/>
<channel id="<xx>-position" typeId="messagePositionType"/>
...
</channels>
-->
</channel-group-type>
<!-- Commands -->
<channel-group-type id="commandsType">
<label>Commands</label>
<channels>
<channel id="start" typeId="start"/>
<channel id="resume_schedule" typeId="resumeSchedule"/>
<channel id="pause" typeId="pause"/>
<channel id="park" typeId="park"/>
<channel id="park_until_next_schedule" typeId="parkUntilNextSchedule"/>
<channel id="park_until_further_notice" typeId="parkUntilFurtherNotice"/>
</channels>
</channel-group-type>
<channel-type id="nameType">
<item-type>String</item-type>
@@ -170,7 +264,7 @@
<state readOnly="true">
<options>
<option value="UNKNOWN">Unknown</option>
<option value="NOT_APPLICABLE">N/A</option>
<option value="NOT_APPLICABLE">Not Applicable</option>
<option value="MOWING">Mowing</option>
<option value="GOING_HOME">Returning to charging station</option>
<option value="CHARGING">Charging</option>
@@ -181,6 +275,19 @@
</state>
</channel-type>
<channel-type id="inactiveReasonType">
<item-type>String</item-type>
<label>Inactive Reason</label>
<description>The current reason for being inactive</description>
<state readOnly="true">
<options>
<option value="NONE">No inactive reason</option>
<option value="PLANNING">The mower is planning a path or a work area</option>
<option value="SEARCHING_FOR_SATELLITES">Waiting for fix when using EPOS</option>
</options>
</state>
</channel-type>
<channel-type id="stateType">
<item-type>String</item-type>
<label>State</label>
@@ -193,13 +300,17 @@
<option value="IN_OPERATION">Working</option>
<option value="WAIT_UPDATING">Downloading new firmware</option>
<option value="WAIT_POWER_UP">Booting mower</option>
<option value="RESTRICTED_NONE">Waiting</option>
<option value="RESTRICTED_NONE">No restricted reason</option>
<option value="RESTRICTED_WEEK_SCHEDULE">Restricted by week schedule</option>
<option value="RESTRICTED_PARK_OVERRIDE">Forced to park</option>
<option value="RESTRICTED_SENSOR">Restricted by sensor</option>
<option value="RESTRICTED_DAILY_LIMIT">Restricted by daily limit</option>
<option value="RESTRICTED_FOTA">Restricted by FOTA transfer</option>
<option value="RESTRICTED_FROST">Restricted by frost sensor</option>
<option value="RESTRICTED_ALL_WORK_AREAS_COMPLETED">Restricted: All work areas completed</option>
<option value="RESTRICTED_EXTERNAL">Restricted by external reason</option>
<option value="OFF">Off</option>
<option value="STOPPED">Stopped- Manual intervention required</option>
<option value="STOPPED">Stopped: Manual intervention required</option>
<option value="ERROR">Error</option>
<option value="FATAL_ERROR">Fatal error</option>
<option value="ERROR_AT_POWER_UP">Boot error</option>
@@ -207,6 +318,20 @@
</state>
</channel-type>
<channel-type id="workAreaIdType" advanced="true">
<item-type>Number</item-type>
<label>Work Area Id</label>
<description>Id of the active work area</description>
<state readOnly="true"/>
</channel-type>
<channel-type id="workAreaType">
<item-type>String</item-type>
<label>Work Area Name</label>
<description>Name of the active work area</description>
<state readOnly="true"/>
</channel-type>
<channel-type id="lastUpdateType">
<item-type>DateTime</item-type>
<label>Last Update</label>
@@ -214,6 +339,19 @@
<state readOnly="true"/>
</channel-type>
<channel-type id="lastPollUpdateType" advanced="true">
<item-type>DateTime</item-type>
<label>Last Poll Update</label>
<description>The time when the binding polled the last update from the cloud</description>
<state readOnly="true"/>
</channel-type>
<channel-type id="pollUpdateType" advanced="true">
<item-type>Switch</item-type>
<label>Poll Update</label>
<description>Poll mower status update from the cloud</description>
</channel-type>
<channel-type id="batteryType">
<item-type>Number:Dimensionless</item-type>
<label>Battery</label>
@@ -221,11 +359,16 @@
<state readOnly="true" pattern="%d %%"/>
</channel-type>
<channel-type id="errorCodeType">
<channel-type id="errorCodeType" advanced="true">
<item-type>Number</item-type>
<label>Error Code</label>
<description>The error code at the time of last update</description>
<state readOnly="true"/>
</channel-type>
<channel-type id="errorMessageType">
<item-type>String</item-type>
<label>Error Message</label>
<description>The error message at the time of last update</description>
</channel-type>
<channel-type id="errorTimestampType">
@@ -235,7 +378,14 @@
<state readOnly="true"/>
</channel-type>
<channel-type id="plannerNextStartTimestampType">
<channel-type id="errorConfirmableType" advanced="true">
<item-type>Switch</item-type>
<label>Error Confirmable</label>
<description>If the mower has an Error Code this attribute states if the error is confirmable</description>
<state readOnly="true"/>
</channel-type>
<channel-type id="nextStartType">
<item-type>DateTime</item-type>
<label>Next Auto Start</label>
<description>The channel providing the time for the next auto start. If the mower is charging then the value is the
@@ -243,27 +393,312 @@
<state readOnly="true"/>
</channel-type>
<channel-type id="plannerOverrideActionType">
<channel-type id="overrideActionType">
<item-type>String</item-type>
<label>Override Action</label>
<description>The channel providing an action that overrides current planner operation.</description>
<state readOnly="true"/>
</channel-type>
<channel-type id="calendarTasksType">
<channel-type id="restrictedReasonType" advanced="true">
<item-type>String</item-type>
<label>Planner Info JSON</label>
<description>The channel providing a JSON with the information about the planner tasks.</description>
<label>Restricted Reason</label>
<description>The channel providing a reason that restrics current planner operation.</description>
<state readOnly="true">
<options>
<option value="NONE">No restricted reason</option>
<option value="WEEK_SCHEDULE">Restricted by week schedule</option>
<option value="PARK_OVERRIDE">Forced to park</option>
<option value="SENSOR">Restricted by sensor</option>
<option value="DAILY_LIMIT">Restricted by daily limit</option>
<option value="FOTA">Restricted by FOTA transfer</option>
<option value="FROST">Restricted by frost sensor</option>
<option value="ALL_WORK_AREAS_COMPLETED">Restricted: All work areas completed</option>
<option value="EXTERNAL">Restricted by external reason</option>
</options>
</state>
</channel-type>
<channel-type id="externalReasonType" advanced="true">
<item-type>Number</item-type>
<label>External Reason</label>
<description>The channel providing an external reason that restrics current planner operation.</description>
<state readOnly="true"/>
</channel-type>
<channel-type id="positionType">
<channel-type id="settingCuttingHeightType">
<item-type>Number</item-type>
<label>Cutting Height</label>
<description>Prescaled cutting height, range: 1-9</description>
</channel-type>
<channel-type id="settingHeadlightModeType">
<item-type>String</item-type>
<label>Headlight Mode</label>
<description>Information about headlights</description>
</channel-type>
<channel-type id="statCuttingBladeUsageTimeType">
<item-type>Number:Time</item-type>
<label>Cutting Blade Usage Time</label>
<description>The time since the last reset of the cutting blade usage counter</description>
<state pattern="%.1f h"/>
</channel-type>
<channel-type id="statDownTimeType" advanced="true">
<item-type>Number:Time</item-type>
<label>Down Time</label>
<description>The time the mower has been disconnected from the cloud</description>
<state readOnly="true" pattern="%1$tHh:%1$tMm:%1$tSs"/>
</channel-type>
<channel-type id="statNumberOfChargingCyclesType">
<item-type>Number</item-type>
<label>Number of Charging Cycles</label>
<description>Number of charging cycles</description>
<state readOnly="true"/>
</channel-type>
<channel-type id="statNumberOfCollisionsType">
<item-type>Number</item-type>
<label>Number of Collisions</label>
<description>The total number of collisions</description>
<state readOnly="true"/>
</channel-type>
<channel-type id="statTotalChargingTimeType">
<item-type>Number:Time</item-type>
<label>Total Charging Time</label>
<description>Total charging time</description>
<state readOnly="true" pattern="%.1f h"/>
</channel-type>
<channel-type id="statTotalCuttingTimeType">
<item-type>Number:Time</item-type>
<label>Total Cutting Time</label>
<description>Total cutting time</description>
<state readOnly="true" pattern="%.1f h"/>
</channel-type>
<channel-type id="statTotalCuttingPercentType">
<item-type>Number:Dimensionless</item-type>
<label>Relative Total Cutting Time</label>
<description>Total cutting time in percent</description>
<state readOnly="true" pattern="%.1f %%"/>
</channel-type>
<channel-type id="statTotalDriveDistanceType">
<item-type>Number:Length</item-type>
<label>Total Drive Distance</label>
<description>Total driven distance</description>
<state readOnly="true" pattern="%.1f km"/>
</channel-type>
<channel-type id="statTotalRunningTimeType">
<item-type>Number:Time</item-type>
<label>Total Running Time</label>
<description>The total running time (the wheel motors have been running)</description>
<state readOnly="true" pattern="%.1f h"/>
</channel-type>
<channel-type id="statTotalSearchingTimeType">
<item-type>Number:Time</item-type>
<label>Total Searching Time</label>
<description>The total searching time</description>
<state readOnly="true" pattern="%.1f h"/>
</channel-type>
<channel-type id="statTotalSearchingPercentType">
<item-type>Number:Dimensionless</item-type>
<label>Relative Total Searching Time</label>
<description>The total searching time in percent</description>
<state readOnly="true" pattern="%.1f %%"/>
</channel-type>
<channel-type id="statUpTimeType" advanced="true">
<item-type>Number:Time</item-type>
<label>Up Time</label>
<description>The time the mower has been connected to the cloud</description>
<state readOnly="true" pattern="%1$tHh:%1$tMm:%1$tSs"/>
</channel-type>
<channel-type id="lastPositionType" advanced="false">
<item-type>Location</item-type>
<label>Last GPS Position</label>
<description>Last GPS position of the mower</description>
<state readOnly="true"/>
</channel-type>
<channel-type id="positionType" advanced="true">
<item-type>Location</item-type>
<label>GPS Position</label>
<description>The channel providing a waypoint of the mower's activity.</description>
<description>A waypoint of the mower's activity</description>
<state readOnly="true"/>
</channel-type>
<!-- Calendar Tasks -->
<channel-type id="calendarTaskStartType" advanced="true">
<item-type unitHint="min">Number:Time</item-type>
<label>Start Time</label>
<description>Start time relative to midnight</description>
<state pattern="%1$tHh:%1$tMm"/>
</channel-type>
<channel-type id="calendarTaskDurationType" advanced="true">
<item-type unitHint="min">Number:Time</item-type>
<label>Duration</label>
<description>Duration time</description>
<state pattern="%1$tHh:%1$tMm"/>
</channel-type>
<channel-type id="calendarTaskMondayType" advanced="true">
<item-type>Switch</item-type>
<label>Enabled on Mondays</label>
<description>Enabled on Mondays</description>
</channel-type>
<channel-type id="calendarTaskTuesdayType" advanced="true">
<item-type>Switch</item-type>
<label>Enabled on Tuesdays</label>
<description>Enabled on Tuesdays</description>
</channel-type>
<channel-type id="calendarTaskWednesdayType" advanced="true">
<item-type>Switch</item-type>
<label>Enabled on Wednesdays</label>
<description>Enabled on Wednesdays</description>
</channel-type>
<channel-type id="calendarTaskThursdayType" advanced="true">
<item-type>Switch</item-type>
<label>Enabled on Thursdays</label>
<description>Enabled on Thursdays</description>
</channel-type>
<channel-type id="calendarTaskFridayType" advanced="true">
<item-type>Switch</item-type>
<label>Enabled on Fridays</label>
<description>Enabled on Fridays</description>
</channel-type>
<channel-type id="calendarTaskSaturdayType" advanced="true">
<item-type>Switch</item-type>
<label>Enabled on Saturdays</label>
<description>Enabled on Saturdays</description>
</channel-type>
<channel-type id="calendarTaskSundayType" advanced="true">
<item-type>Switch</item-type>
<label>Enabled on Sundays</label>
<description>Enabled on Sundays</description>
</channel-type>
<channel-type id="calendarTaskWorkAreaIdType" advanced="true">
<item-type>Number</item-type>
<label>Work Area Id of Calendar</label>
<description>Work Area Id mapped to this calendar</description>
<state readOnly="true"/>
</channel-type>
<!-- Stayout Zones -->
<channel-type id="zoneDirtyType" advanced="true">
<item-type>Switch</item-type>
<label>Stayout Zones Dirty Flag</label>
<description>If the stay-out zones are synchronized with the Husqvarna cloud. If the map is dirty you can not enable
or disable a stay-out zone.</description>
<state readOnly="true"/>
</channel-type>
<channel-type id="zoneIdType" advanced="true">
<item-type>String</item-type>
<label>Stayout Zone Id</label>
<description>Id of the Stayout zone</description>
<state readOnly="true"/>
</channel-type>
<channel-type id="zoneNameType" advanced="true">
<item-type>String</item-type>
<label>Stayout Zone Name</label>
<description>The name of the Stayout zone</description>
<state readOnly="true"/>
</channel-type>
<channel-type id="zoneEnabledType" advanced="true">
<item-type>Switch</item-type>
<label>Stayout Zone Enabled</label>
<description>If the Stayout zone is enabled, the Automower® will not access the zone</description>
</channel-type>
<!-- Work Areas -->
<channel-type id="workareaIdType" advanced="true">
<item-type>Number</item-type>
<label>Work Area Id</label>
<description>Id of the Work Area</description>
<state readOnly="true"/>
</channel-type>
<channel-type id="workareaNameType" advanced="true">
<item-type>String</item-type>
<label>Work Area Name</label>
<description>Name of the work area</description>
<state readOnly="true"/>
</channel-type>
<channel-type id="workareaCuttingHeightType" advanced="true">
<item-type>Number:Dimensionless</item-type>
<label>Cutting Height</label>
<description>Cutting height of the work area, range: 0-100</description>
<state pattern="%d %%"/>
</channel-type>
<channel-type id="workareaEnabledType" advanced="true">
<item-type>Switch</item-type>
<label>Work Area Enabled</label>
<description>If the work area is enabled or disabled</description>
</channel-type>
<channel-type id="workareaProgressType" advanced="true">
<item-type>Number:Dimensionless</item-type>
<label>Work Area Progress</label>
<description>The progress on a work area. EPOS mowers and systematic mowing work areas only.</description>
<state readOnly="true" pattern="%d %%"/>
</channel-type>
<channel-type id="workareaLastTimeCompletedType" advanced="true">
<item-type>DateTime</item-type>
<label>Last Time Completed</label>
<description>Timestamp when the work area was last completed. EPOS mowers and systematic mowing work areas only.</description>
<state readOnly="true"/>
</channel-type>
<!-- Messages -->
<channel-type id="messageTimeType" advanced="true">
<item-type>DateTime</item-type>
<label>Timestamp</label>
<description>Timestamp when the event occurred</description>
<state readOnly="true"/>
</channel-type>
<channel-type id="messageCodeType" advanced="true">
<item-type>Number</item-type>
<label>Code</label>
<description>(Error) code of the event</description>
<state readOnly="true"/>
</channel-type>
<channel-type id="messageType" advanced="true">
<item-type>String</item-type>
<label>Message</label>
<description>The Message</description>
<state readOnly="true"/>
</channel-type>
<channel-type id="messageSeverityType" advanced="true">
<item-type>String</item-type>
<label>Severity</label>
<description>The severity of the event</description>
<state readOnly="true"/>
</channel-type>
<channel-type id="messagePositionType" advanced="true">
<item-type>Location</item-type>
<label>GPS Position</label>
<description>GPS Position of the event (if available)</description>
<state readOnly="true"/>
</channel-type>
<!-- Commands -->
<channel-type id="start">
<item-type>Number</item-type>
<label>Start with Duration</label>
@@ -301,5 +736,4 @@
<label>Park and Pause the Schedule</label>
<description>Park and pause the mower schedule until manual resume</description>
</channel-type>
</thing:thing-descriptions>
@@ -0,0 +1,181 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
<update:update-descriptions xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:update="https://openhab.org/schemas/update-description/v1.0.0"
xsi:schemaLocation="https://openhab.org/schemas/update-description/v1.0.0 https://openhab.org/schemas/update-description-1.0.0.xsd">
<thing-type uid="automower:automower">
<instruction-set targetVersion="1">
<!-- Status -->
<update-channel id="name" groupIds="status">
<type>automower:nameType</type>
</update-channel>
<update-channel id="mode" groupIds="status">
<type>automower:modeType</type>
</update-channel>
<update-channel id="activity" groupIds="status">
<type>automower:activityType</type>
</update-channel>
<add-channel id="inactive-reason" groupIds="status">
<type>automower:inactiveReasonType</type>
</add-channel>
<update-channel id="state" groupIds="status">
<type>automower:stateType</type>
</update-channel>
<update-channel id="last-update" groupIds="status">
<type>automower:lastUpdateType</type>
</update-channel>
<add-channel id="last-poll-update" groupIds="status">
<type>automower:lastPollUpdateType</type>
</add-channel>
<add-channel id="poll-update" groupIds="status">
<type>automower:pollUpdateType</type>
</add-channel>
<update-channel id="battery" groupIds="status">
<type>system:battery-level</type>
</update-channel>
<update-channel id="error-code" groupIds="status">
<type>automower:errorCodeType</type>
</update-channel>
<add-channel id="error-message" groupIds="status">
<type>automower:errorMessageType</type>
</add-channel>
<update-channel id="error-timestamp" groupIds="status">
<type>automower:errorTimestampType</type>
</update-channel>
<update-channel id="next-start" groupIds="status">
<type>automower:nextStartType</type>
</update-channel>
<update-channel id="override-action" groupIds="status">
<type>automower:overrideActionType</type>
</update-channel>
<add-channel id="restricted-reason" groupIds="status">
<type>automower:restrictedReasonType</type>
</add-channel>
<add-channel id="external-reason" groupIds="status">
<type>automower:externalReasonType</type>
</add-channel>
<remove-channel id="planner-next-start"/>
<remove-channel id="planner-override-action"/>
<!-- Settings -->
<add-channel id="cutting-height" groupIds="settings">
<type>automower:settingCuttingHeightType</type>
</add-channel>
<!-- Statistics -->
<add-channel id="cutting-blade-usage-time" groupIds="statistics">
<type>automower:statCuttingBladeUsageTimeType</type>
</add-channel>
<add-channel id="down-time" groupIds="statistics">
<type>automower:statDownTimeType</type>
</add-channel>
<add-channel id="number-of-charging-cycles" groupIds="statistics">
<type>automower:statNumberOfChargingCyclesType</type>
</add-channel>
<add-channel id="number-of-collisions" groupIds="statistics">
<type>automower:statNumberOfCollisionsType</type>
</add-channel>
<add-channel id="total-charging-time" groupIds="statistics">
<type>automower:statTotalChargingTimeType</type>
</add-channel>
<add-channel id="total-cutting-time" groupIds="statistics">
<type>automower:statTotalCuttingTimeType</type>
</add-channel>
<add-channel id="total-cutting-percent" groupIds="statistics">
<type>automower:statTotalCuttingPercentType</type>
</add-channel>
<add-channel id="total-drive-distance" groupIds="statistics">
<type>automower:statTotalDriveDistanceType</type>
</add-channel>
<add-channel id="total-running-time" groupIds="statistics">
<type>automower:statTotalRunningTimeType</type>
</add-channel>
<add-channel id="total-searching-time" groupIds="statistics">
<type>automower:statTotalSearchingTimeType</type>
</add-channel>
<add-channel id="total-searching-percent" groupIds="statistics">
<type>automower:statTotalSearchingPercentType</type>
</add-channel>
<add-channel id="up-time" groupIds="statistics">
<type>automower:statUpTimeType</type>
</add-channel>
<!-- Calendar Tasks -->
<remove-channel id="calendar-tasks"/>
<!-- Positions -->
<remove-channel id="last-position"/>
<remove-channel id="position01"/>
<remove-channel id="position02"/>
<remove-channel id="position03"/>
<remove-channel id="position04"/>
<remove-channel id="position05"/>
<remove-channel id="position06"/>
<remove-channel id="position07"/>
<remove-channel id="position08"/>
<remove-channel id="position09"/>
<remove-channel id="position10"/>
<remove-channel id="position11"/>
<remove-channel id="position12"/>
<remove-channel id="position13"/>
<remove-channel id="position14"/>
<remove-channel id="position15"/>
<remove-channel id="position16"/>
<remove-channel id="position17"/>
<remove-channel id="position18"/>
<remove-channel id="position19"/>
<remove-channel id="position20"/>
<remove-channel id="position21"/>
<remove-channel id="position22"/>
<remove-channel id="position23"/>
<remove-channel id="position24"/>
<remove-channel id="position25"/>
<remove-channel id="position26"/>
<remove-channel id="position27"/>
<remove-channel id="position28"/>
<remove-channel id="position29"/>
<remove-channel id="position30"/>
<remove-channel id="position31"/>
<remove-channel id="position32"/>
<remove-channel id="position33"/>
<remove-channel id="position34"/>
<remove-channel id="position35"/>
<remove-channel id="position36"/>
<remove-channel id="position37"/>
<remove-channel id="position38"/>
<remove-channel id="position39"/>
<remove-channel id="position40"/>
<remove-channel id="position41"/>
<remove-channel id="position42"/>
<remove-channel id="position43"/>
<remove-channel id="position44"/>
<remove-channel id="position45"/>
<remove-channel id="position46"/>
<remove-channel id="position47"/>
<remove-channel id="position48"/>
<remove-channel id="position49"/>
<remove-channel id="position50"/>
<!-- Commands -->
<update-channel id="start" groupIds="commands">
<type>automower:start</type>
</update-channel>
<update-channel id="resume_schedule" groupIds="commands">
<type>automower:resumeSchedule</type>
</update-channel>
<update-channel id="pause" groupIds="commands">
<type>automower:pause</type>
</update-channel>
<update-channel id="park" groupIds="commands">
<type>automower:park</type>
</update-channel>
<update-channel id="park_until_next_schedule" groupIds="commands">
<type>automower:parkUntilNextSchedule</type>
</update-channel>
<update-channel id="park_until_further_notice" groupIds="commands">
<type>automower:parkUntilFurtherNotice</type>
</update-channel>
</instruction-set>
</thing-type>
</update:update-descriptions>