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

{
  "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)

{
  "type": "Feature",
  "properties": { "type": "farm_boundary" },
  "geometry": {
    "type": "Polygon",
    "coordinates": [[[lon, lat], ...]]
  }
}

2. Pump location (Point)

{
  "type": "Feature",
  "properties": {
    "type": "pump",
    "pump_hp": 5.0
  },
  "geometry": {
    "type": "Point",
    "coordinates": [lon, lat]
  }
}

3. Crop zones (one or more Polygons)

{
  "type": "Feature",
  "properties": {
    "type": "crop_zone",
    "crop": "tomato"
  },
  "geometry": {
    "type": "Polygon",
    "coordinates": [[[lon, lat], ...]]
  }
}

Optional features

Elevation data (Point with properties)

{
  "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

{
  "type": "FeatureCollection",
  "properties": {
    "type": "farm_design",
    "design_summary": { ... },
    "bom": { ... }
  },
  "features": [ ... ]
}

Design Summary (top-level properties)

{
  "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)

{
  "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:

{
  "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:

{
  "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

{
  "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:

{
  "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:

{
  "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