Source: docs/grazing.md
Cycle grazing
Move the herd through paddocks on a schedule. You draw each paddock once, then set the order and how long the herd stays in each. The server runs the moves.
How a move works
- Grazing. The tags enforce the current paddock. When its time is up, the move starts.
- Opening. The server sends a fence covering the current and next paddock (the "gate"). It waits until every tag confirms it.
- Moving. Cattle walk to the fresh grass on their own. The server waits until every tag has reported from at least 5 m inside the next paddock since the gate opened.
- Settling. It sends the next paddock's fence and waits for every tag to confirm. The old paddock's rest clock starts.
The code is in src/herdtag/server/rotation.py (engine, API, scheduler) and src/herdtag/server/fences.py (fence creation, assignment, sync tracking).
Safety rules
- Never closes on a cow. If any tag is outside the next paddock, or hasn't reported since the gate opened, or has been silent for 2 hours, the gate stays open. After
move_timeout_h(6 h by default) the farmer gets arotation_stragglersalert naming the tags, repeated at most hourly. - Never shrinks a fence before tags have the bigger one. Each phase waits for every tag to acknowledge its new fence. After 2 hours waiting, there's a
rotation_sync_slowalert. - Rest periods. A paddock isn't re-entered until
rest_daysafter the herd last left it. The herd waits where it is, with arotation_rest_holdalert. When a plan is created, the server warns if the cycle can't give a paddock its rest. - Water. Every paddock the herd stays in (more than 0 hours) must be marked as having water, unless the plan sets
allow_no_water. - Paddocks must touch. Consecutive paddocks need at least 5 m of shared fence line. Hand-drawn gaps up to 3 m are closed automatically. For paddocks that don't touch, add a lane paddock with 0 hours between them.
- Gate fences are simplified to the firmware's 32-corner limit without losing more than 3% of area, or the plan is refused.
Farmer controls
On the map page, under Grazing rotation: draw paddocks, plan a rotation, then Start. While it runs you can:
- Move now: end grazing early.
- Close gate anyway: close behind the herd despite stragglers. Their tags will report them as out.
- Pause / Resume: stop scheduling for a while; tags keep their current fence.
- Stop: end the rotation; tags keep whatever fence they have.
API
| Method | Path | Body / notes |
|---|---|---|
| GET | /api/paddocks |
All paddocks (not archived) |
| POST | /api/paddocks |
{name, points: [[lat, lon], ...], has_water, rest_days} |
| DELETE | /api/paddocks/{id} |
Archive; 409 if a running rotation uses it |
| GET | /api/rotations |
Status of every rotation |
| POST | /api/rotations |
{name, steps: [{paddock_id, graze_hours}], dev_ids?, loop, allow_no_water, move_timeout_h}; returns warnings |
| GET | /api/rotations/{id} |
Status: status, phase, step, steps, herd_size, unsynced, next_move_at, next_paddock, moved |
| POST | /api/rotations/{id}/start |
Optional ?step=N |
| POST | /api/rotations/{id}/pause, /resume, /move-now, /close-gate, /stop |
See farmer controls |
The scheduler runs inside the server every 30 s. Set HERDTAG_NO_SCHEDULER=1 to turn it off (tests do).
Try it
uv run herdtag-server
uv run herdtag demo --rotation 0.05 # two paddocks, 3 minutes each, real time