泥潭日报 uscardforum · 内容汇总

手搓了一个电子通勤看板

内容摘要

美卡用户分享MBTA通勤看板教程,并讨论纽约MTA数据可用性。

关键信息

  • 项目目标:为伴侣(LD)制作显示波士顿MBTA列车时间的电子看板,解决早起赶火车需求。
  • 核心硬件
    • 服务器端:24/7运行的Home Assistant设备(NAS/软路由/树莓派均可)。
    • 显示端:越狱的Kindle Paperwhite 3(第七代),屏幕分辨率1072x1448。
  • 软件生态:基于Home Assistant (HA) + MBTA Live插件获取数据,通过Lovelace卡片定制界面,利用hass-lovelace-kindle-screensaver生成截图推送到Kindle。

经验与数据点

  • API优势:波士顿MBTA API(api-v3.mbta.com)免费版支持每分钟1000次请求,性能强劲,适合高频刷新场景 #p-8404979-h-5。
  • HA配置细节
    • 需安装HACS及多个插件:MBTALive, lovelace-mushroom, card-mod, kiosk-mode, hass-lovelace-kindle-screensaver #p-8404979-home-assistant-4。
    • Dashboard布局建议选Masonry模式以保留留白,并使用Raw Configuration Editor添加hide_header: truehide_sidebar: true实现全屏显示 #p-8404979-h-5。
    • 需生成Long-lived access tokens供截屏插件使用 #p-8404979-h-5。
  • Kindle端关键设置
    • 越狱后需安装KUAL、MRPI及onlinescreensaver插件。推荐使用网友魔改的onlinescreensaverPW2版本,稳定性优于原版 #p-8404979-kindle-6。
    • 刷新策略优化:为避免Kindle频繁开关Wi-Fi导致损坏或耗电过快,建议设置差异化刷新间隔。例如早高峰(06:30-09:30)每分钟刷新一次,其余时间每10分钟刷新一次 #p-8404979-kindle-7。
    • 关闭日志记录(LOGGING=0)以延长存储寿命 #p-8404979-kindle-7。

风险/限制/注意事项

  • Kindle屏幕保护程序兼容性:网上魔改版本众多,部分为了省电无法实现1分钟高频刷新,需仔细筛选测试 #p-8404979-kindle-6。
  • 渲染延迟:插件配置中RENDERING_DELAY不建议设为0,需预留缓冲时间以防Bug #p-8404979-h-5。
  • 地域限制与数据差异:该方案高度依赖MBTA API。纽约地区用户反馈MTA信息不如MBTA全面,但仅查看未来几趟车的时间仍足够使用;长岛火车(LIRR)API支持情况尚不明确 #p-8404979-h-5, #p-8404979-kindle-3, #p-8404979-kindle-5。

闲聊脉络

  • 楼主分享了完整的“手搓”教程,强调本地搭建的优势(无刷新限制、调试方便、永久免费),并呼吁大神研究免费托管方案以惠及没有Home Server的用户 #p-8404979-h-8。
  • 回复者#2询问手机端显示效果,未展开讨论 #2
  • 后续讨论转向其他城市交通数据的可用性,用户确认纽约MTA数据虽不全但基本可用,引发对跨地域复用的探讨 #p-8404979-kindle-3, #p-8404979-kindle-5。
原始内容
--- 第 1 楼来自 Libertad 的回复 (2026-06-19 15:58:47 PDT) ---

#p-8404979-h-1前言 波士顿有最烂的基建和最好的公交API #p-8404979-h-2正文 应LD要求,用废旧Kindle手搓了一个显示列车时间的电子看板,方便LD早上赶火车。 /uploads/short-url/ifzVLmN6xb3YY5bG4mYQRK9gb6S.jpeg?dl=1 #p-8404979-h-3硬件要求 一台24x7的已安装Home Assistant的设备,NAS/软路由/树莓派随意。 一台可越狱的Kindle,随便收个便宜二手就行。本文以Paperwhite 3(官方所谓第七代)为例。 #p-8404979-home-assistant-4Home Assistant要安装的插件 先设置一下自己家的地址,确认天气预报已开启。 https://www.hacs.xyz/docs/use/download/download/ https://github.com/chiabre/MBTALive 抓取公交信息 https://github.com/piitaya/lovelace-mushroom 制作看板卡片 https://github.com/thomasloven/lovelace-card-mod 微调CSS效果 https://github.com/maykar/kiosk-mode 隐藏HA侧边栏 https://github.com/sibbl/hass-lovelace-kindle-screensaver 给Kindle生成截图。HAOS直接在 Settings -> Apps 里面安装,docker版HA需要在外面安装容器。 #p-8404979-h-5服务器端操作流程 申请一个免费的MBTA API Key:https://api-v3.mbta.com。免费版每分钟1000次请求,这个API强大得不像是美国政府部门做的。 进入HA,点击 Settings -> Devices & services -> Integrations -> Add integration ,添加一个MBTA Live设备。填入站名和API Key然后提交。 大部分传感器都默认关闭了,可参考我的选项按需打开: Alerts , Arrival Delay , Arrival Time , Departure Delay , Departure Time , Following , From , To , Upcoming . 创建一个专用的Dashboard,点击 Settings -> Dashboards -> Add dashboard -> New dashboard from scratch ,这里给它起名为 Kindle 。 进入新创建好的Dashboard,右下角 Add card -> By card 拉到最下面 Manual ,把代码粘贴进去。我不会写前端,vibe coding搓了一个适合通勤铁路的。 请根据你的传感器名称批量替换 sensor.mbta_route_128_ruggles 。 展开代码 type: vertical-stack cards: - type: horizontal-stack cards: - type: custom:mushroom-template-card primary: "{{ now().strftime('%a %b %d') }}" secondary: "{{ now().strftime('%-I:%M%p') }}" icon: mdi:calendar-month-outline card_mod: style: ha-tile-info$: | .primary { font-size: 18px !important; line-height: normal !important; } .secondary { font-size: 14px !important; line-height: normal !important; } .: | ha-tile-icon { --mdc-icon-size: 32px !important; } - type: custom:mushroom-template-card entity: weather.forecast_home primary: > {{ state_attr('weather.forecast_home', 'temperature') }}°F / {{ state_attr('weather.forecast_home', 'humidity') }}% secondary: | {{ state_translated('weather.forecast_home') }} icon: > {% set state = states('weather.forecast_home') %} {% set spec = {'clear-night': 'mdi:weather-night', 'partlycloudy': 'mdi:weather-partly-cloudy', 'lightning-rain': 'mdi:weather-lightning-rainy', 'exceptional': 'mdi:alert-circle-outline'} %} {% set std = ['sunny','cloudy','fog','rainy','pouring','lightning','snowy','snowy-rainy','hail','windy','windy-variant'] %} {{ spec.get(state, 'mdi:weather-' ~ state if state in std else 'mdi:weather-partly-cloudy') }} icon_color: grey card_mod: style: ha-tile-info$: | .primary { font-size: 18px !important; line-height: normal !important; } .secondary { font-size: 14px !important; line-height: normal !important; } .: | ha-tile-icon { --mdc-icon-size: 32px !important; } - type: custom:mushroom-template-card primary: > {% set time = states('sensor.mbta_route_128_ruggles_departure_time') | as_timestamp(0) | timestamp_custom('%-I:%M%p', true, '--:--') %} {% set d = states('sensor.mbta_route_128_ruggles_departure_delay') %} {% set txt = ' (On time)' if d|int(0) == 0 else ' (' ~ d|int ~ 'm late)' if d|int(0) > 0 else ' (' ~ d|int|abs ~ 'm early)' %} {{ states('sensor.mbta_route_128_ruggles_from') }} @ {{ time }}{{ txt if has_value('sensor.mbta_route_128_ruggles_departure_delay') else '' }} secondary: > {% set time = states('sensor.mbta_route_128_ruggles_arrival_time') | as_timestamp(0) | timestamp_custom('%-I:%M%p', true, '--:--') %} {% set d = states('sensor.mbta_route_128_ruggles_arrival_delay') %} {% set txt = ' (On time)' if d|int(0) == 0 else ' (' ~ d|int ~ 'm late)' if d|int(0) > 0 else ' (' ~ d|int|abs ~ 'm early)' %} {{ states('sensor.mbta_route_128_ruggles_to') }} @ {{ time }}{{ txt if has_value('sensor.mbta_route_128_ruggles_arrival_delay') else '' }} icon: > {% set s1, s2 = 'sensor.mbta_route_128_ruggles_departure_delay', 'sensor.mbta_route_128_ruggles_arrival_delay' %} {% set val = states(s1) if has_value(s1) else states(s2) if has_value(s2) else none %} {{ 'mdi:clock-time-outline' if val is none else 'mdi:clock-alert-outline' if val|int(0) > 0 else 'mdi:clock-fast' if val|int(0) < 0 else 'mdi:clock-check-outline' }} icon_color: > {% set s1, s2 = 'sensor.mbta_route_128_ruggles_departure_delay', 'sensor.mbta_route_128_ruggles_arrival_delay' %} {% set val = states(s1) if has_value(s1) else states(s2) if has_value(s2) else none %} {{ 'black' if val is not none and val|int(0) != 0 else 'grey' }} card_mod: style: ha-tile-info$: | .primary { font-size: 18px !important; line-height: normal !important; } .secondary { font-size: 14px !important; line-height: normal !important; } .: | ha-tile-icon { --mdc-icon-size: 32px !important; } - type: horizontal-stack cards: - type: custom:mushroom-template-card primary: > {% set time = states('sensor.mbta_route_128_ruggles_upcoming')%} {{ '-' if time == 'unavailable' else time }} secondary: null icon: mdi:train icon_color: black card_mod: style: ha-tile-info$: | .primary { font-size: 18px !important; line-height: normal !important; } .: | ha-tile-icon { --mdc-icon-size: 32px !important; } - type: custom:mushroom-template-card primary: > {% set time = states('sensor.mbta_route_128_ruggles_following')%} {{ '-' if time == 'unavailable' else time }} secondary: null icon: mdi:train icon_color: grey card_mod: style: ha-tile-info$: | .primary { font-size: 18px !important; line-height: normal !important; } .: | ha-tile-icon { --mdc-icon-size: 32px !important; } - type: custom:mushroom-template-card primary: > {{ 'No Alerts' if states('sensor.mbta_route_128_ruggles_alerts') | int(0) == 0 }} secondary: > {% set count = states('sensor.mbta_route_128_ruggles_alerts') | int(0) %} {% set text = state_attr('sensor.mbta_route_128_ruggles_alerts', 'alerts') %} {{ text if count > 0 and text }} multiline_secondary: true icon: > {{ 'mdi:alert' if states('sensor.mbta_route_128_ruggles_alerts') | int(0) > 0 else 'mdi:check-circle' }} icon_color: > {{ 'black' if states('sensor.mbta_route_128_ruggles_alerts') | int(0) > 0 else 'grey' }} card_mod: style: ha-tile-info$: | .primary { font-size: 18px !important; line-height: normal !important; } .secondary { font-size: 8px !important; line-height: normal !important; } .: | ha-tile-icon { --mdc-icon-size: 32px !important; } 现在应该能看到看板卡片了,点右上角 Edit Dashboard ,然后在左上角的 Unnamed view 点编辑,Layout选 Masonry 然后保存,这样两边有留白比较好看。如果选 Panel (single card) 是完全没有留白的。 点右上角三个点,选`Raw configuration editor`,在代码的最前面粘贴三行代码 kiosk_mode: hide_header: true hide_sidebar: true 然后保存刷新。这时候侧边栏和顶栏就全部消失了(仅限这个给Kindle专用的dashboard)。如果之后需要再编辑就要在网页地址后面添加 ?disable_km ,例如 http://[服务器IP地址]/dashboard-kindle/0?disable_km 点击左下角 用户头像->Security->Long-lived access tokens ,给截屏插件创建一个token。名字随便起,token只显示一次请保存好。 进入 Settings -> Apps -> Lovelace Kindle Screensaver -> Configuration ,填入如下信息 Item Value Comment HA_BASE_URL http://[服务器IP地址]:8123 HA默认端口8123 HA_SCREENSHOT_URL /dashboard-kindle/0 假定Dashboard名字为Kindle CRON_JOB * * * * * 假定每分钟刷新一次 RENDERING_DELAY 100 不要写0,渲染可能有延迟,容易出bug RENDERING_SCREEN_HEIGHT 1448 for Paperwhite 3 RENDERING_SCREEN_WIDTH 1072 for Paperwhite 3 ROTATION 90 横屏显示 SCALING 4 根据实际情况自己调整 IMAGE_FORMAT png COLOR_MODE GrayScale 然后保存,回 Info 面板启动插件。稍等几十秒后,访问 http://[服务器IP地址]:5000 应该能看到渲染好的旋转90度图片。 至此HA服务器端大功告成。 #p-8404979-kindle-6Kindle要安装的插件 越狱流程参考 https://bookfere.com/post/1075.html 不再赘述。确保已安装如下插件 https://www.mobileread.com/forums/showthread.php?t=225030%EF%BC%9A https://www.mobileread.com/forums/showthread.php?t=225030%EF%BC%9A Tools Snapshots of NiLuJe's hacks Kindle Developer's Corner MobileRead Package Installer (MRPI) Kindle Unified Application Launcher (KUAL) USBNetwork,并且已配置好SSH key login ScreenSavers Hack (linkss) onlinescreensaver 这个是最坑的地方,网友魔改版本众多,为了省电无所不用其极,做不到1分钟刷新一次。经试验这个很久没更新的版本反而最好用 https://github.com/Kuhno92/onlinescreensaverPW2 https://github.com/Kuhno92/onlinescreensaverPW2 Fork of the onlinescreensaver extension for PaperWhite 2 #p-8404979-kindle-7Kindle端操作流程 SSH登入Kindle后编辑 /mnt/us/extensions/onlinescreensaver/bin/config.sh # 早高峰1分钟间隔,其他时间10分钟间隔 SCHEDULE="00:00-06:30=10 06:30-09:30=1 09:30-24:00=10" IMAGE_URI="http://[服务器IP地址]:5000/" # 每分钟更新日志真的会炸 LOGGING=0 # 每分钟开关一次Wi-Fi还嫌坏的不够快? DISABLE_WIFI=0 保存退出,然后进KUAL打开auto-download,锁屏即可。 #p-8404979-h-8后记 其他城市的谭友理论上可以在此基础上修改,Home Assistant上总能找到爱好者做的插件。不过API有没有波士顿这么好用就不知道了。 本地搭建的好处是刷新无限制,调试方便,永久免费。当然看板理论上也可以托管在外面的服务器上,希望有大神能够研究出免费羊毛造福更多没有home server的谭友。

--- 第 2 楼来自 zhangs 的回复 (2026-06-19 16:04:54 PDT) ---

手机上看不一样?

--- 第 3 楼来自 美卡小白用户 的回复 (2026-06-19 16:16:05 PDT) ---

貌似纽约地铁、长岛火车没有波士顿 MBTA 这么好的 API?

--- 第 4 楼来自 Pocky 的回复 (2026-06-19 16:17:16 PDT) ---

这个牛!

--- 第 5 楼来自 Libertad 的回复 (2026-06-19 16:57:36 PDT) ---

MTA信息没这么全,不过只看未来几趟车时间还是够用的。