132 lines
4.1 KiB
Python
132 lines
4.1 KiB
Python
# services/external/app/ingestion/adapters/madrid_adapter.py
|
|
"""
|
|
Madrid city data adapter - Uses existing AEMET and Madrid OpenData clients
|
|
"""
|
|
|
|
from typing import List, Dict, Any
|
|
from datetime import datetime
|
|
import structlog
|
|
|
|
from ..base_adapter import CityDataAdapter
|
|
from app.external.aemet import AEMETClient
|
|
from app.external.apis.madrid_traffic_client import MadridTrafficClient
|
|
|
|
logger = structlog.get_logger()
|
|
|
|
|
|
class MadridAdapter(CityDataAdapter):
|
|
"""Adapter for Madrid using AEMET + Madrid OpenData"""
|
|
|
|
def __init__(self, city_id: str, config: Dict[str, Any]):
|
|
super().__init__(city_id, config)
|
|
self.aemet_client = AEMETClient()
|
|
self.traffic_client = MadridTrafficClient()
|
|
|
|
self.madrid_lat = 40.4168
|
|
self.madrid_lon = -3.7038
|
|
|
|
async def fetch_historical_weather(
|
|
self,
|
|
start_date: datetime,
|
|
end_date: datetime
|
|
) -> List[Dict[str, Any]]:
|
|
"""Fetch historical weather from AEMET"""
|
|
try:
|
|
logger.info(
|
|
"Fetching Madrid historical weather",
|
|
start=start_date.isoformat(),
|
|
end=end_date.isoformat()
|
|
)
|
|
|
|
weather_data = await self.aemet_client.get_historical_weather(
|
|
self.madrid_lat,
|
|
self.madrid_lon,
|
|
start_date,
|
|
end_date
|
|
)
|
|
|
|
for record in weather_data:
|
|
record['city_id'] = self.city_id
|
|
record['city_name'] = 'Madrid'
|
|
|
|
logger.info(
|
|
"Madrid weather data fetched",
|
|
records=len(weather_data)
|
|
)
|
|
|
|
return weather_data
|
|
|
|
except Exception as e:
|
|
logger.error("Error fetching Madrid weather", error=str(e))
|
|
return []
|
|
|
|
async def fetch_historical_traffic(
|
|
self,
|
|
start_date: datetime,
|
|
end_date: datetime
|
|
) -> List[Dict[str, Any]]:
|
|
"""Fetch historical traffic from Madrid OpenData"""
|
|
try:
|
|
logger.info(
|
|
"Fetching Madrid historical traffic",
|
|
start=start_date.isoformat(),
|
|
end=end_date.isoformat()
|
|
)
|
|
|
|
traffic_data = await self.traffic_client.get_historical_traffic(
|
|
self.madrid_lat,
|
|
self.madrid_lon,
|
|
start_date,
|
|
end_date
|
|
)
|
|
|
|
for record in traffic_data:
|
|
record['city_id'] = self.city_id
|
|
record['city_name'] = 'Madrid'
|
|
|
|
logger.info(
|
|
"Madrid traffic data fetched",
|
|
records=len(traffic_data)
|
|
)
|
|
|
|
return traffic_data
|
|
|
|
except Exception as e:
|
|
logger.error("Error fetching Madrid traffic", error=str(e))
|
|
return []
|
|
|
|
async def validate_connection(self) -> bool:
|
|
"""Validate connection to AEMET and Madrid OpenData
|
|
|
|
Note: Validation is lenient - passes if traffic API works.
|
|
AEMET rate limits may cause weather validation to fail during initialization.
|
|
"""
|
|
try:
|
|
test_traffic = await self.traffic_client.get_current_traffic(
|
|
self.madrid_lat,
|
|
self.madrid_lon
|
|
)
|
|
|
|
# Traffic API must work (critical for operations)
|
|
if test_traffic is None:
|
|
logger.error("Traffic API validation failed - this is critical")
|
|
return False
|
|
|
|
# Try weather API, but don't fail validation if rate limited
|
|
test_weather = await self.aemet_client.get_current_weather(
|
|
self.madrid_lat,
|
|
self.madrid_lon
|
|
)
|
|
|
|
if test_weather is None:
|
|
logger.warning("Weather API validation failed (likely rate limited) - proceeding anyway")
|
|
else:
|
|
logger.info("Weather API validation successful")
|
|
|
|
# Pass validation if traffic works (weather can be fetched later)
|
|
return True
|
|
|
|
except Exception as e:
|
|
logger.error("Madrid adapter connection validation failed", error=str(e))
|
|
return False
|