|
| 1 | +# Weather Data Caching & History API |
| 2 | + |
| 3 | +This release introduces endpoints for **cached location management** and **historical weather data retrieval**. |
| 4 | +It enables local caching, scheduled updates, and seamless fallback to external services (Open-Meteo) — ensuring data availability even in low-connectivity environments. |
| 5 | + |
| 6 | +--- |
| 7 | + |
| 8 | +## 1. Cached Location Management API |
| 9 | + |
| 10 | +The system maintains a **cache of locations** for which weather history data are stored locally and periodically updated. |
| 11 | +Each cached location automatically schedules a background job that fetches new data daily and removes the oldest record — maintaining a **sliding 30-day window** of historical weather. |
| 12 | + |
| 13 | +### Add a Location (Unique Cache) |
| 14 | + |
| 15 | +**Endpoint:** |
| 16 | +`POST /api/v1/locations/unique` |
| 17 | + |
| 18 | +**Description:** |
| 19 | +Adds a new location to the cache, **skipping duplicates** if another cached location already exists within a configurable proximity radius. |
| 20 | + |
| 21 | +This mechanism avoids redundant storage for nearby points that share the same climatic conditions. |
| 22 | + |
| 23 | +**Example Request** |
| 24 | + |
| 25 | +```json |
| 26 | +{ |
| 27 | + "locations": [ |
| 28 | + { |
| 29 | + "name": "Farm A", |
| 30 | + "lat": 35.0, |
| 31 | + "lon": 33.2 |
| 32 | + } |
| 33 | + ] |
| 34 | +} |
| 35 | +``` |
| 36 | + |
| 37 | +**Example Response** |
| 38 | + |
| 39 | +```json |
| 40 | +[ |
| 41 | + { |
| 42 | + "id": "64f123abc456...", |
| 43 | + "name": "Farm A", |
| 44 | + "lat": 35.0, |
| 45 | + "lon": 33.2, |
| 46 | + "created_at": "2025-08-08T14:23:11.123Z" |
| 47 | + } |
| 48 | +] |
| 49 | +``` |
| 50 | + |
| 51 | +### Why Radius-Based Deduplication? |
| 52 | + |
| 53 | +Nearby locations (within 5–10 km) in flat or coastal areas typically experience **identical weather patterns**. |
| 54 | +Using a proximity radius ensures the system: |
| 55 | +- Minimizes redundant data storage. |
| 56 | +- Reduces API calls to external providers. |
| 57 | +- Improves performance and cost efficiency. |
| 58 | + |
| 59 | +#### Works Well For: |
| 60 | +- Use cases where approximate data are acceptable (e.g., irrigation scheduling, pest/disease models). |
| 61 | +- Plains, coastal regions, or small islands where local variability is low. |
| 62 | + |
| 63 | +#### Limitations: |
| 64 | +- Mountainous or heterogeneous terrain (e.g., high elevation gradients, valley–ridge differences) may show **localized microclimates** where nearby coordinates differ significantly. |
| 65 | +- In such cases, consider **reducing the radius** or **explicitly caching** separate points. |
| 66 | + |
| 67 | +#### Future Alternatives: |
| 68 | +- Dynamically adapt `radius_km` based on topography or [Köppen climate zones](https://koeppen-geiger.vu-wien.ac.at/present.htm). |
| 69 | +- Introduce **grid-based caching** or **spatial clustering** using geohashes. |
| 70 | + |
| 71 | +--- |
| 72 | + |
| 73 | +## 2. Historical Weather Data API |
| 74 | + |
| 75 | +Once a location is cached, you can fetch its historical data either from the **local database** or via **Open-Meteo fallback** if no cached record exists. |
| 76 | + |
| 77 | +### Daily Weather Observations |
| 78 | + |
| 79 | +**Endpoint:** |
| 80 | +`POST /api/v1/history/daily` |
| 81 | + |
| 82 | +**Description:** |
| 83 | +Retrieve **daily weather summaries** for a given coordinate and date range. |
| 84 | +If cached data exist within the specified radius, they are returned directly; otherwise, data are fetched via Open-Meteo and optionally cached. |
| 85 | + |
| 86 | +**Request** |
| 87 | + |
| 88 | +```json |
| 89 | +{ |
| 90 | + "lat": 35.0, |
| 91 | + "lon": 33.2, |
| 92 | + "start": "2025-07-01", |
| 93 | + "end": "2025-07-03", |
| 94 | + "variables": ["temperature_2m_max", "temperature_2m_min"], |
| 95 | + "radius_km": 10 |
| 96 | +} |
| 97 | +``` |
| 98 | + |
| 99 | +**Response** |
| 100 | + |
| 101 | +```json |
| 102 | +{ |
| 103 | + "location": { "lat": 35.0, "lon": 33.2 }, |
| 104 | + "data": [ |
| 105 | + { |
| 106 | + "date": "2025-07-01", |
| 107 | + "values": { |
| 108 | + "temperature_2m_max": 32.1, |
| 109 | + "temperature_2m_min": 22.4 |
| 110 | + } |
| 111 | + }, |
| 112 | + { |
| 113 | + "date": "2025-07-02", |
| 114 | + "values": { |
| 115 | + "temperature_2m_max": 33.3, |
| 116 | + "temperature_2m_min": 21.8 |
| 117 | + } |
| 118 | + } |
| 119 | + ], |
| 120 | + "source": "open-meteo" |
| 121 | +} |
| 122 | +``` |
| 123 | + |
| 124 | +--- |
| 125 | + |
| 126 | +### Hourly Weather Observations |
| 127 | + |
| 128 | +**Endpoint:** |
| 129 | +`POST /api/v1/history/hourly` |
| 130 | + |
| 131 | +**Description:** |
| 132 | +Retrieve **hourly data** for the given coordinates and time range. |
| 133 | +Data are served from the cache if available, otherwise fetched from Open-Meteo. |
| 134 | + |
| 135 | +**Request** |
| 136 | + |
| 137 | +```json |
| 138 | +{ |
| 139 | + "lat": 35.0, |
| 140 | + "lon": 33.2, |
| 141 | + "start": "2025-07-01", |
| 142 | + "end": "2025-07-03", |
| 143 | + "variables": ["temperature_2m", "relative_humidity_2m"], |
| 144 | + "radius_km": 10 |
| 145 | +} |
| 146 | +``` |
| 147 | + |
| 148 | +**Response (cached data)** |
| 149 | + |
| 150 | +```json |
| 151 | +{ |
| 152 | + "location": { "lat": 35.0, "lon": 33.2 }, |
| 153 | + "data": [ |
| 154 | + { |
| 155 | + "timestamp": "2025-07-01T00:00:00Z", |
| 156 | + "values": { |
| 157 | + "temperature_2m": 26.3, |
| 158 | + "relative_humidity_2m": 65 |
| 159 | + } |
| 160 | + } |
| 161 | + ], |
| 162 | + "source": "open-meteo" |
| 163 | +} |
| 164 | +``` |
| 165 | + |
| 166 | +--- |
| 167 | + |
| 168 | +## Background Sliding Window Updates |
| 169 | + |
| 170 | +Each cached location has a **dedicated background job** that: |
| 171 | +- Fetches **yesterday’s data daily** when an internet connection is available. |
| 172 | +- **Removes the oldest record** to maintain a fixed 30-day window. |
| 173 | +- **Stores all results locally** in the database. |
| 174 | + |
| 175 | +This ensures that: |
| 176 | +- **Offline access** is possible even without external APIs. |
| 177 | +- Data remain **up-to-date** automatically when connectivity returns. |
| 178 | + |
| 179 | +--- |
| 180 | + |
| 181 | +## Why This Matters |
| 182 | + |
| 183 | +This design enables hybrid online/offline behavior: |
| 184 | +- **Connected mode:** Data are synced automatically with Open-Meteo. |
| 185 | +- **Offline mode:** Cached history remains queryable, ideal for rural or remote agricultural deployments. |
| 186 | + |
| 187 | +--- |
| 188 | + |
| 189 | +## Example Workflow |
| 190 | + |
| 191 | +1. Add a location for caching: |
| 192 | + ```bash |
| 193 | + curl -X POST http://localhost:8000/api/v1/locations/unique -H "Content-Type: application/json" -d '{"locations": [{"lat": 35.0, "lon": 33.2}], "radius_km": 10}' |
| 194 | + ``` |
| 195 | + |
| 196 | +2. Fetch daily history: |
| 197 | + ```bash |
| 198 | + curl -X POST http://localhost:8000/api/v1/history/daily -H "Content-Type: application/json" -d '{"lat": 35.0, "lon": 33.2, "start": "2025-07-01", "end": "2025-07-03", "variables": ["temperature_2m_max", "temperature_2m_min"], "radius_km": 10}' |
| 199 | + ``` |
| 200 | + |
| 201 | +3. Fetch hourly history: |
| 202 | + ```bash |
| 203 | + curl -X POST http://localhost:8000/api/v1/history/hourly -H "Content-Type: application/json" -d '{"lat": 35.0, "lon": 33.2, "start": "2025-07-01", "end": "2025-07-03", "variables": ["temperature_2m", "relative_humidity_2m"], "radius_km": 10}' |
| 204 | + ``` |
| 205 | + |
| 206 | +## Available Variables |
| 207 | + |
| 208 | +These variables can be requested in the `variables` array of `/history/daily` or `/history/hourly` requests. |
| 209 | + |
| 210 | +### Daily Variables |
| 211 | +| Variable | Description | |
| 212 | +|-----------|--------------| |
| 213 | +| temperature_2m_min | Minimum daily temperature at 2 meters | |
| 214 | +| temperature_2m_max | Maximum daily temperature at 2 meters | |
| 215 | +| temperature_2m_mean | Mean daily temperature at 2 meters | |
| 216 | +| precipitation_sum | Total precipitation (rain + other forms) | |
| 217 | +| rain_sum | Total rainfall only | |
| 218 | +| wind_speed_10m_max | Maximum wind speed at 10 meters | |
| 219 | +| wind_gusts_10m_max | Maximum wind gusts at 10 meters | |
| 220 | +| wind_direction_10m_dominant | Dominant wind direction at 10 meters | |
| 221 | + |
| 222 | +### Hourly Variables |
| 223 | +| Variable | Description | |
| 224 | +|-----------|--------------| |
| 225 | +| temperature_2m | Air temperature at 2 meters | |
| 226 | +| relative_humidity_2m | Relative humidity at 2 meters | |
| 227 | +| precipitation | Hourly precipitation total | |
| 228 | +| rain | Hourly rainfall total | |
| 229 | +| pressure_msl | Mean sea level pressure | |
| 230 | +| surface_pressure | Atmospheric pressure at surface | |
| 231 | +| cloud_cover | Total cloud cover (%) | |
| 232 | +| et0_fao_evapotranspiration | Reference evapotranspiration (FAO Penman-Monteith) | |
| 233 | +| wind_speed_10m | Wind speed at 10 meters | |
| 234 | +| wind_direction_10m | Wind direction at 10 meters | |
| 235 | +| wind_gusts_10m | Wind gusts at 10 meters | |
| 236 | +| soil_temperature_0_to_7cm | Soil temperature (0–7 cm depth) | |
| 237 | +| soil_temperature_7_to_28cm | Soil temperature (7–28 cm depth) | |
| 238 | +| soil_temperature_28_to_100cm | Soil temperature (28–100 cm depth) | |
| 239 | +| soil_temperature_100_to_255cm | Soil temperature (100–255 cm depth) | |
| 240 | +| soil_moisture_0_to_7cm | Soil moisture (0–7 cm depth) | |
| 241 | +| soil_moisture_7_to_28cm | Soil moisture (7–28 cm depth) | |
| 242 | +| soil_moisture_28_to_100cm | Soil moisture (28–100 cm depth) | |
| 243 | +| soil_moisture_100_to_255cm | Soil moisture (100–255 cm depth) | |
| 244 | + |
0 commit comments