> ## Documentation index
> Fetch the complete documentation index at: https://developer.rhombus.com/llms.txt
> Use it to discover all available pages before exploring further.

# Recon Routes and Patrols

> Author the rounds a Recon robot makes: routes as ordered stops with dwell times and arrival actions, and patrols that put a route on a robot and run it on a schedule. Covers creating, changing and deleting both.

A **route** is the path: an ordered list of stops on one map. A **patrol** is a route given to one robot, with an optional schedule. You can run one route on several robots, each with its own patrol. The examples use the `robot_api` helper from the [overview](https://developer.rhombus.com/robots/overview#conventions).

**You need** an API key with admin access to the map's location for routes, and admin access to the robot for patrols.

## Create a route

[`createRobotRoute`](https://developer.rhombus.com/api-reference/robot-webservice/create-a-robot-route) takes a name, the map, and the stops in the order the robot visits them. Each stop either references a [waypoint](https://developer.rhombus.com/robots/maps-and-waypoints#waypoints) or carries a pose of its own:

```python Python
route = robot_api("createRobotRoute", {
    "name": "Night perimeter",
    "mapUuid": MAP_UUID,
    "waypoints": [
        {"name": "Dock door", "waypointRefUuid": DOCK_DOOR_WAYPOINT_UUID, "dwellStrategy": "DURATION", "dwellTimeSecs": 30},
        {"name": "North fence", "pose": {"position": [40.0, 8.5, 0.0], "orientation": [0.0, 0.0, 0.0, 1.0]}, "dwellStrategy": "NONE"},
        {"name": "Server room", "waypointRefUuid": SERVER_ROOM_WAYPOINT_UUID, "dwellStrategy": "DURATION", "dwellTimeSecs": 60},
    ],
})["routeView"]["route"]
```

- **Order** is the order of the list.
- **Dwell:** `DURATION` holds the robot at the stop for `dwellTimeSecs` seconds; `NONE` moves on as soon as it arrives. A stop that sets neither `dwellStrategy` nor `dwellTimeSecs` dwells for 15 seconds. Use these two strategies; the others behave like `NONE`.
- **One run per dispatch.** The robot visits each stop once and the run ends. If it can't reach a stop, the whole run ends as `FAILED`. Repeat a route with a [patrol schedule](https://developer.rhombus.com/robots/routes-and-patrols#schedules).
- Schedules belong to patrols: a route request with `deployConditions` or `deviceUuid` is refused.

The response's `route.waypointMap` holds the stops, keyed by **stop ID**, each with its `ordinal` (0 for the first stop), its pose or `waypointRefUuid`, and `dwellTimeMs`. Stop IDs are what [arrival actions](https://developer.rhombus.com/robots/routes-and-patrols#arrival-actions) and the robot's progress (`waypointUuid` in its state and events) refer to; they aren't the IDs of the waypoints a stop references.

Read routes back with [`getRobotRoute`](https://developer.rhombus.com/api-reference/robot-webservice/retrieve-a-robot-route-by-its-uuid) (`uuid`) or every route on a map with [`findRobotRoutesByMap`](https://developer.rhombus.com/api-reference/robot-webservice/find-routes-by-map) (`mapUuid`).

## Change a route

[`updateRobotRoute`](https://developer.rhombus.com/api-reference/robot-webservice/update-robot-routes-for-a-map) changes one route, addressed by its `uuid`. A list of `waypoints` **replaces all of the route's stops**, so send every stop you want to keep, each with:

- its `uuid`, to keep that stop's ID. A stop without one is created as a new stop with a new ID, and a patrol's arrival actions for the old ID stop applying;
- its `ordinal`, because on update the order comes from the ordinals, not from the list;
- its `rules`, because a stop sent without them loses its arrival actions.

The safe way to edit is to read the route, change it, and send all of it back:

```python Python
route = robot_api("getRobotRoute", {"uuid": ROUTE_UUID})["routeView"]
stops = sorted(route["route"]["waypointMap"].values(), key=lambda s: s["ordinal"])
rules = route.get("waypointRules") or {}

def as_request(stop, ordinal):
    request = {
        "uuid": stop["uuid"],
        "name": stop["name"],
        "ordinal": ordinal,
        "dwellStrategy": stop.get("dwellStrategy", "DURATION"),
        "dwellTimeSecs": stop.get("dwellTimeMs", 15000) // 1000,
        "rules": [{"ruleName": r["name"], "action": r["action"], "ruleFilters": r.get("ruleFilters")} for r in rules.get(stop["uuid"], [])],
    }
    if stop.get("waypointRefUuid"):
        request["waypointRefUuid"] = stop["waypointRefUuid"]
    else:
        request["pose"] = stop["pose"]
    return request

stops[0]["dwellTimeMs"] = 45000  # dwell 45 seconds at the first stop
robot_api("updateRobotRoute", {
    "uuid": ROUTE_UUID,
    "waypoints": [as_request(stop, i) for i, stop in enumerate(stops)],
})
```

To rename a route, send only `uuid` and `name`; leaving `waypoints` out keeps the stops as they are. A route can't move to another map.

[`deleteRobotRoute`](https://developer.rhombus.com/api-reference/robot-webservice/delete-a-robot-route) (`uuid`) is refused while patrols use the route: delete those patrols first ([`findPatrolsByRoute`](https://developer.rhombus.com/api-reference/robot-webservice/find-patrols-by-route) lists them).

## Arrival actions

A stop can run actions when the robot gets there. They're rules, in the same form as the actions of other Rhombus rules: each has a `ruleName` and an `action`, and optionally `ruleFilters` with `scheduleUuids` to run only during a schedule. For example, `"action": {"alertAction": true}` raises an alert in Rhombus at that stop.

They can live in two places:

|                     | Set with                                                                     | Runs for                            |
| ------------------- | ---------------------------------------------------------------------------- | ----------------------------------- |
| On the route's stop | `rules` on each stop in `createRobotRoute` or `updateRobotRoute`             | **Every** robot that runs the route |
| On a patrol         | `waypointActions` in `createPatrol` or `updatePatrol`, one entry per stop ID | Only that patrol's robot            |

Prefer patrol arrival actions when robots share a route.

- The route's and the patrol's actions come back in `waypointRules`, keyed by stop ID.
- Arrival actions also run when the robot gives up on a stop (that leg failed or was canceled). When it matters whether the robot really got there, check its [events](https://developer.rhombus.com/robots/monitor#event-history).
- Change these actions only through the robot operations, not with the rules operations under `/api/rules/`.

## Create a patrol

[`createPatrol`](https://developer.rhombus.com/api-reference/robot-webservice/create-a-robot-patrol) gives a route to a robot. The route must be on the robot's assigned map:

```python Python
patrol = robot_api("createPatrol", {
    "deviceUuid": ROBOT_UUID,
    "routeUuid": ROUTE_UUID,
    "name": "Night perimeter (east robot)",
    "deployConditions": [{"type": "SCHEDULED_EVENT", "minOfDay": 1320}],
    "waypointActions": [
        {"routeWaypointUuid": SERVER_ROOM_STOP_ID, "rules": [{"ruleName": "Server room check", "action": {"alertAction": True}}]},
    ],
})["patrolView"]["patrol"]
print(patrol["uuid"], patrol["enabled"])
```

Leave out `deployConditions` for a patrol that runs only when you [dispatch](https://developer.rhombus.com/robots/dispatch) it. A new patrol is enabled.

### Schedules

A patrol's schedule is its first deploy condition. Send one:

| Runs                                      | `deployConditions`                                                           | `scheduleUuid`                                                           |
| ----------------------------------------- | ---------------------------------------------------------------------------- | ------------------------------------------------------------------------ |
| Once a day at a set time                  | `[{"type": "SCHEDULED_EVENT", "minOfDay": 1320}]` (22:00)                    | Optional: runs it only within the schedule, for example on weekdays      |
| Every N minutes or hours during set times | `[{"type": "RECURRING_EVENT", "repeatInterval": 30, "timeUnit": "MINUTES"}]` | **Required**: the hours it repeats in. Without one the patrol never runs |

- `minOfDay` is minutes after midnight in the time zone of the robot's location.
- `scheduleUuid` is one of your organization's schedules ([`getSchedules`](https://developer.rhombus.com/api-reference/schedule-webservice/get-schedules)).
- **The robot keeps the schedule itself.** When a run is due while the robot is busy (already patrolling, recharging, or being driven), that run is skipped, not queued.

## Change, pause or delete a patrol

[`updatePatrol`](https://developer.rhombus.com/api-reference/robot-webservice/update-a-robot-patrol) addresses the patrol by `patrolUuid` and changes only the fields you send:

| Field                                                              | Effect                                                                                                                                |
| ------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------- |
| `name`                                                             | Renames the patrol                                                                                                                    |
| `enabled`                                                          | `false` pauses the schedule and refuses dispatches of this patrol; `true` resumes it. Always send a boolean: `null` counts as `false` |
| `deployConditions`, with `scheduleUuid` when the schedule uses one | A non-empty list replaces the schedule; an empty list removes it                                                                      |
| `waypointActions`                                                  | Replaces all of the patrol's arrival actions                                                                                          |

```python Python
robot_api("updatePatrol", {"patrolUuid": PATROL_UUID, "enabled": False})
```

[`findPatrolsByRobot`](https://developer.rhombus.com/api-reference/robot-webservice/find-a-robots-patrols-on-its-assigned-map) (`deviceUuid`) lists a robot's patrols on its assigned map, [`getPatrol`](https://developer.rhombus.com/api-reference/robot-webservice/get-a-robot-patrol) (`patrolUuid`) returns one, and [`deletePatrol`](https://developer.rhombus.com/api-reference/robot-webservice/delete-a-robot-patrol) (`patrolUuid`) deletes it with its schedule and arrival actions. A patrol's robot and route can't change: create a new patrol instead.
