|
|
import aiohttp |
|
|
import asyncio |
|
|
import os |
|
|
import xarray as xr |
|
|
import requests |
|
|
from datetime import datetime |
|
|
from typing import Dict, Any |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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: |
|
|
|
|
|
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) |
|
|
|
|
|
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)}"} |
|
|
|