# Kindle 市级位置方案 ## 背景 当前仓库里的天气位置来源仍在 `calendar/` 前端: - [calendar/src/lib/weather.ts](/Users/gavin/kindle-dash/calendar/src/lib/weather.ts) 会优先尝试 `navigator.geolocation` - 失败时回退到固定默认值 `杭州` 这条路径不适合当前 Kindle 运行架构,原因有两个: 1. Kindle 实机显示的不是一个在设备上实时运行的天气网页,而是先在别处渲染,再同步为背景图。 2. 如果由 Web 服务器代查 IP 位置,拿到的是服务器公网 IP,对应的是服务器所在城市,不是 Kindle 所在城市。 本方案的目标是: - 位置精度只要求到“市”颗粒度 - 位置来源应尽量接近 Kindle 当前网络出口 - 在 SSH 暂时不可用的情况下,先把方案文档明确下来,后续恢复 SSH 后再实现 ## 结论 浏览器网页定位不应继续作为主路径。 推荐改成: 1. Kindle 侧自己请求 GeoIP 接口,获取当前公网 IP 对应的城市、经纬度和时区 2. 把结果缓存到本地 3. 天气与相关展示统一读取这份缓存 4. 当 GeoIP 不可用或结果异常时,回退到 Kindle 侧固定配置的 `city/lat/lon/timezone` 这是一个“市级近似定位”方案,不是 GPS 精确定位方案。 ## 为什么 Kindle 侧 GeoIP 可行 GeoIP 的前提是“由目标设备自己发请求”。 对当前项目,正确的请求路径应该是: ```text Kindle -> GeoIP 服务 -> 返回 city / lat / lon / timezone ``` 而不是: ```text Kindle -> 你的 Web 服务 -> Web 服务代查 GeoIP ``` 后一种方式只会得到 Web 服务所在机房或服务器出口的位置。 如果 Kindle 走家庭 Wi-Fi,且只要求“市级”颗粒度,GeoIP 通常够用。 如果 Kindle 走手机热点、VPN、代理、企业网络或运营商 NAT,结果可能偏到邻近城市,必须接受这种误差。 ## 目标能力 实现后需要具备以下能力: 1. Kindle 联网后,能够自己获取当前网络出口对应的城市信息 2. 获取结果会写入本地缓存 3. 断网时仍可继续使用上次缓存 4. GeoIP 失败时可回退到固定配置 5. 只需要市级位置,不追求街道级精度 ## 推荐数据模型 建议在 Kindle 侧维护一份位置缓存文件。 路径建议: ```text /mnt/us/dashboard/local/state/location.env ``` 字段建议: ```text LOCATION_SOURCE=geoip LOCATION_CITY=杭州 LOCATION_LAT=30.274084 LOCATION_LON=120.155070 LOCATION_TIMEZONE=Asia/Shanghai LOCATION_UPDATED_AT=2026-03-17T10:00:00+08:00 ``` 同时保留一份固定兜底配置,例如: ```text LOCATION_FALLBACK_CITY=杭州 LOCATION_FALLBACK_LAT=30.274084 LOCATION_FALLBACK_LON=120.155070 LOCATION_FALLBACK_TIMEZONE=Asia/Shanghai ``` ## 运行时脚本设计 建议新增 Kindle 侧脚本: ```text dash/src/local/location-sync.sh ``` 职责: 1. 检查网络是否可用 2. 由 Kindle 自己请求 GeoIP 接口 3. 解析响应中的城市、经纬度、时区 4. 校验字段是否完整 5. 写入本地缓存 6. 失败时保留旧缓存,不要清空已有结果 建议同时新增一个只负责读取并导出环境变量的脚本,例如: ```text dash/src/local/location-env.sh ``` 职责: 1. 优先读取新鲜的 GeoIP 缓存 2. 没有新鲜缓存时读取旧缓存 3. 缓存不存在或无效时回退到固定配置 4. 对外输出统一的 `LOCATION_CITY/LAT/LON/TIMEZONE` ## 刷新策略 位置不需要高频刷新。 建议策略: 1. 启动 dashboard 且确认联网后,首次同步一次位置 2. 每 12 小时或 24 小时刷新一次 3. 手动切换主题时不强制刷新位置 4. 天气刷新与位置刷新解耦 5. 位置同步失败时继续使用现有缓存 ## 与现有架构的衔接方式 当前项目是“背景图 + Kindle 本地时钟覆盖”的架构,不是“Kindle 上实时跑完整天气网页”的架构。 因此接入位置数据时,有两条可选路径。 ### 路径 A:最小改动路径 保留当前背景图生成方式,但让背景图生成时显式读取 Kindle 侧缓存导出的城市与经纬度。 优点: - 改动面相对小 - 仍可复用现有天气卡片布局与导出流程 缺点: - 需要重新梳理“背景图生成端”如何拿到 Kindle 缓存 - 如果背景仍在 Mac 侧导出,就必须把 Kindle 缓存同步回 Mac 或转成请求参数 ### 路径 B:更符合现状的运行时路径 把“城市文本、天气数据”也逐步下沉到 Kindle 运行时,和本地时钟一样由设备端控制。 优点: - 位置与天气都由 Kindle 自己决定 - 不会再混入 Mac 浏览器位置或服务器 IP 位置 缺点: - 改动更大 - 需要重新设计天气卡的本地渲染方式 ## 当前推荐 短期推荐先做: 1. Kindle 侧 GeoIP 获取 2. 本地缓存 3. 固定配置兜底 等 SSH 恢复后,再决定位置数据如何喂给天气展示层。 也就是说,先把“位置来源”稳定下来,再改“展示方式”。 ## 实施顺序 建议按下面顺序落地: 1. 新增 `location-sync.sh` 2. 新增 `location-env.sh` 3. 在 Kindle 运行时目录中引入固定兜底配置 4. 在主循环启动阶段接入位置缓存刷新 5. 让天气读取逻辑改为优先使用 Kindle 侧位置缓存 6. 最后补文档和手动刷新命令 ## 验收标准 实现完成后,至少应满足以下验收条件: 1. Kindle 联网后可生成位置缓存文件 2. 缓存中至少包含 `city/lat/lon/timezone` 3. 断网后仍能继续使用旧缓存 4. GeoIP 失败时会稳定回退到固定城市 5. 显示出的城市与 Kindle 当前所在城市大体一致 ## 注意事项 1. GeoIP 只能提供近似位置,不要当作精确定位 2. 手机热点、VPN、代理、企业网络都会降低城市准确率 3. 城市级结果可以用于天气展示,但不适合做严格地理判断 4. 任何实现都必须保证“失败不影响 dashboard 主循环” ## 现阶段状态 当前仅完成方案设计,尚未开始代码实现。 直接原因是: - 目前 SSH 还未恢复 - 设备侧脚本还不能方便地下发、调试和验证 后续等 SSH 恢复后,再按本方案分步实施。