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