fix: align telegram runway slope with settlement endpoint
This commit is contained in:
@@ -897,14 +897,24 @@ def _wind_regime_label(city: str, wind_dir: Optional[int], language: Optional[st
|
||||
return None
|
||||
|
||||
|
||||
def _compute_slope_15m(icao: str, current_temp: float) -> Optional[float]:
|
||||
def _runway_row_temp_for_city(city: str, row: Dict[str, Any]) -> Optional[float]:
|
||||
endpoint = _settlement_endpoint_for_point(city, row.get("runway"), row)
|
||||
if endpoint is not None:
|
||||
return _safe_float(endpoint.get("temp"))
|
||||
target_runway_max = _safe_float(row.get("target_runway_max"))
|
||||
if target_runway_max is not None:
|
||||
return target_runway_max
|
||||
return _safe_float(row.get("tdz_temp"))
|
||||
|
||||
|
||||
def _compute_slope_15m(icao: str, current_temp: float, city: str = "") -> Optional[float]:
|
||||
"""Estimate 15-minute temperature trend from runway_obs_log."""
|
||||
try:
|
||||
db = DBManager()
|
||||
rows = db.get_runway_obs_recent(icao, minutes=20)
|
||||
temps = []
|
||||
for r in rows:
|
||||
t = r.get("target_runway_max") or r.get("tdz_temp")
|
||||
t = _runway_row_temp_for_city(city, r)
|
||||
if t is not None:
|
||||
temps.append(float(t))
|
||||
if len(temps) >= 2:
|
||||
@@ -1147,7 +1157,7 @@ def _build_airport_status_message(
|
||||
|
||||
# ── Heat model ──
|
||||
wind_dir = amos.get("wind_dir") if is_amsc else None
|
||||
slope_15m = _compute_slope_15m(amos_icao, display_temp) if is_amsc and display_temp is not None else None
|
||||
slope_15m = _compute_slope_15m(amos_icao, display_temp, city) if is_amsc and display_temp is not None else None
|
||||
heat_signal = _runway_heat_signal(display_temp or 0, slope_15m, wind_dir, city, language) if is_amsc else ""
|
||||
wind_label = _wind_regime_label(city, wind_dir, language) if is_amsc and wind_dir is not None else None
|
||||
|
||||
@@ -1192,14 +1202,11 @@ def _build_airport_status_message(
|
||||
end = pts.get("end_temp")
|
||||
is_settlement = _is_settlement_runway(city, r1, r2)
|
||||
marker = f" {_copy(language, '★Settlement', '★结算')}" if is_settlement else ""
|
||||
tmax = pts.get("target_runway_max")
|
||||
if tdz is not None or mid is not None or end is not None:
|
||||
line = f"{r1}/{r2}{marker} TDZ:{_fmt(tdz)} MID:{_fmt(mid)} END:{_fmt(end)}"
|
||||
settlement_line_endpoint = _settlement_endpoint_for_point(city, (r1, r2), pts) if is_settlement else None
|
||||
if settlement_line_endpoint is not None:
|
||||
line += f" settle:{float(settlement_line_endpoint['temp']):.1f}"
|
||||
elif tmax is not None:
|
||||
line += f" max:{float(tmax):.1f}"
|
||||
lines.append(line)
|
||||
else:
|
||||
temp_symbol = str(city_weather.get("temp_symbol") or "°C").strip()
|
||||
|
||||
@@ -2,6 +2,7 @@ from src.utils.telegram_push import (
|
||||
HIGH_FREQ_AIRPORT_CITIES,
|
||||
HIGH_FREQ_AIRPORT_ICAO,
|
||||
_build_airport_status_message,
|
||||
_compute_slope_15m,
|
||||
_run_high_freq_airport_cycle,
|
||||
_telegram_push_language,
|
||||
)
|
||||
@@ -43,6 +44,7 @@ def test_airport_status_message_defaults_to_bilingual_runway_copy(monkeypatch):
|
||||
assert "TDZ:23.0" in text
|
||||
assert "Settlement runway now / 结算跑道当前:" in text
|
||||
assert "Today's runway high / 今日跑道高点:" in text
|
||||
assert "max:" not in text
|
||||
assert "DEB: 24.0°C" in text
|
||||
|
||||
|
||||
@@ -98,6 +100,61 @@ def test_airport_status_uses_tdz_when_settlement_target_is_first_runway():
|
||||
assert "02L/20R ★Settlement / ★结算 TDZ:24.4 MID:26.1 END:27.9 settle:24.4" in text
|
||||
assert "Settlement runway now / 结算跑道当前: 24.4°C" in text
|
||||
assert "Settlement runway now / 结算跑道当前: 27.9°C" not in text
|
||||
assert "max:" not in text
|
||||
|
||||
|
||||
def test_airport_status_removes_max_when_runway_endpoints_are_shown():
|
||||
text = _build_airport_status_message(
|
||||
"shanghai",
|
||||
{
|
||||
"current": {"temp": 24.0},
|
||||
"airport_current": {"max_so_far": 25.0, "max_temp_time": "07:00"},
|
||||
"amos": {
|
||||
"source": "amsc_awos",
|
||||
"runway_obs": {
|
||||
"runway_pairs": [("35R", "17L"), ("34L", "16R")],
|
||||
"temperatures": [(25.2, None), (25.4, None)],
|
||||
"point_temperatures": [
|
||||
{"runway": "35R/17L", "tdz_temp": 25.2, "mid_temp": None, "end_temp": 24.6, "target_runway_max": 25.2},
|
||||
{"runway": "34L/16R", "tdz_temp": 25.4, "mid_temp": None, "end_temp": 24.8, "target_runway_max": 25.4},
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
27.2,
|
||||
"10:58",
|
||||
)
|
||||
|
||||
assert "35R/17L ★Settlement / ★结算 TDZ:25.2 MID:-- END:24.6 settle:25.2" in text
|
||||
assert "34L/16R TDZ:25.4 MID:-- END:24.8" in text
|
||||
assert "max:" not in text
|
||||
|
||||
|
||||
def test_telegram_slope_uses_settlement_endpoint_not_runway_max(monkeypatch):
|
||||
import src.utils.telegram_push as telegram_push
|
||||
|
||||
class FakeDB:
|
||||
def get_runway_obs_recent(self, icao, minutes=20):
|
||||
return [
|
||||
{
|
||||
"runway": "20R/02L",
|
||||
"tdz_temp": 33.7,
|
||||
"mid_temp": 34.1,
|
||||
"end_temp": 30.8,
|
||||
"target_runway_max": 34.1,
|
||||
},
|
||||
{
|
||||
"runway": "20R/02L",
|
||||
"tdz_temp": 33.8,
|
||||
"mid_temp": 34.5,
|
||||
"end_temp": 31.2,
|
||||
"target_runway_max": 34.5,
|
||||
},
|
||||
]
|
||||
|
||||
monkeypatch.setattr(telegram_push, "DBManager", lambda: FakeDB())
|
||||
|
||||
assert _compute_slope_15m("ZUCK", 31.2, "chongqing") == 0.4
|
||||
|
||||
|
||||
def test_singapore_is_in_telegram_push_city_lists():
|
||||
|
||||
Reference in New Issue
Block a user