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

# Monitor Recon Robots

> Watch a Recon fleet from your own tools: connection and battery, what each robot is doing and how far along it is, and the history of every activity it ran, from the robot state and event operations.

Two kinds of reads cover a robot fleet: the **state** operations say what each robot is doing now, and the **events** operation says what it did. The examples use the `robot_api` helper from the [overview](https://developer.rhombus.com/robots/overview#conventions).

**You need** an API key with read-only access to the robots' locations.

## Fleet state

[`getMinimalStateList`](https://developer.rhombus.com/api-reference/robot-webservice/get-minimal-robot-state-list) returns one entry per robot:

```python Python
for robot in robot_api("getMinimalStateList", {})["minimalStates"]:
    progress = ""
    if robot.get("activity") == "ROUTE_RUN" and robot.get("waypointTotal"):
        progress = f"stop {robot['waypointIndex'] + 1} of {robot['waypointTotal']}"
    print(f"{robot['name']}: {robot['connectionStatus']}, {robot.get('batteryPercent')}%, {robot.get('activity')} {progress}")
```

| Field                                                         | Meaning                                                                                                                                                                                                                                         |
| ------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `uuid`, `name`, `locationUuid`                                | The robot, as the other robot operations and the console know it                                                                                                                                                                                |
| `connectionStatus`, `healthStatus`                            | `GREEN`, `YELLOW`, `ORANGE` or `RED`, best to worst, as for every device                                                                                                                                                                        |
| `batteryPercent`                                              | Battery level, 0 to 100                                                                                                                                                                                                                         |
| `activity`, `activityUuid`                                    | What the robot is doing ([below](https://developer.rhombus.com/robots/monitor#activities)) and that activity's ID. For a dispatch, `activityUuid` is the `routeRunUuid` that [`deploy`](https://developer.rhombus.com/robots/dispatch) returned |
| `event`, `phase`, `phaseEvent`                                | The latest step of the activity: `event` is its lifecycle ([below](https://developer.rhombus.com/robots/monitor#event-history)), `phase` the part in progress, such as `NAVIGATING`, `DWELLING`, `UNDOCKING` or `CHARGING`                      |
| `routeUuid`, `waypointUuid`, `waypointIndex`, `waypointTotal` | During a patrol: the route, the current stop (a stop ID from the route), its position counted from 0, and the number of stops                                                                                                                   |
| `goalPose`, `pose`, `mapId`                                   | Where the robot is heading, where it is, and the map those poses are on                                                                                                                                                                         |
| `estimatedTimeRemainingSec`, `distanceRemaining`              | Time (seconds) and distance (meters) left to the current goal                                                                                                                                                                                   |
| `failureReason`                                               | Why the latest activity failed, when it did                                                                                                                                                                                                     |
| `firmwareVersion`, `hwVariation`                              | Firmware and hardware model                                                                                                                                                                                                                     |

For one robot, [`getFullState`](https://developer.rhombus.com/api-reference/robot-webservice/get-full-robot-state) returns the same fields plus the robot's capabilities. Include `force` (`false` is fine); the call is refused without it:

```python Python
state = robot_api("getFullState", {"deviceUuid": ROBOT_UUID, "force": False})["fullState"]
capability = state.get("robotPlatformCapability") or {}
print(state["activity"], state.get("phase"), capability.get("supportedActions"))
```

Use `activity` and `phase` to tell whether a robot is docked, charging or out working; the `mode` and `charging` fields aren't reported.

### Activities

| `activity`                                            | The robot is                                                                              |
| ----------------------------------------------------- | ----------------------------------------------------------------------------------------- |
| `IDLE`                                                | Waiting for a command                                                                     |
| `ROUTE_RUN`                                           | Running a patrol or route. `phase` is `DWELLING` while it waits at a stop                 |
| `NAVIGATE_TO_POSE`                                    | Going to a point it was sent to                                                           |
| `NAVIGATE_TO_HOME`                                    | Returning to its charging pad because it was sent home                                    |
| `IDLE_DOCKING`                                        | Returning to its charging pad on its own, after its work is done or it has sat idle       |
| `LOW_BATTERY_DOCKING`                                 | Returning to its charging pad to recharge. It refuses new work until the battery recovers |
| `MANUAL_CMD_VEL`, `MANUAL_ACTION`, `MANUAL_POSTURE`   | Being driven live by an operator                                                          |
| `EMERGENCY`                                           | Stopped by an emergency stop, until someone releases it                                   |
| `EXPLORE_AND_MAP`, `EXPLORE_AREA`, `MAINTENANCE_HOLD` | Mapping its space, or held for map maintenance                                            |

New values can be added. Treat one you don't recognize as busy.

## Event history

[`findRobotEvents`](https://developer.rhombus.com/api-reference/robot-webservice/find-robot-events) returns what a robot did between `startMs` (inclusive) and `endMs` (exclusive). The response is **newline-delimited JSON** (`application/x-ndjson`), one event per line, newest first:

```python Python
import json
import time

def robot_events(robot_uuid, start_ms, end_ms):
    response = requests.post(
        f"{API}/findRobotEvents",
        headers=HEADERS,
        json={"deviceUuid": robot_uuid, "startMs": start_ms, "endMs": end_ms},
        timeout=60,
    )
    response.raise_for_status()
    events = []
    for line in response.text.splitlines():
        if not line.strip():
            continue
        event = json.loads(line)
        if "_error" in event:
            raise RuntimeError(f"findRobotEvents stopped early: {event.get('_message')}")
        events.append(event)
    return events

now = int(time.time() * 1000)
for event in robot_events(ROBOT_UUID, now - 24 * 3600 * 1000, now):
    print(event["timestampMs"], event.get("activity"), event.get("event"), event.get("phase"), event.get("failureReason"))
```

- **There's no paging.** Ask for a window you can handle, a day for example, and walk back window by window for longer periods.
- **A last line with `_error`** means the stream stopped before the end, though the status is `200`. Retry that window.
- **Events can arrive late.** A robot that was offline uploads what it recorded when it reconnects, with the original `timestampMs`. When you collect events on a schedule, overlap the windows and skip events whose `uuid` you've already stored.

| Field                                                         | Meaning                                                                                        |
| ------------------------------------------------------------- | ---------------------------------------------------------------------------------------------- |
| `uuid`                                                        | The event's ID; use it to skip duplicates                                                      |
| `timestampMs`                                                 | When it happened, by the robot's clock                                                         |
| `activity`, `activityUuid`                                    | The activity the event belongs to                                                              |
| `event`                                                       | `STARTED`, `PROGRESS`, `SUSPENDED`, `RESUMED`, `COMPLETED`, `FAILED`, `CANCELED` or `REJECTED` |
| `phase`, `phaseEvent`                                         | For `PROGRESS`, the phase that `STARTED` or `COMPLETED`                                        |
| `routeUuid`, `waypointUuid`, `waypointIndex`, `waypointTotal` | The route and the stop, during a patrol                                                        |
| `preemptedBy`                                                 | For `SUSPENDED` or `REJECTED`, the activity that took priority                                 |
| `failureReason`                                               | For `FAILED`, why                                                                              |
| `originator`                                                  | Who or what started the activity: `type` is `USER`, `API_TOKEN` or `RULE`, for example         |

Each activity follows the same lifecycle: `STARTED`, then `PROGRESS` events as it moves through its phases (arriving at a stop is a `PROGRESS` event whose `phaseEvent` is `COMPLETED`), possibly `SUSPENDED` and `RESUMED` when something with higher priority interrupts it, and exactly one of `COMPLETED`, `FAILED` or `CANCELED` at the end. An activity the robot refused is a single `REJECTED` event, with `preemptedBy` naming what blocked it.

## Alert on what matters

| Condition                     | Check                                                                                         |
| ----------------------------- | --------------------------------------------------------------------------------------------- |
| Offline                       | `connectionStatus` isn't `GREEN` on two polls in a row                                        |
| Low battery away from the pad | `batteryPercent` under your threshold while `activity` isn't one of the docking activities    |
| Patrol failed                 | A `FAILED` event for a `ROUTE_RUN`, with its `failureReason`                                  |
| Dispatch refused              | A `REJECTED` event, with `preemptedBy`                                                        |
| Stuck                         | The same `activity`, `phase` and `waypointIndex` for much longer than the route usually takes |

Polling the state list every minute or two is far below your [rate limit](https://developer.rhombus.com/rate-limits). Robot events don't arrive on the [event WebSocket](https://developer.rhombus.com/websocket/overview) or on organization webhooks; for real-time updates, connect to the [robot live socket](https://developer.rhombus.com/robots/live-socket).
