spacedout-bits's picture
Add JSON integration schemas for user app interop
b9e0ad7
# JSON Integration Schemas
This directory contains sample JSON formats for integrating the Farm Layout Model with your user app.
All formats follow **GeoJSON RFC 7946** standard for maximum compatibility with map libraries (Leaflet, Mapbox, Google Maps, etc.).
## Files
- `input_example.json` β€” What your user app sends to the layout engine
- `output_example.json` β€” What the layout engine returns
## Input Schema
### Top-level structure
```json
{
"type": "FeatureCollection",
"properties": { ... }, // Farm-level metadata
"features": [ ... ] // List of geometric features
}
```
### Top-level properties (farm metadata)
| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `farm_id` | string | Yes | Unique identifier for the farm |
| `farm_name` | string | No | Human-readable name |
| `pump_hp` | float | Yes | Pump horsepower (for flow calculation) |
| `centralized` | boolean | Yes | `true` = centralized manifold, `false` = distributed |
| `headland_buffer_m` | float | No | Inward buffer from field edge (default: 1.0m) |
| `override_lateral_spacing_m` | float\|null | No | Override crop default spacing |
### Required features
**1. Farm boundary (Polygon)**
```json
{
"type": "Feature",
"properties": { "type": "farm_boundary" },
"geometry": {
"type": "Polygon",
"coordinates": [[[lon, lat], ...]]
}
}
```
**2. Pump location (Point)**
```json
{
"type": "Feature",
"properties": {
"type": "pump",
"pump_hp": 5.0
},
"geometry": {
"type": "Point",
"coordinates": [lon, lat]
}
}
```
**3. Crop zones (one or more Polygons)**
```json
{
"type": "Feature",
"properties": {
"type": "crop_zone",
"crop": "tomato"
},
"geometry": {
"type": "Polygon",
"coordinates": [[[lon, lat], ...]]
}
}
```
### Optional features
**Elevation data (Point with properties)**
```json
{
"type": "Feature",
"properties": {
"type": "elevation",
"min_elevation_m": 920,
"max_elevation_m": 923
},
"geometry": {
"type": "Point",
"coordinates": [lon, lat]
}
}
```
### Supported crop types
`tomato`, `pepper`, `lettuce`, `cucumber`, `orchard`, `generic`
## Output Schema
### Top-level structure
```json
{
"type": "FeatureCollection",
"properties": {
"type": "farm_design",
"design_summary": { ... },
"bom": { ... }
},
"features": [ ... ]
}
```
### Design Summary (top-level properties)
```json
{
"farm_area_ha": 0.24,
"total_valves": 3,
"total_drip_tape_m": 480.5,
"total_main_line_m": 45.2,
"total_emitters": 1202,
"pump_hp": 5.0,
"pump_flow_lph": 500,
"manifold_strategy": "distributed"
}
```
### Bill of Materials (top-level properties)
```json
{
"main_line_16mm_m": 45.2,
"drip_tape_16mm_m": 480.5,
"inline_emitters": 1202,
"total_pipe_m": 525.7,
"valves_count": 3,
"cost_main": 22.60,
"cost_drip_tape": 72.08,
"cost_emitters": 96.16,
"cost_valves": 45.00,
"total_cost_usd": 235.84
}
```
### Output feature types
| `properties.type` | Geometry | Purpose |
|-------------------|----------|---------|
| `farm_boundary` | Polygon | Echo of input farm boundary |
| `valve` | Point | Valve placement with metadata |
| `valve_zone` | Polygon | Area controlled by each valve |
| `main_line` | LineString | Main irrigation line |
| `lateral` | LineString | Individual drip lateral |
### Valve metadata
Each valve Feature has these properties:
```json
{
"type": "valve",
"id": "valve_000",
"strategy": "distributed", // or "centralized"
"reason": "crop_type", // or "capacity_split", "topography_split", "hydraulics_split"
"crop": "tomato",
"flow_capacity_lph": 500,
"estimated_demand_lph": 480
}
```
### Lateral metadata
Each lateral Feature has:
```json
{
"type": "lateral",
"index": 0,
"length_m": 30.0,
"valve_id": "valve_000", // Which valve controls this lateral
"spacing_m": 0.5
}
```
## Rendering on Your Map
All coordinates are in **WGS84 (EPSG:4326)** β€” lat/lon format compatible with:
- **Leaflet**: `L.geoJSON(data).addTo(map)`
- **Mapbox GL JS**: `map.addSource('design', { type: 'geojson', data })`
- **Google Maps**: `map.data.addGeoJson(data)`
### Recommended styling
```javascript
{
"farm_boundary": { color: "green", weight: 3, fillOpacity: 0.1 },
"valve": { color: "red", radius: 8, fillColor: "red" },
"valve_zone": { color: "purple", weight: 1, fillOpacity: 0.2 },
"main_line": { color: "blue", weight: 4 },
"lateral": { color: "cyan", weight: 1, opacity: 0.6 }
}
```
## Coordinate Order Note
GeoJSON uses **[longitude, latitude]** order (not lat/lon).
Always double-check your user app sends coordinates in this order.
## Example: Minimal Input
If your user app only has farm boundary + pump + one crop:
```json
{
"type": "FeatureCollection",
"properties": {
"pump_hp": 5.0,
"centralized": false
},
"features": [
{
"type": "Feature",
"properties": { "type": "farm_boundary" },
"geometry": {
"type": "Polygon",
"coordinates": [[[77.59, 12.97], [77.60, 12.97], [77.60, 12.98], [77.59, 12.98], [77.59, 12.97]]]
}
},
{
"type": "Feature",
"properties": { "type": "pump", "pump_hp": 5.0 },
"geometry": { "type": "Point", "coordinates": [77.59, 12.97] }
},
{
"type": "Feature",
"properties": { "type": "crop_zone", "crop": "tomato" },
"geometry": {
"type": "Polygon",
"coordinates": [[[77.59, 12.97], [77.60, 12.97], [77.60, 12.98], [77.59, 12.98], [77.59, 12.97]]]
}
}
]
}
```
## Error Response Format
If the engine fails to generate a design:
```json
{
"type": "FeatureCollection",
"properties": {
"type": "farm_design_error",
"error": {
"code": "INVALID_POLYGON",
"message": "Farm boundary self-intersects at coordinates [77.59, 12.97]",
"details": { ... }
}
},
"features": []
}
```
### Error codes
- `INVALID_POLYGON` β€” Farm boundary is invalid (self-intersecting, too small, etc.)
- `NO_PUMP_FOUND` β€” No pump feature in input
- `NO_CROP_ZONES` β€” No crop zones specified
- `INVALID_PUMP_HP` β€” pump_hp missing or ≀ 0
- `HEADLAND_TOO_LARGE` β€” Headland buffer exceeds field dimensions
- `INTERNAL_ERROR` β€” Unexpected server error