Skip to content

v1.2.5

Latest

Choose a tag to compare

@github-actions github-actions released this 04 Aug 08:19
· 1 commit to main since this release

[1.2.5] - 2026-08-04

中文

正确性 + 性能补丁版本 —— 0 项数据库改动。本版本修复 7 个 HIGH 严重度 Bug(数据错误、单位错算、跨日时区漂移、并发死锁等),并完成 6 项性能优化(异步化、并行、缓存、连接复用、写盘去抖)。共修改 ~352 行代码 + 新增 ~334 行测试代码,所有改动均为只读 SELECT 查询优化或 Python 逻辑改进,可直接 git pull 升级,无需迁移或停机。

🐛 Bug 修复(7 项)

数据正确性(7 项)

  • BUG-A tesla_live 速度单位错算:TeslaMate positions.speed 存的就是 km/h,但代码当作 m/s 处理 —— 100 km/h 真实速度被报告成 360 km/h(3.6 倍虚高)。已改为直接使用 km/h 值,imperial 走 0.621371 换算。
  • BUG-B NULL 续航产生虚假能耗:多工具的 (start_ideal_range_km - end_ideal_range_km) * kwh_per_km 计算中,只要任一端为 NULL,Python or 0 把缺失当作 0,产出 (400-0)*0.15 = 60 kWh 之类的巨型虚假能耗。10 处 SQL 聚合已加 IS NOT NULL 谓词 + FILTER 子句,tesla_drives 循环已改用 is None 跳过缺失行。
  • BUG-C end_date 跨 DST 边界错位:9 个工具用 parse_date(end) + timedelta(days=1) 构造排他右边界,在 DST 春令时(23h 日)多算 1h、秋令时(25h 日)少算 1h。新增 _next_local_day() helper,改用"下一个本地日历日"再 _parse_date,对所有时区 DST 安全。
  • BUG-D 月度吸血鬼误判长驾驶为停车耗电:_monthly_report_compute / tesla_monthly_summaryevents CTE 丢失 kind 字段,导致一次 10h 长驾驶的 drive_start → drive_end 配对被错误归入 vampire(20% 电量差算成停车耗电)。已加 kind='drive_end' AND next_kind IN ('drive_start','charge_start') 过滤,并把硬编的 8h/168h 阈值改为 %s 参数,统一与 VAMPIRE_MIN_HOURS/VAMPIRE_MAX_HOURS 对齐。
  • BUG-E get_vehicle_persona_status 忽略 year/month 截止:工具计算了 start 和 end,但所有 SQL 只用 start_date >= cutoff,end 边界从未传进去。请求 2025 年 1 月实际返回 1 月至今所有数据,idle_percentage 分母与分子口径不一致。已为 3 处查询加 FILTER ... AND start_date < end_boundary,state 区间按 [start, end] 裁剪。
  • BUG-F tesla_location_history 报"跨度"而非"累计停留":SQL 用 MAX(date) - MIN(date) 计算 span_hours,周一停 1h + 周五停 1h → 报告 120h。已改用 LAG() + 同聚类内 SUM(stay_seconds),跨聚类 / 间隔 > 30 分钟的采样正确排除。
  • BUG-G _cached_result 不是 cancellation-safe:leader 任务被取消时 CancelledError 不被 except Exception 捕获,共享 future 永远 pending,follower 死锁;follower 取消时 await 传播取消到共享 future,后续 set_resultInvalidStateError。已改 except BaseException + follower 走 asyncio.shield(inflight),set 前检查 done()

⚡ 性能优化(6 项)

  • OPT-1 _savings_compute._merge 异步化:嵌套 sync 函数调 _query_one 阻塞事件循环,statement_timeout=30s 触发时整个 MCP 服务器冻结 30 秒。已改为 async def _merge + _query_one_async,无事件循环阻塞。
  • OPT-2 TESLA_DB_MAXCONN env 真正生效:之前硬编 maxconn=8,但错误消息引导运维提高 TESLA_DB_MAXCONN,实际无效。已读取 env(maxconn/minconn 均支持),启动日志输出实际值。
  • OPT-3 13 个昂贵工具加缓存:tesla_vampire_drain / tesla_driving_score / tesla_location_history / tesla_state_history / tesla_tpms_history / tesla_monthly_driving_report(24h 历史 / 5min 当月)/ tesla_driving_score / check_driving_achievements / check_daily_quest / get_driver_profile / get_charging_vintage_data / generate_weekend_blindbox / generate_travel_narrative_context / get_longest_trip_on_single_charge / calculate_eco_savings_vs_icev 全部包装 _cached_result(_vkey(...), ttl=...),LLM agent 重试 / 后续问题时不再重复全表扫。
  • OPT-12 QWeather asyncio.gather 并行:tesla_vampire_drain 5 个停车点 + tesla_efficiency_by_weather 60 个采样 × 2 调用,均从串行改为并行。实测加速 5x(serial 0.51s → parallel 0.10s),最坏情况 5×8s=40s 串行 → ~8s 并行。
  • OPT-13 httpx.AsyncClient 模块级单例:5 个调用点(AMAP / QWeather ×3 / Nominatim)每次都新建 client → 50-200ms TCP/TLS 握手。已抽 _get_http_client(),atexit 时 aclose()。每次 QWeather 调用省 ~100ms。
  • OPT-14 geocode cache 紧凑 JSON + 去抖:每次 miss 全文件重写 + indent=2(150KB 在锁内串行执行)→ 改 separators=(",", ":")(~40% 小)+ threading.Timer 去抖 1s 合并。20 个目的地 trip 计划从 3MB 写 + 150ms×20 等待,降到 30KB + 一次写。atexit 安全网保证未刷盘数据不丢失。

测试

  • 新增 test_bugfixes.py (334 行,无需 fastmcp/DB 即可运行):覆盖 7 个 bug 的核心逻辑 + 6 个优化的结构与行为断言,14/14 测试组全部通过(36 个独立断言)。
  • 现有 test_all.py 仍 100% 兼容,继续覆盖 80+ smoke 测试。

配置

  • 新增 TESLA_DB_MAXCONN (默认 8) + TESLA_DB_MINCONN (默认 2),实际生效。
  • TESLA_GEOCODE_CACHE_DEBOUNCE_SEC 默认 1.0s(可调)。
  • 全部向后兼容,默认值与历史行为一致。

备注

  • 数据库访问仍然 100% 只读。46 个 SQL 查询全部为 SELECT / WITH...SELECT,0 处 INSERT/UPDATE/DELETE/TRUNCATE/CREATE/ALTER/DROP/commit/rollback,cur.execute 仅 2 处(_query L815 / _query_one L845),后接 fetchall()/fetchone()
  • 所有 7 个 bug 修复均为只读 SELECT 查询文本优化或 Python 逻辑改进,部署无需任何 schema 迁移或权限变更,直接替换 tesla.py 即可生效。

English

Correctness + performance patch release — 0 database changes. Fixes 7 HIGH-severity bugs (data errors, unit mistakes, DST drift, cancellation deadlock, etc.) and lands 6 performance optimizations (async, parallel, cache, client reuse, debounced writes). ~352 lines modified + ~334 lines of tests added; every change is a read-only SELECT text optimization or Python logic improvement — deployable via git pull with no migration or downtime.

🐛 Bug fixes (7)

Data correctness (7)

  • BUG-A tesla_live speed unit wrong: TeslaMate positions.speed is km/h, but the code treated it as m/s — 100 km/h was reported as 360 km/h (3.6× inflation). Now uses km/h directly; imperial goes through 0.621371.
  • BUG-B NULL range endpoints produced fake energy: Multiple tools computed (start - end) * kwh_per_km with or 0 coercion — if either endpoint was NULL, the missing side was treated as 0, producing e.g. (400-0)*0.15 = 60 kWh of phantom energy. Added IS NOT NULL predicates + FILTER clauses to 10 SQL aggregates; tesla_drives Python loop now uses is None to skip incomplete rows.
  • BUG-C end_date DST drift: 9 tools built the exclusive end boundary as parse_date(end) + timedelta(days=1), which over-counts 1h on spring-forward (23h) days and under-counts 1h on fall-back (25h) days. New _next_local_day() helper computes the next local calendar date then re-parses — DST-safe for all zones.
  • BUG-D Monthly vampire misclassified long drives as parked drain: _monthly_report_compute / tesla_monthly_summary lost the kind column from the events CTE, so a 10h drive_end → drive_start pair (with 20% battery drop) was tallied as vampire drain. Added kind='drive_end' AND next_kind IN ('drive_start','charge_start') filter; hardcoded 8h/168h thresholds replaced with %s params bound to VAMPIRE_MIN_HOURS/VAMPIRE_MAX_HOURS.
  • BUG-E get_vehicle_persona_status ignored year/month end: The tool computed start and end, but every SQL only used start_date >= cutoff — the end boundary was never passed. Querying year=2025, month=1 returned everything from January through "now". Added FILTER ... AND start_date < end_boundary to all 3 queries; state intervals clipped to [start, end].
  • BUG-F tesla_location_history reported span, not cumulative stay: SQL used MAX(date) - MIN(date) for span_hours — Monday 1h + Friday 1h reported as ~120h. Replaced with LAG() + intra-cluster SUM(stay_seconds). Cross-cluster transitions and >30min gaps correctly excluded.
  • BUG-G _cached_result was not cancellation-safe: Leader task cancellation (a BaseException) wasn't caught by except Exception, leaving the shared future pending forever → follower deadlock. Follower cancellation propagated to the shared future → leader's set_result raised InvalidStateError. Now uses except BaseException, follower wraps in asyncio.shield(inflight), and set_* checks done() first.

⚡ Performance optimizations (6)

  • OPT-1 _savings_compute._merge async: Nested sync function called _query_one blocking the event loop; a 30s statement_timeout froze the entire MCP server. Now async def _merge + _query_one_async — no event-loop block.
  • OPT-2 TESLA_DB_MAXCONN env actually works: Hardcoded maxconn=8 misled operators (the error message even told them to raise TESLA_DB_MAXCONN). Now reads env (maxconn + minconn both supported); startup log shows actual values.
  • OPT-3 13 expensive tools cached: tesla_vampire_drain / tesla_driving_score / tesla_location_history / tesla_state_history / tesla_tpms_history / generate_monthly_driving_report (24h historical / 5min current month) / check_driving_achievements / check_daily_quest / get_driver_profile / get_charging_vintage_data / generate_weekend_blindbox / generate_travel_narrative_context / get_longest_trip_on_single_charge / calculate_eco_savings_vs_icev all wrapped in _cached_result(_vkey(...), ttl=...). LLM agent retries / follow-ups no longer re-scan full tables.
  • OPT-12 QWeather asyncio.gather parallel: 5 parking spots in tesla_vampire_drain + 60 samples × 2 calls in tesla_efficiency_by_weather — both moved from serial to parallel. Measured 5× speedup (serial 0.51s → parallel 0.10s); worst case 5×8s = 40s serial → ~8s parallel.
  • OPT-13 httpx.AsyncClient module-level singleton: 5 call sites (AMAP / QWeather ×3 / Nominatim) each rebuilt a client → 50-200ms TCP/TLS handshake per call. Extracted _get_http_client(), aclose() on atexit. Saves ~100ms per QWeather call.
  • OPT-14 geocode cache compact JSON + debounced writes: Every miss rewrote the entire 150KB JSON with indent=2 under the cache lock. Now separators=(",", ":") (~40% smaller) + threading.Timer 1s debounce coalescing bursts. 20-destination trip planning: 3MB writes + 150ms×20 wait → 30KB + one write. atexit safety net guarantees no pending writes are lost.

Testing

  • New test_bugfixes.py (334 lines, runs without fastmcp/DB): covers the core logic of all 7 bugs + structural and behavioural assertions for all 6 optimizations. 14/14 test groups pass (36 individual assertions).
  • Existing test_all.py remains 100% compatible, still covering 80+ smoke tests.

Configuration

  • New TESLA_DB_MAXCONN (default 8) + TESLA_DB_MINCONN (default 2), both effective.
  • TESLA_GEOCODE_CACHE_DEBOUNCE_SEC default 1.0s (tunable).
  • All backward compatible — defaults preserve historical behaviour.

Notes

  • Database access remains 100% read-only. All 46 SQL queries are SELECT / WITH...SELECT; 0 INSERT/UPDATE/DELETE/TRUNCATE/CREATE/ALTER/DROP/commit/rollback. cur.execute only fires from 2 sites (_query L815 / _query_one L845), both followed by fetchall()/fetchone().
  • All 7 bug fixes are read-only SELECT text optimizations or Python logic improvements — no schema migration, no permission changes needed. Drop in the new tesla.py and you're done.