接入 KNMI 阿姆斯特丹史基浦机场 10 分钟数据源
通过 KNMI Open Data API 获取 Schiphol 机场 10 分钟观测数据(NetCDF 格式)。 需设置 KNMI_API_KEY 环境变量。Docker 镜像新增 libhdf5-dev/netCDF4 依赖。 Constraint: KNMI API key 为 JWT 格式,通过 Authorization header 传递 Scope-risk: 中高,新增系统依赖 libhdf5-dev + netCDF4 Tested: pytest 176 passed, KNMI API 连通性验证通过
This commit is contained in:
@@ -16,10 +16,11 @@ from src.data_collection.nmc_sources import NmcSourceMixin
|
||||
from src.data_collection.nws_open_meteo_sources import NwsOpenMeteoSourceMixin
|
||||
from src.data_collection.amos_station_sources import AmosStationSourceMixin
|
||||
from src.data_collection.fmi_sources import FmiSourceMixin
|
||||
from src.data_collection.knmi_sources import KnmiSourceMixin
|
||||
from src.database.db_manager import DBManager
|
||||
|
||||
|
||||
class WeatherDataCollector(OpenMeteoCacheMixin, SettlementSourceMixin, MetarSourceMixin, MgmSourceMixin, JmaAmedasSourceMixin, RussiaStationSourceMixin, NmcSourceMixin, NwsOpenMeteoSourceMixin, AmosStationSourceMixin, FmiSourceMixin):
|
||||
class WeatherDataCollector(OpenMeteoCacheMixin, SettlementSourceMixin, MetarSourceMixin, MgmSourceMixin, JmaAmedasSourceMixin, RussiaStationSourceMixin, NmcSourceMixin, NwsOpenMeteoSourceMixin, AmosStationSourceMixin, FmiSourceMixin, KnmiSourceMixin):
|
||||
"""
|
||||
Multi-source weather data collector
|
||||
|
||||
@@ -227,6 +228,11 @@ class WeatherDataCollector(OpenMeteoCacheMixin, SettlementSourceMixin, MetarSour
|
||||
)
|
||||
self._fmi_cache: Dict[str, Dict] = {}
|
||||
self._fmi_cache_lock = threading.Lock()
|
||||
self.knmi_cache_ttl_sec = int(
|
||||
os.getenv("KNMI_CACHE_TTL_SEC", "120")
|
||||
)
|
||||
self._knmi_cache: Dict[str, Dict] = {}
|
||||
self._knmi_cache_lock = threading.Lock()
|
||||
self.cwa_open_data_auth = (
|
||||
os.getenv("CWA_OPEN_DATA_AUTH")
|
||||
or os.getenv("CWA_OPEN_DATA_API_KEY")
|
||||
@@ -737,6 +743,8 @@ class WeatherDataCollector(OpenMeteoCacheMixin, SettlementSourceMixin, MetarSour
|
||||
self._jma_cache.pop(f"{normalized}:{use_fahrenheit}", None)
|
||||
with self._fmi_cache_lock:
|
||||
self._fmi_cache.pop(f"fmi:{normalized}:{use_fahrenheit}", None)
|
||||
with self._knmi_cache_lock:
|
||||
self._knmi_cache.pop(f"knmi:{normalized}:{use_fahrenheit}", None)
|
||||
with self._nmc_cache_lock:
|
||||
self._nmc_cache.pop(f"{normalized}:{use_fahrenheit}", None)
|
||||
with self._ru_station_cache_lock:
|
||||
@@ -899,6 +907,31 @@ class WeatherDataCollector(OpenMeteoCacheMixin, SettlementSourceMixin, MetarSour
|
||||
except Exception:
|
||||
logger.exception("airport_obs_log append failed for jma city={}", city_lower)
|
||||
|
||||
def _attach_knmi_official_nearby(
|
||||
self, results: Dict, city_lower: str, use_fahrenheit: bool
|
||||
) -> None:
|
||||
if city_lower != "amsterdam":
|
||||
return
|
||||
rows = self.fetch_knmi_official_nearby(
|
||||
city_lower, use_fahrenheit=use_fahrenheit
|
||||
)
|
||||
if not rows:
|
||||
return
|
||||
results["knmi_official_nearby"] = rows
|
||||
if "mgm_nearby" not in results:
|
||||
results["mgm_nearby"] = rows
|
||||
results["nearby_source"] = "knmi"
|
||||
try:
|
||||
row = rows[0] if rows else {}
|
||||
DBManager().append_airport_obs(
|
||||
icao=str(row.get("icao") or "EHAM"),
|
||||
city=city_lower,
|
||||
temp_c=row.get("temp"),
|
||||
obs_time=str(row.get("obs_time") or datetime.now().isoformat()),
|
||||
)
|
||||
except Exception:
|
||||
logger.exception("airport_obs_log append failed for knmi city={}", city_lower)
|
||||
|
||||
def _attach_fmi_official_nearby(
|
||||
self, results: Dict, city_lower: str, use_fahrenheit: bool
|
||||
) -> None:
|
||||
@@ -1086,6 +1119,7 @@ class WeatherDataCollector(OpenMeteoCacheMixin, SettlementSourceMixin, MetarSour
|
||||
self._attach_china_official_nearby(results, city_lower, use_fahrenheit)
|
||||
self._attach_japan_official_nearby(results, city_lower, use_fahrenheit)
|
||||
self._attach_fmi_official_nearby(results, city_lower, use_fahrenheit)
|
||||
self._attach_knmi_official_nearby(results, city_lower, use_fahrenheit)
|
||||
self._attach_russia_official_nearby(results, city_lower, use_fahrenheit)
|
||||
if city_lower == "warsaw":
|
||||
self._attach_warsaw_official_nearby(results, use_fahrenheit)
|
||||
@@ -1129,6 +1163,7 @@ class WeatherDataCollector(OpenMeteoCacheMixin, SettlementSourceMixin, MetarSour
|
||||
self._attach_china_official_nearby(results, city_lower, use_fahrenheit)
|
||||
self._attach_japan_official_nearby(results, city_lower, use_fahrenheit)
|
||||
self._attach_fmi_official_nearby(results, city_lower, use_fahrenheit)
|
||||
self._attach_knmi_official_nearby(results, city_lower, use_fahrenheit)
|
||||
self._attach_russia_official_nearby(results, city_lower, use_fahrenheit)
|
||||
if city_lower == "warsaw":
|
||||
self._attach_warsaw_official_nearby(results, use_fahrenheit)
|
||||
|
||||
Reference in New Issue
Block a user