diff --git a/custom_components/robonect/__init__.py b/custom_components/robonect/__init__.py index c864e30..ea2780a 100644 --- a/custom_components/robonect/__init__.py +++ b/custom_components/robonect/__init__.py @@ -37,6 +37,8 @@ EVENT_ROBONECT_RESPONSE, PLATFORMS, SENSOR_GROUPS, + SERVICE_DIRECT, + SERVICE_DIRECT_SCHEMA, SERVICE_JOB, SERVICE_JOB_AFTER_VALUES, SERVICE_JOB_CORRIDOR_VALUES, @@ -122,6 +124,21 @@ async def timer(service: ServiceCall) -> bool: DOMAIN, SERVICE_TIMER, timer, schema=SERVICE_TIMER_SCHEMA ) + async def direct(service: ServiceCall) -> bool: + """Modify a direction.""" + params = {} + try: + params |= {"left": service.data["left"]} + params |= {"right": service.data["right"]} + params |= {"timeout": service.data["timeout"]} + except ValueError as error: + raise RobonectException(error) + await async_send_command(hass, entry, "direct", params) + + hass.services.async_register( + DOMAIN, SERVICE_DIRECT, direct, schema=SERVICE_DIRECT_SCHEMA + ) + async def job(service: ServiceCall) -> bool: """Schedule a mowing job.""" params = {"mode": "job"} diff --git a/custom_components/robonect/const.py b/custom_components/robonect/const.py index 25745a2..7fc5853 100644 --- a/custom_components/robonect/const.py +++ b/custom_components/robonect/const.py @@ -13,6 +13,13 @@ ) import voluptuous as vol + +# Custom validator for degrees (allowing positive and negative integers) +def validate_degrees(value): + """Validate degree value.""" + return vol.Coerce(int)(value) + + PLATFORMS: Final = [ Platform.BINARY_SENSOR, Platform.SENSOR, @@ -77,6 +84,7 @@ SERVICE_SLEEP = "sleep" SERVICE_TIMER = "timer" SERVICE_JOB = "job" +SERVICE_DIRECT = "direct" CONF_ENTRY_ID = "entry_id" @@ -139,6 +147,21 @@ } ) +SERVICE_DIRECT_SCHEMA = vol.Schema( + { + vol.Required(CONF_ENTITY_ID): cv.entity_id, # Validate entity ID + vol.Required( + "left" + ): validate_degrees, # Validate left as an integer (positive or negative) + vol.Required( + "right" + ): validate_degrees, # Validate right as an integer (positive or negative) + vol.Required("timeout"): vol.All( + cv.positive_int, vol.Range(max=5000) + ), # Validate timeout as a positive integer with a max of 5000 + } +) + SERVICE_MODE_SCHEMA = vol.Schema( { vol.Required("mode", default="auto"): vol.In(SERVICE_MODE_VALUES), diff --git a/custom_components/robonect/manifest.json b/custom_components/robonect/manifest.json index abbc5c4..e1badb6 100644 --- a/custom_components/robonect/manifest.json +++ b/custom_components/robonect/manifest.json @@ -17,7 +17,7 @@ "automower/mqtt" ], "requirements": [ - "aiorobonect>=1.1.3", + "aiorobonect>=1.2.0", "jsonpath" ], "version": "v1.8.0" diff --git a/custom_components/robonect/services.yaml b/custom_components/robonect/services.yaml index 2e8e24e..f42f0bb 100644 --- a/custom_components/robonect/services.yaml +++ b/custom_components/robonect/services.yaml @@ -194,3 +194,45 @@ timer: value: sa - label: Sunday value: su + +direct: + name: Direct the mower + description: Direct a Robonect mower by setting the speed percentage for each wheel and a duration + fields: + entity_id: + name: Entity ID + description: Entity ID of the Robonect Vacuum + required: true + example: vacuum.automower_robonect + selector: + entity: + domain: vacuum + integration: robonect + left: + name: Left + description: "The percentage of speed on the left wheel. Can be positive or negative." + required: true + example: 50 + selector: + number: + mode: box + unit_of_measurement: "%" + right: + name: Right + description: "The percentage of speed on the right wheel. Can be positive or negative." + required: true + example: 50 + selector: + number: + mode: box + unit_of_measurement: "%" + timeout: + name: Timeout + description: "The timeout/duration in milliseconds." + required: true + example: 3000 + selector: + number: + min: 1 + mode: box + unit_of_measurement: ms