feat: Implement PolyWeather web map API and its multi-source weather data collection module.

This commit is contained in:
2569718930@qq.com
2026-03-05 01:50:38 +08:00
parent eee159c533
commit 7c087b2c81
2 changed files with 35 additions and 27 deletions
+6 -6
View File
@@ -1378,25 +1378,20 @@ class WeatherDataCollector:
results["metar"] = metar_data results["metar"] = metar_data
# 对土耳其城市,额外获取 MGM 官方数据与周边测站 # 对土耳其城市,额外获取 MGM 官方数据与周边测站
# 后面可以扩展更多土耳其城市,只需在这里添加映射
turkish_provinces = { turkish_provinces = {
"ankara": ("17130", "Ankara"), # (主测站ID, 省份名用于周边) "ankara": ("17130", "Ankara"),
"istanbul": ("17060", "Istanbul"), "istanbul": ("17060", "Istanbul"),
} }
if city_lower in turkish_provinces: if city_lower in turkish_provinces:
istno, province = turkish_provinces[city_lower] istno, province = turkish_provinces[city_lower]
mgm_data = self.fetch_from_mgm(istno) mgm_data = self.fetch_from_mgm(istno)
if mgm_data: if mgm_data:
results["mgm"] = mgm_data results["mgm"] = mgm_data
# 抓取并追加周边参考站数据 (并发模式)
nearby = self.fetch_mgm_nearby_stations(province) nearby = self.fetch_mgm_nearby_stations(province)
if nearby: if nearby:
results["mgm_nearby"] = nearby results["mgm_nearby"] = nearby
# 全球通用:对有预定义集群的城市,抓取周边 METAR 参考站 # 全球通用:对有预定义集群的城市,抓取周边 METAR 参考站
# 这可以让 Buenos Aires, London, NYC 等城市也拥有类似安卡拉的多测站地图分布
if city_lower in self.CITY_METAR_CLUSTERS and "mgm_nearby" not in results: if city_lower in self.CITY_METAR_CLUSTERS and "mgm_nearby" not in results:
cluster_icaos = self.CITY_METAR_CLUSTERS[city_lower] cluster_icaos = self.CITY_METAR_CLUSTERS[city_lower]
cluster_data = self.fetch_metar_nearby_cluster( cluster_data = self.fetch_metar_nearby_cluster(
@@ -1405,6 +1400,11 @@ class WeatherDataCollector:
if cluster_data: if cluster_data:
results["mgm_nearby"] = cluster_data results["mgm_nearby"] = cluster_data
if open_meteo:
results["open-meteo"] = open_meteo
# 获取时区偏移以过滤 METAR
utc_offset = open_meteo.get("utc_offset", 0)
# 对伦敦,获取 Meteoblue 预测 (公认最准) # 对伦敦,获取 Meteoblue 预测 (公认最准)
if city_lower == "london": if city_lower == "london":
mb_data = self.fetch_from_meteoblue( mb_data = self.fetch_from_meteoblue(
+29 -21
View File
@@ -43,19 +43,19 @@ _weather = WeatherDataCollector(_config)
# City Registry # City Registry
# ────────────────────────────────────────────────────────── # ──────────────────────────────────────────────────────────
CITIES: Dict[str, Dict[str, Any]] = { CITIES: Dict[str, Dict[str, Any]] = {
"ankara": {"lat": 40.1281, "lon": 32.9951, "f": False}, # LTAC (Esenboğa) "ankara": {"lat": 40.1281, "lon": 32.9951, "f": False, "tz": 10800},
"london": {"lat": 51.5048, "lon": 0.0522, "f": False}, # EGLC (London City) "london": {"lat": 51.5048, "lon": 0.0522, "f": False, "tz": 0},
"paris": {"lat": 49.0097, "lon": 2.5480, "f": False}, # LFPG (Charles de Gaulle) "paris": {"lat": 49.0097, "lon": 2.5480, "f": False, "tz": 3600},
"seoul": {"lat": 37.4602, "lon": 126.4407, "f": False}, # RKSI (Incheon) "seoul": {"lat": 37.4602, "lon": 126.4407, "f": False, "tz": 32400},
"toronto": {"lat": 43.6777, "lon": -79.6248, "f": False}, # CYYZ (Pearson) "toronto": {"lat": 43.6777, "lon": -79.6248, "f": False, "tz": -18000},
"buenos aires": {"lat": -34.8222, "lon": -58.5358, "f": False}, # SAEZ (Ezeiza) "buenos aires": {"lat": -34.8222, "lon": -58.5358, "f": False, "tz": -10800},
"wellington": {"lat": -41.3272, "lon": 174.8053, "f": False}, # NZWN (Wellington) "wellington": {"lat": -41.3272, "lon": 174.8053, "f": False, "tz": 46800},
"new york": {"lat": 40.7769, "lon": -73.8740, "f": True}, # KLGA (LaGuardia) "new york": {"lat": 40.7769, "lon": -73.8740, "f": True, "tz": -18000},
"chicago": {"lat": 41.9742, "lon": -87.9073, "f": True}, # KORD (O'Hare) "chicago": {"lat": 41.9742, "lon": -87.9073, "f": True, "tz": -21600},
"dallas": {"lat": 32.8471, "lon": -96.8518, "f": True}, # KDAL (Dallas Love Field) "dallas": {"lat": 32.8471, "lon": -96.8518, "f": True, "tz": -21600},
"miami": {"lat": 25.7959, "lon": -80.2870, "f": True}, # KMIA (Miami) "miami": {"lat": 25.7959, "lon": -80.2870, "f": True, "tz": -18000},
"atlanta": {"lat": 33.6407, "lon": -84.4277, "f": True}, # KATL (Hartsfield-Jackson) "atlanta": {"lat": 33.6407, "lon": -84.4277, "f": True, "tz": -18000},
"seattle": {"lat": 47.4502, "lon": -122.3088, "f": True}, # KSEA (Sea-Tac) "seattle": {"lat": 47.4502, "lon": -122.3088, "f": True, "tz": -28800},
} }
ALIASES = { ALIASES = {
@@ -135,7 +135,8 @@ def _analyze(city: str, force_refresh: bool = False) -> Dict[str, Any]:
obs_time_str = "" obs_time_str = ""
metar_age_min = None metar_age_min = None
obs_t = metar.get("observation_time", "") if metar else "" obs_t = metar.get("observation_time", "") if metar else ""
utc_offset = om.get("utc_offset", 0) # 优先从 API 获取偏移,若失败则使用 CITIES 预设的静态偏移 (兜底当地时间)
utc_offset = om.get("utc_offset", info.get("tz", 0))
if obs_t and "T" in obs_t: if obs_t and "T" in obs_t:
try: try:
dt = datetime.fromisoformat(obs_t.replace("Z", "+00:00")) dt = datetime.fromisoformat(obs_t.replace("Z", "+00:00"))
@@ -150,15 +151,22 @@ def _analyze(city: str, force_refresh: bool = False) -> Dict[str, Any]:
# ── 3. Local time parsing ── # ── 3. Local time parsing ──
local_time_full = om.get("current", {}).get("local_time", "") local_time_full = om.get("current", {}).get("local_time", "")
local_hour, local_minute = 12, 0 local_hour, local_minute = 12, 0
local_date_str = datetime.now().strftime("%Y-%m-%d") now_utc = datetime.now(timezone.utc)
local_now = now_utc + timedelta(seconds=utc_offset)
local_date_str = local_now.strftime("%Y-%m-%d")
try: try:
local_date_str = local_time_full.split(" ")[0] if local_time_full:
tp = local_time_full.split(" ")[1].split(":") local_date_str = local_time_full.split(" ")[0]
local_hour = int(tp[0]) tp = local_time_full.split(" ")[1].split(":")
local_minute = int(tp[1]) if len(tp) > 1 else 0 local_hour = int(tp[0])
local_minute = int(tp[1]) if len(tp) > 1 else 0
else:
local_hour = local_now.hour
local_minute = local_now.minute
except Exception: except Exception:
local_hour = datetime.now().hour local_hour = local_now.hour
local_minute = datetime.now().minute local_minute = local_now.minute
local_time_str = f"{local_hour:02d}:{local_minute:02d}" local_time_str = f"{local_hour:02d}:{local_minute:02d}"
local_hour_frac = local_hour + local_minute / 60 local_hour_frac = local_hour + local_minute / 60