1. 项目概述一个低功耗的物联网数据看板如果你和我一样对硬件编程和物联网项目充满热情同时又希望自己的作品既有实用价值又能作为一件独特的桌面摆件那么这个项目绝对值得一试。我们这次要做的是一个基于Adafruit MagTag开发板和CircuitPython的疫苗接种数据追踪器。它的核心功能很简单通过Wi-Fi自动从公开数据源获取最新的疫苗接种率数据然后在一块低功耗的电子墨水屏上清晰、直观地显示出来。这个项目的魅力在于它的“静默”与“智能”。想象一下一个挂在冰箱上或立在办公桌旁的磁吸式小设备它不需要你频繁操作甚至大部分时间都在深度睡眠以节省电量。但每天它都会“醒来”一次默默地连接网络抓取最新的数据更新屏幕然后再次“睡去”。电子墨水屏的特性使得它在更新后即使断电信息也依然清晰可见这完美契合了长期、低功耗显示的需求。对于关注公共卫生数据、喜欢量化生活或者单纯想打造一个个性化信息终端的硬件爱好者来说这是一个绝佳的练手项目。我们将使用ESP32-S2这颗强大的Wi-Fi微控制器作为大脑它集成了丰富的网络协议栈让联网变得异常简单。而CircuitPython则大大降低了编程门槛你无需复杂的开发环境配置只需像操作U盘一样拖拽代码文件即可完成编程。整个项目融合了硬件选型、嵌入式编程、网络通信和数据可视化是一次非常全面的物联网开发实践。接下来我会带你从零开始一步步完成这个酷炫的小装置。2. 核心硬件与工具选型解析工欲善其事必先利其器。在动手之前我们先来详细拆解一下这个项目需要用到的核心硬件以及为什么选择它们。理解这些背后的考量能帮助你在未来设计自己的项目时做出更明智的决策。2.1 核心硬件Adafruit MagTag项目的核心是Adafruit MagTag开发板。它不是一个简单的ESP32开发板而是一个高度集成、开箱即用的物联网显示终端解决方案。选择它主要基于以下几个关键优势ESP32-S2 微控制器这是板子的“心脏”。ESP32-S2是乐鑫推出的一款单核、高集成度的Wi-Fi SoC。相比经典的ESP32它去掉了蓝牙功能但增强了USB OTG和支持并且在低功耗管理上更为出色。对于这个只需要Wi-Fi联网的项目来说它是性价比和功耗的完美平衡点。其内置的Wi-Fi模块支持802.11 b/g/n协议足以稳定连接家庭路由器。2.9英寸灰度电子墨水屏这是项目的“脸面”。电子墨水屏E-Ink的特性是仅在刷新图像时耗电静态显示时功耗几乎为零。这意味着我们的设备可以显示信息长达数周甚至数月而无需充电。2.9英寸、296x128的分辨率对于显示几行文本和进度条来说清晰度完全足够。灰度显示黑白虽然不如彩色炫酷但对比度高在环境光下阅读体验极佳且驱动更简单刷新速度更快。一体化设计与内置传感器MagTag将显示屏、ESP32-S2、锂电池管理电路、四个RGB NeoPixel LED、三个按钮和一个光线传感器全部集成在一块紧凑的PCB上。这种一体化设计极大简化了我们的搭建过程无需自己焊接屏幕排线、连接电池等降低了硬件门槛。四个角落的磁吸脚垫孔位也让最终成品的安装变得非常优雅。CircuitPython 原生支持Adafruit官方为MagTag提供了完善的CircuitPython库支持adafruit_magtag封装了屏幕驱动、网络连接、深度睡眠等复杂操作让我们可以用几行简单的Python代码就调用高级功能这是快速原型开发的关键。2.2 必备配件清单除了MagTag主板我们还需要一些外围配件来让它真正工作起来锂电池推荐使用3.7V容量在350mAh到500mAh之间的锂聚合物电池。我实测一块420mAh的电池在每天刷新一次屏幕、深度睡眠的模式下可以轻松工作数周。电池通过板载的JST PH连接器接入自带充放电保护电路。USB-C 数据线用于给板子供电、编程和充电。务必确认这是一条支持数据传输的USB线很多廉价的充电线只有电源线会导致电脑无法识别设备这是新手最容易踩的坑。磁吸脚垫这是实现“冰箱贴”功能的关键。Adafruit有配套的Mini Magnet Feet可以直接拧在板子四个角的螺丝孔上吸附力足够强。注意在购买或使用电池时请务必遵循安全规范。不要使用鼓包、破损的电池充电时最好有人看管并避免在极端温度下使用或存放。2.3 软件与环境准备软件开发环境极其简单这要归功于CircuitPython的设计哲学代码编辑器任何能编辑纯文本的软件都可以例如VS Code、Thonny、Mu Editor甚至系统自带的记事本。我个人推荐VS Code因为它对Python语法高亮和代码提示支持很好而且可以通过插件连接串口监视器。串口终端软件用于查看板子运行时打印的调试信息。在CircuitPython中连接USB后设备会作为一个串口出现。你可以使用Mu Editor内置了串口监视器对CircuitPython新手最友好。VS Code配合PlatformIO IDE或相关串口插件。系统自带的终端工具如screen(macOS/Linux) 或Putty(Windows)。硬件和软件准备就绪后我们就可以开始给MagTag注入灵魂——安装CircuitPython固件了。3. CircuitPython 固件安装与网络配置详解这是让硬件“活”起来的第一步。我们将把CircuitPython解释器刷写到ESP32-S2的闪存中并配置Wi-Fi连接。整个过程就像给一台新电脑安装操作系统并连接网络。3.1 固件下载与刷写方法首先访问CircuitPython官网的MagTag下载页面。这里你会看到两个关键文件.UF2和.BIN。.UF2格式是Adafruit推广的一种便捷刷机格式而.BIN是传统的二进制镜像文件。对于绝大多数2023年后生产的MagTag正面PCB为黑色我强烈推荐使用UF2 Bootloader 方式这是最无脑的方法用USB线连接MagTag和电脑。按住板载的“Reset”按钮位于USB-C口旁边再松开然后快速双击它。如果操作成功电脑上会出现一个名为MAGTAGBOOT的U盘。将下载好的.UF2文件直接拖拽或复制到这个MAGTAGBOOT盘里。复制完成后板子会自动重启。几秒钟后电脑上会出现一个新的U盘名为CIRCUITPY。恭喜CircuitPython系统已经安装成功这个CIRCUITPY盘就是你未来的代码和文件存储区。如果你的MagTag是比较早期的版本正面PCB为白色它可能没有预装UF2引导程序。这时你需要使用esptool这个命令行工具来刷写.BIN文件。这需要你在电脑上安装Python和esptool库 (pip install esptool)然后通过指定串口号来刷机。虽然步骤稍多但Adafruit的教程写得非常详细按部就班即可。实操心得双击Reset键进入Bootloader的时机需要练习一两次。如果没出现MAGTAGBOOT盘多试几次重点在“快速双击”。如果始终不行再考虑使用esptool方式。3.2 核心配置文件settings.toml 的秘密CircuitPython系统启动后会自动运行CIRCUITPY根目录下的code.py文件。但在运行任何网络相关的代码前我们必须先配置Wi-Fi。为了安全地管理密码等敏感信息CircuitPython采用了settings.toml文件。这个文件的作用是将配置信息与代码分离。你的Wi-Fi密码、API密钥等私密数据都写在这里而code.py里通过os.getenv()函数来读取。这样当你把代码分享到GitHub或论坛时只需要分享code.py而无需暴露自己的隐私信息。在CIRCUITPY根目录下用文本编辑器新建或打开settings.toml文件填入以下内容# 你的Wi-Fi网络名称和密码 CIRCUITPY_WIFI_SSID 你的Wi-Fi名称 CIRCUITPY_WIFI_PASSWORD 你的Wi-Fi密码 # 用于获取网络时间的Adafruit IO账户信息后续需要 ADAFRUIT_AIO_USERNAME 你的Adafruit IO用户名 ADAFRUIT_AIO_KEY 你的Adafruit IO Active Key # 你的时区用于正确显示本地时间 TIMEZONE Asia/Shanghai # 例如上海关键点解析CIRCUITPY_WIFI_SSID和CIRCUITPY_WIFI_PASSWORD是CircuitPython固件约定的环境变量名用于自动连接Wi-Fi。变量名必须完全一致。TIMEZONE的字符串必须遵循IANA时区数据库的格式如 “America/New_York”, “Europe/London”。你可以去 worldtimeapi.org/timezones 查找你所在城市对应的正确字符串。3.3 网络连接测试与排错配置好settings.toml后我们可以运行一个简单的网络测试脚本来验证一切是否正常。将以下代码保存为CIRCUITPY盘根目录下的code.pyimport os import wifi import socketpool import adafruit_requests import ssl print(MagTag 网络连接测试) print(MAC地址:, [hex(i) for i in wifi.radio.mac_address]) # 扫描并列出附近的Wi-Fi网络可选用于诊断 print(正在扫描网络...) for network in wifi.radio.start_scanning_networks(): print(f\t{str(network.ssid, utf-8)}\t信号强度: {network.rssi}) wifi.radio.stop_scanning_networks() # 从 settings.toml 读取配置并连接 ssid os.getenv(CIRCUITPY_WIFI_SSID) password os.getenv(CIRCUITPY_WIFI_PASSWORD) print(f正在连接网络: {ssid}) wifi.radio.connect(ssid, password) print(连接成功) print(f本机IP地址: {wifi.radio.ipv4_address}) # 测试网络连通性ping 一个公共DNS import ipaddress ping_ip ipaddress.IPv4Address(8.8.8.8) ping_time wifi.radio.ping(ping_ip) if ping_time is not None: print(f网络通畅ping 谷歌DNS耗时: {ping_time * 1000:.0f} ms) else: print(警告ping 测试失败但可能仍可连接互联网。) # 尝试发起一个简单的HTTP请求 pool socketpool.SocketPool(wifi.radio) requests adafruit_requests.Session(pool, ssl.create_default_context()) try: response requests.get(http://httpbin.org/get) print(fHTTP请求测试成功状态码: {response.status_code}) except Exception as e: print(fHTTP请求失败: {e}) print(网络测试完成。)保存文件后MagTag会自动重启并运行。打开串口监视器如Mu Editor你就能看到详细的输出日志。如果看到“连接成功”和“网络通畅”那么恭喜你硬件和基础网络环境已经完美就绪。常见问题排查连接超时/失败首先检查settings.toml中的SSID和密码是否正确注意大小写。其次检查路由器是否设置了MAC地址过滤或隐藏了SSIDCircuitPython默认不支持连接隐藏网络。无法获取IP地址可能是路由器DHCP服务器问题尝试重启路由器或者检查Wi-Fi信号强度是否太弱。串口无输出检查USB线是否支持数据传输尝试按一下Reset键或换一个USB口。在设备管理器中查看是否正确识别了串行端口。4. 疫苗接种追踪器代码深度剖析与定制网络通了我们就可以开始实现核心功能获取数据并显示。原项目代码已经提供了一个很好的框架但知其然更要知其所以然。我们来逐段拆解并探讨如何定制它以适应你自己的需求。4.1 项目库文件与依赖管理在CircuitPython中第三方库以.mpy或.py文件的形式存放在CIRCUITPY盘的lib文件夹下。对于这个项目我们需要以下库adafruit_magtag.mpyMagTag硬件抽象层库封装了屏幕、网络、睡眠等所有硬件操作。adafruit_progressbar.mpy用于在屏幕上绘制进度条。adafruit_requests.mpy用于发起HTTP网络请求。adafruit_io.mpy可选如果使用Adafruit IO服务获取时间则需要。最方便的方法是直接下载Adafruit提供的项目包Project Bundle。这是一个zip文件里面包含了code.py和所有必需的库文件。解压后将整个lib文件夹和code.py复制到CIRCUITPY根目录即可。这是管理CircuitPython项目依赖最推荐的方式避免了手动寻找和下载不同版本库文件的麻烦。4.2 核心代码逻辑拆解让我们深入看一下核心的code.py理解每一部分在做什么1. 初始化与数据源定义from adafruit_magtag.magtag import MagTag from adafruit_progressbar.progressbar import ProgressBar DATA_SOURCE https://raw.githubusercontent.com/owid/covid-19-data/master/public/data/vaccinations/country_data/United%20States.csv magtag MagTag(urlDATA_SOURCE) magtag.network.connect()DATA_SOURCE定义了数据的来源URL。这里指向Our World in Data项目在GitHub上维护的CSV文件包含了美国按日的疫苗接种数据。这是整个项目的关键你可以通过修改这个URL来追踪不同国家或地区的数据。MagTag对象的初始化非常简洁传入URL后后续的fetch()方法就会自动从这里获取数据。2. 用户界面布局设计代码通过多次调用magtag.add_text()在屏幕上预定义了四个文本显示区域分别用于显示标题、日期、接种率文本和完全接种率文本。每个区域都指定了字体、位置和对齐点。magtag.add_text( text_font/fonts/ncenR14.pcf, # 使用内置的字体文件 text_position((magtag.graphics.display.width // 2) - 1, 8), # 屏幕水平居中纵坐标8像素 text_anchor_point(0.5, 0.5), # 文本的中心点对齐到上面设定的位置 is_dataFalse, # 这个文本不是从网络数据直接填充的 )紧接着代码创建了两个ProgressBar对象用来图形化地展示接种进度。这里计算了进度条在屏幕上的位置和尺寸确保其居中显示。3. 数据获取、解析与显示这是最核心的try代码块try: # 1. 获取并解析数据 table magtag.fetch().split(\n) # 获取CSV文本并按行分割 latest table[-2].split(,) # 取倒数第二行最后一行可能是空行并按逗号分割成列表 # 假设CSV列顺序为location, date, total_vaccinations, people_vaccinated, people_fully_vaccinated... location latest[0] date latest[1] people_vaccinated int(latest[3]) # 注意索引需根据实际CSV列调整 people_fully_vaccinated int(latest[4]) # 2. 计算百分比 (以美国人口约3.32亿为例) total_population 331984513 vaccinated_pct people_vaccinated / total_population fully_vaccinated_pct people_fully_vaccinated / total_population # 3. 更新屏幕内容 magtag.set_text(f{location} Vaccination Rates, 0, False) # 标题 magtag.set_text(date, 1, False) # 日期 magtag.set_text(fVaccinated: {vaccinated_pct:.2%}, 2, False) # 接种率文本 magtag.set_text(fFully Vaccinated: {fully_vaccinated_pct:.2%}, 3, False) # 完全接种率文本 # 4. 更新进度条 progress_bar.progress vaccinated_pct progress_bar_1.progress fully_vaccinated_pct # 5. 刷新电子墨水屏 magtag.refresh() # 6. 进入深度睡眠24小时 SECONDS_TO_SLEEP 24 * 60 * 60 magtag.exit_and_deep_sleep(SECONDS_TO_SLEEP)关键逻辑magtag.fetch()这个方法封装了HTTP GET请求从DATA_SOURCE获取原始数据。数据解析原始数据是CSV格式我们需要按行和列进行分割。这里有一个潜在的坑CSV中如果字段内包含逗号会用引号包裹。原项目的l_split函数就是用来处理这种情况的健壮解析方法。如果数据源格式简单直接用split(,)也可以。百分比计算分母是固定的人口总数。这是需要根据你追踪的地区手动修改的重要参数你必须查找对应国家或地区的准确人口数据。magtag.refresh()这是更新电子墨水屏显示的命令。电子墨水屏刷新相对较慢约2-4秒且全屏刷新会有闪烁。adafruit_magtag库已经做了优化但刷新过程仍然可见。magtag.exit_and_deep_sleep()这是实现超低功耗的关键。调用此函数后ESP32-S2会进入深度睡眠模式此时绝大部分电路关闭功耗可低至10微安左右。定时器会在设定的秒数这里是24小时后唤醒芯片从头开始执行code.py。4. 异常处理except块用于捕获网络错误、数据解析错误等。一旦出错它会打印错误信息并设置一个较短的睡眠时间例如1小时然后重试。这保证了设备在网络不稳定或数据源暂时不可用时具备自我恢复的能力。4.3 如何定制你的追踪器原项目追踪的是美国数据。你可以轻松地将其改造成追踪任何提供类似CSV格式数据的地域。更换数据源去DATA_SOURCE指向的GitHub仓库Our World in Data在country_data或us_state_data文件夹下找到你感兴趣的国家或地区的CSV文件替换URL即可。例如将United%20States.csv改为Germany.csv。更新人口基数在计算百分比的代码行中将331984513替换为你所追踪地区的准确人口估计数。可以在世界银行或联合国数据网站找到。调整显示内容你可以修改magtag.add_text和magtag.set_text来显示不同的指标比如“总接种剂量”、“每日新增”等只要数据源CSV中有对应的列。修改更新频率修改SECONDS_TO_SLEEP变量。例如设置为6 * 60 * 60就是每6小时更新一次。注意电子墨水屏有刷新寿命通常几十万次过于频繁的刷新会缩短屏幕寿命且对于疫苗接种这种日更数据来说意义不大。5. 功耗优化、部署与进阶玩法项目基本功能完成后我们还需要考虑如何让它更稳定、更省电以及如何玩出更多花样。5.1 深度睡眠与功耗管理实战MagTag的深度睡眠功能是其长续航的灵魂。在深度睡眠期间只有RTC实时时钟和极少数电路在工作ESP32-S2的主CPU和Wi-Fi模块是完全关闭的。唤醒后程序从code.py的第一行重新开始执行。实测功耗数据活跃状态Wi-Fi连接、刷新屏幕峰值电流可达~150mA但持续时间很短约10-20秒。深度睡眠状态电流可降至~20μA左右。续航估算以420mAh电池为例假设每天工作30秒消耗约 0.15A * (30/3600)h ≈ 0.00125 Ah睡眠23.9小时消耗约 0.00002A * 23.9h ≈ 0.000478 Ah。每日总耗电约 0.00173 Ah。理论续航可达 420mAh / 0.00173 Ah/天 ≈243天。实际受电池自放电、温度等因素影响维持1-3个月是完全可以期待的。优化建议减少不必要的刷新确保只在获取新数据并需要更新显示时才调用magtag.refresh()。优化网络连接时间在magtag.network.connect()前确保Wi-Fi信号良好。信号弱会导致重试和连接超时增加功耗。使用更高效的请求如果数据源支持可以尝试只请求增量数据或使用更轻量的数据格式如JSON减少网络传输时间和数据解析时间。5.2 部署与安装建议电池安装将锂电池的JST插头牢固地插入MagTag背面的电池插座。注意正负极不要反接通常红线为正。磁吸脚垫安装将四个磁吸脚垫用附带的螺丝固定在板子四角。现在你的追踪器就可以牢牢吸附在任何铁质表面上了比如冰箱、文件柜、白板等。首次上电与测试连接USB线供电观察串口输出确认设备能正常启动、联网、获取数据并显示。然后拔掉USB线让电池供电。设备应该执行一次完整流程后进入睡眠。你可以等待设定的睡眠时间过后观察它是否能自动唤醒并再次更新。放置位置选择一个Wi-Fi信号稳定的位置。电子墨水屏在光线充足的环境下显示效果最佳避免阳光直射导致高温。5.3 项目扩展与进阶思路这个项目是一个完美的起点你可以基于它拓展出更多有趣的应用追踪其他数据空气质量指数AQI、股市指数、加密货币价格、天气预报、待办事项、日历事件等。只要你能找到提供简单API最好是返回JSON或CSV的数据源就可以替换DATA_SOURCE和解析逻辑。美化界面利用adafruit_display_text和adafruit_bitmap_font库使用更漂亮的字体或者加载自定义的位图背景支持BMP格式。你甚至可以用四个RGB LED来显示数据状态比如用颜色表示空气质量等级。交互功能MagTag有三个按钮。你可以修改代码使其在按下按钮时强制刷新数据或者切换显示不同的数据视图。多数据源聚合编写更复杂的代码从多个API获取数据经过计算如平均值、趋势后再显示。使用Adafruit IO除了直接抓取公开数据你还可以将MagTag作为Adafruit IO的客户端订阅Subscribe其他设备发布Publish的数据流构建更复杂的物联网仪表盘。5.4 常见问题与故障排除实录在开发和部署过程中你可能会遇到以下问题这里是我的排查记录屏幕刷新后残留鬼影现象更新后上一屏的内容有淡淡的残留。原因电子墨水屏的物理特性导致尤其是局部刷新时。解决adafruit_magtag库在refresh()时默认会进行全屏刷新以清空残影。如果问题严重可以尝试在代码中偶尔比如每第10次刷新调用magtag.display.refresh()时传入full_updateTrue参数如果库支持强制全刷。或者设计界面时避免大面积黑白频繁切换。深度睡眠后无法唤醒现象设备睡下去就再也没醒过来。排查首先检查电池电量是否充足。用万用表测量电池电压低于3.3V可能就无法正常启动了。检查代码中exit_and_deep_sleep()的参数是否正确单位是秒。确保没有在深度睡眠前关闭了必要的唤醒源对于MagTag通常使用RTC定时器唤醒库已处理好。解决连接USB线通过串口监视器查看睡眠前的最后一条打印信息确认睡眠指令已执行。然后尝试短按Reset键看设备是否能被手动唤醒并重新运行。网络请求经常失败现象频繁进入except块睡眠时间缩短为1小时。排查串口打印的错误信息是什么是连接超时、DNS解析失败还是HTTP错误码检查Wi-Fi信号强度RSSI。可以在连接前打印出来看看。数据源URL是否依然有效尝试在电脑浏览器中直接访问该URL。解决增强Wi-Fi信号或调整设备位置。在代码中增加重试机制。例如在try块内用循环包裹magtag.fetch()失败后延迟几秒重试2-3次再最终失败才进入异常处理。考虑使用更稳定的数据源或者添加备用数据源。电池消耗过快现象理论上能撑几个月结果几周就没电了。排查用电流表串联测量深度睡眠时的实际电流确认是否真的在20μA左右。如果过高可能是硬件故障或代码中某个外设如LED没有关闭。检查更新频率是否被意外改得很短。是否处于信号极差的环境设备可能会不断尝试重连Wi-Fi导致活跃时间变长。解决确保在进入深度睡眠前所有外围设备如NeoPixel LED已被显式关闭magtag.peripherals.neopixels.fill(0)并magtag.peripherals.neopixels.show()。将设备移到信号好的地方。这个项目从硬件刷写、网络配置到代码编写、数据解析完整地走通了一个物联网设备的数据流闭环。它不仅仅是一个简单的显示器更是一个体现了低功耗设计、离线运行、定时任务等核心物联网概念的微型系统。当你看到自己制作的设备静静地贴在冰箱上每天自动更新着远方的数据时那种连接物理世界与数字世界的成就感正是硬件开发的乐趣所在。希望这份详细的指南能帮助你成功复现并理解这个项目并激发你创造出属于自己的物联网信息看板。如果在实践中遇到任何新的问题不妨回到串口监视器那里面打印的每一行日志都是设备与你最直接的对话。