免费获取学习方案
ARTICLE DETAIL

资讯详情

深耕编程基础知识与建站技术分享的一线实战洞察。

基于树莓派与Chromium Kiosk模式打造DIY智能信息显示屏

基于树莓派与Chromium Kiosk模式打造DIY智能信息显示屏 1. 项目概述为什么现在动手做一块智能显示屏几年前智能音箱火得一塌糊涂但很快我就发现了一个问题很多信息光靠“听”是不够的。查个天气得等它念完一周的预报看个菜谱得在脑子里记下每一步哪怕是看个时间也得等它回应。这时候一块能“看”的屏幕就显得尤为重要。市面上的智能显示屏选择不少从大厂出品到各种“智慧屏”功能看似丰富但要么价格不菲要么被捆绑在特定的生态里你想自定义个界面、加个自己需要的小功能难。这就是“DIY Smart Display”项目的出发点。它不是一个复杂的嵌入式开发板也不是一个需要你从零写操作系统的硬核项目。它的核心思路是利用成熟的、低成本的硬件比如树莓派搭配开源的软件生态打造一块完全属于你自己、功能高度定制的智能信息终端。你可以把它想象成一块“数字画布”上面可以展示任何你关心的信息日历、待办事项、天气预报、新闻头条、智能家居控制面板甚至是你自己写的股票监控工具。它不依赖于任何商业云服务的“施舍”数据源、界面样式、交互逻辑全部由你掌控。适合谁来玩这个项目如果你对智能家居有点兴趣但又不想被品牌绑架如果你是个喜欢折腾的极客享受“创造”的乐趣或者你只是想给家里添一个实用又酷炫的电子相框兼信息中心那么这个项目再合适不过。它需要的技术门槛并不高会一点基础的Linux命令能看懂简单的配置文件就成功了一大半。整个过程更像是在组装一个高度定制化的数字乐高。2. 核心思路与方案选型软硬件的“黄金组合”动手之前先得把蓝图规划好。一个DIY智能显示屏无非是“硬件躯壳”“软件灵魂”的组合。我们的目标是在有限的预算内实现稳定、美观、可高度定制的显示效果并且易于维护和扩展。2.1 硬件选型平衡性能、成本与功耗硬件是项目的基石选型直接决定了最终体验的上限和下限。1. 核心计算单元为什么是树莓派在众多单板计算机中树莓派几乎是这个场景下的不二之选。原因有三第一生态无敌。任何你在项目中可能遇到的问题几乎都能在社区找到现成的解决方案或讨论。第二性能足够。以树莓派4B为例其CPU和GPU性能足以流畅驱动一块1080p的屏幕运行我们后续要用的轻量级图形界面毫无压力。第三接口齐全。标准的HDMI输出、USB接口、GPIO针脚为连接屏幕、触摸模块和外设提供了极大便利。注意树莓派5性能更强但功耗和发热也更高。对于常亮显示的智能屏项目如果不需要极致的性能树莓派4B或更早的3B型号在性价比和稳定性上可能是更好的选择。2. 显示屏触摸与非触摸的抉择这是影响成本和体验的关键。如果你希望它不只是“看”还能“点”比如快速切换页面、进行简单设置那么一块HDMI接口的触摸屏是必须的。市面上有大量为树莓派设计的7寸、10寸触摸屏通过排线直接连接到树莓派的DSI或GPIO口驱动成熟即插即用。 如果你的需求只是信息展示比如挂在墙上当仪表盘那么一块普通的电脑显示器、甚至利用旧笔记本的屏幕改造需要搭配驱动板成本会低很多。我个人的建议是如果预算允许优先选择触摸屏。交互带来的便利性会让这个设备的实用价值提升一个档次。3. 外壳与供电颜值与稳定的保障一块裸露着电路板的屏幕显然不适合放在客厅或厨房。3D打印一个外壳是最常见的解决方案各大模型分享网站上有无数设计可供下载。材质上PLA就够了如果追求质感和散热可以考虑PETG。 供电务必稳定。树莓派和屏幕加起来功耗不低特别是带背光的屏幕。务必使用官方推荐或质量可靠的5V/3A以上电源适配器劣质电源导致的电压不稳是系统随机重启、屏幕闪烁的罪魁祸首。4. 可选配件让体验更完整扬声器如果需要语音反馈或播放音乐一个USB小音箱或通过GPIO连接PWM音频输出模块即可。摄像头模块用于视频通话或简单的监控需注意隐私。环境光传感器通过GPIO连接可以实现屏幕亮度根据环境光自动调节非常实用。2.2 软件架构轻量、模块化与开源硬件搭好了灵魂更重要。我们的软件目标是一个始终在前台全屏运行、专注信息展示的“信息面板”应用。1. 操作系统Raspberry Pi OS Lite我们不需要桌面环境那些花哨的窗口管理器它们只会占用宝贵的内存和CPU资源。因此选择Raspberry Pi OS (原Raspbian) 的Lite版本这是一个没有图形桌面的纯命令行系统。我们将在其上直接运行我们的显示应用实现从开机到进入应用的无缝衔接。2. 显示框架为什么是Chromium Kiosk模式这是本项目的核心技巧。我们不需要自己用Qt或GTK从头开发一个图形应用。我们可以利用Chromium浏览器。具体做法是将Chromium启动为“信息亭模式”(Kiosk Mode)。原理Kiosk模式下Chromium会全屏运行隐藏所有浏览器控件地址栏、标签页等并且可以防止用户意外退出。你只需要编写一个本地的HTML页面或者让Chromium打开一个本地服务器如http://localhost:8080提供的网页。优势开发效率极高前端界面完全使用标准的HTML、CSS和JavaScript开发生态丰富学习成本低。高度可定制网页能实现的效果你的智能屏就能展示。动画、图表、交互都不在话下。易于更新更新界面只需替换HTML/JS/CSS文件甚至可以通过网络远程更新。资源隔离每个信息模块可以独立开发通过iframe或前端组件化方式集成互不干扰。3. 信息集成后端服务的角色一个只会显示静态页面的屏幕是没灵魂的。我们需要动态数据。这需要一个轻量级的后端服务来聚合数据。这里有几个选择Python Flask/Django非常灵活可以方便地编写爬虫获取天气、新闻调用智能家居API如Home Assistant处理逻辑后通过REST API提供给前端页面。Node.js Express对于熟悉JavaScript全栈的开发者更友好。直接使用Home Assistant如果你的主要目的是智能家居控制那么Home Assistant本身就是一个极其强大的平台。它提供了专门的“仪表盘”功能可以通过Kiosk模式的浏览器直接访问实现高度定制化的控制面板。在本项目中我将采用“Python Flask提供API 前端HTML页面消费API”的架构因为它足够轻量也便于演示从网络获取数据并展示的完整流程。3. 分步实操从零搭建你的智能信息屏理论说再多不如动手。下面我们一步步来我会尽量详述每个步骤的意图和可能遇到的坑。3.1 硬件组装与基础系统配置步骤1烧录系统与基础设置使用 Raspberry Pi Imager 工具选择Raspberry Pi OS Lite (64-bit)镜像烧录到SD卡。烧录完成后不要急着拔卡。在电脑上打开SD卡的boot分区做两件关键事新建一个名为ssh的空文件无后缀以启用SSH。新建一个名为wpa_supplicant.conf的文件写入你的Wi-Fi配置这样树莓派开机就能自动联网。# wpa_supplicant.conf 内容示例 ctrl_interfaceDIR/var/run/wpa_supplicant GROUPnetdev update_config1 countryCN network{ ssid你的Wi-Fi名称 psk你的Wi-Fi密码 key_mgmtWPA-PSK }将SD卡插入树莓派连接好屏幕、电源、键盘首次配置可能需要。开机。步骤2远程登录与系统更新树莓派启动后通过路由器管理界面或手机APP查找它的IP地址。在电脑上使用SSH客户端如PuTTY或终端连接ssh pi树莓派IP默认密码是raspberry。首次登录后立即修改密码passwd。更新系统这是一个好习惯sudo apt update sudo apt full-upgrade -y sudo reboot步骤3安装必要软件包我们需要安装图形界面基础、浏览器以及我们的后端框架。# 安装X11窗口系统基础图形环境 sudo apt install -y xserver-xorg x11-xserver-utils xinit # 安装Chromium浏览器和中文字体可选 sudo apt install -y chromium-browser fonts-wqy-zenhei # 安装Python3和pip以及Flask和requests库 sudo apt install -y python3 python3-pip pip3 install flask requests3.2 构建核心应用后端API服务我们的后端很简单就是一个提供数据的Flask应用。在树莓派上创建项目目录例如/home/pi/smart_display。1. 创建后端应用 (app.py)# /home/pi/smart_display/app.py from flask import Flask, jsonify from datetime import datetime import requests import json app Flask(__name__) # 示例1获取系统时间和简单问候语 app.route(/api/system_info) def system_info(): now datetime.now() hour now.hour if 5 hour 12: greeting 上午好 elif 12 hour 18: greeting 下午好 else: greeting 晚上好 return jsonify({ time: now.strftime(%H:%M), date: now.strftime(%Y年%m月%d日), greeting: greeting }) # 示例2获取天气信息这里以和风天气API为例你需要申请自己的key # 注意任何API调用都可能失败前端需要处理错误 app.route(/api/weather) def weather(): # 此处应替换为你自己的API Key和城市ID api_key YOUR_HEFENG_API_KEY city_id 101010100 # 北京 url fhttps://devapi.qweather.com/v7/weather/now?location{city_id}key{api_key} try: response requests.get(url, timeout5) data response.json() if data[code] 200: weather_data { temp: data[now][temp], text: data[now][text], humidity: data[now][humidity], windDir: data[now][windDir] } return jsonify(weather_data) else: return jsonify({error: 天气数据获取失败}), 500 except Exception as e: return jsonify({error: str(e)}), 500 # 可以继续添加更多API如新闻、日历事件等 if __name__ __main__: # 监听所有接口端口8080 app.run(host0.0.0.0, port8080, debugFalse) # 生产环境务必关闭debug实操心得API Key等敏感信息不要硬编码在代码里。可以创建一个config.py文件通过.gitignore忽略或者使用环境变量来管理。这里为了演示简化了。2. 测试后端服务运行python3 app.py然后在同一网络的电脑浏览器访问http://树莓派IP:8080/api/system_info应该能看到返回的JSON数据。这说明后端服务正常。3.3 构建核心应用前端显示界面前端是一个独立的HTML页面它会通过JavaScript定时调用后端API更新显示内容。1. 创建前端页面 (index.html)!DOCTYPE html html langzh-CN head meta charsetUTF-8 meta nameviewport contentwidthdevice-width, initial-scale1.0 title我的智能显示屏/title style * { margin: 0; padding: 0; box-sizing: border-box; } body { font-family: WenQuanYi Zen Hei, sans-serif; background: linear-gradient(135deg, #1a1a2e 0%, #16213e 100%); color: #e6e6e6; height: 100vh; display: flex; flex-direction: column; padding: 20px; overflow: hidden; } .header { display: flex; justify-content: space-between; align-items: flex-start; margin-bottom: 30px; } .greeting-section h1 { font-size: 3.5rem; margin-bottom: 5px; } .greeting-section .date { font-size: 1.8rem; color: #a0a0a0; } .time-section { text-align: right; } .time { font-size: 5rem; font-weight: bold; letter-spacing: 2px; } .main-content { display: flex; flex: 1; gap: 20px; } .widget { background: rgba(255, 255, 255, 0.08); border-radius: 20px; padding: 25px; flex: 1; backdrop-filter: blur(10px); border: 1px solid rgba(255,255,255,0.1); } .widget h2 { font-size: 1.8rem; margin-bottom: 20px; color: #4fc3f7; border-bottom: 2px solid #4fc3f7; padding-bottom: 8px; } .weather-info { font-size: 2.5rem; text-align: center; margin-top: 15px; } .weather-info .temp { font-size: 4rem; font-weight: bold; } .error { color: #ff6b6b; text-align: center; padding: 20px; } /style /head body div classheader div classgreeting-section h1 idgreeting你好/h1 div classdate idcurrentDate/div /div div classtime-section div classtime idcurrentTime--:--/div /div /div div classmain-content div classwidget h2天气状况/h2 div idweatherContainer div classweather-info div classtemp idweatherTemp--/div div idweatherText加载中.../div div idweatherExtra湿度: -- | 风向: --/div /div /div /div !-- 可以在这里添加更多.widget比如日历、新闻等 -- div classwidget h2待办事项/h2 div idtodoList待办事项功能预留位置/div /div /div script const API_BASE http://localhost:8080/api; // 后端服务地址 // 更新时间和问候语 function updateSystemInfo() { fetch(${API_BASE}/system_info) .then(response response.json()) .then(data { document.getElementById(currentTime).textContent data.time; document.getElementById(currentDate).textContent data.date; document.getElementById(greeting).textContent data.greeting; }) .catch(err { console.error(获取系统信息失败:, err); // 如果API失败可以尝试用前端时间兜底 const now new Date(); document.getElementById(currentTime).textContent now.toLocaleTimeString(zh-CN, {hour12: false, hour:2-digit, minute:2-digit}); document.getElementById(currentDate).textContent now.toLocaleDateString(zh-CN); }); } // 更新天气信息 function updateWeather() { fetch(${API_BASE}/weather) .then(response { if (!response.ok) throw new Error(HTTP ${response.status}); return response.json(); }) .then(data { if (data.error) { throw new Error(data.error); } document.getElementById(weatherTemp).textContent ${data.temp}°C; document.getElementById(weatherText).textContent data.text; document.getElementById(weatherExtra).textContent 湿度: ${data.humidity}% | 风向: ${data.windDir}; }) .catch(err { console.error(获取天气失败:, err); document.getElementById(weatherText).textContent 天气数据暂时不可用; document.getElementById(weatherExtra).textContent ; }); } // 页面加载后初始化 document.addEventListener(DOMContentLoaded, () { updateSystemInfo(); updateWeather(); // 每秒更新时间 setInterval(updateSystemInfo, 1000); // 每10分钟更新一次天气避免频繁调用API setInterval(updateWeather, 10 * 60 * 1000); }); // 防止页面因长时间不操作而休眠部分浏览器行为 document.addEventListener(mousemove, () {}); setInterval(() { if (document.hidden) { // 如果页面被隐藏理论上Kiosk模式不会尝试重新加载 // location.reload(); } }, 3600000); // 每小时检查一次 /script /body /html将这个文件也保存在/home/pi/smart_display/目录下。3.4 关键一步配置自动启动与Kiosk模式这是让设备“像一台电器一样工作”的关键。我们需要让树莓派开机后自动启动后端服务并让Chromium以全屏Kiosk模式打开我们的前端页面。1. 创建启动脚本创建一个启动脚本用于同时启动后端服务和前端浏览器。# /home/pi/smart_display/start_display.sh #!/bin/bash # 进入项目目录 cd /home/pi/smart_display # 启动后端Flask服务将其放入后台运行 python3 app.py # 等待几秒确保后端服务已经启动 sleep 5 # 启动Chromium进入Kiosk模式打开本地页面 # --kiosk: 全屏模式无浏览器控件 # --noerrdialogs: 不显示错误对话框 # --disable-infobars: 禁用信息栏 # --check-for-update-interval31536000: 禁用自动更新检查 # --incognito: 隐身模式避免缓存或cookies干扰 chromium-browser --kiosk http://localhost:8080/static/index.html --noerrdialogs --disable-infobars --check-for-update-interval31536000 --incognito给脚本执行权限chmod x /home/pi/smart_display/start_display.sh2. 配置系统自动启动使用systemd这是最可靠的方式。创建一个systemd服务单元文件。sudo nano /etc/systemd/system/smart-display.service写入以下内容[Unit] DescriptionSmart Display Service Aftergraphical.target network-online.target Wantsnetwork-online.target [Service] Typesimple Userpi WorkingDirectory/home/pi/smart_display ExecStart/bin/bash /home/pi/smart_display/start_display.sh Restarton-failure RestartSec10 # 防止服务因日志过多导致问题 StandardOutputjournal StandardErrorjournal EnvironmentDISPLAY:0 [Install] WantedBymulti-user.target重要提示Aftergraphical.target确保了在图形系统准备就绪后才启动我们的服务。EnvironmentDISPLAY:0指定了图形显示的目标。3. 启用服务并测试# 重新加载systemd配置 sudo systemctl daemon-reload # 启用服务使其开机自启 sudo systemctl enable smart-display.service # 立即启动服务进行测试 sudo systemctl start smart-display.service # 查看服务状态和日志 sudo systemctl status smart-display.service journalctl -u smart-display.service -f如果一切正常你应该能看到Chromium以全屏模式启动并显示你制作的界面。后端服务也在运行。4. 优化禁用屏幕保护与睡眠为了防止屏幕自动关闭或休眠需要禁用相关的电源管理。# 禁用屏幕保护如果安装了 sudo apt install -y x11-xserver-utils # 设置屏幕永不休眠针对X11 sudo nano /etc/X11/xorg.conf.d/10-screen.conf如果文件不存在就创建添加Section ServerFlags Option BlankTime 0 Option StandbyTime 0 Option SuspendTime 0 Option OffTime 0 EndSection此外还可以设置树莓派本身不休眠# 编辑lightdm配置如果使用的话或者直接设置console blank sudo nano /etc/lightdm/lightdm.conf # 在[Seat:*]部分添加 xserver-commandX -s 0 -dpms-s 0禁用屏幕保护-dpms禁用DPMS显示电源管理信号。4. 功能扩展与深度定制思路基础框架搭好后这个屏幕的潜力才刚开始。你可以根据个人需求无限扩展。4.1 集成智能家居控制如果你使用Home Assistant这是最完美的搭配。有两种方式直接嵌入HA面板在Flask后端做一个代理或者直接让前端页面通过iframe嵌入Home Assistant的某个特定仪表盘视图。你需要处理HA的认证可以使用长效访问令牌。通过HA APIHome Assistant提供了强大的REST API。你可以在Flask后端调用这些API获取设备状态、控制开关然后在前端用更自定义的UI展示出来。这样界面风格可以和你现有的信息屏完全统一。4.2 添加更多信息模块日历与日程集成Google Calendar或Outlook Calendar API显示今日日程。新闻聚合调用新闻API如NewsAPI滚动显示头条。系统监控在Flask后端读取树莓派的CPU温度、负载、内存使用情况并在前端展示。公共交通显示附近地铁、公交的到站时间需要本地交通API。自定义提醒结合后端数据库实现简单的便签或提醒事项功能。4.3 界面美化与交互优化使用前端框架可以考虑使用Vue.js或React来管理更复杂的界面状态使代码更模块化。CSS动画为数据更新添加平滑的过渡动画提升视觉体验。多页面/轮播如果信息太多可以设计多个页面通过触摸滑动或定时轮播切换。语音反馈进阶结合树莓派的音频输出和语音合成库如pyttsx3在特定事件如闹钟时发出语音提示。5. 常见问题与排查实录在实际搭建过程中你几乎一定会遇到下面这些问题。5.1 Chromium启动问题问题执行启动脚本后屏幕黑屏或闪烁后退回命令行。排查首先检查服务状态sudo systemctl status smart-display.service看是否有错误信息。查看详细日志journalctl -u smart-display.service -e。常见错误是找不到DISPLAY。确保脚本中包含了EnvironmentDISPLAY:0并且服务是在图形环境就绪后启动Aftergraphical.target。手动在树莓派命令行接显示器状态下执行startx 启动一个基础的X会话然后再手动运行启动脚本中的Chromium命令看能否启动。这能帮助判断是环境问题还是命令问题。5.2 触摸屏校准与旋转问题触摸位置不准或者屏幕方向不对。解决旋转可以在/boot/config.txt中设置显示旋转例如display_rotate2表示旋转180度。对于触摸屏旋转后触摸坐标可能不对应需要同时校准触摸。校准安装触摸校准工具sudo apt install xinput-calibrator。然后在X环境下运行xinput_calibrator按照提示完成四点校准。校准后的参数可以通过创建/etc/X11/xorg.conf.d/99-calibration.conf文件永久生效。具体参数会在校准程序最后输出。5.3 网络API调用失败问题天气、新闻等模块显示“加载失败”。排查检查树莓派网络ping -c 4 114.114.114.114。检查后端服务日志Flask服务运行时的输出会打印在journalctl日志里查看是否有Python异常比如requests超时、API Key无效等。在前端浏览器检查在树莓派上如果还能操作按CtrlShiftI打开开发者工具查看“网络”(Network)标签页看对/api/weather的请求是否返回错误状态码如403、500。这能快速定位是前端请求问题还是后端API问题。加入重试与降级逻辑如前面前端代码所示一定要用try...catch捕获错误并设置一个合理的超时时间。对于非核心信息显示一个友好的错误提示如“数据暂不可用”比一个一直转圈的加载图标体验更好。5.4 系统稳定性与内存管理问题运行几天后系统变慢或Chromium崩溃。预防与解决禁用不必要的服务Lite系统本身很干净但还可以进一步用sudo raspi-config或systemctl disable关掉蓝牙、Avahi等用不到的服务。Chromium内存泄漏这是Chromium的老问题。在启动Chromium的命令中加入--disable-dev-shm-usage和--disable-accelerated-2d-canvas有时能缓解。最根本的解决方案是定期自动重启。可以加一个cron任务每周在凌晨自动重启树莓派sudo crontab -e添加0 4 * * 0 /sbin/reboot每周日早上4点重启。监控资源可以在前端页面的角落用小字显示树莓派的CPU温度和内存使用率便于日常观察。5.5 开机启动顺序竞争问题有时开机后网络还没完全准备好后端服务或Chromium就开始启动导致连接失败。解决在systemd服务文件中我们使用了Afternetwork-online.target和Wantsnetwork-online.target。但这还不够可以在启动脚本start_display.sh的开头增加一个网络检查循环# 等待网络连接 while ! ping -c 1 -W 2 114.114.114.114 /dev/null 21; do echo 等待网络连接... sleep 2 done echo 网络已连接。这样能确保在尝试启动应用前网络是通的。这个项目最大的乐趣在于它永远没有“完成”的那一刻。今天加个天气明天加个日历后天把界面重新设计一遍。它就像你数字生活的一个物理化锚点静静地展示着你关心的信息。我自己的那块屏已经稳定运行了一年多从最初的简单时间天气到现在集成了智能家居控制、下班公交倒计时、甚至还有我自定义的每日一句它已经成了家里不可或缺的一部分。动手的过程就是学习、创造和解决问题的过程而这正是DIY的精髓所在。
返回列表