{
  "nbformat": 4,
  "nbformat_minor": 0,
  "metadata": {
    "colab": {
      "provenance": []
    },
    "kernelspec": {
      "name": "python3",
      "display_name": "Python 3"
    },
    "language_info": {
      "name": "python"
    }
  },
  "cells": [
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "lcGPUv2p_671",
        "outputId": "d5e274c7-4977-45fb-bf70-accd8caf0199"
      },
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "11.1\n"
          ]
        }
      ],
      "source": [
        "import requests\n",
        "import os\n",
        "import time\n",
        "\n",
        "class SoilPropertyFetcher:\n",
        "    def __init__(self, lat, lon):\n",
        "        self.lat = lat\n",
        "        self.lon = lon\n",
        "        self.rest_url = \"https://rest.isric.org\"\n",
        "        self.prop_query_url = f\"{self.rest_url}/soilgrids/v2.0/properties/query\"\n",
        "\n",
        "\n",
        "    def fetch_property(self, property_name, retries=3, backoff_factor=2):\n",
        "        self.property_name = property_name\n",
        "        params = {\n",
        "            \"lat\": self.lat,\n",
        "            \"lon\": self.lon,\n",
        "            \"property\": self.property_name,\n",
        "            \"depth\": \"5-15cm\",\n",
        "            \"value\": \"mean\"\n",
        "        }\n",
        "\n",
        "        for i in range(retries):\n",
        "            response = requests.get(self.prop_query_url, params=params)\n",
        "            if response.status_code == 200:\n",
        "                data = response.json()\n",
        "                mean_value = data['properties']['layers'][0]['depths'][0]['values']['mean']\n",
        "                time.sleep(12)  # Respect API rate limits\n",
        "                return mean_value / 10  # Scaling the mean value appropriately\n",
        "\n",
        "\n",
        "            elif response.status_code == 429:\n",
        "                wait_time = (backoff_factor ** i) * 10  # Exponential backoff\n",
        "                print(f\"Rate limit exceeded. Retrying in {wait_time} seconds...\")\n",
        "                time.sleep(wait_time)\n",
        "            else:\n",
        "                raise Exception(f\"Error fetching data: {response.status_code} - {response.text}\")\n",
        "\n",
        "\n",
        "\n",
        "        # If all retries fail\n",
        "        raise Exception(f\"Failed to fetch data after {retries} retries due to rate limiting.\")\n",
        "\n",
        "\n",
        "point_1 = SoilPropertyFetcher(42,24)\n",
        "print(point_1.fetch_property(\"clay\"))\n",
        "\n",
        "properties = ['clay', 'sand', 'silt']"
      ]
    },
    {
      "cell_type": "code",
      "source": [
        "import requests\n",
        "import time\n",
        "from urllib.parse import urlencode\n",
        "\n",
        "class SoilPropertyFetcher:\n",
        "    def __init__(self, lat, lon):\n",
        "        self.lat = lat\n",
        "        self.lon = lon\n",
        "        self.base_url = \"https://rest.isric.org/soilgrids/v2.0/properties/query\"\n",
        "\n",
        "    def construct_url(self, properties, depth=\"5-15cm\", value=\"mean\"):\n",
        "        # Create the query parameters dynamically\n",
        "        query_params = {\n",
        "            \"lat\": self.lat,\n",
        "            \"lon\": self.lon,\n",
        "            \"depth\": depth,\n",
        "            \"value\": value\n",
        "        }\n",
        "\n",
        "        # Add each property as a separate query parameter\n",
        "        # This makes sure that multiple properties are added as `property=...` repeatedly\n",
        "        properties_params = [('property', prop) for prop in properties]\n",
        "\n",
        "        # Combine the query parameters with properties\n",
        "        query_string = urlencode(query_params) + '&' + urlencode(properties_params, doseq=True)\n",
        "\n",
        "        # Create the full URL by appending the query string to the base URL\n",
        "        full_url = f\"{self.base_url}?{query_string}\"\n",
        "        return full_url\n",
        "\n",
        "    def fetch_properties(self, properties, retries=3, backoff_factor=2):\n",
        "        results = {}\n",
        "        full_url = self.construct_url(properties)\n",
        "\n",
        "        for i in range(retries):\n",
        "            response = requests.get(full_url, headers={'accept': 'application/json'})\n",
        "            if response.status_code == 200:\n",
        "                data = response.json()\n",
        "                print(data)  # Debugging: Print the response\n",
        "\n",
        "                try:\n",
        "                    # Loop over each property and extract the mean value\n",
        "                    for property_name in properties:\n",
        "                        mean_value = None\n",
        "                        for layer in data['properties']['layers']:\n",
        "                            print(f\"Layer found: {layer['name']}\")\n",
        "                            if layer['name'] == property_name:\n",
        "                                mean_value = layer['depths'][0]['values'].get('mean', None)\n",
        "                                if mean_value is not None:\n",
        "                                    mean_value = mean_value / 10\n",
        "                                break\n",
        "                        if mean_value is None:\n",
        "                            print(f\"No data found for property: {property_name}\")\n",
        "                        results[property_name] = mean_value\n",
        "\n",
        "                    time.sleep(12)\n",
        "                    break\n",
        "\n",
        "                except (KeyError, IndexError):\n",
        "                    print(f\"Error extracting data for properties: {properties}\")\n",
        "                    return None\n",
        "\n",
        "            elif response.status_code == 429:\n",
        "                wait_time = (backoff_factor ** i) * 10\n",
        "                print(f\"Rate limit exceeded. Retrying in {wait_time} seconds...\")\n",
        "                time.sleep(wait_time)\n",
        "            else:\n",
        "                raise Exception(f\"Error fetching data: {response.status_code} - {response.text}\")\n",
        "\n",
        "        else:\n",
        "            raise Exception(f\"Failed to fetch data after {retries} retries due to rate limiting.\")\n",
        "\n",
        "        return results\n",
        "\n",
        "\n",
        "# Example usage\n",
        "lat = 50\n",
        "lon = 24\n",
        "properties = ['clay', 'nitrogen', 'sand', 'silt', 'soc']\n",
        "\n",
        "soil_fetcher = SoilPropertyFetcher(lat, lon)\n",
        "results = soil_fetcher.fetch_properties(properties)\n",
        "\n",
        "# Print the results for each property\n",
        "for property_name, value in results.items():\n",
        "    if value is not None:\n",
        "        print(f\"{property_name}: {value}\")\n",
        "    else:\n",
        "        print(f\"{property_name}: No data found\")\n"
      ],
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "l9sHzgeGObnG",
        "outputId": "9a862142-c366-48e3-b2c8-1388d133481f"
      },
      "execution_count": null,
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "{'type': 'Feature', 'geometry': {'type': 'Point', 'coordinates': [24.0, 50.0]}, 'properties': {'layers': [{'name': 'clay', 'unit_measure': {'d_factor': 10, 'mapped_units': 'g/kg', 'target_units': '%', 'uncertainty_unit': ''}, 'depths': [{'range': {'top_depth': 5, 'bottom_depth': 15, 'unit_depth': 'cm'}, 'label': '5-15cm', 'values': {'mean': 249}}]}, {'name': 'nitrogen', 'unit_measure': {'d_factor': 100, 'mapped_units': 'cg/kg', 'target_units': 'g/kg', 'uncertainty_unit': ''}, 'depths': [{'range': {'top_depth': 5, 'bottom_depth': 15, 'unit_depth': 'cm'}, 'label': '5-15cm', 'values': {'mean': 181}}]}, {'name': 'sand', 'unit_measure': {'d_factor': 10, 'mapped_units': 'g/kg', 'target_units': '%', 'uncertainty_unit': ''}, 'depths': [{'range': {'top_depth': 5, 'bottom_depth': 15, 'unit_depth': 'cm'}, 'label': '5-15cm', 'values': {'mean': 261}}]}, {'name': 'silt', 'unit_measure': {'d_factor': 10, 'mapped_units': 'g/kg', 'target_units': '%', 'uncertainty_unit': ''}, 'depths': [{'range': {'top_depth': 5, 'bottom_depth': 15, 'unit_depth': 'cm'}, 'label': '5-15cm', 'values': {'mean': 490}}]}, {'name': 'soc', 'unit_measure': {'d_factor': 10, 'mapped_units': 'dg/kg', 'target_units': 'g/kg', 'uncertainty_unit': ''}, 'depths': [{'range': {'top_depth': 5, 'bottom_depth': 15, 'unit_depth': 'cm'}, 'label': '5-15cm', 'values': {'mean': 187}}]}]}, 'query_time_s': 1.4560236930847168}\n",
            "Layer found: clay\n",
            "Layer found: clay\n",
            "Layer found: nitrogen\n",
            "Layer found: clay\n",
            "Layer found: nitrogen\n",
            "Layer found: sand\n",
            "Layer found: clay\n",
            "Layer found: nitrogen\n",
            "Layer found: sand\n",
            "Layer found: silt\n",
            "Layer found: clay\n",
            "Layer found: nitrogen\n",
            "Layer found: sand\n",
            "Layer found: silt\n",
            "Layer found: soc\n",
            "clay: 24.9\n",
            "nitrogen: 18.1\n",
            "sand: 26.1\n",
            "silt: 49.0\n",
            "soc: 18.7\n"
          ]
        }
      ]
    }
  ]
}