File size: 4,403 Bytes
b20698b |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 |
import aiohttp
import asyncio
import os
import xarray as xr
import requests
from datetime import datetime
from typing import Dict, Any
# ============================================================================
# SOIL PROPERTIES SERVER (SoilGrids)
# ============================================================================
class SoilPropertiesServer:
"""SoilGrids API Server - Enhanced for reliability"""
async def get_data(self, lat: float, lon: float) -> Dict[str, Any]:
"""Get soil properties with retry logic and rate limit handling"""
try:
properties = ["clay", "sand", "silt", "phh2o", "soc"]
results = {}
timeout = aiohttp.ClientTimeout(total=15, connect=5, sock_read=10)
connector = aiohttp.TCPConnector(limit=1, limit_per_host=1)
async with aiohttp.ClientSession(timeout=timeout, connector=connector) as session:
for prop in properties:
# Retry logic (max 2 attempts)
for attempt in range(2):
try:
url = "https://rest.isric.org/soilgrids/v2.0/properties/query"
params = {
"lon": lon,
"lat": lat,
"property": prop,
"depth": "0-5cm",
"value": "mean"
}
async with session.get(url, params=params) as response:
if response.status == 200:
data = await response.json()
value = data['properties']['layers'][0]['depths'][0]['values']['mean']
if value is not None:
if prop == 'phh2o':
results[prop] = round(value / 10, 1)
elif prop == 'soc':
results[prop] = value
else:
results[prop] = round(value / 10, 1)
else:
results[prop] = None
break
elif response.status == 429:
if attempt == 0:
await asyncio.sleep(1)
continue
else:
results[prop] = None
break
else:
results[prop] = None
break
except asyncio.TimeoutError:
if attempt == 0:
await asyncio.sleep(0.5)
continue
else:
results[prop] = None
break
except Exception:
results[prop] = None
break
await asyncio.sleep(0.2) # Delay between properties
if any(v is not None for v in results.values()):
return {
"status": "success",
"data": {
"clay_percent": results.get("clay"),
"sand_percent": results.get("sand"),
"silt_percent": results.get("silt"),
"pH": results.get("phh2o"),
"organic_carbon_dg_per_kg": results.get("soc"),
"data_source": "SoilGrids API (ISRIC)",
"location": {"latitude": lat, "longitude": lon},
"depth": "0-5cm (topsoil)"
}
}
else:
return {
"status": "error",
"error": "No soil data available for this location"
}
except Exception as e:
return {"status": "error", "error": f"SoilGrids error: {str(e)}"}
|