From 80821d614f0ace9e5dd813acb4d6121df00be811 Mon Sep 17 00:00:00 2001 From: "2569718930@qq.com" <2569718930@qq.com> Date: Sun, 8 Feb 2026 16:36:16 +0800 Subject: [PATCH] feat: add multi-source weather data collector supporting OpenWeatherMap, Visual Crossing, and NOAA METAR. --- bot_listener.py | 83 +++++++++++++++++++++++++- src/data_collection/weather_sources.py | 5 ++ 2 files changed, 87 insertions(+), 1 deletion(-) diff --git a/bot_listener.py b/bot_listener.py index 02fa365f..93cafcbd 100644 --- a/bot_listener.py +++ b/bot_listener.py @@ -103,6 +103,43 @@ def analyze_weather_trend(weather_data, temp_symbol): elif wind_speed >= 10: insights.append(f"🍃 清劲风:空气流动快,虽然有助于散热,但可能伴随阵风引起微小波动。") + # 4. 云层遮挡分析 (对午后增温影响巨大) + clouds = metar.get("current", {}).get("clouds", []) + if clouds and 10 <= local_hour <= 16: + # 取覆盖范围最大的云层 + main_cloud = clouds[-1] # METAR 通常按高度由低到高排列,最后一层往往代表主要云量 + cover = main_cloud.get("cover", "") + + if cover == "OVC": + insights.append(f"☁️ 全阴锁温:机场上空完全遮挡,阳光增温几乎停滞,很难冲破预报高点。") + elif cover == "BKN": + insights.append(f"🌥️ 云层显著:天空大部被遮挡,日照受限,升温速率将明显放缓。") + elif cover in ["SKC", "CLR", "FEW"]: + insights.append(f"☀️ 晴空万里:日照强烈,无云层遮挡,气温有冲向预报上限甚至超出的动能。") + + # 5. 特殊天气现象分析 + wx_desc = metar.get("current", {}).get("wx_desc") + if wx_desc: + if any(x in wx_desc.upper() for x in ["RA", "DZ", "RAIN", "DRIZZLE"]): + insights.append(f"🌧️ 降雨压制:当前有降雨,蒸发吸热将显著拉低实时气温。") + elif any(x in wx_desc.upper() for x in ["SN", "SNOW", "GR", "GS"]): + insights.append(f"❄️ 固态降水:正在降雪或冰雹,气温将由于相变吸热而持续低迷。") + elif any(x in wx_desc.upper() for x in ["FG", "BR", "HZ", "FOG", "MIST"]): + insights.append(f"🌫️ 能见度受限:当前有雾/霭,阻挡阳光并带来高湿,会大幅延缓升温周期。") + + # 6. 风向与能见度 + wind_dir = metar.get("current", {}).get("wind_dir") + if wind_dir is not None: + # 北半球简化逻辑:北风冷,南风暖 + if 315 <= wind_dir or wind_dir <= 45: + insights.append(f"🌬️ 偏北风:冷空气处于主导地位,午后增温阻力较大。") + elif 135 <= wind_dir <= 225: + insights.append(f"🔥 偏南风:正从低纬度输送暖湿气流,气温有超预期上涨的潜力。") + + visibility = metar.get("current", {}).get("visibility_mi") + if visibility is not None and visibility < 3 and local_hour <= 11: + insights.append(f"🌫️ 早晨低见度:能见度极差 ({visibility}mi),阳光无法打透,早间升温将非常缓慢。") + if not insights: return "" @@ -279,7 +316,51 @@ def start_bot(): else: msg_lines.append(f" 🌡️ {metar_temp}{temp_symbol}") if wind is not None: - msg_lines.append(f" 💨 风速: {wind}kt") + wind_dir = metar.get("current", {}).get("wind_dir") + if wind_dir is not None: + # 翻译风向 + dirs = ["北", "东北", "东", "东南", "南", "西南", "西", "西北"] + dir_str = dirs[int((wind_dir + 22.5) % 360 / 45)] + msg_lines.append(f" 💨 风力: {wind}kt ({dir_str}风 {wind_dir}°)") + else: + msg_lines.append(f" 💨 风速: {wind}kt") + + vis = metar.get("current", {}).get("visibility_mi") + if vis is not None: + msg_lines.append(f" 👁️ 能见度: {vis}mi") + + wx = metar.get("current", {}).get("wx_desc") + if wx: + # 常见天象翻译 + wx_map = { + "RA": "雨", "SN": "雪", "DZ": "毛毛雨", "FG": "雾", + "BR": "薄雾", "HZ": "霾", "TS": "雷暴", "GR": "冰雹", + "VC": "附近", "MI": "浅", "BC": "散", "PR": "部分", + "BL": "吹", "SH": "阵", "FZ": "冻", "-": "轻微", "+": "强烈" + } + translated_wx = wx + for code, cn in wx_map.items(): + translated_wx = translated_wx.replace(code, cn) + msg_lines.append(f" 🌧️ 天象: {translated_wx}") + + # 云层显示 + clouds = metar.get("current", {}).get("clouds", []) + if clouds: + cloud_map = { + "SKC": "晴空 (无云)", "CLR": "晴空 (无云)", + "FEW": "少云", "SCT": "散云", + "BKN": "多云 (有遮挡)", "OVC": "阴天 (全覆盖)", + "VV": "垂直能见度受限" + } + main_cloud = clouds[-1] + cover_code = main_cloud.get("cover", "Unknown") + base_height = main_cloud.get("base", "") + cover_desc = cloud_map.get(cover_code, cover_code) + if base_height: + msg_lines.append(f" ☁️ 云层: {cover_desc} ({base_height}ft)") + else: + msg_lines.append(f" ☁️ 云层: {cover_desc}") + msg_lines.append(f" 🕐 观测: {obs_str}") # 3. 添加态势分析 diff --git a/src/data_collection/weather_sources.py b/src/data_collection/weather_sources.py index b316507b..3358a7dd 100644 --- a/src/data_collection/weather_sources.py +++ b/src/data_collection/weather_sources.py @@ -296,6 +296,11 @@ class WeatherDataCollector: "dewpoint": round(dewp, 1) if dewp is not None else None, "humidity": latest.get("rh"), "wind_speed_kt": latest.get("wspd"), + "wind_dir": latest.get("wdir"), + "visibility_mi": latest.get("visib"), + "wx_desc": latest.get("wxString"), + "altimeter": latest.get("altim"), + "clouds": latest.get("clouds", []), }, "unit": unit, }